cyber-agentkit 0.0.0-stage → 1.0.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/.claude-plugin/plugin.json +19 -0
- package/.codex-plugin/plugin.json +19 -0
- package/.cursor-plugin/plugin.json +19 -0
- package/LICENSE +21 -0
- package/bin/cyber-agentkit.mjs +10 -0
- package/dist/cli.js +14307 -0
- package/dist/commands.d.ts +149 -0
- package/dist/commands.js +984 -0
- package/dist/harness-id-BgKL-x6C.d.ts +11 -0
- package/dist/index.d.ts +724 -0
- package/dist/index.js +652 -0
- package/dist/reference-where-BhymfNgA.js +10195 -0
- package/dist/resolve-reference-Cis-Ye6T.d.ts +232 -0
- package/dist/worktrees.d.ts +690 -0
- package/dist/worktrees.js +1456 -0
- package/package.json +89 -3
- package/plugin.json +27 -0
- package/readme.md +423 -0
- package/references/plugin-dependencies.md +31 -0
- package/skills/reference/README.md +63 -0
- package/skills/reference/SKILL.md +109 -0
- package/skills/reference/references/create.md +71 -0
- package/skills/reference/references/load.md +80 -0
- package/skills/reference/scripts/reference.mjs +199 -0
- package/README.md +0 -3
package/dist/index.js
ADDED
|
@@ -0,0 +1,652 @@
|
|
|
1
|
+
import { A as skillFoldersVerified, B as isRecord, C as userReferencesDir, D as adminSkillFolders, F as packageDir, H as stripJsonComments, I as detectHarness, L as installedPlugins, M as pluginManifestName, N as pluginManifestPaths, O as harnessSkillFolders, P as declaredDependencies, R as enabledPlugins, T as skillsIn, U as managedPolicyLocations, V as readText, b as projectReferencesDir, d as parseReferenceName, j as skillsDirectories, k as pluginSkillFolders, l as referenceNames, n as referenceImplementations, o as listReferences, r as checkReferences, s as searchReferences, t as whereReference, u as resolveReference, w as skillName, x as referenceLayers, y as defaultLayer, z as pluginStorage } from "./reference-where-BhymfNgA.js";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
//#region src/plugins/plugin-dependencies.ts
|
|
5
|
+
/**
|
|
6
|
+
* Whether a harness lets a plugin declare other plugins it depends on. Only Claude Code does, via
|
|
7
|
+
* `dependencies` in `plugin.json` (E-CC-X1). The other harnesses' manifests have no such field
|
|
8
|
+
* (E-CUR-X1, E-CODEX-X1, E-COPILOT-X1, E-OC-X1, E-KILO-X1, E-GEM-P4, E-QWEN-P3, E-VSC-X1,
|
|
9
|
+
* E-CLINE-X1, E-CRUSH-X1, E-OH-X1, E-AUG-X1).
|
|
10
|
+
*/
|
|
11
|
+
function supportsPluginDependencies(harness) {
|
|
12
|
+
return harness === "claude-code";
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/dependencies/plugin-dependencies.ts
|
|
16
|
+
/**
|
|
17
|
+
* Read the `dependencies` array of a Claude Code `plugin.json`: `"name"`, `"name@marketplace"`, or
|
|
18
|
+
* `{ name, marketplace, version }` entries (E-DEP-1, E-CC-X1). Entries of any other shape are skipped.
|
|
19
|
+
*/
|
|
20
|
+
function declaredPluginDependencies(manifest) {
|
|
21
|
+
const entries = isRecord(manifest) ? manifest.dependencies : void 0;
|
|
22
|
+
if (!Array.isArray(entries)) return [];
|
|
23
|
+
const dependencies = [];
|
|
24
|
+
for (const entry of entries) {
|
|
25
|
+
const raw = typeof entry === "string" ? entry : isRecord(entry) ? entry.name : void 0;
|
|
26
|
+
if (typeof raw !== "string" || raw === "") continue;
|
|
27
|
+
const [name, inline] = raw.split("@");
|
|
28
|
+
if (name === "") continue;
|
|
29
|
+
const object = isRecord(entry) ? entry : {};
|
|
30
|
+
const marketplace = nonEmpty(object.marketplace) ?? nonEmpty(inline);
|
|
31
|
+
const version = nonEmpty(object.version);
|
|
32
|
+
dependencies.push({
|
|
33
|
+
name,
|
|
34
|
+
...marketplace && { marketplace },
|
|
35
|
+
...version && { version }
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return dependencies;
|
|
39
|
+
}
|
|
40
|
+
const nonEmpty = (value) => typeof value === "string" && value !== "" ? value : void 0;
|
|
41
|
+
/** The extension namespaces a root `plugin.json` may author its dependency list under, newest first (E-DEP-6, E-DEP-7). */
|
|
42
|
+
const extensionNamespaces = ["io.github.cyber-uni.plugin-manager", "org.cyberuni.universal-plugin"];
|
|
43
|
+
/**
|
|
44
|
+
* Read what the plugin at `pluginRoot` declares: `dependencies` under `extensions["io.github.cyber-uni.plugin-manager"]`,
|
|
45
|
+
* else under `extensions["org.cyberuni.universal-plugin"]` in the root `plugin.json`, else `dependencies` in
|
|
46
|
+
* `.claude-plugin/plugin.json` (E-DEP-1, E-DEP-6, E-DEP-7).
|
|
47
|
+
*/
|
|
48
|
+
async function readPluginDependencies(pluginRoot) {
|
|
49
|
+
const root = join(pluginRoot, "plugin.json");
|
|
50
|
+
const sources = [...extensionNamespaces.map((namespace) => ({
|
|
51
|
+
path: root,
|
|
52
|
+
pick: (manifest) => {
|
|
53
|
+
const extensions = isRecord(manifest) ? manifest.extensions : void 0;
|
|
54
|
+
return isRecord(extensions) ? extensions[namespace] : void 0;
|
|
55
|
+
}
|
|
56
|
+
})), {
|
|
57
|
+
path: join(pluginRoot, ".claude-plugin", "plugin.json"),
|
|
58
|
+
pick: (manifest) => manifest
|
|
59
|
+
}];
|
|
60
|
+
let error;
|
|
61
|
+
for (const { path, pick } of sources) try {
|
|
62
|
+
const text = await readText(path);
|
|
63
|
+
if (text === void 0) continue;
|
|
64
|
+
const dependencies = declaredPluginDependencies(pick(JSON.parse(stripJsonComments(text))));
|
|
65
|
+
if (dependencies.length > 0) return {
|
|
66
|
+
dependencies,
|
|
67
|
+
path
|
|
68
|
+
};
|
|
69
|
+
} catch (cause) {
|
|
70
|
+
error ??= `${path}: ${String(cause)}`;
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
dependencies: [],
|
|
74
|
+
path: sources.at(-1)?.path ?? pluginRoot,
|
|
75
|
+
...error && { error }
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const rank = {
|
|
79
|
+
enabled: 3,
|
|
80
|
+
installed: 2,
|
|
81
|
+
disabled: 1,
|
|
82
|
+
missing: 0,
|
|
83
|
+
unknown: 0
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Check which declared dependencies the harness has installed and enabled, and return the steps
|
|
87
|
+
* that settle the rest. Nothing is installed.
|
|
88
|
+
*/
|
|
89
|
+
async function checkPluginDependencies(harness, options = {}) {
|
|
90
|
+
const read = options.dependencies ? {
|
|
91
|
+
dependencies: options.dependencies,
|
|
92
|
+
error: void 0
|
|
93
|
+
} : options.pluginRoot ? await readPluginDependencies(options.pluginRoot) : {
|
|
94
|
+
dependencies: [],
|
|
95
|
+
error: void 0
|
|
96
|
+
};
|
|
97
|
+
const [installed, enabled] = await Promise.all([installedPlugins(harness, options), enabledPlugins(harness, options)]);
|
|
98
|
+
const enablement = new Map(enabled.plugins.map((plugin) => [plugin.id, plugin.enabled]));
|
|
99
|
+
const dependencies = read.dependencies.map((dependency) => {
|
|
100
|
+
if (!installed.supported) return {
|
|
101
|
+
...dependency,
|
|
102
|
+
state: "unknown"
|
|
103
|
+
};
|
|
104
|
+
const ids = installed.plugins.map((plugin) => plugin.id).filter((id) => dependency.marketplace ? id === `${dependency.name}@${dependency.marketplace}` : id.split("@")[0] === dependency.name);
|
|
105
|
+
let best = {
|
|
106
|
+
...dependency,
|
|
107
|
+
state: "missing"
|
|
108
|
+
};
|
|
109
|
+
for (const id of new Set(ids)) {
|
|
110
|
+
const flag = enablement.get(id);
|
|
111
|
+
const state = flag === true ? "enabled" : flag === false ? "disabled" : "installed";
|
|
112
|
+
if (rank[state] > rank[best.state]) best = {
|
|
113
|
+
...dependency,
|
|
114
|
+
state,
|
|
115
|
+
id
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
return best;
|
|
119
|
+
});
|
|
120
|
+
const supported = supportsPluginDependencies(harness);
|
|
121
|
+
return {
|
|
122
|
+
harness,
|
|
123
|
+
supported,
|
|
124
|
+
autoResolved: supported,
|
|
125
|
+
dependencies,
|
|
126
|
+
steps: supported ? claudeCodeSteps(dependencies) : manualSteps(harness, read.dependencies),
|
|
127
|
+
...read.error && { error: read.error },
|
|
128
|
+
research: [
|
|
129
|
+
"E-DEP-1",
|
|
130
|
+
"E-DEP-2",
|
|
131
|
+
"E-DEP-3",
|
|
132
|
+
"E-DEP-4",
|
|
133
|
+
"E-DEP-5",
|
|
134
|
+
"E-DEP-6",
|
|
135
|
+
"E-DEP-7",
|
|
136
|
+
"E-CC-X1"
|
|
137
|
+
]
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
const label = (dependency) => dependency.marketplace ? `${dependency.name}@${dependency.marketplace}` : dependency.name;
|
|
141
|
+
/** E-DEP-2: `plugin install` installs missing dependencies; E-DEP-3: cross-marketplace needs a root allow-list. */
|
|
142
|
+
function claudeCodeSteps(dependencies) {
|
|
143
|
+
const steps = [];
|
|
144
|
+
for (const dependency of dependencies) if (dependency.state === "missing" || dependency.state === "unknown") {
|
|
145
|
+
steps.push(`Install ${label(dependency)}: claude plugin install ${label(dependency)}`);
|
|
146
|
+
if (dependency.marketplace) steps.push(`If ${label(dependency)} is not in the declaring plugin's marketplace, that marketplace's root must list ${dependency.marketplace} in allowCrossMarketplaceDependenciesOn, or you must already have it enabled.`);
|
|
147
|
+
} else if (dependency.state === "disabled") steps.push(`Enable ${dependency.id ?? label(dependency)}: set it to true in enabledPlugins.`);
|
|
148
|
+
if (steps.length > 0) steps.push("Run /reload-plugins.");
|
|
149
|
+
return steps;
|
|
150
|
+
}
|
|
151
|
+
/** E-DEP-4, E-DEP-5, E-CC-X1: no other harness's manifest declares dependencies. */
|
|
152
|
+
function manualSteps(harness, dependencies) {
|
|
153
|
+
if (dependencies.length === 0) return [];
|
|
154
|
+
return [`${harness} has no plugin dependency field, so nothing is resolved for you. Install and enable each plugin yourself.`, ...dependencies.map((dependency) => `Install ${dependency.name}${dependency.marketplace ? ` from ${dependency.marketplace}` : ""} through ${harness}'s plugin install flow, then enable it.`)];
|
|
155
|
+
}
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/harness/harness-id.ts
|
|
158
|
+
const harnessIds = [
|
|
159
|
+
"claude-code",
|
|
160
|
+
"cursor",
|
|
161
|
+
"codex",
|
|
162
|
+
"copilot-cli",
|
|
163
|
+
"opencode",
|
|
164
|
+
"kilo",
|
|
165
|
+
"gemini-cli",
|
|
166
|
+
"qwen-code",
|
|
167
|
+
"vscode-copilot",
|
|
168
|
+
"cline",
|
|
169
|
+
"crush",
|
|
170
|
+
"openhands",
|
|
171
|
+
"augment"
|
|
172
|
+
];
|
|
173
|
+
//#endregion
|
|
174
|
+
//#region src/headless/headless-invocation.ts
|
|
175
|
+
const claudeUsage = {
|
|
176
|
+
event: "result",
|
|
177
|
+
tokens: "usage",
|
|
178
|
+
costUsd: "total_cost_usd",
|
|
179
|
+
accumulate: "last"
|
|
180
|
+
};
|
|
181
|
+
const qwenUsage = {
|
|
182
|
+
event: "result",
|
|
183
|
+
tokens: "usage",
|
|
184
|
+
accumulate: "last"
|
|
185
|
+
};
|
|
186
|
+
const unverified = "has a documented one-shot mode, but its flags were not read directly from a vendor page, so they are not encoded";
|
|
187
|
+
/**
|
|
188
|
+
* How to run a harness non-interactively on one prompt: the command, how to choose the model and
|
|
189
|
+
* permission mode, the output formats and where usage appears in them, the transcript location,
|
|
190
|
+
* and the exit codes.
|
|
191
|
+
*
|
|
192
|
+
* Returns `supported: false` for Copilot in VS Code, which documents no headless mode (E-VSC-H1).
|
|
193
|
+
* Returns `supported: 'unknown'` for OpenCode, Kilo Code, Cline, Crush, OpenHands, and the Auggie
|
|
194
|
+
* CLI: each has a one-shot mode, but the research read it only through a summarizing fetch or from
|
|
195
|
+
* source (E-OC-H1, E-KILO-H1, E-CLINE-H1, E-CRUSH-H1, E-OH-H1, E-AUG-H1).
|
|
196
|
+
*/
|
|
197
|
+
function headlessInvocation(harness) {
|
|
198
|
+
switch (harness) {
|
|
199
|
+
case "claude-code": return {
|
|
200
|
+
harness,
|
|
201
|
+
supported: true,
|
|
202
|
+
executable: "claude",
|
|
203
|
+
oneShot: ["-p"],
|
|
204
|
+
modelFlag: "--model",
|
|
205
|
+
permission: {
|
|
206
|
+
flag: "--permission-mode",
|
|
207
|
+
values: [
|
|
208
|
+
"acceptEdits",
|
|
209
|
+
"auto",
|
|
210
|
+
"bypassPermissions",
|
|
211
|
+
"manual",
|
|
212
|
+
"dontAsk",
|
|
213
|
+
"plan"
|
|
214
|
+
],
|
|
215
|
+
unattended: ["--permission-mode", "bypassPermissions"]
|
|
216
|
+
},
|
|
217
|
+
outputFormats: [
|
|
218
|
+
{
|
|
219
|
+
name: "text",
|
|
220
|
+
args: []
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
name: "json",
|
|
224
|
+
args: ["--output-format", "json"],
|
|
225
|
+
usage: claudeUsage
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
name: "stream-json",
|
|
229
|
+
args: [
|
|
230
|
+
"--output-format",
|
|
231
|
+
"stream-json",
|
|
232
|
+
"--verbose"
|
|
233
|
+
],
|
|
234
|
+
usage: claudeUsage
|
|
235
|
+
}
|
|
236
|
+
],
|
|
237
|
+
transcript: {
|
|
238
|
+
path: "~/.claude/projects/<project>/<session-id>.jsonl",
|
|
239
|
+
baseDirEnv: "CLAUDE_CONFIG_DIR",
|
|
240
|
+
disable: ["--no-session-persistence"]
|
|
241
|
+
},
|
|
242
|
+
exitCodes: [{
|
|
243
|
+
code: 0,
|
|
244
|
+
meaning: "success"
|
|
245
|
+
}, {
|
|
246
|
+
code: 143,
|
|
247
|
+
meaning: "terminated by SIGTERM"
|
|
248
|
+
}],
|
|
249
|
+
research: [
|
|
250
|
+
"E-CC-H1",
|
|
251
|
+
"E-CC-H2",
|
|
252
|
+
"E-CC-H3",
|
|
253
|
+
"E-CC-H4",
|
|
254
|
+
"E-CC-H5",
|
|
255
|
+
"E-CC-H6"
|
|
256
|
+
]
|
|
257
|
+
};
|
|
258
|
+
case "codex": return {
|
|
259
|
+
harness,
|
|
260
|
+
supported: true,
|
|
261
|
+
executable: "codex",
|
|
262
|
+
oneShot: ["exec"],
|
|
263
|
+
modelFlag: "--model",
|
|
264
|
+
permission: {
|
|
265
|
+
flag: "--sandbox",
|
|
266
|
+
values: [
|
|
267
|
+
"read-only",
|
|
268
|
+
"workspace-write",
|
|
269
|
+
"danger-full-access"
|
|
270
|
+
],
|
|
271
|
+
unattended: ["--dangerously-bypass-approvals-and-sandbox"]
|
|
272
|
+
},
|
|
273
|
+
outputFormats: [{
|
|
274
|
+
name: "text",
|
|
275
|
+
args: []
|
|
276
|
+
}, {
|
|
277
|
+
name: "jsonl",
|
|
278
|
+
args: ["--json"],
|
|
279
|
+
usage: {
|
|
280
|
+
event: "turn.completed",
|
|
281
|
+
tokens: "usage",
|
|
282
|
+
accumulate: "sum"
|
|
283
|
+
}
|
|
284
|
+
}],
|
|
285
|
+
transcript: {
|
|
286
|
+
path: "~/.codex/sessions/<yyyy>/<mm>/<dd>/rollout-<timestamp>-<thread-id>.jsonl",
|
|
287
|
+
baseDirEnv: "CODEX_HOME",
|
|
288
|
+
disable: ["--ephemeral"]
|
|
289
|
+
},
|
|
290
|
+
exitCodes: [{
|
|
291
|
+
code: 0,
|
|
292
|
+
meaning: "success"
|
|
293
|
+
}, {
|
|
294
|
+
code: 1,
|
|
295
|
+
meaning: "the run reported a fatal error, or the prompt or options were invalid"
|
|
296
|
+
}],
|
|
297
|
+
research: [
|
|
298
|
+
"E-CODEX-H1",
|
|
299
|
+
"E-CODEX-H2",
|
|
300
|
+
"E-CODEX-H3",
|
|
301
|
+
"E-CODEX-H4",
|
|
302
|
+
"E-CODEX-H5"
|
|
303
|
+
]
|
|
304
|
+
};
|
|
305
|
+
case "copilot-cli": return {
|
|
306
|
+
harness,
|
|
307
|
+
supported: true,
|
|
308
|
+
executable: "copilot",
|
|
309
|
+
oneShot: [],
|
|
310
|
+
promptFlag: "-p",
|
|
311
|
+
modelFlag: "--model",
|
|
312
|
+
permission: {
|
|
313
|
+
values: [],
|
|
314
|
+
unattended: ["--allow-all"]
|
|
315
|
+
},
|
|
316
|
+
outputFormats: [{
|
|
317
|
+
name: "text",
|
|
318
|
+
args: []
|
|
319
|
+
}, {
|
|
320
|
+
name: "json",
|
|
321
|
+
args: ["--output-format", "json"]
|
|
322
|
+
}],
|
|
323
|
+
transcript: {
|
|
324
|
+
path: "~/.copilot/session-state/<session-id>/events.jsonl",
|
|
325
|
+
baseDirEnv: "COPILOT_HOME"
|
|
326
|
+
},
|
|
327
|
+
exitCodes: [],
|
|
328
|
+
research: [
|
|
329
|
+
"E-COPILOT-H1",
|
|
330
|
+
"E-COPILOT-H2",
|
|
331
|
+
"E-COPILOT-H3"
|
|
332
|
+
]
|
|
333
|
+
};
|
|
334
|
+
case "cursor": return {
|
|
335
|
+
harness,
|
|
336
|
+
supported: true,
|
|
337
|
+
executable: "cursor-agent",
|
|
338
|
+
oneShot: ["-p"],
|
|
339
|
+
modelFlag: "--model",
|
|
340
|
+
permission: {
|
|
341
|
+
values: [],
|
|
342
|
+
unattended: ["--force"]
|
|
343
|
+
},
|
|
344
|
+
outputFormats: [
|
|
345
|
+
{
|
|
346
|
+
name: "text",
|
|
347
|
+
args: []
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
name: "json",
|
|
351
|
+
args: ["--output-format", "json"]
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
name: "stream-json",
|
|
355
|
+
args: ["--output-format", "stream-json"]
|
|
356
|
+
}
|
|
357
|
+
],
|
|
358
|
+
exitCodes: [{
|
|
359
|
+
code: 0,
|
|
360
|
+
meaning: "success"
|
|
361
|
+
}, {
|
|
362
|
+
code: 1,
|
|
363
|
+
meaning: "failure"
|
|
364
|
+
}],
|
|
365
|
+
research: [
|
|
366
|
+
"E-CUR-H1",
|
|
367
|
+
"E-CUR-H2",
|
|
368
|
+
"E-CUR-H3"
|
|
369
|
+
]
|
|
370
|
+
};
|
|
371
|
+
case "gemini-cli": return {
|
|
372
|
+
harness,
|
|
373
|
+
supported: true,
|
|
374
|
+
executable: "gemini",
|
|
375
|
+
oneShot: [],
|
|
376
|
+
promptFlag: "-p",
|
|
377
|
+
modelFlag: "--model",
|
|
378
|
+
permission: {
|
|
379
|
+
flag: "--approval-mode",
|
|
380
|
+
values: [
|
|
381
|
+
"default",
|
|
382
|
+
"auto_edit",
|
|
383
|
+
"yolo",
|
|
384
|
+
"plan"
|
|
385
|
+
],
|
|
386
|
+
unattended: ["--approval-mode", "yolo"]
|
|
387
|
+
},
|
|
388
|
+
outputFormats: [
|
|
389
|
+
{
|
|
390
|
+
name: "text",
|
|
391
|
+
args: []
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
name: "json",
|
|
395
|
+
args: ["--output-format", "json"],
|
|
396
|
+
usage: {
|
|
397
|
+
tokens: "stats",
|
|
398
|
+
accumulate: "last"
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
name: "stream-json",
|
|
403
|
+
args: ["--output-format", "stream-json"],
|
|
404
|
+
usage: {
|
|
405
|
+
event: "result",
|
|
406
|
+
tokens: "stats",
|
|
407
|
+
accumulate: "last"
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
],
|
|
411
|
+
transcript: { path: "~/.gemini/tmp/<project_hash>/chats/" },
|
|
412
|
+
exitCodes: [
|
|
413
|
+
{
|
|
414
|
+
code: 0,
|
|
415
|
+
meaning: "success"
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
code: 1,
|
|
419
|
+
meaning: "general error or API failure"
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
code: 42,
|
|
423
|
+
meaning: "input error: an invalid prompt or arguments"
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
code: 53,
|
|
427
|
+
meaning: "turn limit exceeded"
|
|
428
|
+
}
|
|
429
|
+
],
|
|
430
|
+
research: [
|
|
431
|
+
"E-GEM-H1",
|
|
432
|
+
"E-GEM-H2",
|
|
433
|
+
"E-GEM-H3"
|
|
434
|
+
]
|
|
435
|
+
};
|
|
436
|
+
case "qwen-code": return {
|
|
437
|
+
harness,
|
|
438
|
+
supported: true,
|
|
439
|
+
executable: "qwen",
|
|
440
|
+
oneShot: [],
|
|
441
|
+
promptFlag: "-p",
|
|
442
|
+
modelFlag: "--model",
|
|
443
|
+
permission: {
|
|
444
|
+
flag: "--approval-mode",
|
|
445
|
+
values: [
|
|
446
|
+
"plan",
|
|
447
|
+
"default",
|
|
448
|
+
"auto-edit",
|
|
449
|
+
"auto",
|
|
450
|
+
"yolo"
|
|
451
|
+
],
|
|
452
|
+
unattended: ["--approval-mode", "yolo"]
|
|
453
|
+
},
|
|
454
|
+
outputFormats: [
|
|
455
|
+
{
|
|
456
|
+
name: "text",
|
|
457
|
+
args: []
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
name: "json",
|
|
461
|
+
args: ["--output-format", "json"],
|
|
462
|
+
usage: qwenUsage
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
name: "stream-json",
|
|
466
|
+
args: ["--output-format", "stream-json"],
|
|
467
|
+
usage: qwenUsage
|
|
468
|
+
}
|
|
469
|
+
],
|
|
470
|
+
transcript: { path: "~/.qwen/projects/<sanitized-cwd>/chats/" },
|
|
471
|
+
exitCodes: [
|
|
472
|
+
{
|
|
473
|
+
code: 53,
|
|
474
|
+
meaning: "turn limit exceeded"
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
code: 55,
|
|
478
|
+
meaning: "tool-call or wall-time budget exceeded"
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
code: 130,
|
|
482
|
+
meaning: "interrupted by SIGINT"
|
|
483
|
+
}
|
|
484
|
+
],
|
|
485
|
+
research: ["E-QWEN-H1", "E-QWEN-H2"]
|
|
486
|
+
};
|
|
487
|
+
case "vscode-copilot": return {
|
|
488
|
+
harness,
|
|
489
|
+
supported: false,
|
|
490
|
+
reason: "agent mode runs inside the editor; the docs point terminal use to the Copilot CLI",
|
|
491
|
+
research: ["E-VSC-H1"]
|
|
492
|
+
};
|
|
493
|
+
case "opencode": return {
|
|
494
|
+
harness,
|
|
495
|
+
supported: "unknown",
|
|
496
|
+
reason: `\`opencode run\` ${unverified}`,
|
|
497
|
+
research: ["E-OC-H1"]
|
|
498
|
+
};
|
|
499
|
+
case "kilo": return {
|
|
500
|
+
harness,
|
|
501
|
+
supported: "unknown",
|
|
502
|
+
reason: `\`kilo run\` ${unverified}`,
|
|
503
|
+
research: ["E-KILO-H1"]
|
|
504
|
+
};
|
|
505
|
+
case "cline": return {
|
|
506
|
+
harness,
|
|
507
|
+
supported: "unknown",
|
|
508
|
+
reason: `the Cline CLI ${unverified}`,
|
|
509
|
+
research: ["E-CLINE-H1"]
|
|
510
|
+
};
|
|
511
|
+
case "crush": return {
|
|
512
|
+
harness,
|
|
513
|
+
supported: "unknown",
|
|
514
|
+
reason: `\`crush run\` ${unverified}`,
|
|
515
|
+
research: ["E-CRUSH-H1"]
|
|
516
|
+
};
|
|
517
|
+
case "openhands": return {
|
|
518
|
+
harness,
|
|
519
|
+
supported: "unknown",
|
|
520
|
+
reason: `\`openhands --headless\` ${unverified}`,
|
|
521
|
+
research: ["E-OH-H1"]
|
|
522
|
+
};
|
|
523
|
+
case "augment": return {
|
|
524
|
+
harness,
|
|
525
|
+
supported: "unknown",
|
|
526
|
+
reason: `\`auggie --print\` ${unverified}`,
|
|
527
|
+
research: ["E-AUG-H1"]
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* The command line for one headless run, built from `headlessInvocation()`. It does not run it.
|
|
533
|
+
*
|
|
534
|
+
* Returns `undefined` when the harness's headless mode is not supported or not verified. Throws
|
|
535
|
+
* when `outputFormat` names a format the harness lacks, or `permission` names a mode the harness
|
|
536
|
+
* has no flag for.
|
|
537
|
+
*/
|
|
538
|
+
function headlessCommand(harness, options) {
|
|
539
|
+
const mode = headlessInvocation(harness);
|
|
540
|
+
if (mode.supported !== true) return void 0;
|
|
541
|
+
const args = [...mode.oneShot];
|
|
542
|
+
if (options.model !== void 0) args.push(mode.modelFlag, options.model);
|
|
543
|
+
if (options.permission === "unattended") args.push(...mode.permission.unattended);
|
|
544
|
+
else if (options.permission !== void 0) {
|
|
545
|
+
const { flag, values } = mode.permission;
|
|
546
|
+
if (flag === void 0 || !values.includes(options.permission)) throw new Error(`${harness} has no permission mode "${options.permission}"`);
|
|
547
|
+
args.push(flag, options.permission);
|
|
548
|
+
}
|
|
549
|
+
if (options.outputFormat !== void 0) {
|
|
550
|
+
const format = mode.outputFormats.find((f) => f.name === options.outputFormat);
|
|
551
|
+
if (format === void 0) throw new Error(`${harness} has no output format "${options.outputFormat}"`);
|
|
552
|
+
args.push(...format.args);
|
|
553
|
+
}
|
|
554
|
+
if (mode.promptFlag === void 0) args.push(options.prompt);
|
|
555
|
+
else args.push(mode.promptFlag, options.prompt);
|
|
556
|
+
return {
|
|
557
|
+
executable: mode.executable,
|
|
558
|
+
args
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
//#endregion
|
|
562
|
+
//#region src/references/load-reference.ts
|
|
563
|
+
/**
|
|
564
|
+
* Resolves one reference for `root` the way `reference show` does, returning the full record: every
|
|
565
|
+
* field `show` prints with `--metadata` and `--trace`. A name that is not a reference name comes back
|
|
566
|
+
* `invalid`, and one no contribution answers `missing`; neither throws.
|
|
567
|
+
*/
|
|
568
|
+
async function loadReference(name, options) {
|
|
569
|
+
const layers = await referenceLayers({
|
|
570
|
+
...options,
|
|
571
|
+
home: options.home ?? homedir(),
|
|
572
|
+
platform: options.platform ?? process.platform
|
|
573
|
+
});
|
|
574
|
+
return resolveReference(name, layers);
|
|
575
|
+
}
|
|
576
|
+
//#endregion
|
|
577
|
+
//#region src/skills/skill-invocation.ts
|
|
578
|
+
/**
|
|
579
|
+
* How a user invokes a plugin's skill in a harness.
|
|
580
|
+
*
|
|
581
|
+
* Claude Code, Codex, and Copilot in VS Code namespace by plugin; elsewhere two plugins' skills with
|
|
582
|
+
* the same name collide. Codex names a plugin skill `<plugin>:<skill>`, and its `$` mention takes the
|
|
583
|
+
* whole name (E-SR-CODEX-5, E-SR-CODEX-18). Copilot CLI lists `<plugin>:<skill>` only while two
|
|
584
|
+
* enabled plugins share the name (E-SR-COPILOT-8); whether that form can be typed is not verified,
|
|
585
|
+
* so it returns the bare `/<skill>`.
|
|
586
|
+
*
|
|
587
|
+
* Kilo Code returns `/<skill>` in both the CLI and the VS Code extension; when a custom command or
|
|
588
|
+
* MCP prompt has the same name, the skill is typed `/<skill>:skill` instead (E-KILO-S3).
|
|
589
|
+
*
|
|
590
|
+
* OpenCode returns `/<skill>` too, but when a built-in (`init`, `review`), config command, or MCP
|
|
591
|
+
* prompt has the same name, that one wins and the skill has no command (E-OC-S3).
|
|
592
|
+
*
|
|
593
|
+
* Returns `undefined` for Gemini CLI, Qwen Code, and Crush, which document no typed form: the model
|
|
594
|
+
* loads a skill through a tool call when its description matches the task (E-GEM-S2, E-QWEN-S1,
|
|
595
|
+
* E-CRUSH-S1). Crush can also list a skill in its command
|
|
596
|
+
* palette, which is picked, not typed (E-CRUSH-S2). OpenHands triggers skills from the model too;
|
|
597
|
+
* only a plugin's commands take a `/<plugin>:<command>` form (E-OH-S2, E-OH-S3).
|
|
598
|
+
*
|
|
599
|
+
* Also returns `undefined` for the Auggie CLI: a plugin skill's internal name is `<plugin>:<skill>`,
|
|
600
|
+
* but what the user types for it is not confirmed (E-AUG-S3).
|
|
601
|
+
*/
|
|
602
|
+
function skillInvocation(harness, { plugin, skill }) {
|
|
603
|
+
switch (harness) {
|
|
604
|
+
case "claude-code": return {
|
|
605
|
+
text: `/${plugin}:${skill}`,
|
|
606
|
+
namespaced: true,
|
|
607
|
+
research: "E-CC-S1"
|
|
608
|
+
};
|
|
609
|
+
case "cursor": return {
|
|
610
|
+
text: `/${skill}`,
|
|
611
|
+
namespaced: false,
|
|
612
|
+
research: "E-CUR-S1"
|
|
613
|
+
};
|
|
614
|
+
case "codex": return {
|
|
615
|
+
text: `$${plugin}:${skill}`,
|
|
616
|
+
namespaced: true,
|
|
617
|
+
research: "E-SR-CODEX-18"
|
|
618
|
+
};
|
|
619
|
+
case "copilot-cli": return {
|
|
620
|
+
text: `/${skill}`,
|
|
621
|
+
namespaced: false,
|
|
622
|
+
research: "E-COPILOT-S6"
|
|
623
|
+
};
|
|
624
|
+
case "vscode-copilot": return {
|
|
625
|
+
text: `/${plugin}:${skill}`,
|
|
626
|
+
namespaced: true,
|
|
627
|
+
research: "E-VSC-S1"
|
|
628
|
+
};
|
|
629
|
+
case "cline": return {
|
|
630
|
+
text: `/${skill}`,
|
|
631
|
+
namespaced: false,
|
|
632
|
+
research: "E-CLINE-S2"
|
|
633
|
+
};
|
|
634
|
+
case "kilo": return {
|
|
635
|
+
text: `/${skill}`,
|
|
636
|
+
namespaced: false,
|
|
637
|
+
research: "E-KILO-S3"
|
|
638
|
+
};
|
|
639
|
+
case "opencode": return {
|
|
640
|
+
text: `/${skill}`,
|
|
641
|
+
namespaced: false,
|
|
642
|
+
research: "E-OC-S3"
|
|
643
|
+
};
|
|
644
|
+
case "gemini-cli":
|
|
645
|
+
case "qwen-code":
|
|
646
|
+
case "crush":
|
|
647
|
+
case "openhands":
|
|
648
|
+
case "augment": return;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
//#endregion
|
|
652
|
+
export { adminSkillFolders, checkPluginDependencies, checkReferences, declaredDependencies, declaredPluginDependencies, defaultLayer, detectHarness, enabledPlugins, harnessIds, harnessSkillFolders, headlessCommand, headlessInvocation, installedPlugins, listReferences, loadReference, managedPolicyLocations, packageDir, parseReferenceName, pluginManifestName, pluginManifestPaths, pluginSkillFolders, pluginStorage, projectReferencesDir, readPluginDependencies, referenceImplementations, referenceLayers, referenceNames, resolveReference, searchReferences, skillFoldersVerified, skillInvocation, skillName, skillsDirectories, skillsIn, supportsPluginDependencies, userReferencesDir, whereReference };
|