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.
- package/dist/api/endpoint-manifest-live.d.ts.map +1 -1
- package/dist/api/endpoint-manifest-live.js +5 -0
- package/dist/api/endpoint-manifest-live.js.map +1 -1
- package/dist/api/eval-compare.d.ts +306 -0
- package/dist/api/eval-compare.d.ts.map +1 -0
- package/dist/api/eval-compare.js +610 -0
- package/dist/api/eval-compare.js.map +1 -0
- package/dist/api/eval-sample.d.ts +158 -0
- package/dist/api/eval-sample.d.ts.map +1 -0
- package/dist/api/eval-sample.js +88 -0
- package/dist/api/eval-sample.js.map +1 -0
- package/dist/api/routes.d.ts +5 -0
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +31 -0
- package/dist/api/routes.js.map +1 -1
- package/dist/api/run-files.d.ts +12 -2
- package/dist/api/run-files.d.ts.map +1 -1
- package/dist/api/run-files.js +17 -5
- package/dist/api/run-files.js.map +1 -1
- package/dist/api/server.d.ts +20 -0
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +62 -9
- package/dist/api/server.js.map +1 -1
- package/dist/api/skills.d.ts +88 -0
- package/dist/api/skills.d.ts.map +1 -0
- package/dist/api/skills.js +264 -0
- package/dist/api/skills.js.map +1 -0
- package/dist/api/testing.d.ts +2 -75
- package/dist/api/testing.d.ts.map +1 -1
- package/dist/api/testing.js +14 -28
- package/dist/api/testing.js.map +1 -1
- package/dist/core/adapter.d.ts +42 -0
- package/dist/core/adapter.d.ts.map +1 -1
- package/dist/core/adapter.js +83 -12
- package/dist/core/adapter.js.map +1 -1
- package/dist/interactive/bridge-root.d.ts +117 -7
- package/dist/interactive/bridge-root.d.ts.map +1 -1
- package/dist/interactive/bridge-root.js +229 -9
- package/dist/interactive/bridge-root.js.map +1 -1
- package/dist/interactive/doc-delete-routes.d.ts +2 -0
- package/dist/interactive/doc-delete-routes.d.ts.map +1 -1
- package/dist/interactive/doc-delete-routes.js +3 -19
- package/dist/interactive/doc-delete-routes.js.map +1 -1
- package/dist/interactive/doc-list-routes.d.ts +42 -0
- package/dist/interactive/doc-list-routes.d.ts.map +1 -0
- package/dist/interactive/doc-list-routes.js +165 -0
- package/dist/interactive/doc-list-routes.js.map +1 -0
- package/dist/interactive/project-root.d.ts +36 -0
- package/dist/interactive/project-root.d.ts.map +1 -0
- package/dist/interactive/project-root.js +45 -0
- package/dist/interactive/project-root.js.map +1 -0
- package/dist/interactive/proxy-routes.d.ts +4 -1
- package/dist/interactive/proxy-routes.d.ts.map +1 -1
- package/dist/interactive/proxy-routes.js +4 -22
- package/dist/interactive/proxy-routes.js.map +1 -1
- package/dist/projects/default-project.d.ts +10 -0
- package/dist/projects/default-project.d.ts.map +1 -0
- package/dist/projects/default-project.js +10 -0
- package/dist/projects/default-project.js.map +1 -0
- package/dist/projects/routes.d.ts +0 -2
- package/dist/projects/routes.d.ts.map +1 -1
- package/dist/projects/routes.js +1 -2
- package/dist/projects/routes.js.map +1 -1
- package/dist/skills/bundle.d.ts +94 -0
- package/dist/skills/bundle.d.ts.map +1 -0
- package/dist/skills/bundle.js +187 -0
- package/dist/skills/bundle.js.map +1 -0
- package/dist/skills/contain.d.ts +57 -0
- package/dist/skills/contain.d.ts.map +1 -0
- package/dist/skills/contain.js +90 -0
- package/dist/skills/contain.js.map +1 -0
- package/dist/skills/core-closure.d.ts +83 -0
- package/dist/skills/core-closure.d.ts.map +1 -0
- package/dist/skills/core-closure.js +130 -0
- package/dist/skills/core-closure.js.map +1 -0
- package/dist/skills/engine-env.d.ts +48 -0
- package/dist/skills/engine-env.d.ts.map +1 -0
- package/dist/skills/engine-env.js +69 -0
- package/dist/skills/engine-env.js.map +1 -0
- package/dist/skills/frontmatter.d.ts +77 -0
- package/dist/skills/frontmatter.d.ts.map +1 -0
- package/dist/skills/frontmatter.js +190 -0
- package/dist/skills/frontmatter.js.map +1 -0
- package/dist/skills/guards.d.ts +72 -0
- package/dist/skills/guards.d.ts.map +1 -0
- package/dist/skills/guards.js +147 -0
- package/dist/skills/guards.js.map +1 -0
- package/dist/skills/live-generations.d.ts +80 -0
- package/dist/skills/live-generations.d.ts.map +1 -0
- package/dist/skills/live-generations.js +163 -0
- package/dist/skills/live-generations.js.map +1 -0
- package/dist/skills/plugin-source.d.ts +109 -0
- package/dist/skills/plugin-source.d.ts.map +1 -0
- package/dist/skills/plugin-source.js +272 -0
- package/dist/skills/plugin-source.js.map +1 -0
- package/dist/skills/refs.d.ts +58 -0
- package/dist/skills/refs.d.ts.map +1 -0
- package/dist/skills/refs.js +133 -0
- package/dist/skills/refs.js.map +1 -0
- package/dist/skills/root-fence.d.ts +53 -0
- package/dist/skills/root-fence.d.ts.map +1 -0
- package/dist/skills/root-fence.js +109 -0
- package/dist/skills/root-fence.js.map +1 -0
- package/dist/skills/root-names.d.ts +42 -0
- package/dist/skills/root-names.d.ts.map +1 -0
- package/dist/skills/root-names.js +44 -0
- package/dist/skills/root-names.js.map +1 -0
- package/dist/skills/runtime.d.ts +130 -0
- package/dist/skills/runtime.d.ts.map +1 -0
- package/dist/skills/runtime.js +246 -0
- package/dist/skills/runtime.js.map +1 -0
- package/dist/skills/store.d.ts +895 -0
- package/dist/skills/store.d.ts.map +1 -0
- package/dist/skills/store.js +3575 -0
- package/dist/skills/store.js.map +1 -0
- package/dist/skills/tree.d.ts +292 -0
- package/dist/skills/tree.d.ts.map +1 -0
- package/dist/skills/tree.js +645 -0
- package/dist/skills/tree.js.map +1 -0
- package/dist/skills/venv.d.ts +52 -0
- package/dist/skills/venv.d.ts.map +1 -0
- package/dist/skills/venv.js +80 -0
- package/dist/skills/venv.js.map +1 -0
- package/dist/studio/assets/index-CK1uJWs2.css +32 -0
- package/dist/studio/assets/index-FcZg3WDR.js +539 -0
- package/dist/studio/index.html +2 -2
- package/dist/studio/testid-inventory.json +605 -7
- package/endpoint-manifest.json +183 -1
- package/package.json +4 -3
- package/dist/studio/assets/index-C4iz4uAw.js +0 -537
- 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":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAQH,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAyB,MAAM,WAAW,CAAC;AAEtE,8FAA8F;AAC9F,MAAM,CAAC,MAAM,aAAa,GAAG,kBAAkB,CAAC;AAEhD,uFAAuF;AACvF,MAAM,gBAAgB,GAAG,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AAiBlD,MAAM,UAAU,OAAO,CACrB,IAAsB,EACtB,QAA8B,EAC9B,WAAmB,EACnB,QAAgB,EAChB,SAAwB,EAAE;IAE1B,OAAO;QACL,IAAI;QACJ,QAAQ;QACR,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI;QAC3B,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,IAAI;QACzB,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,IAAI;QACzB,YAAY,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,IAAI,IAAI;QAC1C,aAAa,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,IAAI,KAAK;QAC5C,QAAQ;QACR,WAAW;KACZ,CAAC;AACJ,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,SAAS,CAAC,QAA6C;IACrE,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC;QAAE,OAAO,SAAS,CAAC;IACtE,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,UAAU,CAAC;IAC3C,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,OAAO,OAAO,CACZ,cAAc,EACd,UAAU,EACV,kHAAkH,EAClH,QAAQ,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,mBAAmB,aAAa,CAAC,MAAM,EAAE,EACrE,EAAE,KAAK,EAAE,IAAI,EAAE,CAChB,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,iBAAiB,CAAC,MAAM,EAAE,CAAC;QACpF,OAAO,OAAO,CACZ,cAAc,EACd,UAAU,EACV,8BAA8B,iBAAiB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,4CAA4C,iBAAiB,wEAAwE,EACjM,QAAQ,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,gBAAgB,iBAAiB,qCAAqC,EAClG,EAAE,KAAK,EAAE,IAAI,EAAE,CAChB,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,cAAc,CAAC,OAAoB,EAAE,IAAY;IAC/D,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACxC,OAAO,OAAO,CACZ,gBAAgB,EAChB,UAAU,EACV,QAAQ,CAAC,IAAI;QACX,CAAC,CAAC,yKAAyK;QAC3K,CAAC,CAAC,oIAAoI,EACxI,GAAG,IAAI,cAAc,QAAQ,CAAC,GAAG,KAAK,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,GAAG,EAClF,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,EAAE,CACxD,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAA2B,EAC3B,YAAoB,EACpB,IAAwE;IAExE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,UAAU,CAAC;IAC7C,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IACxD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO;YACL,OAAO,CACL,kBAAkB,EAClB,QAAQ,EACR,4EAA4E,EAC5E,kBAAkB,IAAI,CAAC,IAAI,EAAE,EAC7B,MAAM,CACP;SACF,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,OAAO;YACL,OAAO,CACL,qBAAqB,EACrB,QAAQ,EACR,gIAAgI,EAChI,GAAG,IAAI,CAAC,IAAI,iBAAiB,MAAM,CAAC,MAAM,EAAE,EAC5C,MAAM,CACP;SACF,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE,EAAE,CAAC;QAC9C,OAAO;YACL,OAAO,CACL,qBAAqB,EACrB,QAAQ,EACR,iDAAiD,EACjD,GAAG,IAAI,CAAC,IAAI,8BAA8B,EAC1C,MAAM,CACP;SACF,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG;YACV,OAAO,CACL,eAAe,EACf,QAAQ,EACR,4DAA4D,iBAAiB,8GAA8G,EAC3L,oBAAoB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,eAAe,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE,EACzF,MAAM,CACP;SACF,CAAC;QACF,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,GAAG,CAAC,IAAI,CACN,OAAO,CACL,aAAa,EACb,UAAU,EACV,iGAAiG,EACjG,GAAG,YAAY,uBAAuB,EACtC,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAC3D,CACF,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,gBAAgB,CAAC,GAAW,EAAE,KAAoB;IAChE,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAClE,OAAO,OAAO,CACZ,mBAAmB,EACnB,SAAS,EACT,yKAAyK,EACzK,cAAc,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,MAAM,GAAG,EAAE,EACjD,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CACrB,CAAC;AACJ,CAAC;AAED,qGAAqG;AACrG,MAAM,UAAU,sBAAsB,CAAC,GAAW,EAAE,KAAa;IAC/D,IAAI,GAAG,KAAK,UAAU,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC;QAAE,OAAO,IAAI,CAAC;IAClE,OAAO,OAAO,CACZ,qBAAqB,EACrB,UAAU,EACV,4LAA4L,EAC5L,GAAG,GAAG,sCAAsC,KAAK,EAAE,EACnD,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CACrB,CAAC;AACJ,CAAC;AAED,MAAM,uBAAuB,GAAqC;IAChE,aAAa,EAAE,+EAA+E;IAC9F,YAAY,EAAE,8GAA8G;IAC5H,eAAe,EAAE,uHAAuH;CACzI,CAAC;AAEF,oGAAoG;AACpG,MAAM,UAAU,gBAAgB,CAC9B,KAAuC,EACvC,KAAa;IAEb,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QACnD,IAAI,KAAK,KAAK,IAAI;YAAE,SAAS;QAC7B,OAAO,OAAO,CACZ,cAAc,EACd,SAAS,EACT,GAAG,uBAAuB,CAAC,KAAK,CAAC,yMAAyM,EAC1O,GAAG,GAAG,KAAK,KAAK,EAAE,EAClB,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CACrB,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,KAAuB;IACpE,IAAI,CAAC,KAAK,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAC7B,OAAO,OAAO,CACZ,cAAc,EACd,UAAU,EACV,0LAA0L,EAC1L,GAAG,IAAI,uBAAuB,EAC9B,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAC/C,CAAC;AACJ,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,SAAkB;IAC9D,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAC5B,OAAO,OAAO,CACZ,aAAa,EACb,UAAU,EACV,+EAA+E,EAC/E,GAAG,IAAI,gBAAgB,EACvB,EAAE,KAAK,EAAE,IAAI,EAAE,CAChB,CAAC;AACJ,CAAC"}
|