feat(cli): files kind in manifest + reconcile (§11.6 files C4)

- manifest: add CollectionKind::Files (+ "files" in as_str()); the
  string-or-table `collections` form now accepts { name, kind = "files" }.
- apply_service: add "files" to COLLECTION_KINDS. The rest of the
  reconcile (CollectionSpec, diff_collections, validate_bundle,
  state_token, the app-owner rejection) is already kind-generic.
- `pic collections ls` shows the files kind with no code change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-30 19:48:16 +02:00
parent e7c0485dbf
commit 17221a2683
2 changed files with 6 additions and 2 deletions

View File

@@ -110,7 +110,7 @@ fn default_collection_kind() -> String {
} }
/// The shared-collection kinds the apply engine accepts. /// The shared-collection kinds the apply engine accepts.
const COLLECTION_KINDS: &[&str] = &["kv", "docs"]; const COLLECTION_KINDS: &[&str] = &["kv", "docs", "files"];
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct BundleScript { pub struct BundleScript {

View File

@@ -269,6 +269,7 @@ pub struct ManifestGroup {
pub enum CollectionKind { pub enum CollectionKind {
Kv, Kv,
Docs, Docs,
Files,
} }
impl CollectionKind { impl CollectionKind {
@@ -277,6 +278,7 @@ impl CollectionKind {
match self { match self {
Self::Kv => "kv", Self::Kv => "kv",
Self::Docs => "docs", Self::Docs => "docs",
Self::Files => "files",
} }
} }
} }
@@ -726,7 +728,8 @@ mod tests {
// `{ name, kind }` table sets an explicit kind. Both coexist. // `{ name, kind }` table sets an explicit kind. Both coexist.
let m = Manifest::parse( let m = Manifest::parse(
"[group]\nslug = \"acme\"\nname = \"ACME\"\n\n\ "[group]\nslug = \"acme\"\nname = \"ACME\"\n\n\
collections = [\"catalog\", { name = \"articles\", kind = \"docs\" }]\n", collections = [\"catalog\", { name = \"articles\", kind = \"docs\" }, \
{ name = \"assets\", kind = \"files\" }]\n",
) )
.expect("string-or-table collections must parse"); .expect("string-or-table collections must parse");
assert_eq!( assert_eq!(
@@ -734,6 +737,7 @@ mod tests {
vec![ vec![
("catalog".to_string(), "kv".to_string()), ("catalog".to_string(), "kv".to_string()),
("articles".to_string(), "docs".to_string()), ("articles".to_string(), "docs".to_string()),
("assets".to_string(), "files".to_string()),
] ]
); );
// An app manifest carrying `collections` is rejected (no such field + // An app manifest carrying `collections` is rejected (no such field +