@stigmer/plugin-package 3.15.3-dev.20260916211208
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/LICENSE +190 -0
- package/README.md +66 -0
- package/detect.d.ts +50 -0
- package/detect.d.ts.map +1 -0
- package/detect.js +164 -0
- package/detect.js.map +1 -0
- package/dialects/claude.d.ts +30 -0
- package/dialects/claude.d.ts.map +1 -0
- package/dialects/claude.js +71 -0
- package/dialects/claude.js.map +1 -0
- package/dialects/codex.d.ts +18 -0
- package/dialects/codex.d.ts.map +1 -0
- package/dialects/codex.js +19 -0
- package/dialects/codex.js.map +1 -0
- package/dialects/cursor.d.ts +23 -0
- package/dialects/cursor.d.ts.map +1 -0
- package/dialects/cursor.js +63 -0
- package/dialects/cursor.js.map +1 -0
- package/dialects/manifest.d.ts +109 -0
- package/dialects/manifest.d.ts.map +1 -0
- package/dialects/manifest.js +194 -0
- package/dialects/manifest.js.map +1 -0
- package/dialects/open.d.ts +18 -0
- package/dialects/open.d.ts.map +1 -0
- package/dialects/open.js +47 -0
- package/dialects/open.js.map +1 -0
- package/documents.d.ts +43 -0
- package/documents.d.ts.map +1 -0
- package/documents.js +111 -0
- package/documents.js.map +1 -0
- package/files.d.ts +114 -0
- package/files.d.ts.map +1 -0
- package/files.js +187 -0
- package/files.js.map +1 -0
- package/frontmatter.d.ts +51 -0
- package/frontmatter.d.ts.map +1 -0
- package/frontmatter.js +61 -0
- package/frontmatter.js.map +1 -0
- package/index.d.ts +19 -0
- package/index.d.ts.map +1 -0
- package/index.js +17 -0
- package/index.js.map +1 -0
- package/messages.d.ts +39 -0
- package/messages.d.ts.map +1 -0
- package/messages.js +135 -0
- package/messages.js.map +1 -0
- package/normalise/ignored.d.ts +24 -0
- package/normalise/ignored.d.ts.map +1 -0
- package/normalise/ignored.js +68 -0
- package/normalise/ignored.js.map +1 -0
- package/normalise/mcp-servers.d.ts +47 -0
- package/normalise/mcp-servers.d.ts.map +1 -0
- package/normalise/mcp-servers.js +397 -0
- package/normalise/mcp-servers.js.map +1 -0
- package/normalise/overlay.d.ts +27 -0
- package/normalise/overlay.d.ts.map +1 -0
- package/normalise/overlay.js +67 -0
- package/normalise/overlay.js.map +1 -0
- package/normalise/skills.d.ts +31 -0
- package/normalise/skills.d.ts.map +1 -0
- package/normalise/skills.js +116 -0
- package/normalise/skills.js.map +1 -0
- package/normalise/sub-agents.d.ts +44 -0
- package/normalise/sub-agents.d.ts.map +1 -0
- package/normalise/sub-agents.js +168 -0
- package/normalise/sub-agents.js.map +1 -0
- package/normalise/variables.d.ts +27 -0
- package/normalise/variables.d.ts.map +1 -0
- package/normalise/variables.js +155 -0
- package/normalise/variables.js.map +1 -0
- package/outcome.d.ts +46 -0
- package/outcome.d.ts.map +1 -0
- package/outcome.js +21 -0
- package/outcome.js.map +1 -0
- package/package.json +40 -0
- package/placeholders.d.ts +41 -0
- package/placeholders.d.ts.map +1 -0
- package/placeholders.js +68 -0
- package/placeholders.js.map +1 -0
- package/read-plugin-package.d.ts +19 -0
- package/read-plugin-package.d.ts.map +1 -0
- package/read-plugin-package.js +67 -0
- package/read-plugin-package.js.map +1 -0
- package/src/__test-utils__/directory-files.ts +29 -0
- package/src/__test-utils__/read.ts +55 -0
- package/src/__tests__/adversarial.test.ts +434 -0
- package/src/__tests__/detect.test.ts +133 -0
- package/src/__tests__/files.test.ts +119 -0
- package/src/__tests__/fixtures/cursor-plugins/NOTICE +22 -0
- package/src/__tests__/fixtures/cursor-plugins/advisor/.cursor-plugin/plugin.json +33 -0
- package/src/__tests__/fixtures/cursor-plugins/advisor/CHANGELOG.md +8 -0
- package/src/__tests__/fixtures/cursor-plugins/advisor/LICENSE +21 -0
- package/src/__tests__/fixtures/cursor-plugins/advisor/README.md +87 -0
- package/src/__tests__/fixtures/cursor-plugins/advisor/agents/advisor-subagent.md +48 -0
- package/src/__tests__/fixtures/cursor-plugins/advisor/assets/avatar.png +0 -0
- package/src/__tests__/fixtures/cursor-plugins/advisor/hooks/capture-response.sh +20 -0
- package/src/__tests__/fixtures/cursor-plugins/advisor/hooks/hooks.json +27 -0
- package/src/__tests__/fixtures/cursor-plugins/advisor/hooks/lib.sh +61 -0
- package/src/__tests__/fixtures/cursor-plugins/advisor/hooks/mark-pending.sh +27 -0
- package/src/__tests__/fixtures/cursor-plugins/advisor/hooks/record-consult.sh +41 -0
- package/src/__tests__/fixtures/cursor-plugins/advisor/hooks/stop-hook.sh +48 -0
- package/src/__tests__/fixtures/cursor-plugins/advisor/skills/advisor/SKILL.md +123 -0
- package/src/__tests__/fixtures/cursor-plugins/advisor/skills/advisor/references/briefing-template.md +44 -0
- package/src/__tests__/fixtures/cursor-plugins/github/.cursor-plugin/plugin.json +45 -0
- package/src/__tests__/fixtures/cursor-plugins/github/CHANGELOG.md +9 -0
- package/src/__tests__/fixtures/cursor-plugins/github/LICENSE +21 -0
- package/src/__tests__/fixtures/cursor-plugins/github/README.md +64 -0
- package/src/__tests__/fixtures/cursor-plugins/github/assets/logo.svg +0 -0
- package/src/__tests__/fixtures/cursor-plugins/github/mcp.json +11 -0
- package/src/__tests__/fixtures/cursor-plugins/playwright/.cursor-plugin/plugin.json +35 -0
- package/src/__tests__/fixtures/cursor-plugins/playwright/CHANGELOG.md +8 -0
- package/src/__tests__/fixtures/cursor-plugins/playwright/LICENSE +21 -0
- package/src/__tests__/fixtures/cursor-plugins/playwright/README.md +46 -0
- package/src/__tests__/fixtures/cursor-plugins/playwright/assets/logo.svg +0 -0
- package/src/__tests__/fixtures/cursor-plugins/playwright/mcp.json +8 -0
- package/src/__tests__/fixtures/cursor-plugins/salesforce/.cursor-plugin/plugin.json +48 -0
- package/src/__tests__/fixtures/cursor-plugins/salesforce/CHANGELOG.md +10 -0
- package/src/__tests__/fixtures/cursor-plugins/salesforce/LICENSE +21 -0
- package/src/__tests__/fixtures/cursor-plugins/salesforce/README.md +95 -0
- package/src/__tests__/fixtures/cursor-plugins/salesforce/assets/logo.svg +0 -0
- package/src/__tests__/fixtures/cursor-plugins/salesforce/mcp.json +12 -0
- package/src/__tests__/fixtures/cursor-plugins/thermos/.cursor-plugin/plugin.json +32 -0
- package/src/__tests__/fixtures/cursor-plugins/thermos/CHANGELOG.md +8 -0
- package/src/__tests__/fixtures/cursor-plugins/thermos/LICENSE +21 -0
- package/src/__tests__/fixtures/cursor-plugins/thermos/README.md +70 -0
- package/src/__tests__/fixtures/cursor-plugins/thermos/agents/thermo-nuclear-code-quality-review-subagent.md +23 -0
- package/src/__tests__/fixtures/cursor-plugins/thermos/agents/thermo-nuclear-review-subagent.md +28 -0
- package/src/__tests__/fixtures/cursor-plugins/thermos/assets/logo.png +0 -0
- package/src/__tests__/fixtures/cursor-plugins/thermos/skills/thermo-nuclear-code-quality-review/SKILL.md +192 -0
- package/src/__tests__/fixtures/cursor-plugins/thermos/skills/thermo-nuclear-review/SKILL.md +51 -0
- package/src/__tests__/fixtures/cursor-plugins/thermos/skills/thermos/SKILL.md +21 -0
- package/src/__tests__/fixtures/cursor-plugins/xero/.cursor-plugin/plugin.json +53 -0
- package/src/__tests__/fixtures/cursor-plugins/xero/CHANGELOG.md +9 -0
- package/src/__tests__/fixtures/cursor-plugins/xero/LICENSE +21 -0
- package/src/__tests__/fixtures/cursor-plugins/xero/README.md +79 -0
- package/src/__tests__/fixtures/cursor-plugins/xero/assets/logo.png +0 -0
- package/src/__tests__/fixtures/cursor-plugins/xero/mcp.json +16 -0
- package/src/__tests__/fixtures.test.ts +198 -0
- package/src/__tests__/mcp-servers.test.ts +120 -0
- package/src/__tests__/overlay-and-ignored.test.ts +65 -0
- package/src/__tests__/skills.test.ts +89 -0
- package/src/__tests__/sub-agents.test.ts +111 -0
- package/src/__tests__/variables.test.ts +94 -0
- package/src/detect.ts +189 -0
- package/src/dialects/claude.ts +90 -0
- package/src/dialects/codex.ts +24 -0
- package/src/dialects/cursor.ts +73 -0
- package/src/dialects/manifest.ts +237 -0
- package/src/dialects/open.ts +48 -0
- package/src/documents.ts +145 -0
- package/src/files.ts +213 -0
- package/src/frontmatter.ts +70 -0
- package/src/index.ts +59 -0
- package/src/messages.ts +206 -0
- package/src/normalise/ignored.ts +70 -0
- package/src/normalise/mcp-servers.ts +427 -0
- package/src/normalise/overlay.ts +71 -0
- package/src/normalise/skills.ts +126 -0
- package/src/normalise/sub-agents.ts +184 -0
- package/src/normalise/variables.ts +161 -0
- package/src/outcome.ts +122 -0
- package/src/placeholders.ts +74 -0
- package/src/read-plugin-package.ts +74 -0
- package/src/testing.ts +258 -0
- package/src/types.ts +189 -0
- package/testing.d.ts +106 -0
- package/testing.d.ts.map +1 -0
- package/testing.js +182 -0
- package/testing.js.map +1 -0
- package/types.d.ts +152 -0
- package/types.d.ts.map +1 -0
- package/types.js +19 -0
- package/types.js.map +1 -0
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stigmer/plugin-package",
|
|
3
|
+
"version": "3.15.3-dev.20260916211208",
|
|
4
|
+
"description": "Reads an Agent Plugins package — the open 1.0.0 format and the Cursor, Claude Code and Codex dialects — into one normalised description of what Stigmer would install, refusing with one sentence per problem what Stigmer cannot carry; pure over an in-memory file reader, shared by the CLI's offline validation and the server's install",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/stigmer/stigmer.git",
|
|
11
|
+
"directory": "backend/libs/ts/plugin-package"
|
|
12
|
+
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": "^22.13.0 || >=23.4.0"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"stigmer",
|
|
18
|
+
"agent-plugins",
|
|
19
|
+
"plugin",
|
|
20
|
+
"skills",
|
|
21
|
+
"mcp"
|
|
22
|
+
],
|
|
23
|
+
"main": "./index.js",
|
|
24
|
+
"types": "./index.d.ts",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./index.d.ts",
|
|
28
|
+
"import": "./index.js",
|
|
29
|
+
"default": "./index.js"
|
|
30
|
+
},
|
|
31
|
+
"./testing": {
|
|
32
|
+
"types": "./testing.d.ts",
|
|
33
|
+
"import": "./testing.js",
|
|
34
|
+
"default": "./testing.js"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"yaml": "^2.8.2"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `${VAR}` vocabulary: what counts as a variable reference, what counts
|
|
3
|
+
* as a reference to the plugin's own files, and the Claude rewrite.
|
|
4
|
+
*
|
|
5
|
+
* `PLACEHOLDER_PATTERN` is the runner's own scanner, verbatim: the runner
|
|
6
|
+
* resolves `${VAR}` strictly in a server's headers and arguments and refuses
|
|
7
|
+
* to start a server with an unresolved one, so this is the definition of "a
|
|
8
|
+
* reference" in every dialect, including the open format whose text forbids
|
|
9
|
+
* expansion in headers. A plugin's `${API_KEY}` in a header means "the
|
|
10
|
+
* caller's API_KEY" on Stigmer whichever tool wrote it.
|
|
11
|
+
*
|
|
12
|
+
* Claude's `${user_config.KEY}` carries a dot the runner's scanner would
|
|
13
|
+
* never match, so it is rewritten to `${KEY}` before anything reads it; the
|
|
14
|
+
* rewrite is what makes a Claude plugin's server start, not a courtesy.
|
|
15
|
+
*
|
|
16
|
+
* The plugin-root placeholders are the one class the library refuses: the
|
|
17
|
+
* runner mounts nothing from a plugin, so a server that reaches for
|
|
18
|
+
* `${PLUGIN_ROOT}` (any dialect's spelling) can never find what it points
|
|
19
|
+
* at. The set is checked before the generic scan because `${PLUGIN_ROOT}`
|
|
20
|
+
* also matches the generic pattern.
|
|
21
|
+
*/
|
|
22
|
+
/** The runner's `${VAR_NAME}` scanner (`shared/placeholder-resolver.ts`). */
|
|
23
|
+
export declare const PLACEHOLDER_PATTERN: RegExp;
|
|
24
|
+
/** A variable name the runner's scanner can reference. */
|
|
25
|
+
export declare const VARIABLE_NAME_PATTERN: RegExp;
|
|
26
|
+
/**
|
|
27
|
+
* Every spelling of "the plugin's own directory" across the dialects:
|
|
28
|
+
* the open format's, Claude Code's (plus its project directory), Cursor's.
|
|
29
|
+
*/
|
|
30
|
+
export declare const PLUGIN_ROOT_PLACEHOLDERS: ReadonlySet<string>;
|
|
31
|
+
/** The reserved environment names the open format forbids a server's `env` to set. */
|
|
32
|
+
export declare const PLUGIN_ROOT_ENV_NAMES: ReadonlySet<string>;
|
|
33
|
+
/** `${user_config.KEY}` -> `${KEY}`. */
|
|
34
|
+
export declare function rewriteUserConfig(value: string): string;
|
|
35
|
+
/** The first plugin-root placeholder in `value`, or `undefined`. */
|
|
36
|
+
export declare function findPluginRootPlaceholder(value: string): string | undefined;
|
|
37
|
+
/** The variable names referenced in `value`, in order of appearance, deduplicated. */
|
|
38
|
+
export declare function referencedVariables(value: string): readonly string[];
|
|
39
|
+
/** The variable name when `value` is exactly one placeholder and nothing else; otherwise `undefined`. */
|
|
40
|
+
export declare function singlePlaceholderName(value: string): string | undefined;
|
|
41
|
+
//# sourceMappingURL=placeholders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"placeholders.d.ts","sourceRoot":"","sources":["../src/placeholders.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,6EAA6E;AAC7E,eAAO,MAAM,mBAAmB,QAAoC,CAAC;AAErE,0DAA0D;AAC1D,eAAO,MAAM,qBAAqB,QAA6B,CAAC;AAIhE;;;GAGG;AACH,eAAO,MAAM,wBAAwB,EAAE,WAAW,CAAC,MAAM,CAOvD,CAAC;AAEH,sFAAsF;AACtF,eAAO,MAAM,qBAAqB,EAAE,WAAW,CAAC,MAAM,CAA2C,CAAC;AAElG,wCAAwC;AACxC,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,oEAAoE;AACpE,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK3E;AAED,sFAAsF;AACtF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAOpE;AAED,yGAAyG;AACzG,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGvE"}
|
package/placeholders.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `${VAR}` vocabulary: what counts as a variable reference, what counts
|
|
3
|
+
* as a reference to the plugin's own files, and the Claude rewrite.
|
|
4
|
+
*
|
|
5
|
+
* `PLACEHOLDER_PATTERN` is the runner's own scanner, verbatim: the runner
|
|
6
|
+
* resolves `${VAR}` strictly in a server's headers and arguments and refuses
|
|
7
|
+
* to start a server with an unresolved one, so this is the definition of "a
|
|
8
|
+
* reference" in every dialect, including the open format whose text forbids
|
|
9
|
+
* expansion in headers. A plugin's `${API_KEY}` in a header means "the
|
|
10
|
+
* caller's API_KEY" on Stigmer whichever tool wrote it.
|
|
11
|
+
*
|
|
12
|
+
* Claude's `${user_config.KEY}` carries a dot the runner's scanner would
|
|
13
|
+
* never match, so it is rewritten to `${KEY}` before anything reads it; the
|
|
14
|
+
* rewrite is what makes a Claude plugin's server start, not a courtesy.
|
|
15
|
+
*
|
|
16
|
+
* The plugin-root placeholders are the one class the library refuses: the
|
|
17
|
+
* runner mounts nothing from a plugin, so a server that reaches for
|
|
18
|
+
* `${PLUGIN_ROOT}` (any dialect's spelling) can never find what it points
|
|
19
|
+
* at. The set is checked before the generic scan because `${PLUGIN_ROOT}`
|
|
20
|
+
* also matches the generic pattern.
|
|
21
|
+
*/
|
|
22
|
+
/** The runner's `${VAR_NAME}` scanner (`shared/placeholder-resolver.ts`). */
|
|
23
|
+
export const PLACEHOLDER_PATTERN = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
24
|
+
/** A variable name the runner's scanner can reference. */
|
|
25
|
+
export const VARIABLE_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
26
|
+
const USER_CONFIG_PATTERN = /\$\{user_config\.([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
27
|
+
/**
|
|
28
|
+
* Every spelling of "the plugin's own directory" across the dialects:
|
|
29
|
+
* the open format's, Claude Code's (plus its project directory), Cursor's.
|
|
30
|
+
*/
|
|
31
|
+
export const PLUGIN_ROOT_PLACEHOLDERS = new Set([
|
|
32
|
+
"${PLUGIN_ROOT}",
|
|
33
|
+
"${PLUGIN_DATA}",
|
|
34
|
+
"${CLAUDE_PLUGIN_ROOT}",
|
|
35
|
+
"${CLAUDE_PLUGIN_DATA}",
|
|
36
|
+
"${CLAUDE_PROJECT_DIR}",
|
|
37
|
+
"${CURSOR_PLUGIN_ROOT}",
|
|
38
|
+
]);
|
|
39
|
+
/** The reserved environment names the open format forbids a server's `env` to set. */
|
|
40
|
+
export const PLUGIN_ROOT_ENV_NAMES = new Set(["PLUGIN_ROOT", "PLUGIN_DATA"]);
|
|
41
|
+
/** `${user_config.KEY}` -> `${KEY}`. */
|
|
42
|
+
export function rewriteUserConfig(value) {
|
|
43
|
+
return value.replace(USER_CONFIG_PATTERN, (_match, key) => `\${${key}}`);
|
|
44
|
+
}
|
|
45
|
+
/** The first plugin-root placeholder in `value`, or `undefined`. */
|
|
46
|
+
export function findPluginRootPlaceholder(value) {
|
|
47
|
+
for (const placeholder of PLUGIN_ROOT_PLACEHOLDERS) {
|
|
48
|
+
if (value.includes(placeholder))
|
|
49
|
+
return placeholder;
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
/** The variable names referenced in `value`, in order of appearance, deduplicated. */
|
|
54
|
+
export function referencedVariables(value) {
|
|
55
|
+
const names = [];
|
|
56
|
+
for (const match of value.matchAll(PLACEHOLDER_PATTERN)) {
|
|
57
|
+
const name = match[1];
|
|
58
|
+
if (name !== undefined && !names.includes(name))
|
|
59
|
+
names.push(name);
|
|
60
|
+
}
|
|
61
|
+
return names;
|
|
62
|
+
}
|
|
63
|
+
/** The variable name when `value` is exactly one placeholder and nothing else; otherwise `undefined`. */
|
|
64
|
+
export function singlePlaceholderName(value) {
|
|
65
|
+
const match = /^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$/.exec(value);
|
|
66
|
+
return match?.[1];
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=placeholders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"placeholders.js","sourceRoot":"","sources":["../src/placeholders.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,6EAA6E;AAC7E,MAAM,CAAC,MAAM,mBAAmB,GAAG,iCAAiC,CAAC;AAErE,0DAA0D;AAC1D,MAAM,CAAC,MAAM,qBAAqB,GAAG,0BAA0B,CAAC;AAEhE,MAAM,mBAAmB,GAAG,8CAA8C,CAAC;AAE3E;;;GAGG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAwB,IAAI,GAAG,CAAC;IACnE,gBAAgB;IAChB,gBAAgB;IAChB,uBAAuB;IACvB,uBAAuB;IACvB,uBAAuB;IACvB,uBAAuB;CACxB,CAAC,CAAC;AAEH,sFAAsF;AACtF,MAAM,CAAC,MAAM,qBAAqB,GAAwB,IAAI,GAAG,CAAC,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC;AAElG,wCAAwC;AACxC,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,OAAO,KAAK,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC,MAAM,EAAE,GAAW,EAAE,EAAE,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;AACnF,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,yBAAyB,CAAC,KAAa;IACrD,KAAK,MAAM,WAAW,IAAI,wBAAwB,EAAE,CAAC;QACnD,IAAI,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC;YAAE,OAAO,WAAW,CAAC;IACtD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACxD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,yGAAyG;AACzG,MAAM,UAAU,qBAAqB,CAAC,KAAa;IACjD,MAAM,KAAK,GAAG,kCAAkC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7D,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one entry: a `PluginFiles` in, a `PluginReadOutcome` out.
|
|
3
|
+
*
|
|
4
|
+
* The read is a fixed sequence, each stage a pure function over the index
|
|
5
|
+
* and the stages before it: containment of the listed paths; manifest
|
|
6
|
+
* detection and identity; skills; MCP servers; variables (which need the
|
|
7
|
+
* servers' references); sub-agents (which need the skills' names); the
|
|
8
|
+
* `ai.stigmer/` overlay (which needs the servers' names); the ignored
|
|
9
|
+
* components. Every stage records findings and keeps going, so the outcome
|
|
10
|
+
* names every problem in the package at once, and the plugin is returned
|
|
11
|
+
* only when no stage refused.
|
|
12
|
+
*
|
|
13
|
+
* Nothing here throws on a plugin's content. A throw means a reader broke
|
|
14
|
+
* its contract (a listed path that cannot be read) or the library has a bug.
|
|
15
|
+
*/
|
|
16
|
+
import { type PluginFiles } from "./files.js";
|
|
17
|
+
import type { PluginReadOutcome } from "./outcome.js";
|
|
18
|
+
export declare function readPluginPackage(files: PluginFiles): PluginReadOutcome;
|
|
19
|
+
//# sourceMappingURL=read-plugin-package.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-plugin-package.d.ts","sourceRoot":"","sources":["../src/read-plugin-package.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAoC,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAQhF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGtD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,iBAAiB,CA6CvE"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one entry: a `PluginFiles` in, a `PluginReadOutcome` out.
|
|
3
|
+
*
|
|
4
|
+
* The read is a fixed sequence, each stage a pure function over the index
|
|
5
|
+
* and the stages before it: containment of the listed paths; manifest
|
|
6
|
+
* detection and identity; skills; MCP servers; variables (which need the
|
|
7
|
+
* servers' references); sub-agents (which need the skills' names); the
|
|
8
|
+
* `ai.stigmer/` overlay (which needs the servers' names); the ignored
|
|
9
|
+
* components. Every stage records findings and keeps going, so the outcome
|
|
10
|
+
* names every problem in the package at once, and the plugin is returned
|
|
11
|
+
* only when no stage refused.
|
|
12
|
+
*
|
|
13
|
+
* Nothing here throws on a plugin's content. A throw means a reader broke
|
|
14
|
+
* its contract (a listed path that cannot be read) or the library has a bug.
|
|
15
|
+
*/
|
|
16
|
+
import { detectManifests } from "./detect.js";
|
|
17
|
+
import { isContainedPath, PluginFileIndex } from "./files.js";
|
|
18
|
+
import { Findings } from "./messages.js";
|
|
19
|
+
import { dedupeIgnored, ignoredOnDisk } from "./normalise/ignored.js";
|
|
20
|
+
import { normaliseMcpServers } from "./normalise/mcp-servers.js";
|
|
21
|
+
import { normaliseOverlay } from "./normalise/overlay.js";
|
|
22
|
+
import { normaliseSkills } from "./normalise/skills.js";
|
|
23
|
+
import { normaliseSubAgents } from "./normalise/sub-agents.js";
|
|
24
|
+
import { normaliseVariables } from "./normalise/variables.js";
|
|
25
|
+
export function readPluginPackage(files) {
|
|
26
|
+
const findings = new Findings();
|
|
27
|
+
for (const entry of files.entries) {
|
|
28
|
+
if (!isContainedPath(entry.path))
|
|
29
|
+
findings.error("path-uncontained", { path: entry.path });
|
|
30
|
+
}
|
|
31
|
+
const index = new PluginFileIndex(files);
|
|
32
|
+
const set = detectManifests(index, findings);
|
|
33
|
+
if (set === undefined) {
|
|
34
|
+
return { ok: false, errors: findings.errors, warnings: findings.warnings };
|
|
35
|
+
}
|
|
36
|
+
const skills = normaliseSkills(index, set, findings);
|
|
37
|
+
const servers = normaliseMcpServers(index, set.mcpSources, findings);
|
|
38
|
+
const mcpServers = servers.servers;
|
|
39
|
+
const variables = normaliseVariables(set, servers, findings);
|
|
40
|
+
const subAgents = normaliseSubAgents(index, set, skills, findings);
|
|
41
|
+
const overlay = normaliseOverlay(index, servers.declaredNames, findings);
|
|
42
|
+
const ignored = dedupeIgnored([ignoredOnDisk(index, set.readsAgents), ...set.manifests.map((m) => m.ignored)]);
|
|
43
|
+
if (findings.errors.length > 0 || set.name === undefined) {
|
|
44
|
+
return { ok: false, errors: findings.errors, warnings: findings.warnings };
|
|
45
|
+
}
|
|
46
|
+
const identity = set.manifests[0]?.identity ?? {};
|
|
47
|
+
const plugin = {
|
|
48
|
+
name: set.name,
|
|
49
|
+
...(identity.version !== undefined && { version: identity.version }),
|
|
50
|
+
...(identity.description !== undefined && { description: identity.description }),
|
|
51
|
+
...(identity.author !== undefined && { author: identity.author }),
|
|
52
|
+
...(identity.homepage !== undefined && { homepage: identity.homepage }),
|
|
53
|
+
...(identity.repository !== undefined && { repository: identity.repository }),
|
|
54
|
+
...(identity.license !== undefined && { license: identity.license }),
|
|
55
|
+
keywords: identity.keywords ?? [],
|
|
56
|
+
dialect: set.dialect,
|
|
57
|
+
manifestsFound: set.manifests.map((m) => m.path),
|
|
58
|
+
skills,
|
|
59
|
+
mcpServers,
|
|
60
|
+
subAgents,
|
|
61
|
+
variables,
|
|
62
|
+
overlay,
|
|
63
|
+
ignored,
|
|
64
|
+
};
|
|
65
|
+
return { ok: true, plugin, warnings: findings.warnings };
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=read-plugin-package.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-plugin-package.js","sourceRoot":"","sources":["../src/read-plugin-package.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A test-only `PluginFiles` over a directory on disk, for the vendored
|
|
3
|
+
* fixtures. Sorted, symlinks skipped, sizes from `stat`, the contract the
|
|
4
|
+
* CLI's walker honours; kept here (not in the library) because the
|
|
5
|
+
* library's main entry imports no `node:*` module and the CLI owns the
|
|
6
|
+
* real walker with its ignore rules.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
|
|
12
|
+
import { comparePaths, type PluginFileEntry, type PluginFiles } from "../files.js";
|
|
13
|
+
|
|
14
|
+
export function directoryPluginFiles(root: string): PluginFiles {
|
|
15
|
+
const entries: PluginFileEntry[] = [];
|
|
16
|
+
const walk = (dir: string, prefix: string): void => {
|
|
17
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
18
|
+
const path = prefix === "" ? entry.name : `${prefix}/${entry.name}`;
|
|
19
|
+
if (entry.isDirectory()) walk(join(dir, entry.name), path);
|
|
20
|
+
else if (entry.isFile()) entries.push({ path, size: statSync(join(dir, entry.name)).size });
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
walk(root, "");
|
|
24
|
+
entries.sort((a, b) => comparePaths(a.path, b.path));
|
|
25
|
+
return {
|
|
26
|
+
entries,
|
|
27
|
+
read: (path) => new Uint8Array(readFileSync(join(root, ...path.split("/")))),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helpers: read a fixture map, name the finding kinds an outcome
|
|
3
|
+
* carries, and unwrap the arms with a diagnostic when the other arm came
|
|
4
|
+
* back. Kinds are returned SORTED and complete (errors and warnings both),
|
|
5
|
+
* so an adversarial test asserts everything the reader said and a warning
|
|
6
|
+
* that appears beside the error under test is named, never tolerated by
|
|
7
|
+
* omission.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { expect } from "vitest";
|
|
11
|
+
|
|
12
|
+
import { inMemoryPluginFiles } from "../files.js";
|
|
13
|
+
import type { PluginFinding, PluginReadOutcome } from "../outcome.js";
|
|
14
|
+
import { readPluginPackage } from "../read-plugin-package.js";
|
|
15
|
+
import type { PluginFixture } from "../testing.js";
|
|
16
|
+
import type { PluginPackage } from "../types.js";
|
|
17
|
+
|
|
18
|
+
export function read(files: PluginFixture): PluginReadOutcome {
|
|
19
|
+
return readPluginPackage(inMemoryPluginFiles(files));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface Kinds {
|
|
23
|
+
readonly errors: readonly string[];
|
|
24
|
+
readonly warnings: readonly string[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function kindsOf(outcome: PluginReadOutcome): Kinds {
|
|
28
|
+
const sorted = (findings: readonly PluginFinding[]): string[] => findings.map((f) => f.kind).sort();
|
|
29
|
+
return outcome.ok
|
|
30
|
+
? { errors: [], warnings: sorted(outcome.warnings) }
|
|
31
|
+
: { errors: sorted(outcome.errors), warnings: sorted(outcome.warnings) };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** The plugin, failing with every finding's sentence when the read refused. */
|
|
35
|
+
export function accepted(outcome: PluginReadOutcome): PluginPackage {
|
|
36
|
+
if (!outcome.ok) {
|
|
37
|
+
expect.fail(`expected an accepted plugin, got refusals:\n${outcome.errors.map((f) => ` ${f.kind}: ${f.message}`).join("\n")}`);
|
|
38
|
+
}
|
|
39
|
+
return outcome.plugin;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** The errors, failing when the read accepted. */
|
|
43
|
+
export function refused(outcome: PluginReadOutcome): readonly PluginFinding[] {
|
|
44
|
+
if (outcome.ok) {
|
|
45
|
+
expect.fail(`expected a refusal, got an accepted plugin '${outcome.plugin.name}'`);
|
|
46
|
+
}
|
|
47
|
+
return outcome.errors;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** The one finding of `kind`, failing when it is absent or repeated. */
|
|
51
|
+
export function findingOf(findings: readonly PluginFinding[], kind: string): PluginFinding {
|
|
52
|
+
const matches = findings.filter((f) => f.kind === kind);
|
|
53
|
+
expect(matches, `exactly one '${kind}' finding`).toHaveLength(1);
|
|
54
|
+
return matches[0] as PluginFinding;
|
|
55
|
+
}
|