@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/src/testing.ts
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory plugin builders for tests (exported as
|
|
3
|
+
* `@stigmer/plugin-package/testing`).
|
|
4
|
+
*
|
|
5
|
+
* One builder per dialect, each writing the exact file layout that
|
|
6
|
+
* dialect's tools produce: `openPlugin` a root `plugin.json` with the
|
|
7
|
+
* canonical `$schema` and an `mcp.json` beside it; `claudePlugin` a
|
|
8
|
+
* `.claude-plugin/plugin.json` with `.mcp.json`; `cursorPlugin` a
|
|
9
|
+
* `.cursor-plugin/plugin.json` declaring `./skills/`, `./agents/` and
|
|
10
|
+
* `./mcp.json` the way every published Cursor plugin does; `codexPlugin`
|
|
11
|
+
* the legacy `.codex-plugin/plugin.json` compatibility layout. The
|
|
12
|
+
* adversarial suite starts from a valid plugin and breaks exactly one
|
|
13
|
+
* thing with the mutators (`withFile`, `withoutFile`,
|
|
14
|
+
* `withManifestField`), so each test reads as "this plugin, minus this",
|
|
15
|
+
* and the consumers' tests (the CLI's, the server's) craft their fixtures
|
|
16
|
+
* from the same source so the shapes never drift apart.
|
|
17
|
+
*
|
|
18
|
+
* Builders return a path -> content map; `inMemoryPluginFiles` turns one
|
|
19
|
+
* into the `PluginFiles` the reader takes. Zipping a fixture for an
|
|
20
|
+
* archive-based consumer is `@stigmer/zip-structure/testing`'s job.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { stringify as stringifyYaml } from "yaml";
|
|
24
|
+
|
|
25
|
+
import { inMemoryPluginFiles } from "./files.js";
|
|
26
|
+
import { AGENT_PLUGINS_MANIFEST_SCHEMA, AGENT_PLUGINS_MCP_SCHEMA, MANIFEST_LOCATIONS } from "./messages.js";
|
|
27
|
+
|
|
28
|
+
export { inMemoryPluginFiles };
|
|
29
|
+
|
|
30
|
+
/** A plugin as files: plugin-relative path -> content. */
|
|
31
|
+
export type PluginFixture = Map<string, string | Uint8Array>;
|
|
32
|
+
|
|
33
|
+
export interface SkillFixture {
|
|
34
|
+
/** The frontmatter `name`; also the directory name unless `dir` says otherwise. */
|
|
35
|
+
readonly name: string;
|
|
36
|
+
readonly description?: string;
|
|
37
|
+
/** Directory under `skills/` (or the declared skills root); defaults to `name`. */
|
|
38
|
+
readonly dir?: string;
|
|
39
|
+
/** Extra frontmatter fields, or `null` for a `SKILL.md` with no frontmatter at all. */
|
|
40
|
+
readonly frontmatter?: Readonly<Record<string, unknown>> | null;
|
|
41
|
+
readonly body?: string;
|
|
42
|
+
/** Extra files inside the skill directory, relative to it. */
|
|
43
|
+
readonly files?: Readonly<Record<string, string>>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface AgentFixture {
|
|
47
|
+
/** File name under `agents/`, without `.md`. */
|
|
48
|
+
readonly file: string;
|
|
49
|
+
/** Frontmatter fields, or `null` for a bare prompt with no frontmatter. */
|
|
50
|
+
readonly frontmatter?: Readonly<Record<string, unknown>> | null;
|
|
51
|
+
readonly body?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
interface CommonFixture {
|
|
55
|
+
readonly name?: string;
|
|
56
|
+
readonly version?: string;
|
|
57
|
+
readonly description?: string;
|
|
58
|
+
/** Extra or overriding manifest fields, merged last. */
|
|
59
|
+
readonly manifest?: Readonly<Record<string, unknown>>;
|
|
60
|
+
readonly skills?: readonly SkillFixture[];
|
|
61
|
+
/** Extra files anywhere in the plugin. */
|
|
62
|
+
readonly files?: Readonly<Record<string, string | Uint8Array>>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface OpenPluginFixture extends CommonFixture {
|
|
66
|
+
/** The manifest `$schema`; `null` omits it. Defaults to the canonical 1.0.0 identifier. */
|
|
67
|
+
readonly schema?: string | null;
|
|
68
|
+
/** The `mcpServers` map for `mcp.json`; absent means no `mcp.json`. */
|
|
69
|
+
readonly mcpServers?: Readonly<Record<string, unknown>>;
|
|
70
|
+
/** The `mcp.json` `$schema`; `null` omits it. */
|
|
71
|
+
readonly mcpSchema?: string | null;
|
|
72
|
+
/** Extra top-level `mcp.json` fields. */
|
|
73
|
+
readonly mcpConfig?: Readonly<Record<string, unknown>>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface ClaudePluginFixture extends CommonFixture {
|
|
77
|
+
readonly agents?: readonly AgentFixture[];
|
|
78
|
+
/** The `mcpServers` map for `.mcp.json`; absent means no `.mcp.json`. */
|
|
79
|
+
readonly mcpServers?: Readonly<Record<string, unknown>>;
|
|
80
|
+
readonly userConfig?: Readonly<Record<string, unknown>>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface CursorPluginFixture extends CommonFixture {
|
|
84
|
+
readonly agents?: readonly AgentFixture[];
|
|
85
|
+
/** The `mcpServers` map for `mcp.json`, declared as `"mcpServers": "./mcp.json"`. */
|
|
86
|
+
readonly mcpServers?: Readonly<Record<string, unknown>>;
|
|
87
|
+
/** The `variables` JSON Schema: property name -> `{ type, title, description }`. */
|
|
88
|
+
readonly variables?: Readonly<Record<string, Readonly<Record<string, unknown>>>>;
|
|
89
|
+
readonly required?: readonly string[];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface CodexPluginFixture extends CommonFixture {
|
|
93
|
+
/** The `mcpServers` map for `.mcp.json`, declared as `"mcpServers": "./.mcp.json"`. */
|
|
94
|
+
readonly mcpServers?: Readonly<Record<string, unknown>>;
|
|
95
|
+
/** The `apps` map for `.app.json`. */
|
|
96
|
+
readonly apps?: Readonly<Record<string, unknown>>;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const DEFAULT_NAME = "example";
|
|
100
|
+
|
|
101
|
+
/** An Agent Plugins 1.0.0 package. */
|
|
102
|
+
export function openPlugin(fixture: OpenPluginFixture = {}): PluginFixture {
|
|
103
|
+
const files: PluginFixture = new Map();
|
|
104
|
+
const manifest: Record<string, unknown> = {
|
|
105
|
+
...(fixture.schema !== null && { $schema: fixture.schema ?? AGENT_PLUGINS_MANIFEST_SCHEMA }),
|
|
106
|
+
name: fixture.name ?? DEFAULT_NAME,
|
|
107
|
+
...(fixture.version !== undefined && { version: fixture.version }),
|
|
108
|
+
...(fixture.description !== undefined && { description: fixture.description }),
|
|
109
|
+
...fixture.manifest,
|
|
110
|
+
};
|
|
111
|
+
files.set(MANIFEST_LOCATIONS["agent-plugins"], json(manifest));
|
|
112
|
+
if (fixture.mcpServers !== undefined) {
|
|
113
|
+
files.set(
|
|
114
|
+
"mcp.json",
|
|
115
|
+
json({
|
|
116
|
+
...(fixture.mcpSchema !== null && { $schema: fixture.mcpSchema ?? AGENT_PLUGINS_MCP_SCHEMA }),
|
|
117
|
+
mcpServers: fixture.mcpServers,
|
|
118
|
+
...fixture.mcpConfig,
|
|
119
|
+
}),
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
writeSkills(files, "skills", fixture.skills);
|
|
123
|
+
writeExtra(files, fixture.files);
|
|
124
|
+
return files;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** A Claude Code plugin. */
|
|
128
|
+
export function claudePlugin(fixture: ClaudePluginFixture = {}): PluginFixture {
|
|
129
|
+
const files: PluginFixture = new Map();
|
|
130
|
+
const manifest: Record<string, unknown> = {
|
|
131
|
+
name: fixture.name ?? DEFAULT_NAME,
|
|
132
|
+
...(fixture.version !== undefined && { version: fixture.version }),
|
|
133
|
+
...(fixture.description !== undefined && { description: fixture.description }),
|
|
134
|
+
...(fixture.userConfig !== undefined && { userConfig: fixture.userConfig }),
|
|
135
|
+
...fixture.manifest,
|
|
136
|
+
};
|
|
137
|
+
files.set(MANIFEST_LOCATIONS.claude, json(manifest));
|
|
138
|
+
if (fixture.mcpServers !== undefined) files.set(".mcp.json", json({ mcpServers: fixture.mcpServers }));
|
|
139
|
+
writeSkills(files, "skills", fixture.skills);
|
|
140
|
+
writeAgents(files, "agents", fixture.agents);
|
|
141
|
+
writeExtra(files, fixture.files);
|
|
142
|
+
return files;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** A Cursor plugin, declaring its components the way the published catalogue does. */
|
|
146
|
+
export function cursorPlugin(fixture: CursorPluginFixture = {}): PluginFixture {
|
|
147
|
+
const files: PluginFixture = new Map();
|
|
148
|
+
const manifest: Record<string, unknown> = {
|
|
149
|
+
name: fixture.name ?? DEFAULT_NAME,
|
|
150
|
+
...(fixture.version !== undefined && { version: fixture.version }),
|
|
151
|
+
...(fixture.description !== undefined && { description: fixture.description }),
|
|
152
|
+
...(fixture.skills !== undefined && { skills: "./skills/" }),
|
|
153
|
+
...(fixture.agents !== undefined && { agents: "./agents/" }),
|
|
154
|
+
...(fixture.variables !== undefined && {
|
|
155
|
+
variables: {
|
|
156
|
+
type: "object",
|
|
157
|
+
properties: fixture.variables,
|
|
158
|
+
...(fixture.required !== undefined && { required: fixture.required }),
|
|
159
|
+
},
|
|
160
|
+
}),
|
|
161
|
+
...(fixture.mcpServers !== undefined && { mcpServers: "./mcp.json" }),
|
|
162
|
+
...fixture.manifest,
|
|
163
|
+
};
|
|
164
|
+
files.set(MANIFEST_LOCATIONS.cursor, json(manifest));
|
|
165
|
+
if (fixture.mcpServers !== undefined) files.set("mcp.json", json({ mcpServers: fixture.mcpServers }));
|
|
166
|
+
writeSkills(files, "skills", fixture.skills);
|
|
167
|
+
writeAgents(files, "agents", fixture.agents);
|
|
168
|
+
writeExtra(files, fixture.files);
|
|
169
|
+
return files;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** The legacy Codex compatibility layout (`.codex-plugin/plugin.json`, `.mcp.json`, `.app.json`). */
|
|
173
|
+
export function codexPlugin(fixture: CodexPluginFixture = {}): PluginFixture {
|
|
174
|
+
const files: PluginFixture = new Map();
|
|
175
|
+
const manifest: Record<string, unknown> = {
|
|
176
|
+
name: fixture.name ?? DEFAULT_NAME,
|
|
177
|
+
...(fixture.version !== undefined && { version: fixture.version }),
|
|
178
|
+
...(fixture.description !== undefined && { description: fixture.description }),
|
|
179
|
+
...(fixture.skills !== undefined && { skills: "./skills/" }),
|
|
180
|
+
...(fixture.mcpServers !== undefined && { mcpServers: "./.mcp.json" }),
|
|
181
|
+
...(fixture.apps !== undefined && { apps: "./.app.json" }),
|
|
182
|
+
...fixture.manifest,
|
|
183
|
+
};
|
|
184
|
+
files.set(MANIFEST_LOCATIONS.codex, json(manifest));
|
|
185
|
+
if (fixture.mcpServers !== undefined) files.set(".mcp.json", json({ mcpServers: fixture.mcpServers }));
|
|
186
|
+
if (fixture.apps !== undefined) files.set(".app.json", json({ apps: fixture.apps }));
|
|
187
|
+
writeSkills(files, "skills", fixture.skills);
|
|
188
|
+
writeExtra(files, fixture.files);
|
|
189
|
+
return files;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** A copy of `files` with `path` set to `content`. */
|
|
193
|
+
export function withFile(files: PluginFixture, path: string, content: string | Uint8Array): PluginFixture {
|
|
194
|
+
const copy = new Map(files);
|
|
195
|
+
copy.set(path, content);
|
|
196
|
+
return copy;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** A copy of `files` without `path`. */
|
|
200
|
+
export function withoutFile(files: PluginFixture, path: string): PluginFixture {
|
|
201
|
+
const copy = new Map(files);
|
|
202
|
+
copy.delete(path);
|
|
203
|
+
return copy;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* A copy of `files` with one top-level field of the JSON document at
|
|
208
|
+
* `manifestPath` set (or removed, when `value` is `undefined`).
|
|
209
|
+
*/
|
|
210
|
+
export function withManifestField(files: PluginFixture, manifestPath: string, field: string, value: unknown): PluginFixture {
|
|
211
|
+
const current = files.get(manifestPath);
|
|
212
|
+
if (current === undefined) throw new Error(`fixture has no document at '${manifestPath}'`);
|
|
213
|
+
const text = typeof current === "string" ? current : new TextDecoder().decode(current);
|
|
214
|
+
const document = JSON.parse(text) as Record<string, unknown>;
|
|
215
|
+
if (value === undefined) delete document[field];
|
|
216
|
+
else document[field] = value;
|
|
217
|
+
return withFile(files, manifestPath, json(document));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** A `SKILL.md` document from a fixture description. */
|
|
221
|
+
export function skillMarkdown(skill: SkillFixture): string {
|
|
222
|
+
const body = skill.body ?? `# ${skill.name}\n\nInstructions for the ${skill.name} skill.\n`;
|
|
223
|
+
if (skill.frontmatter === null) return body;
|
|
224
|
+
const frontmatter = {
|
|
225
|
+
name: skill.name,
|
|
226
|
+
...(skill.description !== undefined && { description: skill.description }),
|
|
227
|
+
...skill.frontmatter,
|
|
228
|
+
};
|
|
229
|
+
return `---\n${stringifyYaml(frontmatter)}---\n${body}`;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** A sub-agent document from a fixture description. */
|
|
233
|
+
export function agentMarkdown(agent: AgentFixture): string {
|
|
234
|
+
const body = agent.body ?? `You are the ${agent.file} sub-agent. Do the task thoroughly and report back.\n`;
|
|
235
|
+
if (agent.frontmatter === null) return body;
|
|
236
|
+
const frontmatter = { name: agent.file, ...agent.frontmatter };
|
|
237
|
+
return `---\n${stringifyYaml(frontmatter)}---\n${body}`;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function writeSkills(files: PluginFixture, root: string, skills: readonly SkillFixture[] | undefined): void {
|
|
241
|
+
for (const skill of skills ?? []) {
|
|
242
|
+
const dir = `${root}/${skill.dir ?? skill.name}`;
|
|
243
|
+
files.set(`${dir}/SKILL.md`, skillMarkdown(skill));
|
|
244
|
+
for (const [path, content] of Object.entries(skill.files ?? {})) files.set(`${dir}/${path}`, content);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function writeAgents(files: PluginFixture, root: string, agents: readonly AgentFixture[] | undefined): void {
|
|
249
|
+
for (const agent of agents ?? []) files.set(`${root}/${agent.file}.md`, agentMarkdown(agent));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function writeExtra(files: PluginFixture, extra: Readonly<Record<string, string | Uint8Array>> | undefined): void {
|
|
253
|
+
for (const [path, content] of Object.entries(extra ?? {})) files.set(path, content);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function json(value: unknown): string {
|
|
257
|
+
return `${JSON.stringify(value, null, 2)}\n`;
|
|
258
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The normalised description of a plugin: what Stigmer would install from a
|
|
3
|
+
* package, whatever dialect the package was written in.
|
|
4
|
+
*
|
|
5
|
+
* These are the library's own plain types, deliberately not the protos. The
|
|
6
|
+
* library describes the plugin FORMAT; the server maps this description onto
|
|
7
|
+
* resources when it installs, and the CLI validates offline without pulling
|
|
8
|
+
* the resource schemas in for a parse. Field names still mirror the protos
|
|
9
|
+
* (`SubAgent.name/description/instructions/model_override`,
|
|
10
|
+
* `EnvVarDeclaration.is_secret/description/optional`, the
|
|
11
|
+
* `McpServerSpec` `stdio`/`http` variants) so the server's mapping is one
|
|
12
|
+
* function per kind and a proto rename is a visible edit here.
|
|
13
|
+
*
|
|
14
|
+
* Every path in this description is plugin-relative, POSIX, with no leading
|
|
15
|
+
* `./`: one path vocabulary for the whole package, whichever reader produced
|
|
16
|
+
* the files.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** The manifest that gave the plugin its identity. */
|
|
20
|
+
export type PluginDialect = "agent-plugins" | "claude" | "cursor" | "codex";
|
|
21
|
+
|
|
22
|
+
export interface PluginAuthor {
|
|
23
|
+
readonly name?: string;
|
|
24
|
+
readonly email?: string;
|
|
25
|
+
readonly url?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* One skill: a directory holding `SKILL.md`. `files` lists every file under
|
|
30
|
+
* `dir` (plugin-relative), so an installer can build the skill's own archive
|
|
31
|
+
* without walking the package again; `SKILL.md` is among them. For a plugin
|
|
32
|
+
* that IS a single skill (a root `SKILL.md`, the Claude Code layout) `dir` is
|
|
33
|
+
* the empty string and `files` is the whole package.
|
|
34
|
+
*/
|
|
35
|
+
export interface PluginSkill {
|
|
36
|
+
readonly name: string;
|
|
37
|
+
readonly description?: string;
|
|
38
|
+
readonly dir: string;
|
|
39
|
+
readonly files: readonly string[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* One MCP server in the shape `McpServerSpec` takes. `env` is the list of
|
|
44
|
+
* variable NAMES the server references (in headers, arguments or its stdio
|
|
45
|
+
* environment), which is what `McpServerSpec.env` declares; values never
|
|
46
|
+
* appear anywhere in this library.
|
|
47
|
+
*/
|
|
48
|
+
export type PluginMcpServer =
|
|
49
|
+
| {
|
|
50
|
+
readonly name: string;
|
|
51
|
+
readonly transport: "http";
|
|
52
|
+
readonly url: string;
|
|
53
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
54
|
+
readonly env: readonly string[];
|
|
55
|
+
}
|
|
56
|
+
| {
|
|
57
|
+
readonly name: string;
|
|
58
|
+
readonly transport: "stdio";
|
|
59
|
+
readonly command: string;
|
|
60
|
+
readonly args: readonly string[];
|
|
61
|
+
readonly env: readonly string[];
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* A dialect's `model` value classified into an alias the server resolves
|
|
66
|
+
* against its model registry. The library never names a Stigmer model id:
|
|
67
|
+
* the runner drops a sub-agent whose `model_override` is unregistered, so an
|
|
68
|
+
* id the parser could not verify would silently remove sub-agents at run
|
|
69
|
+
* time. `inherit` and an absent `model` both mean "no override"; `unknown`
|
|
70
|
+
* carries the raw text for the server's warning.
|
|
71
|
+
*/
|
|
72
|
+
export type ModelAlias = "fast" | "sonnet" | "opus" | "haiku" | "inherit" | "unknown";
|
|
73
|
+
|
|
74
|
+
export interface ModelHint {
|
|
75
|
+
readonly raw: string;
|
|
76
|
+
readonly alias: ModelAlias;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** One sub-agent file (`agents/*.md`) in the shape `SubAgent` takes. */
|
|
80
|
+
export interface PluginSubAgent {
|
|
81
|
+
readonly name: string;
|
|
82
|
+
readonly description?: string;
|
|
83
|
+
readonly instructions: string;
|
|
84
|
+
/** Plugin skill names this sub-agent asked for (Claude `skills:`), resolved to `skill_refs` by the installer. */
|
|
85
|
+
readonly skillNames: readonly string[];
|
|
86
|
+
readonly modelHint?: ModelHint;
|
|
87
|
+
/** The agent file, for messages that point at it. */
|
|
88
|
+
readonly path: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* One variable in the shape `EnvVarDeclaration` takes. `declaredBy` says
|
|
93
|
+
* where the declaration came from: a Cursor `variables` schema, a Claude
|
|
94
|
+
* `userConfig` entry, or inference from an undeclared `${VAR}` reference,
|
|
95
|
+
* which the library declares as a required secret because the runner hands a
|
|
96
|
+
* server only the variables its spec declares.
|
|
97
|
+
*/
|
|
98
|
+
export interface PluginVariable {
|
|
99
|
+
readonly name: string;
|
|
100
|
+
readonly description?: string;
|
|
101
|
+
readonly isSecret: boolean;
|
|
102
|
+
readonly optional: boolean;
|
|
103
|
+
readonly declaredBy: "cursor" | "claude" | "inferred";
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* A document under `ai.stigmer/`, handed over as bytes. The library locates
|
|
108
|
+
* these and checks they name things the plugin declares; parsing them into
|
|
109
|
+
* resources is the installer's, where the resource schemas live.
|
|
110
|
+
*/
|
|
111
|
+
export interface OverlayDocument {
|
|
112
|
+
readonly path: string;
|
|
113
|
+
readonly bytes: Uint8Array;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface OverlayNamedDocument extends OverlayDocument {
|
|
117
|
+
/** The file stem, the workflow's name. */
|
|
118
|
+
readonly name: string;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface OverlayServerDocument extends OverlayDocument {
|
|
122
|
+
/** The MCP server (a `mcpServers` key) this overlay layers over. */
|
|
123
|
+
readonly server: string;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface StigmerOverlay {
|
|
127
|
+
/** `ai.stigmer/agent.yaml`: the Agent that replaces the composed default. */
|
|
128
|
+
readonly agent?: OverlayDocument;
|
|
129
|
+
/** `ai.stigmer/workflows/<name>.yaml`. */
|
|
130
|
+
readonly workflows: readonly OverlayNamedDocument[];
|
|
131
|
+
/** `ai.stigmer/mcp-servers/<server>.yaml`: the richer `McpServer` overlay. */
|
|
132
|
+
readonly mcpServers: readonly OverlayServerDocument[];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* The component kinds Stigmer reads past without carrying. Recorded once per
|
|
137
|
+
* component (a directory, a file or a manifest field), never per file, so
|
|
138
|
+
* an author sees "hooks/ is not installed" once.
|
|
139
|
+
*/
|
|
140
|
+
export type IgnoredComponentKind =
|
|
141
|
+
| "agents"
|
|
142
|
+
| "apps"
|
|
143
|
+
| "assets"
|
|
144
|
+
| "bin"
|
|
145
|
+
| "canvases"
|
|
146
|
+
| "channels"
|
|
147
|
+
| "commands"
|
|
148
|
+
| "default-enabled"
|
|
149
|
+
| "dependencies"
|
|
150
|
+
| "evals"
|
|
151
|
+
| "extension"
|
|
152
|
+
| "hooks"
|
|
153
|
+
| "logo"
|
|
154
|
+
| "lsp-servers"
|
|
155
|
+
| "min-client-versions"
|
|
156
|
+
| "monitors"
|
|
157
|
+
| "output-styles"
|
|
158
|
+
| "rules"
|
|
159
|
+
| "settings"
|
|
160
|
+
| "themes"
|
|
161
|
+
| "workflows";
|
|
162
|
+
|
|
163
|
+
export interface IgnoredComponent {
|
|
164
|
+
readonly kind: IgnoredComponentKind;
|
|
165
|
+
/** The directory, file, or `<manifest path>#<field>` the component came from. */
|
|
166
|
+
readonly path: string;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** What Stigmer would install from the package. */
|
|
170
|
+
export interface PluginPackage {
|
|
171
|
+
readonly name: string;
|
|
172
|
+
/** As written; Semantic Versioning is recommended by the format, not enforced. */
|
|
173
|
+
readonly version?: string;
|
|
174
|
+
readonly description?: string;
|
|
175
|
+
readonly author?: PluginAuthor;
|
|
176
|
+
readonly homepage?: string;
|
|
177
|
+
readonly repository?: string;
|
|
178
|
+
readonly license?: string;
|
|
179
|
+
readonly keywords: readonly string[];
|
|
180
|
+
readonly dialect: PluginDialect;
|
|
181
|
+
/** Every manifest the reader consulted, identity first. */
|
|
182
|
+
readonly manifestsFound: readonly string[];
|
|
183
|
+
readonly skills: readonly PluginSkill[];
|
|
184
|
+
readonly mcpServers: readonly PluginMcpServer[];
|
|
185
|
+
readonly subAgents: readonly PluginSubAgent[];
|
|
186
|
+
readonly variables: readonly PluginVariable[];
|
|
187
|
+
readonly overlay: StigmerOverlay;
|
|
188
|
+
readonly ignored: readonly IgnoredComponent[];
|
|
189
|
+
}
|
package/testing.d.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory plugin builders for tests (exported as
|
|
3
|
+
* `@stigmer/plugin-package/testing`).
|
|
4
|
+
*
|
|
5
|
+
* One builder per dialect, each writing the exact file layout that
|
|
6
|
+
* dialect's tools produce: `openPlugin` a root `plugin.json` with the
|
|
7
|
+
* canonical `$schema` and an `mcp.json` beside it; `claudePlugin` a
|
|
8
|
+
* `.claude-plugin/plugin.json` with `.mcp.json`; `cursorPlugin` a
|
|
9
|
+
* `.cursor-plugin/plugin.json` declaring `./skills/`, `./agents/` and
|
|
10
|
+
* `./mcp.json` the way every published Cursor plugin does; `codexPlugin`
|
|
11
|
+
* the legacy `.codex-plugin/plugin.json` compatibility layout. The
|
|
12
|
+
* adversarial suite starts from a valid plugin and breaks exactly one
|
|
13
|
+
* thing with the mutators (`withFile`, `withoutFile`,
|
|
14
|
+
* `withManifestField`), so each test reads as "this plugin, minus this",
|
|
15
|
+
* and the consumers' tests (the CLI's, the server's) craft their fixtures
|
|
16
|
+
* from the same source so the shapes never drift apart.
|
|
17
|
+
*
|
|
18
|
+
* Builders return a path -> content map; `inMemoryPluginFiles` turns one
|
|
19
|
+
* into the `PluginFiles` the reader takes. Zipping a fixture for an
|
|
20
|
+
* archive-based consumer is `@stigmer/zip-structure/testing`'s job.
|
|
21
|
+
*/
|
|
22
|
+
import { inMemoryPluginFiles } from "./files.js";
|
|
23
|
+
export { inMemoryPluginFiles };
|
|
24
|
+
/** A plugin as files: plugin-relative path -> content. */
|
|
25
|
+
export type PluginFixture = Map<string, string | Uint8Array>;
|
|
26
|
+
export interface SkillFixture {
|
|
27
|
+
/** The frontmatter `name`; also the directory name unless `dir` says otherwise. */
|
|
28
|
+
readonly name: string;
|
|
29
|
+
readonly description?: string;
|
|
30
|
+
/** Directory under `skills/` (or the declared skills root); defaults to `name`. */
|
|
31
|
+
readonly dir?: string;
|
|
32
|
+
/** Extra frontmatter fields, or `null` for a `SKILL.md` with no frontmatter at all. */
|
|
33
|
+
readonly frontmatter?: Readonly<Record<string, unknown>> | null;
|
|
34
|
+
readonly body?: string;
|
|
35
|
+
/** Extra files inside the skill directory, relative to it. */
|
|
36
|
+
readonly files?: Readonly<Record<string, string>>;
|
|
37
|
+
}
|
|
38
|
+
export interface AgentFixture {
|
|
39
|
+
/** File name under `agents/`, without `.md`. */
|
|
40
|
+
readonly file: string;
|
|
41
|
+
/** Frontmatter fields, or `null` for a bare prompt with no frontmatter. */
|
|
42
|
+
readonly frontmatter?: Readonly<Record<string, unknown>> | null;
|
|
43
|
+
readonly body?: string;
|
|
44
|
+
}
|
|
45
|
+
interface CommonFixture {
|
|
46
|
+
readonly name?: string;
|
|
47
|
+
readonly version?: string;
|
|
48
|
+
readonly description?: string;
|
|
49
|
+
/** Extra or overriding manifest fields, merged last. */
|
|
50
|
+
readonly manifest?: Readonly<Record<string, unknown>>;
|
|
51
|
+
readonly skills?: readonly SkillFixture[];
|
|
52
|
+
/** Extra files anywhere in the plugin. */
|
|
53
|
+
readonly files?: Readonly<Record<string, string | Uint8Array>>;
|
|
54
|
+
}
|
|
55
|
+
export interface OpenPluginFixture extends CommonFixture {
|
|
56
|
+
/** The manifest `$schema`; `null` omits it. Defaults to the canonical 1.0.0 identifier. */
|
|
57
|
+
readonly schema?: string | null;
|
|
58
|
+
/** The `mcpServers` map for `mcp.json`; absent means no `mcp.json`. */
|
|
59
|
+
readonly mcpServers?: Readonly<Record<string, unknown>>;
|
|
60
|
+
/** The `mcp.json` `$schema`; `null` omits it. */
|
|
61
|
+
readonly mcpSchema?: string | null;
|
|
62
|
+
/** Extra top-level `mcp.json` fields. */
|
|
63
|
+
readonly mcpConfig?: Readonly<Record<string, unknown>>;
|
|
64
|
+
}
|
|
65
|
+
export interface ClaudePluginFixture extends CommonFixture {
|
|
66
|
+
readonly agents?: readonly AgentFixture[];
|
|
67
|
+
/** The `mcpServers` map for `.mcp.json`; absent means no `.mcp.json`. */
|
|
68
|
+
readonly mcpServers?: Readonly<Record<string, unknown>>;
|
|
69
|
+
readonly userConfig?: Readonly<Record<string, unknown>>;
|
|
70
|
+
}
|
|
71
|
+
export interface CursorPluginFixture extends CommonFixture {
|
|
72
|
+
readonly agents?: readonly AgentFixture[];
|
|
73
|
+
/** The `mcpServers` map for `mcp.json`, declared as `"mcpServers": "./mcp.json"`. */
|
|
74
|
+
readonly mcpServers?: Readonly<Record<string, unknown>>;
|
|
75
|
+
/** The `variables` JSON Schema: property name -> `{ type, title, description }`. */
|
|
76
|
+
readonly variables?: Readonly<Record<string, Readonly<Record<string, unknown>>>>;
|
|
77
|
+
readonly required?: readonly string[];
|
|
78
|
+
}
|
|
79
|
+
export interface CodexPluginFixture extends CommonFixture {
|
|
80
|
+
/** The `mcpServers` map for `.mcp.json`, declared as `"mcpServers": "./.mcp.json"`. */
|
|
81
|
+
readonly mcpServers?: Readonly<Record<string, unknown>>;
|
|
82
|
+
/** The `apps` map for `.app.json`. */
|
|
83
|
+
readonly apps?: Readonly<Record<string, unknown>>;
|
|
84
|
+
}
|
|
85
|
+
/** An Agent Plugins 1.0.0 package. */
|
|
86
|
+
export declare function openPlugin(fixture?: OpenPluginFixture): PluginFixture;
|
|
87
|
+
/** A Claude Code plugin. */
|
|
88
|
+
export declare function claudePlugin(fixture?: ClaudePluginFixture): PluginFixture;
|
|
89
|
+
/** A Cursor plugin, declaring its components the way the published catalogue does. */
|
|
90
|
+
export declare function cursorPlugin(fixture?: CursorPluginFixture): PluginFixture;
|
|
91
|
+
/** The legacy Codex compatibility layout (`.codex-plugin/plugin.json`, `.mcp.json`, `.app.json`). */
|
|
92
|
+
export declare function codexPlugin(fixture?: CodexPluginFixture): PluginFixture;
|
|
93
|
+
/** A copy of `files` with `path` set to `content`. */
|
|
94
|
+
export declare function withFile(files: PluginFixture, path: string, content: string | Uint8Array): PluginFixture;
|
|
95
|
+
/** A copy of `files` without `path`. */
|
|
96
|
+
export declare function withoutFile(files: PluginFixture, path: string): PluginFixture;
|
|
97
|
+
/**
|
|
98
|
+
* A copy of `files` with one top-level field of the JSON document at
|
|
99
|
+
* `manifestPath` set (or removed, when `value` is `undefined`).
|
|
100
|
+
*/
|
|
101
|
+
export declare function withManifestField(files: PluginFixture, manifestPath: string, field: string, value: unknown): PluginFixture;
|
|
102
|
+
/** A `SKILL.md` document from a fixture description. */
|
|
103
|
+
export declare function skillMarkdown(skill: SkillFixture): string;
|
|
104
|
+
/** A sub-agent document from a fixture description. */
|
|
105
|
+
export declare function agentMarkdown(agent: AgentFixture): string;
|
|
106
|
+
//# sourceMappingURL=testing.d.ts.map
|
package/testing.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"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"}
|