wicked-crew 0.7.25 → 0.7.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/dist/api/endpoint-manifest-live.d.ts.map +1 -1
  2. package/dist/api/endpoint-manifest-live.js +5 -0
  3. package/dist/api/endpoint-manifest-live.js.map +1 -1
  4. package/dist/api/eval-compare.d.ts +306 -0
  5. package/dist/api/eval-compare.d.ts.map +1 -0
  6. package/dist/api/eval-compare.js +610 -0
  7. package/dist/api/eval-compare.js.map +1 -0
  8. package/dist/api/eval-sample.d.ts +158 -0
  9. package/dist/api/eval-sample.d.ts.map +1 -0
  10. package/dist/api/eval-sample.js +88 -0
  11. package/dist/api/eval-sample.js.map +1 -0
  12. package/dist/api/routes.d.ts +5 -0
  13. package/dist/api/routes.d.ts.map +1 -1
  14. package/dist/api/routes.js +31 -0
  15. package/dist/api/routes.js.map +1 -1
  16. package/dist/api/run-files.d.ts +12 -2
  17. package/dist/api/run-files.d.ts.map +1 -1
  18. package/dist/api/run-files.js +17 -5
  19. package/dist/api/run-files.js.map +1 -1
  20. package/dist/api/server.d.ts +20 -0
  21. package/dist/api/server.d.ts.map +1 -1
  22. package/dist/api/server.js +62 -9
  23. package/dist/api/server.js.map +1 -1
  24. package/dist/api/skills.d.ts +88 -0
  25. package/dist/api/skills.d.ts.map +1 -0
  26. package/dist/api/skills.js +264 -0
  27. package/dist/api/skills.js.map +1 -0
  28. package/dist/api/testing.d.ts +2 -75
  29. package/dist/api/testing.d.ts.map +1 -1
  30. package/dist/api/testing.js +14 -28
  31. package/dist/api/testing.js.map +1 -1
  32. package/dist/core/adapter.d.ts +42 -0
  33. package/dist/core/adapter.d.ts.map +1 -1
  34. package/dist/core/adapter.js +83 -12
  35. package/dist/core/adapter.js.map +1 -1
  36. package/dist/interactive/bridge-root.d.ts +117 -7
  37. package/dist/interactive/bridge-root.d.ts.map +1 -1
  38. package/dist/interactive/bridge-root.js +229 -9
  39. package/dist/interactive/bridge-root.js.map +1 -1
  40. package/dist/interactive/doc-delete-routes.d.ts +2 -0
  41. package/dist/interactive/doc-delete-routes.d.ts.map +1 -1
  42. package/dist/interactive/doc-delete-routes.js +3 -19
  43. package/dist/interactive/doc-delete-routes.js.map +1 -1
  44. package/dist/interactive/doc-list-routes.d.ts +42 -0
  45. package/dist/interactive/doc-list-routes.d.ts.map +1 -0
  46. package/dist/interactive/doc-list-routes.js +165 -0
  47. package/dist/interactive/doc-list-routes.js.map +1 -0
  48. package/dist/interactive/project-root.d.ts +36 -0
  49. package/dist/interactive/project-root.d.ts.map +1 -0
  50. package/dist/interactive/project-root.js +45 -0
  51. package/dist/interactive/project-root.js.map +1 -0
  52. package/dist/interactive/proxy-routes.d.ts +4 -1
  53. package/dist/interactive/proxy-routes.d.ts.map +1 -1
  54. package/dist/interactive/proxy-routes.js +4 -22
  55. package/dist/interactive/proxy-routes.js.map +1 -1
  56. package/dist/projects/default-project.d.ts +10 -0
  57. package/dist/projects/default-project.d.ts.map +1 -0
  58. package/dist/projects/default-project.js +10 -0
  59. package/dist/projects/default-project.js.map +1 -0
  60. package/dist/projects/routes.d.ts +0 -2
  61. package/dist/projects/routes.d.ts.map +1 -1
  62. package/dist/projects/routes.js +1 -2
  63. package/dist/projects/routes.js.map +1 -1
  64. package/dist/skills/bundle.d.ts +94 -0
  65. package/dist/skills/bundle.d.ts.map +1 -0
  66. package/dist/skills/bundle.js +187 -0
  67. package/dist/skills/bundle.js.map +1 -0
  68. package/dist/skills/contain.d.ts +57 -0
  69. package/dist/skills/contain.d.ts.map +1 -0
  70. package/dist/skills/contain.js +90 -0
  71. package/dist/skills/contain.js.map +1 -0
  72. package/dist/skills/core-closure.d.ts +83 -0
  73. package/dist/skills/core-closure.d.ts.map +1 -0
  74. package/dist/skills/core-closure.js +130 -0
  75. package/dist/skills/core-closure.js.map +1 -0
  76. package/dist/skills/engine-env.d.ts +48 -0
  77. package/dist/skills/engine-env.d.ts.map +1 -0
  78. package/dist/skills/engine-env.js +69 -0
  79. package/dist/skills/engine-env.js.map +1 -0
  80. package/dist/skills/frontmatter.d.ts +77 -0
  81. package/dist/skills/frontmatter.d.ts.map +1 -0
  82. package/dist/skills/frontmatter.js +190 -0
  83. package/dist/skills/frontmatter.js.map +1 -0
  84. package/dist/skills/guards.d.ts +72 -0
  85. package/dist/skills/guards.d.ts.map +1 -0
  86. package/dist/skills/guards.js +147 -0
  87. package/dist/skills/guards.js.map +1 -0
  88. package/dist/skills/live-generations.d.ts +80 -0
  89. package/dist/skills/live-generations.d.ts.map +1 -0
  90. package/dist/skills/live-generations.js +163 -0
  91. package/dist/skills/live-generations.js.map +1 -0
  92. package/dist/skills/plugin-source.d.ts +109 -0
  93. package/dist/skills/plugin-source.d.ts.map +1 -0
  94. package/dist/skills/plugin-source.js +272 -0
  95. package/dist/skills/plugin-source.js.map +1 -0
  96. package/dist/skills/refs.d.ts +58 -0
  97. package/dist/skills/refs.d.ts.map +1 -0
  98. package/dist/skills/refs.js +133 -0
  99. package/dist/skills/refs.js.map +1 -0
  100. package/dist/skills/root-fence.d.ts +53 -0
  101. package/dist/skills/root-fence.d.ts.map +1 -0
  102. package/dist/skills/root-fence.js +109 -0
  103. package/dist/skills/root-fence.js.map +1 -0
  104. package/dist/skills/root-names.d.ts +42 -0
  105. package/dist/skills/root-names.d.ts.map +1 -0
  106. package/dist/skills/root-names.js +44 -0
  107. package/dist/skills/root-names.js.map +1 -0
  108. package/dist/skills/runtime.d.ts +130 -0
  109. package/dist/skills/runtime.d.ts.map +1 -0
  110. package/dist/skills/runtime.js +246 -0
  111. package/dist/skills/runtime.js.map +1 -0
  112. package/dist/skills/store.d.ts +895 -0
  113. package/dist/skills/store.d.ts.map +1 -0
  114. package/dist/skills/store.js +3575 -0
  115. package/dist/skills/store.js.map +1 -0
  116. package/dist/skills/tree.d.ts +292 -0
  117. package/dist/skills/tree.d.ts.map +1 -0
  118. package/dist/skills/tree.js +645 -0
  119. package/dist/skills/tree.js.map +1 -0
  120. package/dist/skills/venv.d.ts +52 -0
  121. package/dist/skills/venv.d.ts.map +1 -0
  122. package/dist/skills/venv.js +80 -0
  123. package/dist/skills/venv.js.map +1 -0
  124. package/dist/studio/assets/index-CK1uJWs2.css +32 -0
  125. package/dist/studio/assets/index-FcZg3WDR.js +539 -0
  126. package/dist/studio/index.html +2 -2
  127. package/dist/studio/testid-inventory.json +605 -7
  128. package/endpoint-manifest.json +183 -1
  129. package/package.json +4 -3
  130. package/dist/studio/assets/index-C4iz4uAw.js +0 -537
  131. package/dist/studio/assets/index-DEEQcRQ_.css +0 -32
