@crewhaus/target-claude-plugin 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +23 -0
- package/dist/index.js +65 -3
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -27,6 +27,13 @@
|
|
|
27
27
|
* - `crew` → one agent .md per role; the entry role becomes the
|
|
28
28
|
* primary SKILL.md.
|
|
29
29
|
*
|
|
30
|
+
* On top of that PROJECTION, `opts.assets` carries the harness's
|
|
31
|
+
* AUTHORED surface — the `.crewhaus/skills/**` and `.crewhaus/commands/*.md`
|
|
32
|
+
* files the user hand-wrote — through verbatim, so an exported plugin is
|
|
33
|
+
* not a strictly smaller agent than the harness it came from. The caller
|
|
34
|
+
* reads them (this package still does no I/O) and they override a
|
|
35
|
+
* synthesized file at the same path.
|
|
36
|
+
*
|
|
30
37
|
* This is a strict-emission package: no I/O, returns a `Bundle` of
|
|
31
38
|
* files for the caller (the CLI) to write to disk. Pure functions.
|
|
32
39
|
*
|
|
@@ -56,6 +63,22 @@ export type EmitClaudePluginOptions = {
|
|
|
56
63
|
* Anthropic recommends 1-2 sentences describing trigger conditions.
|
|
57
64
|
*/
|
|
58
65
|
readonly description?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Item 14 — the harness's AUTHORED assets, already read from the
|
|
68
|
+
* `.crewhaus/` workspace by the caller (this package does no I/O) and
|
|
69
|
+
* addressed at their plugin-relative destination: `skills/<name>/SKILL.md`
|
|
70
|
+
* (plus anything else under the skill dir) and `commands/<name>.md`.
|
|
71
|
+
*
|
|
72
|
+
* Without these, an export of a spec whose harness ships hand-written
|
|
73
|
+
* skills + slash commands emitted only the ONE skill synthesized from
|
|
74
|
+
* `agent.instructions` and no `commands/` dir at all — the plugin was a
|
|
75
|
+
* strictly smaller agent than the harness it came from.
|
|
76
|
+
*
|
|
77
|
+
* Merged AFTER the synthesized files and overriding them on a path
|
|
78
|
+
* collision: a hand-authored `skills/<ir.name>/SKILL.md` is the author's
|
|
79
|
+
* explicit intent and beats the projection of `agent.instructions`.
|
|
80
|
+
*/
|
|
81
|
+
readonly assets?: ReadonlyArray<PluginFile>;
|
|
59
82
|
};
|
|
60
83
|
/**
|
|
61
84
|
* Main entry. Returns a `PluginBundle` of files; the caller writes
|
package/dist/index.js
CHANGED
|
@@ -27,6 +27,13 @@
|
|
|
27
27
|
* - `crew` → one agent .md per role; the entry role becomes the
|
|
28
28
|
* primary SKILL.md.
|
|
29
29
|
*
|
|
30
|
+
* On top of that PROJECTION, `opts.assets` carries the harness's
|
|
31
|
+
* AUTHORED surface — the `.crewhaus/skills/**` and `.crewhaus/commands/*.md`
|
|
32
|
+
* files the user hand-wrote — through verbatim, so an exported plugin is
|
|
33
|
+
* not a strictly smaller agent than the harness it came from. The caller
|
|
34
|
+
* reads them (this package still does no I/O) and they override a
|
|
35
|
+
* synthesized file at the same path.
|
|
36
|
+
*
|
|
30
37
|
* This is a strict-emission package: no I/O, returns a `Bundle` of
|
|
31
38
|
* files for the caller (the CLI) to write to disk. Pure functions.
|
|
32
39
|
*
|
|
@@ -96,8 +103,61 @@ export function emitClaudePlugin(ir, opts) {
|
|
|
96
103
|
// typed TargetClaudePluginError above, not a renderer error over a
|
|
97
104
|
// malformed variant; inserted at index 1 to keep the historical
|
|
98
105
|
// plugin.json → README.md → … file order.
|
|
99
|
-
|
|
100
|
-
|
|
106
|
+
const assets = opts.assets ?? [];
|
|
107
|
+
files.splice(1, 0, { path: "README.md", content: renderReadme(ir, description, assets) });
|
|
108
|
+
return { files: mergeAssets(files, assets) };
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Append the caller-supplied authored assets to the synthesized files,
|
|
112
|
+
* deduping by path: an asset that collides with a synthesized file REPLACES
|
|
113
|
+
* it in place (author beats projection) instead of appending a second entry
|
|
114
|
+
* for the same path — the CLI writes the bundle file-by-file and reports
|
|
115
|
+
* `files.length`, so a duplicate path would silently inflate that count.
|
|
116
|
+
*/
|
|
117
|
+
function mergeAssets(files, assets) {
|
|
118
|
+
const merged = [];
|
|
119
|
+
const indexByPath = new Map();
|
|
120
|
+
for (const file of [...files, ...assets]) {
|
|
121
|
+
const at = indexByPath.get(file.path);
|
|
122
|
+
if (at === undefined) {
|
|
123
|
+
indexByPath.set(file.path, merged.length);
|
|
124
|
+
merged.push(file);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
merged[at] = file;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return merged;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* The `Authored assets` README section — names the skills and slash commands
|
|
134
|
+
* carried verbatim out of the harness's `.crewhaus/` workspace, so a reader of
|
|
135
|
+
* the emitted plugin can tell hand-written surface from the projection of
|
|
136
|
+
* `agent.instructions`. Returns `undefined` when nothing was carried.
|
|
137
|
+
*/
|
|
138
|
+
function renderAssetsSection(assets) {
|
|
139
|
+
if (assets.length === 0)
|
|
140
|
+
return undefined;
|
|
141
|
+
const skills = new Set();
|
|
142
|
+
const commands = new Set();
|
|
143
|
+
for (const asset of assets) {
|
|
144
|
+
const skill = asset.path.match(/^skills\/([^/]+)\//);
|
|
145
|
+
if (skill?.[1] !== undefined) {
|
|
146
|
+
skills.add(skill[1]);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const command = asset.path.match(/^commands\/([^/]+)\.md$/);
|
|
150
|
+
if (command?.[1] !== undefined)
|
|
151
|
+
commands.add(command[1]);
|
|
152
|
+
}
|
|
153
|
+
const lines = ["Carried verbatim from the harness's `.crewhaus/` workspace:", ""];
|
|
154
|
+
if (skills.size > 0) {
|
|
155
|
+
lines.push(`- Skills: ${[...skills].map((s) => `\`${s}\``).join(", ")}`);
|
|
156
|
+
}
|
|
157
|
+
if (commands.size > 0) {
|
|
158
|
+
lines.push(`- Commands: ${[...commands].map((c) => `\`/${c}\``).join(", ")}`);
|
|
159
|
+
}
|
|
160
|
+
return { heading: "Authored assets", body: lines.join("\n") };
|
|
101
161
|
}
|
|
102
162
|
function defaultDescription(ir) {
|
|
103
163
|
return `${ir.name} — CrewHaus ${ir.target} agent compiled to Claude Code plugin format.`;
|
|
@@ -121,7 +181,8 @@ function renderPluginJson(name, description, author) {
|
|
|
121
181
|
* note is suppressed — a Claude Code plugin has no CrewHaus runtime
|
|
122
182
|
* workspace.
|
|
123
183
|
*/
|
|
124
|
-
function renderReadme(ir, description) {
|
|
184
|
+
function renderReadme(ir, description, assets = []) {
|
|
185
|
+
const assetsSection = renderAssetsSection(assets);
|
|
125
186
|
return renderBundleReadme(ir, {
|
|
126
187
|
description,
|
|
127
188
|
usage: {
|
|
@@ -130,6 +191,7 @@ function renderReadme(ir, description) {
|
|
|
130
191
|
},
|
|
131
192
|
includeWorkspaceNote: false,
|
|
132
193
|
extraSections: [
|
|
194
|
+
...(assetsSection !== undefined ? [assetsSection] : []),
|
|
133
195
|
{
|
|
134
196
|
heading: "Origin",
|
|
135
197
|
body: [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crewhaus/target-claude-plugin",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Track H / §59 — emits an Anthropic-compatible Claude Code plugin directory from any CrewHaus IR variant. Source: claude-plugins-official (Anthropic).",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"test": "bun test src"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@crewhaus/errors": "0.4.
|
|
19
|
-
"@crewhaus/ir": "0.4.
|
|
18
|
+
"@crewhaus/errors": "0.4.2",
|
|
19
|
+
"@crewhaus/ir": "0.4.2"
|
|
20
20
|
},
|
|
21
21
|
"license": "Apache-2.0",
|
|
22
22
|
"author": {
|