zelari-code 2.54.0 → 2.56.0
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/README.md +1 -1
- package/dist/cli/app.js +2 -2
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/commands/evolve.js +247 -0
- package/dist/cli/commands/evolve.js.map +1 -0
- package/dist/cli/commands/replay.js +202 -0
- package/dist/cli/commands/replay.js.map +1 -0
- package/dist/cli/commands/session.js +264 -0
- package/dist/cli/commands/session.js.map +1 -0
- package/dist/cli/commands/spineSession.js +77 -0
- package/dist/cli/commands/spineSession.js.map +1 -0
- package/dist/cli/components/StatusBar.js +6 -2
- package/dist/cli/components/StatusBar.js.map +1 -1
- package/dist/cli/components/statusChips.js +43 -0
- package/dist/cli/components/statusChips.js.map +1 -1
- package/dist/cli/councilDispatcher.js +12 -0
- package/dist/cli/councilDispatcher.js.map +1 -1
- package/dist/cli/evolution/controller.js +107 -0
- package/dist/cli/evolution/controller.js.map +1 -0
- package/dist/cli/evolution/ledger.js +42 -0
- package/dist/cli/evolution/ledger.js.map +1 -1
- package/dist/cli/headless/runOneTurn.js +18 -0
- package/dist/cli/headless/runOneTurn.js.map +1 -1
- package/dist/cli/hooks/useChatTurn.js +39 -1
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/hooks/useSlashDispatch.js +8 -0
- package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
- package/dist/cli/inbox.js +63 -10
- package/dist/cli/inbox.js.map +1 -1
- package/dist/cli/inboxSources.js +173 -0
- package/dist/cli/inboxSources.js.map +1 -0
- package/dist/cli/main.bundled.js +9650 -6423
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +80 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/plugins/bundleCommand.js +238 -0
- package/dist/cli/plugins/bundleCommand.js.map +1 -0
- package/dist/cli/plugins/bundleDiscover.js +74 -0
- package/dist/cli/plugins/bundleDiscover.js.map +1 -0
- package/dist/cli/plugins/bundleFs.js +57 -0
- package/dist/cli/plugins/bundleFs.js.map +1 -0
- package/dist/cli/plugins/bundleHookDef.js +70 -0
- package/dist/cli/plugins/bundleHookDef.js.map +1 -0
- package/dist/cli/plugins/bundleLoad.js +180 -0
- package/dist/cli/plugins/bundleLoad.js.map +1 -0
- package/dist/cli/plugins/bundleManifest.js +233 -0
- package/dist/cli/plugins/bundleManifest.js.map +1 -0
- package/dist/cli/plugins/bundleMcp.js +41 -0
- package/dist/cli/plugins/bundleMcp.js.map +1 -0
- package/dist/cli/plugins/bundleState.js +142 -0
- package/dist/cli/plugins/bundleState.js.map +1 -0
- package/dist/cli/runHeadless.js +40 -0
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/safety/decisionEmit.js +43 -0
- package/dist/cli/safety/decisionEmit.js.map +1 -0
- package/dist/cli/safety/permissionGate.js +239 -0
- package/dist/cli/safety/permissionGate.js.map +1 -0
- package/dist/cli/safety/permissionPolicy.js +279 -0
- package/dist/cli/safety/permissionPolicy.js.map +1 -0
- package/dist/cli/safety/permissionRules.js +145 -0
- package/dist/cli/safety/permissionRules.js.map +1 -0
- package/dist/cli/safety/sessionSink.js +169 -0
- package/dist/cli/safety/sessionSink.js.map +1 -0
- package/dist/cli/slashCommands.js +28 -2
- package/dist/cli/slashCommands.js.map +1 -1
- package/dist/cli/slashHandlers/evolve.js +41 -0
- package/dist/cli/slashHandlers/evolve.js.map +1 -0
- package/dist/cli/slashHandlers/permissions.js +170 -0
- package/dist/cli/slashHandlers/permissions.js.map +1 -0
- package/dist/cli/statusline/inboxFeed.js +76 -0
- package/dist/cli/statusline/inboxFeed.js.map +1 -0
- package/dist/cli/statusline/statuslineItems.js +15 -0
- package/dist/cli/statusline/statuslineItems.js.map +1 -1
- package/dist/cli/toolRegistry.js +161 -7
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/tools/askUser.js +17 -2
- package/dist/cli/tools/askUser.js.map +1 -1
- package/dist/cli/tools/execProcess.js +15 -1
- package/dist/cli/tools/execProcess.js.map +1 -1
- package/dist/cli/tools/krakenWorktree.js +334 -43
- package/dist/cli/tools/krakenWorktree.js.map +1 -1
- package/dist/cli/tools/taskTool.js +179 -43
- package/dist/cli/tools/taskTool.js.map +1 -1
- package/dist/cli/tools/verifyDebtSpine.js +41 -0
- package/dist/cli/tools/verifyDebtSpine.js.map +1 -1
- package/package.json +5 -2
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* plugins/bundleDiscover — find bundle directories under the scan roots.
|
|
3
|
+
*
|
|
4
|
+
* Used by `plugin list` and by name-based `plugin enable|disable`.
|
|
5
|
+
*
|
|
6
|
+
* The candidate rule is deliberately narrow: a directory is a bundle ONLY when
|
|
7
|
+
* it carries a manifest. Anything else — a bundle's own `hooks/` / `skills/`
|
|
8
|
+
* subdirectory, or a different kind of example such as
|
|
9
|
+
* `examples/extensions/echo-tool` — is not a bundle and must not be reported as
|
|
10
|
+
* a broken one. A manifest that IS present but invalid still surfaces, as
|
|
11
|
+
* INVALID: that one the user needs to see.
|
|
12
|
+
*
|
|
13
|
+
* @since v2.58.0 (WS6 / plugin bundle v1)
|
|
14
|
+
*/
|
|
15
|
+
import { readdir } from 'node:fs/promises';
|
|
16
|
+
import path from 'node:path';
|
|
17
|
+
import { BUNDLE_MANIFEST_FILE } from './bundleManifest.js';
|
|
18
|
+
import { readBundle } from './bundleLoad.js';
|
|
19
|
+
import { isDir, isFile } from './bundleFs.js';
|
|
20
|
+
/**
|
|
21
|
+
* The roots `plugin list` scans: the repo examples, then the configured paths.
|
|
22
|
+
*
|
|
23
|
+
* Deduped (case-insensitively, Windows-safe): `plugin enable` records the
|
|
24
|
+
* directory CONTAINING a bundle, which is very often the default root itself —
|
|
25
|
+
* listing the same directory twice in the report would read as a bug.
|
|
26
|
+
*/
|
|
27
|
+
export function defaultBundleRoots(projectRoot, state) {
|
|
28
|
+
const roots = [path.join(projectRoot, 'examples', 'extensions')];
|
|
29
|
+
for (const p of state.paths)
|
|
30
|
+
roots.push(path.resolve(projectRoot, p));
|
|
31
|
+
const unique = new Map();
|
|
32
|
+
for (const root of roots)
|
|
33
|
+
unique.set(path.resolve(root).toLowerCase(), root);
|
|
34
|
+
return [...unique.values()];
|
|
35
|
+
}
|
|
36
|
+
/** Scan every root for bundle directories and validate each one. Skips dupes. */
|
|
37
|
+
export async function discoverBundles(roots) {
|
|
38
|
+
const out = [];
|
|
39
|
+
const seen = new Set();
|
|
40
|
+
for (const root of roots) {
|
|
41
|
+
if (!(await isDir(root)))
|
|
42
|
+
continue;
|
|
43
|
+
let entries;
|
|
44
|
+
try {
|
|
45
|
+
entries = (await readdir(root, { withFileTypes: true }))
|
|
46
|
+
.filter((e) => e.isDirectory())
|
|
47
|
+
.map((e) => e.name)
|
|
48
|
+
.sort();
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
for (const entry of entries) {
|
|
54
|
+
const dir = path.join(root, entry);
|
|
55
|
+
if (!(await isFile(path.join(dir, BUNDLE_MANIFEST_FILE))))
|
|
56
|
+
continue;
|
|
57
|
+
const key = path.resolve(dir);
|
|
58
|
+
if (seen.has(key))
|
|
59
|
+
continue;
|
|
60
|
+
seen.add(key);
|
|
61
|
+
const result = await readBundle(dir);
|
|
62
|
+
out.push({
|
|
63
|
+
dir,
|
|
64
|
+
name: result.bundle?.name ?? entry,
|
|
65
|
+
ok: result.bundle !== undefined,
|
|
66
|
+
errors: result.errors,
|
|
67
|
+
warnings: result.warnings,
|
|
68
|
+
...(result.bundle ? { version: result.bundle.version } : {}),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=bundleDiscover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundleDiscover.js","sourceRoot":"","sources":["../../../src/cli/plugins/bundleDiscover.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* plugins/bundleFs — the filesystem primitives a bundle check needs.
|
|
3
|
+
*
|
|
4
|
+
* Extracted so `bundleLoad.ts`, `bundleDiscover.ts` and `bundleCommand.ts`
|
|
5
|
+
* agree on ONE definition of "the declared file exists and stays inside the
|
|
6
|
+
* bundle" instead of each growing its own copy.
|
|
7
|
+
*
|
|
8
|
+
* @since v2.58.0 (WS6 / plugin bundle v1)
|
|
9
|
+
*/
|
|
10
|
+
import { stat } from 'node:fs/promises';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
/** `true` only for an existing regular file; never throws. */
|
|
13
|
+
export async function isFile(p) {
|
|
14
|
+
try {
|
|
15
|
+
return (await stat(p)).isFile();
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** `true` only for an existing directory; never throws. */
|
|
22
|
+
export async function isDir(p) {
|
|
23
|
+
try {
|
|
24
|
+
return (await stat(p)).isDirectory();
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Narrow a parsed JSON value to an object literal (not an array, not null). */
|
|
31
|
+
export function isRecord(value) {
|
|
32
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Resolve one declared bundle-relative path and prove it is a real file INSIDE
|
|
36
|
+
* the bundle directory.
|
|
37
|
+
*
|
|
38
|
+
* `bundleManifest.ts` already rejects an absolute path or a `..` segment, so
|
|
39
|
+
* this is defence in depth: a bundle may only ever read files it actually
|
|
40
|
+
* contains, even if a future path rule loosens. On failure the message names
|
|
41
|
+
* the manifest, the FIELD and what was wrong; `null` is returned and the
|
|
42
|
+
* caller skips the entry.
|
|
43
|
+
*/
|
|
44
|
+
export async function resolveInsideBundle(root, relPath, at, manifestPath, errors) {
|
|
45
|
+
const abs = path.resolve(root, relPath);
|
|
46
|
+
const rel = path.relative(root, abs);
|
|
47
|
+
if (rel === '' || rel.startsWith('..') || path.isAbsolute(rel)) {
|
|
48
|
+
errors.push(`${manifestPath}: invalid bundle manifest at '${at}': path escapes the bundle directory ('${relPath}')`);
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
if (!(await isFile(abs))) {
|
|
52
|
+
errors.push(`${manifestPath}: invalid bundle manifest at '${at}': file not found ('${relPath}')`);
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
return abs;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=bundleFs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundleFs.js","sourceRoot":"","sources":["../../../src/cli/plugins/bundleFs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,8DAA8D;AAC9D,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,CAAS;IACpC,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,2DAA2D;AAC3D,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,CAAS;IACnC,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAAY,EACZ,OAAe,EACf,EAAU,EACV,YAAoB,EACpB,MAAgB;IAEhB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACrC,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/D,MAAM,CAAC,IAAI,CACT,GAAG,YAAY,iCAAiC,EAAE,0CAA0C,OAAO,IAAI,CACxG,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,GAAG,YAAY,iCAAiC,EAAE,uBAAuB,OAAO,IAAI,CAAC,CAAC;QAClG,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { BUNDLE_HOOK_EVENTS } from './bundleManifest.js';
|
|
2
|
+
import { isRecord } from './bundleFs.js';
|
|
3
|
+
/** Runtime guard for the bundle hook-event vocabulary. */
|
|
4
|
+
export function isBundleHookEvent(value) {
|
|
5
|
+
return typeof value === 'string' && BUNDLE_HOOK_EVENTS.includes(value);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Validate `raw` (the hook file's text) as a `HookDefinition` that subscribes
|
|
9
|
+
* to `event`. Returns either a definition ready for `runner.addHook` or an
|
|
10
|
+
* error naming the FILE and what is wrong — never both, never a partial one.
|
|
11
|
+
*
|
|
12
|
+
* `warnings` collects non-fatal observations (e.g. an event the bundle
|
|
13
|
+
* vocabulary does not know).
|
|
14
|
+
*/
|
|
15
|
+
export function readHookDefinition(raw, file, event, warnings) {
|
|
16
|
+
let json;
|
|
17
|
+
try {
|
|
18
|
+
json = JSON.parse(raw);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
return { error: `${file}: invalid JSON (${err instanceof Error ? err.message : String(err)})` };
|
|
22
|
+
}
|
|
23
|
+
if (!isRecord(json))
|
|
24
|
+
return { error: `${file}: hook definition must be a JSON object` };
|
|
25
|
+
const name = json['name'];
|
|
26
|
+
if (typeof name !== 'string' || name.trim() === '') {
|
|
27
|
+
return { error: `${file}: hook definition is missing a non-empty "name"` };
|
|
28
|
+
}
|
|
29
|
+
const match = json['match'];
|
|
30
|
+
if (!isRecord(match)) {
|
|
31
|
+
return { error: `${file}: hook definition is missing a "match" object` };
|
|
32
|
+
}
|
|
33
|
+
const events = match['events'];
|
|
34
|
+
if (!Array.isArray(events) || events.length === 0) {
|
|
35
|
+
return { error: `${file}: hook "match.events" must be a non-empty array` };
|
|
36
|
+
}
|
|
37
|
+
if (!events.includes(event)) {
|
|
38
|
+
return {
|
|
39
|
+
error: `${file}: hook does not subscribe to '${event}' (match.events: ${events.join(', ')})`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const hasCommand = typeof json['command'] === 'string' && json['command'].trim() !== '';
|
|
43
|
+
const hasUrl = typeof json['url'] === 'string' && json['url'].trim() !== '';
|
|
44
|
+
if (hasCommand === hasUrl) {
|
|
45
|
+
return { error: `${file}: exactly one of "command" or "url" is required` };
|
|
46
|
+
}
|
|
47
|
+
for (const extra of events) {
|
|
48
|
+
if (isBundleHookEvent(extra))
|
|
49
|
+
continue;
|
|
50
|
+
warnings.push(`${file}: hook also lists non-bundle event '${String(extra)}' (ignored by the bundle)`);
|
|
51
|
+
}
|
|
52
|
+
const tools = match['tools'];
|
|
53
|
+
const definition = {
|
|
54
|
+
name,
|
|
55
|
+
match: {
|
|
56
|
+
tools: Array.isArray(tools) ? tools.map(String) : ['*'],
|
|
57
|
+
events: events,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
if (hasCommand)
|
|
61
|
+
definition.command = json['command'];
|
|
62
|
+
if (hasUrl)
|
|
63
|
+
definition.url = json['url'];
|
|
64
|
+
if (typeof json['timeoutMs'] === 'number')
|
|
65
|
+
definition.timeoutMs = json['timeoutMs'];
|
|
66
|
+
if (typeof json['cwd'] === 'string')
|
|
67
|
+
definition.cwd = json['cwd'];
|
|
68
|
+
return { definition };
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=bundleHookDef.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundleHookDef.js","sourceRoot":"","sources":["../../../src/cli/plugins/bundleHookDef.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,kBAAkB,EAAwB,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,0DAA0D;AAC1D,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,kBAAwC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAChG,CAAC;AAOD;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,GAAW,EACX,IAAY,EACZ,KAAsB,EACtB,QAAkB;IAElB,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,mBAAmB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;IAClG,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,yCAAyC,EAAE,CAAC;IAExF,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACnD,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,iDAAiD,EAAE,CAAC;IAC7E,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,+CAA+C,EAAE,CAAC;IAC3E,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClD,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,iDAAiD,EAAE,CAAC;IAC7E,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO;YACL,KAAK,EAAE,GAAG,IAAI,iCAAiC,KAAK,oBAAoB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;SAC7F,CAAC;IACJ,CAAC;IACD,MAAM,UAAU,GAAG,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;IACxF,MAAM,MAAM,GAAG,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,QAAQ,IAAK,IAAI,CAAC,KAAK,CAAY,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;IACxF,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QAC1B,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,iDAAiD,EAAE,CAAC;IAC7E,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,iBAAiB,CAAC,KAAK,CAAC;YAAE,SAAS;QACvC,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,uCAAuC,MAAM,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IACxG,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,MAAM,UAAU,GAAmB;QACjC,IAAI;QACJ,KAAK,EAAE;YACL,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YACvD,MAAM,EAAE,MAAwB;SACjC;KACF,CAAC;IACF,IAAI,UAAU;QAAE,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAW,CAAC;IAC/D,IAAI,MAAM;QAAE,UAAU,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAW,CAAC;IACnD,IAAI,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,QAAQ;QAAE,UAAU,CAAC,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;IACpF,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,QAAQ;QAAE,UAAU,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;IAClE,OAAO,EAAE,UAAU,EAAE,CAAC;AACxB,CAAC"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* plugins/bundleLoad — read, validate and LOAD a WS6 plugin bundle.
|
|
3
|
+
*
|
|
4
|
+
* Three layers, deliberately separated:
|
|
5
|
+
*
|
|
6
|
+
* 1. {@link readBundle} — I/O + validation. Reads the manifest, then checks
|
|
7
|
+
* every DECLARED path: does it exist, does it stay inside the bundle
|
|
8
|
+
* directory, and does it parse as the format it claims? Skill files go
|
|
9
|
+
* through the REAL loader parser (`skillsMd.parseSkillMd`, the same one
|
|
10
|
+
* `/skill` uses), hooks through `bundleHookDef.ts`, and MCP presets through
|
|
11
|
+
* the REAL preset registry (`bundleMcp.ts`) — nothing is re-implemented.
|
|
12
|
+
* 2. {@link projectBundleContributions} — PURE. Given a bundle and the enable
|
|
13
|
+
* state it returns the contribution list, and executes NOTHING.
|
|
14
|
+
* 3. {@link loadBundle} — 1 + 2, the function callers actually want.
|
|
15
|
+
*
|
|
16
|
+
* Fail-closed, matching the rest of the CLI: a bundle that is present but not
|
|
17
|
+
* listed as enabled in `.zelari/plugins.json` contributes NOTHING (not just
|
|
18
|
+
* "nothing dangerous" — nothing at all). A bundle that fails to read produces
|
|
19
|
+
* no contributions, never a partial set.
|
|
20
|
+
*
|
|
21
|
+
* Module map: manifest schema → `bundleManifest.ts`, FS guards → `bundleFs.ts`,
|
|
22
|
+
* hook-file validator → `bundleHookDef.ts`, MCP resolution → `bundleMcp.ts`,
|
|
23
|
+
* discovery → `bundleDiscover.ts`, enable state → `bundleState.ts`, CLI →
|
|
24
|
+
* `bundleCommand.ts`.
|
|
25
|
+
*
|
|
26
|
+
* @since v2.58.0 (WS6 / plugin bundle v1)
|
|
27
|
+
*/
|
|
28
|
+
import { readFile } from 'node:fs/promises';
|
|
29
|
+
import path from 'node:path';
|
|
30
|
+
import { isObserverEvent } from '@zelari/core/harness';
|
|
31
|
+
import { parseSkillMd } from '../skillsMd.js';
|
|
32
|
+
import { BUNDLE_MANIFEST_FILE, parseBundleManifest, } from './bundleManifest.js';
|
|
33
|
+
import { isDir, resolveInsideBundle } from './bundleFs.js';
|
|
34
|
+
import { readHookDefinition } from './bundleHookDef.js';
|
|
35
|
+
import { readMcp } from './bundleMcp.js';
|
|
36
|
+
/** Read the declared skills, each through the real SKILL.md parser. */
|
|
37
|
+
async function readSkills(manifestSkills, root, manifestPath, errors) {
|
|
38
|
+
const skills = [];
|
|
39
|
+
for (let i = 0; i < manifestSkills.length; i += 1) {
|
|
40
|
+
const ref = manifestSkills[i];
|
|
41
|
+
const abs = await resolveInsideBundle(root, ref.path, `skills.${i}.path`, manifestPath, errors);
|
|
42
|
+
if (!abs)
|
|
43
|
+
continue;
|
|
44
|
+
const skill = parseSkillMd(await readFile(abs, 'utf8'), abs);
|
|
45
|
+
if (!skill) {
|
|
46
|
+
errors.push(`${manifestPath}: invalid bundle manifest at 'skills.${i}.path': '${ref.path}' is not a valid SKILL.md ` +
|
|
47
|
+
'(needs YAML frontmatter with name + description and a non-empty body)');
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (skill.name !== ref.id) {
|
|
51
|
+
errors.push(`${manifestPath}: invalid bundle manifest at 'skills.${i}.id': id '${ref.id}' ` +
|
|
52
|
+
`does not match the SKILL.md name '${skill.name}' in '${ref.path}'`);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
skills.push({ id: ref.id, path: abs, skill });
|
|
56
|
+
}
|
|
57
|
+
return skills;
|
|
58
|
+
}
|
|
59
|
+
/** Read the declared hooks, each validated against the event it claims. */
|
|
60
|
+
async function readHooks(manifestHooks, root, manifestPath, errors, warnings) {
|
|
61
|
+
const hooks = [];
|
|
62
|
+
for (let i = 0; i < manifestHooks.length; i += 1) {
|
|
63
|
+
const ref = manifestHooks[i];
|
|
64
|
+
const abs = await resolveInsideBundle(root, ref.path, `hooks.${i}.path`, manifestPath, errors);
|
|
65
|
+
if (!abs)
|
|
66
|
+
continue;
|
|
67
|
+
const result = readHookDefinition(await readFile(abs, 'utf8'), abs, ref.event, warnings);
|
|
68
|
+
if (!result.definition) {
|
|
69
|
+
errors.push(`${manifestPath}: invalid bundle manifest at 'hooks.${i}.path': ${result.error ?? 'invalid hook'}`);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
// `hooks[].config` may only override timeoutMs/cwd — the hook FILE owns
|
|
73
|
+
// command, url, match and name (see the schema).
|
|
74
|
+
hooks.push({
|
|
75
|
+
event: ref.event,
|
|
76
|
+
path: abs,
|
|
77
|
+
observer: isObserverEvent(ref.event),
|
|
78
|
+
definition: { ...result.definition, ...(ref.config ?? {}) },
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return hooks;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Read + validate one bundle directory. Never throws: every problem is an
|
|
85
|
+
* entry in `errors` naming the file and the field.
|
|
86
|
+
*/
|
|
87
|
+
export async function readBundle(dir, manifestFileName = BUNDLE_MANIFEST_FILE) {
|
|
88
|
+
const errors = [];
|
|
89
|
+
const warnings = [];
|
|
90
|
+
const root = path.resolve(dir);
|
|
91
|
+
const manifestPath = path.join(root, manifestFileName);
|
|
92
|
+
if (!(await isDir(root))) {
|
|
93
|
+
return { errors: [`${root}: not a bundle directory`], warnings };
|
|
94
|
+
}
|
|
95
|
+
let manifestRaw;
|
|
96
|
+
try {
|
|
97
|
+
manifestRaw = await readFile(manifestPath, 'utf8');
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return { errors: [`${manifestPath}: bundle manifest not found`], warnings };
|
|
101
|
+
}
|
|
102
|
+
const parsed = parseBundleManifest(manifestRaw, manifestPath);
|
|
103
|
+
if (!parsed.manifest)
|
|
104
|
+
return { errors: parsed.errors, warnings };
|
|
105
|
+
const manifest = parsed.manifest;
|
|
106
|
+
const skills = await readSkills(manifest.skills, root, manifestPath, errors);
|
|
107
|
+
const hooks = await readHooks(manifest.hooks, root, manifestPath, errors, warnings);
|
|
108
|
+
const mcp = readMcp(manifest.mcp, manifestPath, errors, warnings);
|
|
109
|
+
const agents = [];
|
|
110
|
+
for (let i = 0; i < manifest.agents.length; i += 1) {
|
|
111
|
+
const ref = manifest.agents[i];
|
|
112
|
+
const at = `agents.${i}.path`;
|
|
113
|
+
const abs = await resolveInsideBundle(root, ref.path, at, manifestPath, errors);
|
|
114
|
+
if (!abs)
|
|
115
|
+
continue;
|
|
116
|
+
if ((await readFile(abs, 'utf8')).trim() === '') {
|
|
117
|
+
errors.push(`${manifestPath}: invalid bundle manifest at '${at}': '${ref.path}' is empty`);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
agents.push({ id: ref.id, path: abs, ...(ref.description ? { description: ref.description } : {}) });
|
|
121
|
+
}
|
|
122
|
+
if (agents.length > 0) {
|
|
123
|
+
warnings.push('agents are declared and validated but NOT executed (no agent loader in this release)');
|
|
124
|
+
}
|
|
125
|
+
if (errors.length > 0)
|
|
126
|
+
return { errors, warnings };
|
|
127
|
+
return {
|
|
128
|
+
bundle: {
|
|
129
|
+
name: manifest.name,
|
|
130
|
+
version: manifest.version,
|
|
131
|
+
...(manifest.description ? { description: manifest.description } : {}),
|
|
132
|
+
dir: root,
|
|
133
|
+
manifestPath,
|
|
134
|
+
skills,
|
|
135
|
+
hooks,
|
|
136
|
+
mcp,
|
|
137
|
+
agents,
|
|
138
|
+
warnings,
|
|
139
|
+
},
|
|
140
|
+
errors,
|
|
141
|
+
warnings,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* PURE projection: bundle + enable state → contribution list. Executes nothing
|
|
146
|
+
* and reads nothing. A disabled bundle contributes NOTHING (fail-closed), which
|
|
147
|
+
* is the seam a future apply/eval step consumes.
|
|
148
|
+
*/
|
|
149
|
+
export function projectBundleContributions(bundle, opts) {
|
|
150
|
+
const base = {
|
|
151
|
+
bundle: bundle.name,
|
|
152
|
+
version: bundle.version,
|
|
153
|
+
dir: bundle.dir,
|
|
154
|
+
warnings: bundle.warnings,
|
|
155
|
+
};
|
|
156
|
+
if (!opts.enabled) {
|
|
157
|
+
return { ...base, enabled: false, skills: [], hooks: [], mcp: [], agents: [] };
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
...base,
|
|
161
|
+
enabled: true,
|
|
162
|
+
skills: bundle.skills,
|
|
163
|
+
hooks: bundle.hooks,
|
|
164
|
+
mcp: bundle.mcp,
|
|
165
|
+
agents: bundle.agents,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/** Read + validate + project. `ok:false` ⇒ no contributions, never partial. */
|
|
169
|
+
export async function loadBundle(dir, opts) {
|
|
170
|
+
const read = await readBundle(dir);
|
|
171
|
+
if (!read.bundle)
|
|
172
|
+
return { ok: false, errors: read.errors, warnings: read.warnings };
|
|
173
|
+
return {
|
|
174
|
+
ok: true,
|
|
175
|
+
errors: [],
|
|
176
|
+
warnings: read.warnings,
|
|
177
|
+
contributions: projectBundleContributions(read.bundle, { enabled: opts.enabled }),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=bundleLoad.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundleLoad.js","sourceRoot":"","sources":["../../../src/cli/plugins/bundleLoad.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* plugins/bundleManifest — the WS6 plugin BUNDLE manifest, format v1.
|
|
3
|
+
*
|
|
4
|
+
* A *bundle* is a DIRECTORY holding one manifest (`zelari-plugin.json`) plus
|
|
5
|
+
* the files it declares:
|
|
6
|
+
*
|
|
7
|
+
* ```json
|
|
8
|
+
* {
|
|
9
|
+
* "$comment": "optional documentation slot — accepted and stripped",
|
|
10
|
+
* "formatVersion": 1,
|
|
11
|
+
* "name": "my-bundle",
|
|
12
|
+
* "version": "1.0.0",
|
|
13
|
+
* "description": "what it gives you",
|
|
14
|
+
* "skills": [{ "id": "repo-hygiene", "path": "skills/repo-hygiene/SKILL.md" }],
|
|
15
|
+
* "hooks": [{ "event": "PermissionRequest", "path": "hooks/observer.json" }],
|
|
16
|
+
* "mcp": [{ "name": "my-server", "preset": "unreal-mcp" }],
|
|
17
|
+
* "agents": [{ "id": "auditor", "path": "agents/auditor.md" }]
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* This module is PURE: it parses and validates TEXT. It never touches the
|
|
22
|
+
* filesystem (does a declared `path` EXIST? — see bundleLoad.ts) and never
|
|
23
|
+
* executes anything. Every schema is `.strict()`: an unknown key is a
|
|
24
|
+
* MALFORMED manifest, not a silently ignored option — the `$comment`
|
|
25
|
+
* documentation slot is the one exception, ACCEPTED AND STRIPPED exactly as in
|
|
26
|
+
* `safety/permissionPolicy.ts`, so a comment can never change a decision.
|
|
27
|
+
*
|
|
28
|
+
* Errors always NAME the file and the offending field
|
|
29
|
+
* (`<file>: invalid bundle manifest at 'skills.0.path': …`), and ALL problems
|
|
30
|
+
* are reported — a validator that stops at the first typo turns fixing a
|
|
31
|
+
* manifest into a guessing game.
|
|
32
|
+
*
|
|
33
|
+
* @since v2.58.0 (WS6 / plugin bundle v1)
|
|
34
|
+
*/
|
|
35
|
+
import path from 'node:path';
|
|
36
|
+
import { z } from 'zod';
|
|
37
|
+
/** Manifest file name expected inside a bundle directory. */
|
|
38
|
+
export const BUNDLE_MANIFEST_FILE = 'zelari-plugin.json';
|
|
39
|
+
/** The only format this CLI understands. A future v2 must not load as v1. */
|
|
40
|
+
export const BUNDLE_FORMAT_VERSION = 1;
|
|
41
|
+
/** Slug rule for bundle name / skill id / agent id (mirrors skillsMd.ts). */
|
|
42
|
+
export const BUNDLE_SLUG_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
43
|
+
/** MCP server-name rule — mirrors the one `upsertMcpServer` enforces. */
|
|
44
|
+
export const BUNDLE_MCP_NAME_RE = /^[a-zA-Z0-9_-]+$/;
|
|
45
|
+
/**
|
|
46
|
+
* Every event a bundle hook may declare: the four v1.32 GATE events plus the
|
|
47
|
+
* four v2.57 OBSERVER events (WS5). `satisfies readonly AnyHookEvent[]` makes
|
|
48
|
+
* the compiler reject a typo or a renamed event here; `OBSERVER_HOOK_EVENTS`
|
|
49
|
+
* has no runtime counterpart for the gate half, so
|
|
50
|
+
* `tests/unit/plugin-bundle.test.ts` additionally asserts this list still
|
|
51
|
+
* contains every event core exports as an observer.
|
|
52
|
+
*/
|
|
53
|
+
export const BUNDLE_HOOK_EVENTS = [
|
|
54
|
+
'PreToolUse',
|
|
55
|
+
'PostToolUse',
|
|
56
|
+
'SessionStart',
|
|
57
|
+
'SessionEnd',
|
|
58
|
+
'PermissionRequest',
|
|
59
|
+
'SubagentStart',
|
|
60
|
+
'SubagentEnd',
|
|
61
|
+
'Notification',
|
|
62
|
+
];
|
|
63
|
+
/**
|
|
64
|
+
* `$comment` — the ONE non-config key these schemas tolerate. ACCEPTED AND
|
|
65
|
+
* STRIPPED: never validated, never reaching any consumer, so documentation can
|
|
66
|
+
* never change behaviour. Every other unknown key stays fatal (same contract
|
|
67
|
+
* as the WS1 permission policy).
|
|
68
|
+
*/
|
|
69
|
+
const commentSchema = z.string().optional();
|
|
70
|
+
/** Shallow copy of a validated object without its documentation slot. */
|
|
71
|
+
function stripComment(value) {
|
|
72
|
+
const { $comment: _comment, ...rest } = value;
|
|
73
|
+
return rest;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* A declared path must stay INSIDE the bundle directory: relative, no drive
|
|
77
|
+
* letter / root, no `..` segment. `path.win32.isAbsolute` is checked too, so a
|
|
78
|
+
* `C:\…` path is rejected even when the validator itself runs on POSIX.
|
|
79
|
+
*/
|
|
80
|
+
function escapesBundleRoot(p) {
|
|
81
|
+
if (path.isAbsolute(p) || path.win32.isAbsolute(p))
|
|
82
|
+
return true;
|
|
83
|
+
return p.split(/[\\/]+/).includes('..');
|
|
84
|
+
}
|
|
85
|
+
const bundleRelativePath = z
|
|
86
|
+
.string()
|
|
87
|
+
.min(1)
|
|
88
|
+
.refine((p) => !escapesBundleRoot(p), {
|
|
89
|
+
message: 'must be a path relative to the bundle directory (no absolute path, no "..")',
|
|
90
|
+
});
|
|
91
|
+
const bundleSlug = (what) => z.string().regex(BUNDLE_SLUG_RE, `${what} must be a slug: lowercase letters, digits, hyphens (max 64)`);
|
|
92
|
+
/** `skills: [{ id, path }]` — one SKILL.md the bundle ships. */
|
|
93
|
+
export const BundleSkillRefSchema = z
|
|
94
|
+
.object({
|
|
95
|
+
$comment: commentSchema,
|
|
96
|
+
id: bundleSlug('skill id'),
|
|
97
|
+
path: bundleRelativePath,
|
|
98
|
+
})
|
|
99
|
+
.strict()
|
|
100
|
+
.transform(stripComment);
|
|
101
|
+
/**
|
|
102
|
+
* `hooks: [{ event, path, config? }]` — one hook definition FILE plus an
|
|
103
|
+
* optional overlay.
|
|
104
|
+
*
|
|
105
|
+
* `config` may set ONLY `timeoutMs` / `cwd`: the hook file stays authoritative
|
|
106
|
+
* for `command` / `url` / `match` / `name`, so a manifest can never smuggle an
|
|
107
|
+
* executable that the hook file does not already declare.
|
|
108
|
+
*/
|
|
109
|
+
export const BundleHookRefSchema = z
|
|
110
|
+
.object({
|
|
111
|
+
$comment: commentSchema,
|
|
112
|
+
event: z.enum(BUNDLE_HOOK_EVENTS, {
|
|
113
|
+
message: `unknown hook event (expected one of: ${BUNDLE_HOOK_EVENTS.join(', ')})`,
|
|
114
|
+
}),
|
|
115
|
+
path: bundleRelativePath,
|
|
116
|
+
config: z
|
|
117
|
+
.object({
|
|
118
|
+
timeoutMs: z.number().int().positive().optional(),
|
|
119
|
+
cwd: z.string().min(1).optional(),
|
|
120
|
+
})
|
|
121
|
+
.strict()
|
|
122
|
+
.optional(),
|
|
123
|
+
})
|
|
124
|
+
.strict()
|
|
125
|
+
.transform(stripComment);
|
|
126
|
+
/**
|
|
127
|
+
* `mcp: [{ name, preset | command, args? }]` — exactly ONE of `preset`
|
|
128
|
+
* (a repo preset id, resolved by `mcp/mcpPresets.ts`) or `command` (a stdio
|
|
129
|
+
* server) must be given. No `env`: secrets never travel inside a bundle — a
|
|
130
|
+
* preset factory reads its key from the environment at APPLY time.
|
|
131
|
+
*/
|
|
132
|
+
export const BundleMcpRefSchema = z
|
|
133
|
+
.object({
|
|
134
|
+
$comment: commentSchema,
|
|
135
|
+
name: z
|
|
136
|
+
.string()
|
|
137
|
+
.regex(BUNDLE_MCP_NAME_RE, 'mcp name must use letters, digits, underscore or hyphen'),
|
|
138
|
+
preset: z.string().min(1).optional(),
|
|
139
|
+
command: z.string().min(1).optional(),
|
|
140
|
+
args: z.array(z.string()).optional(),
|
|
141
|
+
})
|
|
142
|
+
.strict()
|
|
143
|
+
.transform(stripComment)
|
|
144
|
+
.refine((m) => (m.preset === undefined) !== (m.command === undefined), {
|
|
145
|
+
message: 'exactly one of "preset" (repo preset id) or "command" (stdio server) is required',
|
|
146
|
+
path: ['preset'],
|
|
147
|
+
});
|
|
148
|
+
/**
|
|
149
|
+
* `agents: [{ id, path, description? }]` — declared, validated, surfaced as a
|
|
150
|
+
* contribution, NOT executed: WS6 ships no agent loader (see the debt in
|
|
151
|
+
* docs/TOOLS.md).
|
|
152
|
+
*/
|
|
153
|
+
export const BundleAgentRefSchema = z
|
|
154
|
+
.object({
|
|
155
|
+
$comment: commentSchema,
|
|
156
|
+
id: bundleSlug('agent id'),
|
|
157
|
+
path: bundleRelativePath,
|
|
158
|
+
description: z.string().min(1).optional(),
|
|
159
|
+
})
|
|
160
|
+
.strict()
|
|
161
|
+
.transform(stripComment);
|
|
162
|
+
/** The bundle manifest envelope (`.strict()`: unknown key ⇒ malformed). */
|
|
163
|
+
export const BundleManifestSchema = z
|
|
164
|
+
.object({
|
|
165
|
+
$comment: commentSchema,
|
|
166
|
+
formatVersion: z
|
|
167
|
+
.literal(BUNDLE_FORMAT_VERSION, {
|
|
168
|
+
message: `unsupported bundle format — this CLI reads formatVersion ${BUNDLE_FORMAT_VERSION}`,
|
|
169
|
+
})
|
|
170
|
+
.optional()
|
|
171
|
+
.default(BUNDLE_FORMAT_VERSION),
|
|
172
|
+
name: bundleSlug('bundle name'),
|
|
173
|
+
version: z.string().min(1),
|
|
174
|
+
description: z.string().min(1).optional(),
|
|
175
|
+
skills: z.array(BundleSkillRefSchema).default([]),
|
|
176
|
+
hooks: z.array(BundleHookRefSchema).default([]),
|
|
177
|
+
mcp: z.array(BundleMcpRefSchema).default([]),
|
|
178
|
+
agents: z.array(BundleAgentRefSchema).default([]),
|
|
179
|
+
})
|
|
180
|
+
.strict()
|
|
181
|
+
.transform(stripComment);
|
|
182
|
+
/** Format every zod issue as `<file>: invalid bundle manifest at '<field>': <why>`. */
|
|
183
|
+
function formatIssues(error, filePath) {
|
|
184
|
+
return error.issues.map((issue) => {
|
|
185
|
+
const at = issue.path.length > 0 ? issue.path.join('.') : 'file';
|
|
186
|
+
return `${filePath}: invalid bundle manifest at '${at}': ${issue.message}`;
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Cross-field rules zod cannot express per-field: an ambiguous manifest
|
|
191
|
+
* (two entries fighting for the same id / server name) is REJECTED rather than
|
|
192
|
+
* silently resolved, so "which one won" can never depend on array order.
|
|
193
|
+
*/
|
|
194
|
+
function duplicateErrors(manifest, filePath) {
|
|
195
|
+
const errors = [];
|
|
196
|
+
const check = (values, kind, field) => {
|
|
197
|
+
const seen = new Set();
|
|
198
|
+
values.forEach((value, i) => {
|
|
199
|
+
if (seen.has(value)) {
|
|
200
|
+
errors.push(`${filePath}: invalid bundle manifest at '${field}.${i}': duplicate ${kind} '${value}'`);
|
|
201
|
+
}
|
|
202
|
+
seen.add(value);
|
|
203
|
+
});
|
|
204
|
+
};
|
|
205
|
+
check(manifest.skills.map((s) => s.id), 'skill id', 'skills');
|
|
206
|
+
check(manifest.mcp.map((m) => m.name), 'mcp server name', 'mcp');
|
|
207
|
+
check(manifest.agents.map((a) => a.id), 'agent id', 'agents');
|
|
208
|
+
return errors;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Parse manifest TEXT (already read from disk). Invalid JSON, a schema
|
|
212
|
+
* violation, an unknown key (`$comment` aside), a declared path escaping the
|
|
213
|
+
* bundle root, or a duplicate id all come back as `errors` naming the file and
|
|
214
|
+
* the field; `manifest` is then absent — never a half-usable manifest.
|
|
215
|
+
*/
|
|
216
|
+
export function parseBundleManifest(raw, filePath) {
|
|
217
|
+
let json;
|
|
218
|
+
try {
|
|
219
|
+
json = JSON.parse(raw);
|
|
220
|
+
}
|
|
221
|
+
catch (err) {
|
|
222
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
223
|
+
return { errors: [`${filePath}: invalid JSON (${detail})`] };
|
|
224
|
+
}
|
|
225
|
+
const parsed = BundleManifestSchema.safeParse(json);
|
|
226
|
+
if (!parsed.success)
|
|
227
|
+
return { errors: formatIssues(parsed.error, filePath) };
|
|
228
|
+
const errors = duplicateErrors(parsed.data, filePath);
|
|
229
|
+
if (errors.length > 0)
|
|
230
|
+
return { errors };
|
|
231
|
+
return { manifest: parsed.data, errors: [] };
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=bundleManifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundleManifest.js","sourceRoot":"","sources":["../../../src/cli/plugins/bundleManifest.ts"],"names":[],"mappings":"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"}
|