@@ -0,0 +1,69 @@
1
+ /**
2
+ * The engine handoff: `WICKED_SKILLS_SNAPSHOT` — exactly ONE variable (design v3 DECISION 2,
3
+ * v3.1 §2, v3.4 §2).
4
+ *
5
+ * wicked-core consumes exactly one skills input — the absolute REAL path of a published snapshot
6
+ * (`<state home>/skills/snapshots/<gen>`, every component — the LAST included — a real directory;
7
+ * never the `current` link itself and never a parent dir it would have to infer a manifest from;
8
+ * `WICKED_SKILLS_CURRENT` is withdrawn — v3.1 §2). Crew resolves `current` and exports the path
9
+ * here; the engine reads `process.env` per worker spawn (the `WICKED_WORKER_HOME` discipline in
10
+ * api/seat-signin.ts), so applying it at boot and after every publish is the whole mechanism — the
11
+ * next spawn sees the new snapshot, no daemon or engine restart.
12
+ *
13
+ * `WICKED_CREW_STATE_HOME` is RETIRED as an engine input (v3.4 §2 — it reverses the round-4
14
+ * "passed alongside" decision; core#399 pass 6 retires it on the engine side too). Core derives the
15
+ * state home it fences from the snapshot path's fixed layout — parent named `snapshots`,
16
+ * grandparent named `skills`, else a config error naming the path — so crew exports NOTHING beside
17
+ * the snapshot. The canonical state home is still REPORTED to humans (`GET /diagnostics` →
18
+ * `skills.stateHome`, `canonicalCrewStateHome()`); it is never an engine input.
19
+ *
20
+ * The degradation ladder (v3 §3) is the engine's: with the snapshot variable unset it falls back to
21
+ * the live installed garden cache and logs `skills.fallback`; with it set to a path that does not
22
+ * resolve, every launch FAILS loudly (config error). Crew uses both rungs deliberately
23
+ * (runtime.ts): a VERIFIED snapshot path when it has one; the boot value / unset ONLY when the
24
+ * configuration is absent (no garden installed — an operator-exported value, or the hermetic test
25
+ * arming, survives); and a non-existent refusal path (`<root>/refused/skills.{blocked,config}`)
26
+ * when the configuration is present but defective — a blocked first publish or a corrupt root
27
+ * must never be "restored" into a live-cache fallback that bypasses recorded disablement.
28
+ */
29
+ import { realpathSync } from 'node:fs';
30
+ import { resolve } from 'node:path';
31
+ import { crewStateHome } from '../projects/state-home.js';
32
+ export const SKILLS_SNAPSHOT_ENGINE_ENV = 'WICKED_SKILLS_SNAPSHOT';
33
+ /** The value this process BOOTED with (the `BOOT_WORKER_HOME` discipline): what "nothing to offer" restores. */
34
+ export const BOOT_SKILLS_SNAPSHOT = process.env[SKILLS_SNAPSHOT_ENGINE_ENV];
35
+ /**
36
+ * `crewStateHome()` with every link resolved — the spelling `GET /diagnostics` reports as
37
+ * `skills.stateHome` for humans (NOT an engine input, v3.4 §2). A state home that does not exist
38
+ * yet (a fresh `--db` parent before the first store lands) is spelled absolute, unresolved.
39
+ */
40
+ export function canonicalCrewStateHome() {
41
+ const home = crewStateHome();
42
+ try {
43
+ return realpathSync(home);
44
+ }
45
+ catch {
46
+ return resolve(home);
47
+ }
48
+ }
49
+ /**
50
+ * Point the engine at `snapshotPath`, or — when the daemon has no published snapshot — restore
51
+ * the booted value EXACTLY: deleted when the process booted without one, and PRESERVED when it
52
+ * booted with an explicitly empty one (design v3.5 §4, v3.1 restated: set-but-empty is a
53
+ * configuration error core refuses loudly; only an ABSENT variable reaches the live-cache fallback
54
+ * rung — converting `""` to "unset" would have opened that rung by accident). `fallback` is the
55
+ * boot value; tests pass it explicitly. Nothing else is exported: the snapshot path is the engine's
56
+ * ONE skills input (v3.4 §2).
57
+ */
58
+ export function applySkillsSnapshotEnv(snapshotPath, fallback = BOOT_SKILLS_SNAPSHOT) {
59
+ if (typeof snapshotPath === 'string' && snapshotPath !== '') {
60
+ process.env[SKILLS_SNAPSHOT_ENGINE_ENV] = snapshotPath;
61
+ }
62
+ else if (fallback === undefined) {
63
+ delete process.env[SKILLS_SNAPSHOT_ENGINE_ENV];
64
+ }
65
+ else {
66
+ process.env[SKILLS_SNAPSHOT_ENGINE_ENV] = fallback; // `''` included — preserved, never widened into "unset"
67
+ }
68
+ }
69
+ //# sourceMappingURL=engine-env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-env.js","sourceRoot":"","sources":["../../src/skills/engine-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE1D,MAAM,CAAC,MAAM,0BAA0B,GAAG,wBAAwB,CAAC;AAEnE,gHAAgH;AAChH,MAAM,CAAC,MAAM,oBAAoB,GAAuB,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;AAEhG;;;;GAIG;AACH,MAAM,UAAU,sBAAsB;IACpC,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC;IAC7B,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,sBAAsB,CACpC,YAAuC,EACvC,WAA+B,oBAAoB;IAEnD,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,KAAK,EAAE,EAAE,CAAC;QAC5D,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,GAAG,YAAY,CAAC;IACzD,CAAC;SAAM,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAClC,OAAO,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;IACjD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,GAAG,QAAQ,CAAC,CAAC,wDAAwD;IAC9G,CAAC;AACH,CAAC"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * SKILL.md frontmatter — the reader the skills store keys on, parsed by a REAL YAML grammar.
3
+ *
4
+ * A skill's identity in the manifest is its frontmatter `name` (verified against the live garden
5
+ * plugin: all 142 SKILL.md files carry `name: wicked-garden-<dir path joined by '-'>`, unique).
6
+ * Everything the store derives is a flat scalar — `name`, `context: fork`, `user-invocable: true`.
7
+ *
8
+ * Earlier passes hand-rolled a bracket-depth heuristic; it accepted invalid YAML a real parser
9
+ * rejects (`[a, {b: c]]`, `"bad\q"`, `"hello" "world"` — codex round 3). We now parse the block
10
+ * with the `yaml` library (the same grammar Claude Code loads a skill with) and refuse ANYTHING it
11
+ * rejects, then enforce a STRICT SUBSET on top:
12
+ *
13
+ * - a single YAML document that is a top-level MAPPING (`key: value` pairs) — not a sequence,
14
+ * not a bare scalar, not multiple documents;
15
+ * - `name`, if present, is a SCALAR (a mapping/sequence is refused — the manifest is keyed by it);
16
+ * - `mandates`, if present, is a LIST of non-empty STRINGS (a scalar/mapping, or an entry that is
17
+ * not a string, is refused).
18
+ *
19
+ * `fields` flattens the top-level scalars to strings (`user-invocable: true` → `"true"`,
20
+ * `name: "x"` → `"x"`) — the only shapes the store reads. A non-scalar value (a nested mapping the
21
+ * strict checks above do not forbid for that key) is serialized to JSON so `fields` stays a flat
22
+ * `Record<string, string>`; the store never reads those.
23
+ *
24
+ * `mandates` is ALSO handed out structurally (`MandateDecl[]`): the qualified name each entry
25
+ * spells AS THE PARSER DECODED IT (`"wicked-garden-gamma"` is `wicked-garden-gamma`; the Claude
26
+ * plugin form `wicked-garden:x` is normalized to `wicked-garden-x`) with the 1-based line of the
27
+ * entry, taken from the YAML node's range — never from a regex over the raw block (codex round 4:
28
+ * the core closure used to find mandates by scanning raw text, so an escaped scalar hid one).
29
+ */
30
+ import type { SkillKind } from '../core/types.js';
31
+ /** One declared mandate: the catalog name it spells (normalized) and its 1-based line in the file. */
32
+ export interface MandateDecl {
33
+ name: string;
34
+ line: number;
35
+ }
36
+ export type FrontmatterResult = {
37
+ ok: true;
38
+ fields: Record<string, string>;
39
+ mandates: MandateDecl[];
40
+ } | {
41
+ ok: false;
42
+ reason: string;
43
+ };
44
+ /**
45
+ * `text` with its frontmatter block (both fences included) replaced by blank lines — the same
46
+ * line count, so a line number found in the result is a line number in the file. Prose scans
47
+ * (core-closure.ts) run over THIS, never over the frontmatter: a declared mandate comes from the
48
+ * parser (`parseFrontmatter().mandates`), a frontmatter scalar is not prose. A text without a
49
+ * complete frontmatter block is returned unchanged (its guard reports the missing fence).
50
+ */
51
+ export declare function bodyWithFrontmatterBlanked(text: string): string;
52
+ /**
53
+ * Parse the frontmatter block at the top of `text` with a real YAML parser and enforce the strict
54
+ * subset (single-document mapping, scalar `name`, list `mandates`). Anything the parser rejects is
55
+ * a parse failure carrying the parser's own reason; a well-formed block yields the flat scalar
56
+ * `fields` the store keys on.
57
+ */
58
+ export declare function parseFrontmatter(text: string): FrontmatterResult;
59
+ /** The catalog name a declared mandate spells: the Claude plugin form `wicked-garden:x` is `wicked-garden-x`. */
60
+ export declare function qualifiedSkillName(raw: string): string;
61
+ /**
62
+ * The skill kind the frontmatter declares (design v3 §5, fork-first): `context: fork` is a fork
63
+ * worker (a subagent body) even when it is also user-invocable (`archetype`, `smaht`);
64
+ * `user-invocable: true` a router (an operator-facing entry point); everything else a module (a
65
+ * nested reference skill routers/workers pull in).
66
+ */
67
+ export declare function skillKindOf(fields: Readonly<Record<string, string>>): SkillKind;
68
+ /** The plugin the effective root impersonates — the identity workers already invoke skills under. */
69
+ export declare const PLUGIN_NAME = "wicked-garden";
70
+ /** Every manifest key carries this prefix: `wicked-garden-<dir segments joined by '-'>`. */
71
+ export declare const SKILL_NAME_PREFIX = "wicked-garden-";
72
+ /**
73
+ * The frontmatter name a skill at `skills/<relDir>` must declare — `relDir` is POSIX-relative to
74
+ * the plugin's `skills/` directory (`engineering/frontend` → `wicked-garden-engineering-frontend`).
75
+ */
76
+ export declare function derivedSkillName(relDir: string): string;
77
+ //# sourceMappingURL=frontmatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/skills/frontmatter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,sGAAsG;AACtG,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,QAAQ,EAAE,WAAW,EAAE,CAAA;CAAE,GACrE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAgBlC;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO/D;AAUD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAgDhE;AA8BD,iHAAiH;AACjH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAI/E;AAED,qGAAqG;AACrG,eAAO,MAAM,WAAW,kBAAkB,CAAC;AAE3C,4FAA4F;AAC5F,eAAO,MAAM,iBAAiB,mBAAoB,CAAC;AAEnD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEvD"}
@@ -0,0 +1,190 @@
1
+ /**
2
+ * SKILL.md frontmatter — the reader the skills store keys on, parsed by a REAL YAML grammar.
3
+ *
4
+ * A skill's identity in the manifest is its frontmatter `name` (verified against the live garden
5
+ * plugin: all 142 SKILL.md files carry `name: wicked-garden-<dir path joined by '-'>`, unique).
6
+ * Everything the store derives is a flat scalar — `name`, `context: fork`, `user-invocable: true`.
7
+ *
8
+ * Earlier passes hand-rolled a bracket-depth heuristic; it accepted invalid YAML a real parser
9
+ * rejects (`[a, {b: c]]`, `"bad\q"`, `"hello" "world"` — codex round 3). We now parse the block
10
+ * with the `yaml` library (the same grammar Claude Code loads a skill with) and refuse ANYTHING it
11
+ * rejects, then enforce a STRICT SUBSET on top:
12
+ *
13
+ * - a single YAML document that is a top-level MAPPING (`key: value` pairs) — not a sequence,
14
+ * not a bare scalar, not multiple documents;
15
+ * - `name`, if present, is a SCALAR (a mapping/sequence is refused — the manifest is keyed by it);
16
+ * - `mandates`, if present, is a LIST of non-empty STRINGS (a scalar/mapping, or an entry that is
17
+ * not a string, is refused).
18
+ *
19
+ * `fields` flattens the top-level scalars to strings (`user-invocable: true` → `"true"`,
20
+ * `name: "x"` → `"x"`) — the only shapes the store reads. A non-scalar value (a nested mapping the
21
+ * strict checks above do not forbid for that key) is serialized to JSON so `fields` stays a flat
22
+ * `Record<string, string>`; the store never reads those.
23
+ *
24
+ * `mandates` is ALSO handed out structurally (`MandateDecl[]`): the qualified name each entry
25
+ * spells AS THE PARSER DECODED IT (`"wicked-garden-gamma"` is `wicked-garden-gamma`; the Claude
26
+ * plugin form `wicked-garden:x` is normalized to `wicked-garden-x`) with the 1-based line of the
27
+ * entry, taken from the YAML node's range — never from a regex over the raw block (codex round 4:
28
+ * the core closure used to find mandates by scanning raw text, so an escaped scalar hid one).
29
+ */
30
+ import { isScalar, isSeq, parseDocument } from 'yaml';
31
+ const OPEN_FENCE = '---\n';
32
+ /** Find the closing fence: a `---` line by itself after the opening fence, or -1. */
33
+ function closingFence(src) {
34
+ let from = OPEN_FENCE.length;
35
+ for (;;) {
36
+ const i = src.indexOf('\n---', from);
37
+ if (i < 0)
38
+ return -1;
39
+ const after = src.charAt(i + 4);
40
+ if (after === '' || after === '\n')
41
+ return i;
42
+ from = i + 4;
43
+ }
44
+ }
45
+ /**
46
+ * `text` with its frontmatter block (both fences included) replaced by blank lines — the same
47
+ * line count, so a line number found in the result is a line number in the file. Prose scans
48
+ * (core-closure.ts) run over THIS, never over the frontmatter: a declared mandate comes from the
49
+ * parser (`parseFrontmatter().mandates`), a frontmatter scalar is not prose. A text without a
50
+ * complete frontmatter block is returned unchanged (its guard reports the missing fence).
51
+ */
52
+ export function bodyWithFrontmatterBlanked(text) {
53
+ const src = text.replace(/\r\n/g, '\n');
54
+ if (!src.startsWith(OPEN_FENCE))
55
+ return src;
56
+ const close = closingFence(src);
57
+ if (close < 0)
58
+ return src;
59
+ const end = close + 4; // through the closing `---`
60
+ return src.slice(0, end).replace(/[^\n]/g, '') + src.slice(end);
61
+ }
62
+ /** Flatten one top-level YAML value to the string `fields` carries (only scalars are ever read). */
63
+ function fieldValue(value) {
64
+ if (value === null || value === undefined)
65
+ return '';
66
+ if (typeof value === 'string')
67
+ return value;
68
+ if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint')
69
+ return String(value);
70
+ return JSON.stringify(value);
71
+ }
72
+ /**
73
+ * Parse the frontmatter block at the top of `text` with a real YAML parser and enforce the strict
74
+ * subset (single-document mapping, scalar `name`, list `mandates`). Anything the parser rejects is
75
+ * a parse failure carrying the parser's own reason; a well-formed block yields the flat scalar
76
+ * `fields` the store keys on.
77
+ */
78
+ export function parseFrontmatter(text) {
79
+ const src = text.replace(/\r\n/g, '\n');
80
+ if (!src.startsWith(OPEN_FENCE)) {
81
+ return { ok: false, reason: 'missing opening `---` fence on line 1' };
82
+ }
83
+ const close = closingFence(src);
84
+ if (close < 0)
85
+ return { ok: false, reason: 'missing closing `---` fence' };
86
+ const block = src.slice(OPEN_FENCE.length, close);
87
+ let doc;
88
+ try {
89
+ // `uniqueKeys` (default true) rejects duplicate keys; the block carries no internal `---`, so
90
+ // a single document is parsed. Any grammar error lands in `doc.errors` (parseDocument does not throw).
91
+ doc = parseDocument(block, { prettyErrors: false });
92
+ }
93
+ catch (err) {
94
+ return { ok: false, reason: err instanceof Error ? err.message : String(err) };
95
+ }
96
+ if (doc.errors.length > 0) {
97
+ return { ok: false, reason: doc.errors[0]?.message ?? 'invalid YAML' };
98
+ }
99
+ let js;
100
+ try {
101
+ js = doc.toJS();
102
+ }
103
+ catch (err) {
104
+ return { ok: false, reason: err instanceof Error ? err.message : String(err) };
105
+ }
106
+ // An empty block (only comments / blank lines) is a valid, name-less frontmatter — the caller's
107
+ // `name` guard reports the missing name; here it is simply an empty mapping.
108
+ if (js === null || js === undefined)
109
+ return { ok: true, fields: {}, mandates: [] };
110
+ if (typeof js !== 'object' || Array.isArray(js)) {
111
+ return { ok: false, reason: 'frontmatter must be a single YAML mapping (`key: value` pairs), not a sequence or a bare scalar' };
112
+ }
113
+ const obj = js;
114
+ if (Object.hasOwn(obj, 'name')) {
115
+ const name = obj['name'];
116
+ if (name !== null && typeof name === 'object') {
117
+ return { ok: false, reason: '`name` must be a scalar — the manifest is keyed by it' };
118
+ }
119
+ }
120
+ if (Object.hasOwn(obj, 'mandates') && !Array.isArray(obj['mandates'])) {
121
+ return { ok: false, reason: '`mandates` must be a YAML list' };
122
+ }
123
+ const mandates = Object.hasOwn(obj, 'mandates') ? declaredMandates(doc, block) : [];
124
+ if (typeof mandates === 'string')
125
+ return { ok: false, reason: mandates };
126
+ const fields = {};
127
+ for (const [key, value] of Object.entries(obj))
128
+ fields[key] = fieldValue(value);
129
+ return { ok: true, fields, mandates };
130
+ }
131
+ /**
132
+ * The `mandates` list as the PARSER holds it: every entry a non-empty string scalar (its decoded
133
+ * value — escapes resolved), positioned by its node range. Anything else is a strict-subset
134
+ * failure (the reason), so a mandate can neither hide behind an escape nor be a shape the closure
135
+ * cannot read.
136
+ */
137
+ function declaredMandates(doc, block) {
138
+ const node = doc.get('mandates', true);
139
+ if (!isSeq(node))
140
+ return '`mandates` must be a YAML list';
141
+ const out = [];
142
+ for (const item of node.items) {
143
+ if (!isScalar(item) || typeof item.value !== 'string' || item.value === '') {
144
+ return '`mandates` entries must be non-empty strings (qualified skill names)';
145
+ }
146
+ out.push({ name: qualifiedSkillName(item.value), line: lineOf(block, item.range?.[0] ?? node.range?.[0]) });
147
+ }
148
+ return out;
149
+ }
150
+ /** 1-based line in the FILE of `offset` into the frontmatter block (the block starts on line 2). */
151
+ function lineOf(block, offset) {
152
+ let line = 2;
153
+ if (offset === undefined)
154
+ return line;
155
+ const upto = Math.min(offset, block.length);
156
+ for (let i = 0; i < upto; i += 1)
157
+ if (block.charCodeAt(i) === 10)
158
+ line += 1;
159
+ return line;
160
+ }
161
+ /** The catalog name a declared mandate spells: the Claude plugin form `wicked-garden:x` is `wicked-garden-x`. */
162
+ export function qualifiedSkillName(raw) {
163
+ const colon = `${PLUGIN_NAME}:`;
164
+ return raw.startsWith(colon) ? SKILL_NAME_PREFIX + raw.slice(colon.length) : raw;
165
+ }
166
+ /**
167
+ * The skill kind the frontmatter declares (design v3 §5, fork-first): `context: fork` is a fork
168
+ * worker (a subagent body) even when it is also user-invocable (`archetype`, `smaht`);
169
+ * `user-invocable: true` a router (an operator-facing entry point); everything else a module (a
170
+ * nested reference skill routers/workers pull in).
171
+ */
172
+ export function skillKindOf(fields) {
173
+ if (fields['context'] === 'fork')
174
+ return 'fork-worker';
175
+ if (fields['user-invocable'] === 'true')
176
+ return 'router';
177
+ return 'module';
178
+ }
179
+ /** The plugin the effective root impersonates — the identity workers already invoke skills under. */
180
+ export const PLUGIN_NAME = 'wicked-garden';
181
+ /** Every manifest key carries this prefix: `wicked-garden-<dir segments joined by '-'>`. */
182
+ export const SKILL_NAME_PREFIX = `${PLUGIN_NAME}-`;
183
+ /**
184
+ * The frontmatter name a skill at `skills/<relDir>` must declare — `relDir` is POSIX-relative to
185
+ * the plugin's `skills/` directory (`engineering/frontend` → `wicked-garden-engineering-frontend`).
186
+ */
187
+ export function derivedSkillName(relDir) {
188
+ return SKILL_NAME_PREFIX + relDir.split('/').join('-');
189
+ }
190
+ //# sourceMappingURL=frontmatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/skills/frontmatter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Deterministic guards on every skills write/enable (design v3 §API) — v1 has NO semantic analyzer;
3
+ * these are the checks a file manager can decide from the manifest and the bytes alone, answered
4
+ * identically on every daemon:
5
+ *
6
+ * - name charset + prefix; name UNIQUE across the FULL catalog, disabled skills included
7
+ * (a manifest is keyed by name — a duplicate is a blocking collision, annotated with whether
8
+ * the skill it collides with is core-by-reference, so the UI can say why it matters);
9
+ * - the SKILL.md frontmatter parses and its `name` equals the path-derived name (a rename in
10
+ * place would desynchronize the manifest key, the invocation identity, and the directory);
11
+ * - disabling or renaming a core-by-reference skill is blocking — a governed run would dispatch
12
+ * a phase whose skill is gone from the snapshot;
13
+ * - a `SKILL.md` anywhere but a skill's root is blocking: it would create an unregistered nested
14
+ * skill through the parent's endpoint (nested ownership, v3 §6) — `POST /skills` adds skills;
15
+ * - an edit under `scripts/` or `schemas/` (a skill's own, or the root support tree) is allowed
16
+ * but a WARNING: those files back behavior, not prose, and every invocation shares them;
17
+ * - content that makes a skill non-portable (`${CLAUDE_PLUGIN_ROOT}`, cwd-relative scripts,
18
+ * `../` links) is a warning: the skill becomes Claude-only and leaves every non-Claude
19
+ * delivery view (`views/copilot/`, the per-launch `--skill` lists core builds).
20
+ *
21
+ * `{verdict, findings[]}` is the ONE result shape; a mutation with a `blocked` verdict writes nothing.
22
+ * Publish-time validation (unresolved refs, core closure, drift) lives in the store — it needs the
23
+ * whole tree.
24
+ */
25
+ import type { SkillConflictFinding, SkillFindingKind, SkillFindingSeverity, SkillVerdict } from '../core/types.js';
26
+ /** The name charset — a manifest key, a directory segment, and a URL path segment at once. */
27
+ export declare const SKILL_NAME_RE: RegExp;
28
+ /** The catalog facts the guards consult — structural, so the store hands its manifest in directly. */
29
+ export interface CatalogEntryView {
30
+ core: boolean;
31
+ enabled: boolean;
32
+ dir: string;
33
+ }
34
+ export type CatalogView = Readonly<Record<string, CatalogEntryView>>;
35
+ export interface FindingAnchor {
36
+ skill?: string | null;
37
+ file?: string | null;
38
+ line?: number | null;
39
+ against?: {
40
+ name: string;
41
+ core: boolean;
42
+ };
43
+ }
44
+ export declare function finding(kind: SkillFindingKind, severity: SkillFindingSeverity, explanation: string, evidence: string, anchor?: FindingAnchor): SkillConflictFinding;
45
+ /** `blocked` when any finding blocks, `warnings` when any warns, `clear` otherwise. */
46
+ export declare function verdictOf(findings: ReadonlyArray<SkillConflictFinding>): SkillVerdict;
47
+ /** Charset + the `wicked-garden-` prefix with a non-empty remainder. */
48
+ export declare function nameGuard(name: string): SkillConflictFinding | null;
49
+ /** Unique across the FULL catalog, disabled skills included. */
50
+ export declare function collisionGuard(catalog: CatalogView, name: string): SkillConflictFinding | null;
51
+ /**
52
+ * The SKILL.md body must carry parseable frontmatter whose `name` is exactly `expectedName`.
53
+ * A mismatch on a core skill additionally reports `core-rename` — the workflow that names it
54
+ * would dispatch into a void. `severity` lets publish-time validation downgrade a DISABLED
55
+ * skill's defects to warnings (it is not in the snapshot).
56
+ */
57
+ export declare function frontmatterGuard(skillMd: string | undefined, expectedName: string, opts: {
58
+ isCore: boolean;
59
+ file: string;
60
+ severity?: SkillFindingSeverity;
61
+ }): SkillConflictFinding[];
62
+ /** A path under `scripts/` or `schemas/` → warning. `rel` is relative to the tree being edited. */
63
+ export declare function supportFileGuard(rel: string, skill: string | null): SkillConflictFinding | null;
64
+ /** A `SKILL.md` anywhere but the skill root would create an unregistered nested skill → blocking. */
65
+ export declare function nestedSkillCreateGuard(rel: string, skill: string): SkillConflictFinding | null;
66
+ /** Content that makes a skill non-portable → warning (it leaves every non-Claude delivery view). */
67
+ export declare function nonPortableGuard(files: Readonly<Record<string, string>>, skill: string): SkillConflictFinding | null;
68
+ /** Disabling a core-by-reference skill is blocking. */
69
+ export declare function coreDisableGuard(name: string, entry: CatalogEntryView): SkillConflictFinding | null;
70
+ /** Reset needs a baseline; a user-added skill has none. */
71
+ export declare function noBaselineGuard(name: string, userAdded: boolean): SkillConflictFinding | null;
72
+ //# sourceMappingURL=guards.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../../src/skills/guards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EACV,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,YAAY,EACb,MAAM,kBAAkB,CAAC;AAI1B,8FAA8F;AAC9F,eAAO,MAAM,aAAa,QAAqB,CAAC;AAKhD,sGAAsG;AACtG,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AACD,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAErE,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC;CAC3C;AAED,wBAAgB,OAAO,CACrB,IAAI,EAAE,gBAAgB,EACtB,QAAQ,EAAE,oBAAoB,EAC9B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,aAAkB,GACzB,oBAAoB,CAYtB;AAED,uFAAuF;AACvF,wBAAgB,SAAS,CAAC,QAAQ,EAAE,aAAa,CAAC,oBAAoB,CAAC,GAAG,YAAY,CAIrF;AAED,wEAAwE;AACxE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI,CAoBnE;AAED,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI,CAY9F;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,oBAAoB,CAAA;CAAE,GACvE,oBAAoB,EAAE,CA8DxB;AAED,mGAAmG;AACnG,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,oBAAoB,GAAG,IAAI,CAS/F;AAED,qGAAqG;AACrG,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI,CAS9F;AAQD,oGAAoG;AACpG,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACvC,KAAK,EAAE,MAAM,GACZ,oBAAoB,GAAG,IAAI,CAa7B;AAED,uDAAuD;AACvD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,oBAAoB,GAAG,IAAI,CASnG;AAED,2DAA2D;AAC3D,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,oBAAoB,GAAG,IAAI,CAS7F"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Deterministic guards on every skills write/enable (design v3 §API) — v1 has NO semantic analyzer;
3
+ * these are the checks a file manager can decide from the manifest and the bytes alone, answered
4
+ * identically on every daemon:
5
+ *
6
+ * - name charset + prefix; name UNIQUE across the FULL catalog, disabled skills included
7
+ * (a manifest is keyed by name — a duplicate is a blocking collision, annotated with whether
8
+ * the skill it collides with is core-by-reference, so the UI can say why it matters);
9
+ * - the SKILL.md frontmatter parses and its `name` equals the path-derived name (a rename in
10
+ * place would desynchronize the manifest key, the invocation identity, and the directory);
11
+ * - disabling or renaming a core-by-reference skill is blocking — a governed run would dispatch
12
+ * a phase whose skill is gone from the snapshot;
13
+ * - a `SKILL.md` anywhere but a skill's root is blocking: it would create an unregistered nested
14
+ * skill through the parent's endpoint (nested ownership, v3 §6) — `POST /skills` adds skills;
15
+ * - an edit under `scripts/` or `schemas/` (a skill's own, or the root support tree) is allowed
16
+ * but a WARNING: those files back behavior, not prose, and every invocation shares them;
17
+ * - content that makes a skill non-portable (`${CLAUDE_PLUGIN_ROOT}`, cwd-relative scripts,
18
+ * `../` links) is a warning: the skill becomes Claude-only and leaves every non-Claude
19
+ * delivery view (`views/copilot/`, the per-launch `--skill` lists core builds).
20
+ *
21
+ * `{verdict, findings[]}` is the ONE result shape; a mutation with a `blocked` verdict writes nothing.
22
+ * Publish-time validation (unresolved refs, core closure, drift) lives in the store — it needs the
23
+ * whole tree.
24
+ */
25
+ import { parseFrontmatter, SKILL_NAME_PREFIX } from './frontmatter.js';
26
+ import { portabilityIssueOf } from './refs.js';
27
+ /** The name charset — a manifest key, a directory segment, and a URL path segment at once. */
28
+ export const SKILL_NAME_RE = /^[A-Za-z0-9_-]+$/;
29
+ /** Support-file prefixes inside a skill dir — behavior, not prose (design v3 §API). */
30
+ const SUPPORT_PREFIXES = ['scripts/', 'schemas/'];
31
+ export function finding(kind, severity, explanation, evidence, anchor = {}) {
32
+ return {
33
+ kind,
34
+ severity,
35
+ skill: anchor.skill ?? null,
36
+ file: anchor.file ?? null,
37
+ line: anchor.line ?? null,
38
+ againstSkill: anchor.against?.name ?? null,
39
+ againstIsCore: anchor.against?.core ?? false,
40
+ evidence,
41
+ explanation,
42
+ };
43
+ }
44
+ /** `blocked` when any finding blocks, `warnings` when any warns, `clear` otherwise. */
45
+ export function verdictOf(findings) {
46
+ if (findings.some((f) => f.severity === 'blocking'))
47
+ return 'blocked';
48
+ if (findings.length > 0)
49
+ return 'warnings';
50
+ return 'clear';
51
+ }
52
+ /** Charset + the `wicked-garden-` prefix with a non-empty remainder. */
53
+ export function nameGuard(name) {
54
+ if (!SKILL_NAME_RE.test(name)) {
55
+ return finding('name-invalid', 'blocking', 'a skill name is a manifest key, a directory segment, and a URL segment — only [A-Za-z0-9_-] is safe in all three', `name ${JSON.stringify(name)} does not match ${SKILL_NAME_RE.source}`, { skill: name });
56
+ }
57
+ if (!name.startsWith(SKILL_NAME_PREFIX) || name.length === SKILL_NAME_PREFIX.length) {
58
+ return finding('name-invalid', 'blocking', `workers invoke skills as \`${SKILL_NAME_PREFIX.slice(0, -1)}:<dir>\`; the frontmatter name must be \`${SKILL_NAME_PREFIX}<dir>\` so the manifest key and the invocation identity stay one thing`, `name ${JSON.stringify(name)} lacks the \`${SKILL_NAME_PREFIX}\` prefix (or has nothing after it)`, { skill: name });
59
+ }
60
+ return null;
61
+ }
62
+ /** Unique across the FULL catalog, disabled skills included. */
63
+ export function collisionGuard(catalog, name) {
64
+ const existing = catalog[name];
65
+ if (existing === undefined)
66
+ return null;
67
+ return finding('name-collision', 'blocking', existing.core
68
+ ? 'this name is a core-by-reference skill (a registered workflow dispatches phases to it); replace it through its own replace action instead of adding a second definition'
69
+ : 'the catalog already has a skill with this name (disabled skills count — the manifest is keyed by name); use replace to override it', `${name} exists at ${existing.dir} (${existing.enabled ? 'enabled' : 'disabled'})`, { skill: name, against: { name, core: existing.core } });
70
+ }
71
+ /**
72
+ * The SKILL.md body must carry parseable frontmatter whose `name` is exactly `expectedName`.
73
+ * A mismatch on a core skill additionally reports `core-rename` — the workflow that names it
74
+ * would dispatch into a void. `severity` lets publish-time validation downgrade a DISABLED
75
+ * skill's defects to warnings (it is not in the snapshot).
76
+ */
77
+ export function frontmatterGuard(skillMd, expectedName, opts) {
78
+ const severity = opts.severity ?? 'blocking';
79
+ const anchor = { skill: expectedName, file: opts.file };
80
+ if (skillMd === undefined) {
81
+ return [
82
+ finding('missing-skill-md', severity, 'a skill is its SKILL.md — the files map must include one at the skill root', `no SKILL.md at ${opts.file}`, anchor),
83
+ ];
84
+ }
85
+ const parsed = parseFrontmatter(skillMd);
86
+ if (!parsed.ok) {
87
+ return [
88
+ finding('frontmatter-invalid', severity, 'Claude Code discovers a skill from its frontmatter; a body it cannot parse is a skill that silently vanishes from every worker', `${opts.file} frontmatter: ${parsed.reason}`, anchor),
89
+ ];
90
+ }
91
+ const declared = parsed.fields['name'];
92
+ if (declared === undefined || declared === '') {
93
+ return [
94
+ finding('frontmatter-invalid', severity, 'the manifest is keyed by the frontmatter `name`', `${opts.file} frontmatter has no \`name\``, anchor),
95
+ ];
96
+ }
97
+ if (declared !== expectedName) {
98
+ const out = [
99
+ finding('name-mismatch', severity, `the frontmatter name must equal the path-derived name (\`${SKILL_NAME_PREFIX}<dir segments joined by '-'>\`) — the manifest key, the directory, and the invocation identity are one thing`, `frontmatter name ${JSON.stringify(declared)} ≠ expected ${JSON.stringify(expectedName)}`, anchor),
100
+ ];
101
+ if (opts.isCore) {
102
+ out.push(finding('core-rename', 'blocking', 'a registered workflow dispatches phases to this skill by name; renaming it strands those phases', `${expectedName} is core-by-reference`, { ...anchor, against: { name: expectedName, core: true } }));
103
+ }
104
+ return out;
105
+ }
106
+ return [];
107
+ }
108
+ /** A path under `scripts/` or `schemas/` → warning. `rel` is relative to the tree being edited. */
109
+ export function supportFileGuard(rel, skill) {
110
+ if (!SUPPORT_PREFIXES.some((p) => rel.startsWith(p)))
111
+ return null;
112
+ return finding('support-file-edit', 'warning', "support files back the skill's behavior (scripts run, schemas validate) and are shared by every invocation — an edit here changes what the skill DOES, not what it says", `edit under ${rel.split('/')[0] ?? rel}/: ${rel}`, { skill, file: rel });
113
+ }
114
+ /** A `SKILL.md` anywhere but the skill root would create an unregistered nested skill → blocking. */
115
+ export function nestedSkillCreateGuard(rel, skill) {
116
+ if (rel === 'SKILL.md' || !rel.endsWith('/SKILL.md'))
117
+ return null;
118
+ return finding('nested-skill-create', 'blocking', "a SKILL.md defines a skill; placing one inside another skill's tree through that skill's endpoint would create a nested skill the manifest never registered — add skills with POST /skills", `${rel} would define a nested skill under ${skill}`, { skill, file: rel });
119
+ }
120
+ const PORTABILITY_EXPLANATION = {
121
+ 'plugin-root': 'the content resolves `${CLAUDE_PLUGIN_ROOT}`, which only Claude Code provides',
122
+ 'cwd-script': 'the content invokes a plugin script relative to the worktree cwd, which only the Claude plugin path arranges',
123
+ 'relative-link': 'the content links a sibling via `../`, which the flat `<name>/SKILL.md` layout of every non-Claude view cannot follow',
124
+ };
125
+ /** Content that makes a skill non-portable → warning (it leaves every non-Claude delivery view). */
126
+ export function nonPortableGuard(files, skill) {
127
+ for (const rel of Object.keys(files).sort()) {
128
+ const issue = portabilityIssueOf(files[rel] ?? '');
129
+ if (issue === null)
130
+ continue;
131
+ return finding('non-portable', 'warning', `${PORTABILITY_EXPLANATION[issue]}; the skill becomes Claude-only — excluded from the snapshot's copilot view and from the per-launch skill lists core builds for pi/opencode, so a non-Claude seat that requires it is refused at launch`, `${rel}: ${issue}`, { skill, file: rel });
132
+ }
133
+ return null;
134
+ }
135
+ /** Disabling a core-by-reference skill is blocking. */
136
+ export function coreDisableGuard(name, entry) {
137
+ if (!entry.core)
138
+ return null;
139
+ return finding('core-disable', 'blocking', 'a registered workflow dispatches phases to this skill by name (`skill_ref`), directly or through a skill it mandates; disabling it would publish a snapshot those phases cannot run from', `${name} is core-by-reference`, { skill: name, against: { name, core: true } });
140
+ }
141
+ /** Reset needs a baseline; a user-added skill has none. */
142
+ export function noBaselineGuard(name, userAdded) {
143
+ if (!userAdded)
144
+ return null;
145
+ return finding('no-baseline', 'blocking', 'reset restores a skill from its shipped baseline; a user-added skill has none', `${name} is user-added`, { skill: name });
146
+ }
147
+ //# sourceMappingURL=guards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.js","sourceRoot":"","sources":["../../src/skills/guards.ts"],"names":[],"mappings":"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"}