codiedev 0.9.80 → 0.10.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -5
- package/dist/backup/cache.js +1 -5
- package/dist/backup/match.js +0 -6
- package/dist/backup/run.js +3 -35
- package/dist/captureExclusions.js +0 -12
- package/dist/captureLog.js +0 -28
- package/dist/captureReadiness.js +0 -58
- package/dist/captureSignals.js +0 -11
- package/dist/cli.js +11 -33
- package/dist/cliSession.js +3 -60
- package/dist/codexHookTrust.js +0 -28
- package/dist/codexLimitScan.js +0 -107
- package/dist/codie.js +64 -57
- package/dist/codieBrandInstall.js +0 -18
- package/dist/codieLauncher.js +1 -72
- package/dist/codieRuntime.js +27 -32
- package/dist/codieRuntimeInstall.js +11 -43
- package/dist/codieUsage.js +0 -49
- package/dist/commands/agentTemplates.generated.js +136 -0
- package/dist/commands/agents.js +1088 -0
- package/dist/commands/agentsSdk.generated.js +7 -0
- package/dist/commands/ask.js +0 -3
- package/dist/commands/capture.js +0 -2
- package/dist/commands/createTicket.js +0 -10
- package/dist/commands/doctor.js +2 -72
- package/dist/commands/evals.js +3 -9
- package/dist/commands/inbox.js +0 -2
- package/dist/commands/library.js +0 -3
- package/dist/commands/pack.js +0 -29
- package/dist/commands/ping.js +0 -2
- package/dist/commands/pull.js +0 -9
- package/dist/commands/push.js +0 -12
- package/dist/commands/search.js +0 -4
- package/dist/commands/send.js +0 -5
- package/dist/commands/share.js +0 -4
- package/dist/commands/shared.js +0 -35
- package/dist/commands/traces.js +0 -13
- package/dist/commands/tracesLabel.js +0 -8
- package/dist/configDir.js +1 -18
- package/dist/connect.js +3 -75
- package/dist/connectFlow.js +0 -15
- package/dist/copilotHooks.js +0 -67
- package/dist/copilotInstallation.js +0 -1
- package/dist/cursorHooks.js +1 -11
- package/dist/cursorLifecycle.js +1 -7
- package/dist/detection.js +0 -30
- package/dist/harnessDirs.js +0 -19
- package/dist/hook.js +43 -293
- package/dist/inboxFormat.js +0 -24
- package/dist/launchContext.js +0 -50
- package/dist/launcher.js +0 -33
- package/dist/limitEvent.js +2 -34
- package/dist/managedPi.js +2 -50
- package/dist/mcp.js +0 -48
- package/dist/nativeSteering.js +1 -4
- package/dist/packs/codie.js +0 -15
- package/dist/packs/harnesses.js +1 -38
- package/dist/packs/hookGate.js +0 -33
- package/dist/packs/install.js +0 -20
- package/dist/packs/manifest.js +1 -15
- package/dist/packs/paths.js +0 -8
- package/dist/packs/shim.js +0 -8
- package/dist/packs/store.js +0 -12
- package/dist/packs/sync.js +0 -20
- package/dist/piHooks.js +4 -45
- package/dist/piRuntime.js +0 -18
- package/dist/repoResolver.js +0 -19
- package/dist/secret.js +0 -3
- package/dist/selfUpdate.js +2 -77
- package/dist/skillMarker.js +0 -14
- package/dist/subagents.js +0 -18
- package/dist/teamSkillContext.js +0 -1
- package/dist/transcriptModels.js +0 -8
- package/dist/upgradeNudge.js +1 -30
- package/dist/utils.js +165 -768
- package/dist/version.js +0 -10
- package/dist/versionCheck.js +0 -33
- package/package.json +13 -8
- package/dist/backup/cache.d.ts +0 -14
- package/dist/backup/match.d.ts +0 -2
- package/dist/backup/run.d.ts +0 -25
- package/dist/captureExclusions.d.ts +0 -30
- package/dist/captureLog.d.ts +0 -20
- package/dist/captureReadiness.d.ts +0 -65
- package/dist/captureSignals.d.ts +0 -47
- package/dist/cli.d.ts +0 -15
- package/dist/cliSession.d.ts +0 -108
- package/dist/codexHookTrust.d.ts +0 -49
- package/dist/codexLimitScan.d.ts +0 -64
- package/dist/codie.d.ts +0 -2
- package/dist/codieBrandInstall.d.ts +0 -11
- package/dist/codieLauncher.d.ts +0 -87
- package/dist/codieRuntime.d.ts +0 -35
- package/dist/codieRuntimeInstall.d.ts +0 -56
- package/dist/codieUsage.d.ts +0 -64
- package/dist/commands/ask.d.ts +0 -1
- package/dist/commands/capture.d.ts +0 -14
- package/dist/commands/createTicket.d.ts +0 -27
- package/dist/commands/delete.d.ts +0 -1
- package/dist/commands/doctor.d.ts +0 -9
- package/dist/commands/evals.d.ts +0 -3
- package/dist/commands/inbox.d.ts +0 -3
- package/dist/commands/library.d.ts +0 -2
- package/dist/commands/note.d.ts +0 -1
- package/dist/commands/pack.d.ts +0 -54
- package/dist/commands/ping.d.ts +0 -1
- package/dist/commands/pull.d.ts +0 -2
- package/dist/commands/push.d.ts +0 -33
- package/dist/commands/search.d.ts +0 -2
- package/dist/commands/send.d.ts +0 -2
- package/dist/commands/share.d.ts +0 -2
- package/dist/commands/shared.d.ts +0 -64
- package/dist/commands/traces.d.ts +0 -72
- package/dist/commands/tracesLabel.d.ts +0 -24
- package/dist/configDir.d.ts +0 -10
- package/dist/connect.d.ts +0 -1
- package/dist/connectFlow.d.ts +0 -34
- package/dist/copilotHooks.d.ts +0 -85
- package/dist/copilotInstallation.d.ts +0 -10
- package/dist/cursorHooks.d.ts +0 -13
- package/dist/cursorLifecycle.d.ts +0 -2
- package/dist/detection.d.ts +0 -30
- package/dist/harnessDirs.d.ts +0 -15
- package/dist/hook.d.ts +0 -6
- package/dist/inboxFormat.d.ts +0 -38
- package/dist/launchContext.d.ts +0 -46
- package/dist/launcher.d.ts +0 -25
- package/dist/limitEvent.d.ts +0 -15
- package/dist/limitEventReporter.d.ts +0 -21
- package/dist/managedPi.d.ts +0 -48
- package/dist/mcp.d.ts +0 -12
- package/dist/nativeSteering.d.ts +0 -5
- package/dist/packs/codie.d.ts +0 -45
- package/dist/packs/harnesses.d.ts +0 -74
- package/dist/packs/hookGate.d.ts +0 -53
- package/dist/packs/install.d.ts +0 -46
- package/dist/packs/manifest.d.ts +0 -52
- package/dist/packs/paths.d.ts +0 -17
- package/dist/packs/shim.d.ts +0 -26
- package/dist/packs/store.d.ts +0 -42
- package/dist/packs/sync.d.ts +0 -40
- package/dist/piHooks.d.ts +0 -22
- package/dist/piRuntime.d.ts +0 -26
- package/dist/repoResolver.d.ts +0 -17
- package/dist/secret.d.ts +0 -1
- package/dist/selfUpdate.d.ts +0 -64
- package/dist/skillMarker.d.ts +0 -6
- package/dist/subagents.d.ts +0 -36
- package/dist/teamSkillContext.d.ts +0 -9
- package/dist/transcriptModels.d.ts +0 -20
- package/dist/upgradeNudge.d.ts +0 -24
- package/dist/utils.d.ts +0 -396
- package/dist/version.d.ts +0 -1
- package/dist/versionCheck.d.ts +0 -68
package/dist/nativeSteering.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseNativeSteering = parseNativeSteering;
|
|
4
|
-
/** Native records only: quoted denial/interrupt text in conversation is not evidence. */
|
|
5
4
|
function parseNativeSteering(content) {
|
|
6
5
|
const interrupts = new Set();
|
|
7
6
|
const abortedTurns = new Set();
|
|
@@ -16,12 +15,10 @@ function parseNativeSteering(content) {
|
|
|
16
15
|
abortedTurns.add(id);
|
|
17
16
|
if (event.type === "agent.rejection")
|
|
18
17
|
rejections.add(id);
|
|
19
|
-
// Cursor tool failures distinguish a user-denied permission from an
|
|
20
|
-
// ordinary tool failure. Don't guess from free-form error messages.
|
|
21
18
|
if (event.type === "tool_result" && event.error?.code === "user_denied")
|
|
22
19
|
rejections.add(id);
|
|
23
20
|
}
|
|
24
|
-
catch {
|
|
21
|
+
catch { }
|
|
25
22
|
}
|
|
26
23
|
return { interrupts: Math.max(interrupts.size, abortedTurns.size), rejections: rejections.size };
|
|
27
24
|
}
|
package/dist/packs/codie.js
CHANGED
|
@@ -37,8 +37,6 @@ exports.levelToModel = levelToModel;
|
|
|
37
37
|
exports.mapAgentModel = mapAgentModel;
|
|
38
38
|
exports.codiePackConfig = codiePackConfig;
|
|
39
39
|
exports.mergeCodiePackConfig = mergeCodiePackConfig;
|
|
40
|
-
// Codie (our OpenCode launcher) installs nothing: at launch it reads
|
|
41
|
-
// installed.json and injects the packs into OPENCODE_CONFIG_CONTENT.
|
|
42
40
|
const fs = __importStar(require("fs"));
|
|
43
41
|
const path = __importStar(require("path"));
|
|
44
42
|
const url_1 = require("url");
|
|
@@ -50,12 +48,6 @@ const LEVEL_LABEL = { opus: "Strongest", sonnet: "Balanced", haiku: "Fastest" };
|
|
|
50
48
|
function newestFirst(a, b) {
|
|
51
49
|
return b.id.localeCompare(a.id, undefined, { numeric: true });
|
|
52
50
|
}
|
|
53
|
-
/** Resolve an agent level (opus = Strongest, sonnet = Balanced, haiku =
|
|
54
|
-
* Fastest) to one of the account's approved models:
|
|
55
|
-
* 1. explicit tier/level metadata on the catalog entry, when the gateway sends it
|
|
56
|
-
* 2. the same model family by name (e.g. a "claude-opus-…" model), newest first
|
|
57
|
-
* 3. by price: Strongest = priciest, Fastest = cheapest, Balanced = in between
|
|
58
|
-
* Otherwise undefined → Codie's governed default. Only catalog ids are returned. */
|
|
59
51
|
function levelToModel(level, catalog) {
|
|
60
52
|
const key = level.toLowerCase();
|
|
61
53
|
const tierNames = {
|
|
@@ -78,8 +70,6 @@ function levelToModel(level, catalog) {
|
|
|
78
70
|
}
|
|
79
71
|
return { how: "none" };
|
|
80
72
|
}
|
|
81
|
-
/** Map a Claude agent `model:` to an OpenCode model id, or undefined to let
|
|
82
|
-
* Codie's governed default apply. */
|
|
83
73
|
function mapAgentModel(value, approved, catalog) {
|
|
84
74
|
const model = (value ?? "").trim();
|
|
85
75
|
if (!model || model === "inherit")
|
|
@@ -118,7 +108,6 @@ function codiePackConfig(root, options = {}) {
|
|
|
118
108
|
result.notes.push(`pack ${slug}: hooks Codie can't run were skipped: ${skipped.join(", ")}`);
|
|
119
109
|
}
|
|
120
110
|
catch {
|
|
121
|
-
// no hooks
|
|
122
111
|
}
|
|
123
112
|
const skills = path.join(dir, "skills");
|
|
124
113
|
if (fs.existsSync(skills))
|
|
@@ -157,19 +146,15 @@ function codiePackConfig(root, options = {}) {
|
|
|
157
146
|
};
|
|
158
147
|
}
|
|
159
148
|
}
|
|
160
|
-
// The shim only exists while some installed pack has hooks.
|
|
161
149
|
const shim = (0, paths_1.shimPath)(root);
|
|
162
150
|
const anyCodie = Object.values(registry.packs).some((e) => Array.isArray(e.harnesses) && e.harnesses.includes("codie"));
|
|
163
151
|
if (anyCodie && fs.existsSync(shim))
|
|
164
152
|
result.plugins.push((0, url_1.pathToFileURL)(shim).href);
|
|
165
153
|
return result;
|
|
166
154
|
}
|
|
167
|
-
/** Merge pack config into an OpenCode config without clobbering anything the
|
|
168
|
-
* user or Codie already set: existing skill paths, agents and plugins win. */
|
|
169
155
|
function mergeCodiePackConfig(existing, packs) {
|
|
170
156
|
const next = { ...existing };
|
|
171
157
|
if (packs.skillPaths.length) {
|
|
172
|
-
// `skills` must be the object form; the array form is rejected by the engine.
|
|
173
158
|
const current = existing.skills;
|
|
174
159
|
const base = Array.isArray(current)
|
|
175
160
|
? { paths: current.filter((p) => typeof p === "string") }
|
package/dist/packs/harnesses.js
CHANGED
|
@@ -43,9 +43,6 @@ exports.cursorPluginDir = cursorPluginDir;
|
|
|
43
43
|
exports.installCursorPlugin = installCursorPlugin;
|
|
44
44
|
exports.removeCursorPlugin = removeCursorPlugin;
|
|
45
45
|
exports.parseHarnessList = parseHarnessList;
|
|
46
|
-
// Per-tool adapters. Each registers the pack's plugin dir (via the shared
|
|
47
|
-
// local marketplace) with one coding tool. Adapters only run for tools that
|
|
48
|
-
// are detected, and one failing never stops the others.
|
|
49
46
|
const fs = __importStar(require("fs"));
|
|
50
47
|
const path = __importStar(require("path"));
|
|
51
48
|
const child_process_1 = require("child_process");
|
|
@@ -69,7 +66,6 @@ function defaultRunner(env) {
|
|
|
69
66
|
};
|
|
70
67
|
};
|
|
71
68
|
}
|
|
72
|
-
/** True when `bin` is an executable file on `env.PATH`. */
|
|
73
69
|
function onPath(bin, env) {
|
|
74
70
|
const dirs = (env.PATH ?? "").split(path.delimiter).filter(Boolean);
|
|
75
71
|
const exts = process.platform === "win32" ? (env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";") : [""];
|
|
@@ -86,7 +82,6 @@ function onPath(bin, env) {
|
|
|
86
82
|
}
|
|
87
83
|
}
|
|
88
84
|
catch {
|
|
89
|
-
// keep looking
|
|
90
85
|
}
|
|
91
86
|
}
|
|
92
87
|
}
|
|
@@ -121,8 +116,6 @@ function alreadyExists(result) {
|
|
|
121
116
|
function wasInstalled(ctx, harness) {
|
|
122
117
|
return Boolean(ctx.previous?.harnesses?.includes(harness));
|
|
123
118
|
}
|
|
124
|
-
/** A same-version reinstall whose content changed: harness caches are keyed
|
|
125
|
-
* by version, so the old copy must be removed before installing again. */
|
|
126
119
|
function contentChangedInPlace(ctx) {
|
|
127
120
|
const prev = ctx.previous;
|
|
128
121
|
return Boolean(prev && prev.version === ctx.manifest.version && prev.contentHash !== ctx.manifest.contentHash);
|
|
@@ -139,10 +132,6 @@ function claudeMarketplaceKnown(env, home) {
|
|
|
139
132
|
return false;
|
|
140
133
|
}
|
|
141
134
|
}
|
|
142
|
-
/** Shared flow for tools that install Claude-format plugins from a local
|
|
143
|
-
* marketplace (Claude Code, Copilot CLI). */
|
|
144
|
-
/** Codex/Copilot register the portable root. Older CLIs registered the main
|
|
145
|
-
* root under the same name, so repoint once (remove, then add) per tool. */
|
|
146
135
|
function ensurePortableMarketplace(ctx, bin) {
|
|
147
136
|
const root = (0, paths_1.portableRoot)(ctx.root);
|
|
148
137
|
const stamp = path.join(root, `.registered-${bin}`);
|
|
@@ -159,7 +148,6 @@ function marketplaceInstall(ctx, bin, harness, verbs, marketplaceKnown, portable
|
|
|
159
148
|
ensurePortableMarketplace(ctx, bin);
|
|
160
149
|
}
|
|
161
150
|
else if (marketplaceKnown) {
|
|
162
|
-
// Directory marketplaces are re-read on update; best-effort.
|
|
163
151
|
ctx.run(bin, ["plugin", "marketplace", "update", paths_1.MARKETPLACE_NAME]);
|
|
164
152
|
}
|
|
165
153
|
else {
|
|
@@ -210,8 +198,6 @@ exports.codexAdapter = {
|
|
|
210
198
|
install: (ctx) => {
|
|
211
199
|
ensurePortableMarketplace(ctx, "codex");
|
|
212
200
|
const ref = pluginRef(ctx);
|
|
213
|
-
// Codex caches by version under plugins/cache/<mkt>/<p>/<version>; remove
|
|
214
|
-
// first so a reinstall always picks up the current content.
|
|
215
201
|
const reinstall = wasInstalled(ctx, "codex");
|
|
216
202
|
if (reinstall)
|
|
217
203
|
ctx.run("codex", ["plugin", "remove", ref]);
|
|
@@ -225,8 +211,6 @@ exports.CURSOR_MARKER = ".codiedev-pack";
|
|
|
225
211
|
function cursorSkillsDir(home) {
|
|
226
212
|
return path.join(home, ".cursor", "skills");
|
|
227
213
|
}
|
|
228
|
-
/** Fallback: copy skills to ~/.cursor/skills/<name>/, never overwriting a
|
|
229
|
-
* skill dir Codiedev didn't write, and pruning ones this pack no longer has. */
|
|
230
214
|
function copyCursorSkills(home, manifest, pluginDirPath) {
|
|
231
215
|
const base = cursorSkillsDir(home);
|
|
232
216
|
fs.mkdirSync(base, { recursive: true });
|
|
@@ -240,7 +224,6 @@ function copyCursorSkills(home, manifest, pluginDirPath) {
|
|
|
240
224
|
}
|
|
241
225
|
}
|
|
242
226
|
catch {
|
|
243
|
-
// not ours
|
|
244
227
|
}
|
|
245
228
|
}
|
|
246
229
|
for (const skill of manifest.skills) {
|
|
@@ -265,7 +248,6 @@ function copyCursorSkills(home, manifest, pluginDirPath) {
|
|
|
265
248
|
}
|
|
266
249
|
return notes;
|
|
267
250
|
}
|
|
268
|
-
/** Remove every ~/.cursor/skills dir this pack's fallback copy wrote. */
|
|
269
251
|
function removeCursorSkills(home, slug) {
|
|
270
252
|
const base = cursorSkillsDir(home);
|
|
271
253
|
let removed = 0;
|
|
@@ -284,16 +266,10 @@ function removeCursorSkills(home, slug) {
|
|
|
284
266
|
}
|
|
285
267
|
}
|
|
286
268
|
catch {
|
|
287
|
-
// not ours
|
|
288
269
|
}
|
|
289
270
|
}
|
|
290
271
|
return removed;
|
|
291
272
|
}
|
|
292
|
-
// Cursor loads every Claude-format plugin dir in ~/.cursor/plugins/local/<name>/
|
|
293
|
-
// (skills, agents and hooks). Its `plugin marketplace add` only takes remote
|
|
294
|
-
// https git, and symlinks pointing outside plugins/local are rejected, so the
|
|
295
|
-
// pack is a real copy. A Cursor team admin can disable "user local plugin
|
|
296
|
-
// imports", in which case Cursor ignores the dir.
|
|
297
273
|
function cursorLocalPluginsDir(home) {
|
|
298
274
|
return path.join(home, ".cursor", "plugins", "local");
|
|
299
275
|
}
|
|
@@ -308,9 +284,6 @@ function markerOwner(dir) {
|
|
|
308
284
|
return null;
|
|
309
285
|
}
|
|
310
286
|
}
|
|
311
|
-
/** Recursive copy that always writes real files/dirs: symlinks are followed
|
|
312
|
-
* (Cursor rejects links whose target is outside plugins/local). fs.cpSync's
|
|
313
|
-
* `dereference` doesn't apply below the top level, so walk it ourselves. */
|
|
314
287
|
function copyTreeNoSymlinks(source, dest, depth = 0) {
|
|
315
288
|
if (depth > 32)
|
|
316
289
|
throw new Error(`plugin tree too deep at ${source}`);
|
|
@@ -318,15 +291,13 @@ function copyTreeNoSymlinks(source, dest, depth = 0) {
|
|
|
318
291
|
for (const entry of fs.readdirSync(source)) {
|
|
319
292
|
const from = path.join(source, entry);
|
|
320
293
|
const to = path.join(dest, entry);
|
|
321
|
-
const stat = fs.statSync(from);
|
|
294
|
+
const stat = fs.statSync(from);
|
|
322
295
|
if (stat.isDirectory())
|
|
323
296
|
copyTreeNoSymlinks(from, to, depth + 1);
|
|
324
297
|
else if (stat.isFile())
|
|
325
298
|
fs.writeFileSync(to, fs.readFileSync(from));
|
|
326
299
|
}
|
|
327
300
|
}
|
|
328
|
-
/** Copy the plugin dir into place via a sibling temp dir + rename. Refuses to
|
|
329
|
-
* replace a dir that doesn't carry our marker for this pack. */
|
|
330
301
|
function installCursorPlugin(home, slug, sourceDir) {
|
|
331
302
|
const parent = cursorLocalPluginsDir(home);
|
|
332
303
|
const target = cursorPluginDir(home, slug);
|
|
@@ -353,7 +324,6 @@ function installCursorPlugin(home, slug, sourceDir) {
|
|
|
353
324
|
fs.rmSync(old, { recursive: true, force: true });
|
|
354
325
|
return target;
|
|
355
326
|
}
|
|
356
|
-
/** Remove our copy (only when it carries our marker). */
|
|
357
327
|
function removeCursorPlugin(home, slug) {
|
|
358
328
|
const target = cursorPluginDir(home, slug);
|
|
359
329
|
if (markerOwner(target) !== slug)
|
|
@@ -369,12 +339,10 @@ exports.cursorAdapter = {
|
|
|
369
339
|
installCursorPlugin(ctx.home, ctx.manifest.slug, ctx.portablePluginDir);
|
|
370
340
|
}
|
|
371
341
|
catch (error) {
|
|
372
|
-
// Last resort: skills only, where Cursor also looks.
|
|
373
342
|
const notes = copyCursorSkills(ctx.home, ctx.manifest, ctx.portablePluginDir);
|
|
374
343
|
const reason = error instanceof Error ? error.message : String(error);
|
|
375
344
|
return [`skills only (couldn't write ~/.cursor/plugins/local: ${reason})`, ...notes].join("; ");
|
|
376
345
|
}
|
|
377
|
-
// Migrate: the plugin now carries the skills; drop old fallback copies.
|
|
378
346
|
const migrated = removeCursorSkills(ctx.home, ctx.manifest.slug);
|
|
379
347
|
return migrated ? `installed (removed ${migrated} old ~/.cursor/skills cop${migrated === 1 ? "y" : "ies"})` : "installed";
|
|
380
348
|
},
|
|
@@ -389,7 +357,6 @@ exports.cursorAdapter = {
|
|
|
389
357
|
};
|
|
390
358
|
exports.codieAdapter = {
|
|
391
359
|
name: "codie",
|
|
392
|
-
// `codie` ships in this package, so it is always available.
|
|
393
360
|
detect: () => true,
|
|
394
361
|
install: () => "loads on next `codie` launch",
|
|
395
362
|
plan: () => "inject skills/agents/hook shim at next codie launch",
|
|
@@ -398,8 +365,6 @@ exports.codieAdapter = {
|
|
|
398
365
|
function piSettingsPath(env, home) {
|
|
399
366
|
return path.join((0, harnessDirs_1.piAgentDir)(env, home), "settings.json");
|
|
400
367
|
}
|
|
401
|
-
/** Rewrite pi's `skills` list, keeping every other setting. Refuses a
|
|
402
|
-
* settings file it can't parse rather than replacing the user's config. */
|
|
403
368
|
function updatePiSkillPaths(file, update) {
|
|
404
369
|
let settings = {};
|
|
405
370
|
if (fs.existsSync(file)) {
|
|
@@ -419,8 +384,6 @@ function updatePiSkillPaths(file, update) {
|
|
|
419
384
|
fs.renameSync(tmp, file);
|
|
420
385
|
return true;
|
|
421
386
|
}
|
|
422
|
-
/** pi has no plugin system; it loads extra skill dirs from settings.json
|
|
423
|
-
* `skills`. Point it at the portable copy (no Claude model aliases). */
|
|
424
387
|
exports.piAdapter = {
|
|
425
388
|
name: "pi",
|
|
426
389
|
detect: (ctx) => onPath("pi", ctx.env) || fs.existsSync((0, harnessDirs_1.piAgentDir)(ctx.env, ctx.home)),
|
package/dist/packs/hookGate.js
CHANGED
|
@@ -44,12 +44,6 @@ exports.planShellCommand = planShellCommand;
|
|
|
44
44
|
exports.planGateCommand = planGateCommand;
|
|
45
45
|
exports.runHookGate = runHookGate;
|
|
46
46
|
exports.runHookGateCli = runHookGateCli;
|
|
47
|
-
// `codiedev hook-gate --skills a,b --cmd-b64 <base64url>`: run a pack hook only
|
|
48
|
-
// while one of the named skills is in use. Reads the harness hook payload on
|
|
49
|
-
// stdin, passes it through to the command unchanged, and exits with its status
|
|
50
|
-
// (including 2 = block). No match / unreadable payload → exit 0, no output.
|
|
51
|
-
// Also accepted: `-- <argv…>` (exec'd directly) and the legacy
|
|
52
|
-
// `-- sh -c '<cmd>'` form saved by earlier pack editors.
|
|
53
47
|
const fs = __importStar(require("fs"));
|
|
54
48
|
const path = __importStar(require("path"));
|
|
55
49
|
const child_process_1 = require("child_process");
|
|
@@ -74,12 +68,6 @@ function stripPlugin(name) {
|
|
|
74
68
|
const index = name.lastIndexOf(":");
|
|
75
69
|
return index >= 0 ? name.slice(index + 1) : name;
|
|
76
70
|
}
|
|
77
|
-
/** Skill names a hook payload shows as running, across the five tools:
|
|
78
|
-
* - Claude: tool_name "Skill", tool_input.skill "<plugin>:<name>"
|
|
79
|
-
* - Copilot: tool_name "skill", tool_input.skill "<name>" (also camelCase toolName/toolArgs)
|
|
80
|
-
* - Codie: tool_name "skill", tool_input.name "<name>"
|
|
81
|
-
* - Cursor: tool_name "Read", tool_input.file_path ".../skills/<name>/SKILL.md"
|
|
82
|
-
* - Codex: tool_name "Bash", tool_input.command containing ".../skills/<name>/SKILL.md" */
|
|
83
71
|
function skillsFromPayload(payload) {
|
|
84
72
|
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
85
73
|
return [];
|
|
@@ -104,15 +92,10 @@ function skillsFromPayload(payload) {
|
|
|
104
92
|
}
|
|
105
93
|
return [];
|
|
106
94
|
}
|
|
107
|
-
/** Largest decoded `--cmd-b64` command we run. */
|
|
108
95
|
exports.MAX_GATED_COMMAND_BYTES = 16 * 1024;
|
|
109
|
-
/** Canonical form (what the portal writes): base64url of the UTF-8 command, no
|
|
110
|
-
* padding. Only [A-Za-z0-9_-], so no shell on any platform expands or
|
|
111
|
-
* re-quotes it — a `$(…)` in the gated command can't run before the gate. */
|
|
112
96
|
function encodeGatedCommand(command) {
|
|
113
97
|
return Buffer.from(command, "utf8").toString("base64url");
|
|
114
98
|
}
|
|
115
|
-
/** Strict decode: canonical base64url only, ≤16KB, valid UTF-8, no NUL. */
|
|
116
99
|
function decodeGatedCommand(value) {
|
|
117
100
|
if (!/^[A-Za-z0-9_-]+$/.test(value) || value.length % 4 === 1)
|
|
118
101
|
throw new Error("--cmd-b64 is not base64url");
|
|
@@ -166,8 +149,6 @@ function gateMatches(skills, payload) {
|
|
|
166
149
|
const running = skillsFromPayload(payload);
|
|
167
150
|
return running.some((name) => skills.includes(name));
|
|
168
151
|
}
|
|
169
|
-
/** Split a CODIEDEV_HOOK_SHELL value ("pwsh -NoProfile -Command") into argv,
|
|
170
|
-
* honouring simple "double" or 'single' quotes. */
|
|
171
152
|
function splitShellOverride(value) {
|
|
172
153
|
const out = [];
|
|
173
154
|
for (const m of value.matchAll(/"([^"]*)"|'([^']*)'|(\S+)/g))
|
|
@@ -182,19 +163,13 @@ function shellFor(line, platform, env) {
|
|
|
182
163
|
return { file, args: [...args, line] };
|
|
183
164
|
}
|
|
184
165
|
if (platform === "win32") {
|
|
185
|
-
// Same invocation Node uses for shell:true on Windows.
|
|
186
166
|
return { file: env.ComSpec || env.COMSPEC || "cmd.exe", args: ["/d", "/s", "/c", `"${line}"`], verbatim: true };
|
|
187
167
|
}
|
|
188
168
|
return { file: "/bin/sh", args: ["-c", line] };
|
|
189
169
|
}
|
|
190
|
-
/** The decoded `--cmd-b64` command line, run by the platform shell
|
|
191
|
-
* (/bin/sh -c on POSIX, cmd.exe /d /s /c on Windows, or CODIEDEV_HOOK_SHELL). */
|
|
192
170
|
function planShellCommand(line, options = {}) {
|
|
193
171
|
return shellFor(line, options.platform ?? process.platform, options.env ?? process.env);
|
|
194
172
|
}
|
|
195
|
-
/** `-- <argv…>`: exec'd directly, no shell. Legacy `sh -c '<cmd>'` (packs saved
|
|
196
|
-
* before --cmd-b64) runs as given, except on Windows without sh, where <cmd>
|
|
197
|
-
* goes to cmd.exe. */
|
|
198
173
|
function planGateCommand(command, options = {}) {
|
|
199
174
|
const platform = options.platform ?? process.platform;
|
|
200
175
|
const env = options.env ?? process.env;
|
|
@@ -215,20 +190,17 @@ function onPathSimple(bin, env, platform) {
|
|
|
215
190
|
return true;
|
|
216
191
|
}
|
|
217
192
|
catch {
|
|
218
|
-
// keep looking
|
|
219
193
|
}
|
|
220
194
|
}
|
|
221
195
|
}
|
|
222
196
|
return false;
|
|
223
197
|
}
|
|
224
|
-
/** Returns the exit status to use. */
|
|
225
198
|
function runHookGate(argv, stdin, env = process.env, options = {}) {
|
|
226
199
|
let args;
|
|
227
200
|
try {
|
|
228
201
|
args = parseGateArgs(argv);
|
|
229
202
|
}
|
|
230
203
|
catch (error) {
|
|
231
|
-
// A misconfigured gate must not block the agent; say why on stderr.
|
|
232
204
|
process.stderr.write(`codiedev hook-gate: ${error.message}\n`);
|
|
233
205
|
return 0;
|
|
234
206
|
}
|
|
@@ -239,7 +211,6 @@ function runHookGate(argv, stdin, env = process.env, options = {}) {
|
|
|
239
211
|
catch {
|
|
240
212
|
return 0;
|
|
241
213
|
}
|
|
242
|
-
// Nothing is decoded or run unless one of the skills is in use.
|
|
243
214
|
if (!gateMatches(args.skills, payload))
|
|
244
215
|
return 0;
|
|
245
216
|
let plan;
|
|
@@ -249,7 +220,6 @@ function runHookGate(argv, stdin, env = process.env, options = {}) {
|
|
|
249
220
|
line = decodeGatedCommand(args.cmdB64);
|
|
250
221
|
}
|
|
251
222
|
catch (error) {
|
|
252
|
-
// Never block the agent on a malformed gate.
|
|
253
223
|
process.stderr.write(`codiedev hook-gate: ${error.message}; hook skipped\n`);
|
|
254
224
|
return 0;
|
|
255
225
|
}
|
|
@@ -267,9 +237,6 @@ function runHookGate(argv, stdin, env = process.env, options = {}) {
|
|
|
267
237
|
windowsHide: true,
|
|
268
238
|
...(plan.verbatim ? { windowsVerbatimArguments: true } : {}),
|
|
269
239
|
});
|
|
270
|
-
// A command that exits without reading its stdin (`exit 2`, `touch x`)
|
|
271
|
-
// closes the pipe before the payload is written; spawnSync then reports
|
|
272
|
-
// EPIPE next to the command's real exit status, which is the answer.
|
|
273
240
|
const ignoredStdin = result.error?.code === "EPIPE" && result.status !== null;
|
|
274
241
|
if (result.error && !ignoredStdin) {
|
|
275
242
|
process.stderr.write(`codiedev hook-gate: ${result.error.message}\n`);
|
package/dist/packs/install.js
CHANGED
|
@@ -39,9 +39,6 @@ exports.installPacks = installPacks;
|
|
|
39
39
|
exports.uninstallPacks = uninstallPacks;
|
|
40
40
|
exports.formatUninstallLines = formatUninstallLines;
|
|
41
41
|
exports.formatResultLines = formatResultLines;
|
|
42
|
-
// Orchestrates `codiedev pack install`: write the plugin dir + marketplace,
|
|
43
|
-
// run every detected tool's adapter, record installed.json, then regenerate
|
|
44
|
-
// the Codex pack trust block and the Codie hook shim from the registry.
|
|
45
42
|
const fs = __importStar(require("fs"));
|
|
46
43
|
const os = __importStar(require("os"));
|
|
47
44
|
const path = __importStar(require("path"));
|
|
@@ -59,7 +56,6 @@ function marketplaceEntries(registry) {
|
|
|
59
56
|
description: entry.description,
|
|
60
57
|
}));
|
|
61
58
|
}
|
|
62
|
-
/** Where Codex unpacked this pack's hooks.json after `codex plugin add`. */
|
|
63
59
|
function codexPackHooksPath(codexDir, slug, version) {
|
|
64
60
|
const base = path.join(codexDir, "plugins", "cache", paths_1.MARKETPLACE_NAME, slug);
|
|
65
61
|
const exact = path.join(base, (0, store_1.pluginVersion)(version), "hooks", "hooks.json");
|
|
@@ -75,7 +71,6 @@ function codexPackHooksPath(codexDir, slug, version) {
|
|
|
75
71
|
best = { file, mtime };
|
|
76
72
|
}
|
|
77
73
|
catch {
|
|
78
|
-
// no hooks in this version dir
|
|
79
74
|
}
|
|
80
75
|
}
|
|
81
76
|
}
|
|
@@ -84,7 +79,6 @@ function codexPackHooksPath(codexDir, slug, version) {
|
|
|
84
79
|
}
|
|
85
80
|
return best?.file ?? null;
|
|
86
81
|
}
|
|
87
|
-
/** Trust entries for every registry pack installed into Codex. */
|
|
88
82
|
function codexPackTrustEntries(registry, codexDir) {
|
|
89
83
|
const bySlug = new Map();
|
|
90
84
|
for (const [slug, entry] of Object.entries(registry.packs).sort(([a], [b]) => a.localeCompare(b))) {
|
|
@@ -94,12 +88,10 @@ function codexPackTrustEntries(registry, codexDir) {
|
|
|
94
88
|
if (!hooksPath)
|
|
95
89
|
continue;
|
|
96
90
|
try {
|
|
97
|
-
// hooks/hooks.json sits at the root of the installed plugin bundle.
|
|
98
91
|
const plugin = { id: `${slug}@${paths_1.MARKETPLACE_NAME}`, root: path.dirname(path.dirname(hooksPath)) };
|
|
99
92
|
bySlug.set(slug, (0, codexHookTrust_1.packCodexHookTrustEntries)(hooksPath, JSON.parse(fs.readFileSync(hooksPath, "utf8")), plugin));
|
|
100
93
|
}
|
|
101
94
|
catch {
|
|
102
|
-
// unreadable hooks → not trusted
|
|
103
95
|
}
|
|
104
96
|
}
|
|
105
97
|
return bySlug;
|
|
@@ -115,7 +107,6 @@ function shimInputs(registry) {
|
|
|
115
107
|
packs.push({ slug, root: entry.dir, hooks: parsed.hooks });
|
|
116
108
|
}
|
|
117
109
|
catch {
|
|
118
|
-
// no hooks for this pack
|
|
119
110
|
}
|
|
120
111
|
}
|
|
121
112
|
return packs;
|
|
@@ -149,9 +140,7 @@ function installPacks(options) {
|
|
|
149
140
|
continue;
|
|
150
141
|
}
|
|
151
142
|
(0, store_1.writePluginDir)(root, manifest);
|
|
152
|
-
// Same plugin with agent model levels removed, for Codex/Copilot/Cursor.
|
|
153
143
|
(0, store_1.writePluginDir)((0, paths_1.portableRoot)(root), manifest, { portable: true });
|
|
154
|
-
// Harnesses read the marketplace during install, so it must list this pack first.
|
|
155
144
|
const pending = {
|
|
156
145
|
packs: {
|
|
157
146
|
...registry.packs,
|
|
@@ -181,8 +170,6 @@ function installPacks(options) {
|
|
|
181
170
|
results.push({ harness: adapter.name, status: "failed", detail: error instanceof Error ? error.message : String(error) });
|
|
182
171
|
}
|
|
183
172
|
}
|
|
184
|
-
// Tools not selected this run keep their previous state; selected ones
|
|
185
|
-
// reflect this run's outcome.
|
|
186
173
|
const kept = (previous?.harnesses ?? []).filter((h) => !selected.has(h));
|
|
187
174
|
const succeeded = results.filter((r) => r.status === "ok").map((r) => r.harness);
|
|
188
175
|
const harnesses = [...new Set([...kept, ...succeeded])].sort();
|
|
@@ -229,11 +216,6 @@ function regenerateCodexTrust(registry, env, home) {
|
|
|
229
216
|
(0, codexHookTrust_1.writeCodexPackHookTrust)(path.join(codexDir, "config.toml"), [...bySlug.values()].flat());
|
|
230
217
|
return bySlug;
|
|
231
218
|
}
|
|
232
|
-
/** Remove packs that no longer apply (unassigned or archived): run each
|
|
233
|
-
* tool's uninstall, drop the plugin dir, the marketplace entry, the registry
|
|
234
|
-
* entry, its Codex trust entries and its shim hooks. Unknown slugs are a
|
|
235
|
-
* no-op. A tool failing to uninstall never keeps the pack registered — the
|
|
236
|
-
* pack is no longer authorized, so local state must stop advertising it. */
|
|
237
219
|
function uninstallPacks(options) {
|
|
238
220
|
const env = options.env ?? process.env;
|
|
239
221
|
const home = options.home ?? os.homedir();
|
|
@@ -270,8 +252,6 @@ function uninstallPacks(options) {
|
|
|
270
252
|
(0, store_1.writeRegistry)(root, registry);
|
|
271
253
|
(0, store_1.writeMarketplace)(root, marketplaceEntries(registry));
|
|
272
254
|
(0, store_1.writeMarketplace)((0, paths_1.portableRoot)(root), marketplaceEntries(registry));
|
|
273
|
-
// Regenerate even when Codex isn't on PATH any more: a stale trust entry
|
|
274
|
-
// for a removed pack must not survive in config.toml.
|
|
275
255
|
const codexConfig = path.join((0, harnessDirs_1.codexHome)(env, home), "config.toml");
|
|
276
256
|
if (fs.existsSync(codexConfig))
|
|
277
257
|
regenerateCodexTrust(registry, env, home);
|
package/dist/packs/manifest.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// Server manifest shape (GET /api/cli/packs/manifest) and its validation.
|
|
3
|
-
// Everything here is untrusted input that becomes file paths and shell hooks
|
|
4
|
-
// on the member's machine, so names are checked strictly before any write.
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.ManifestError = void 0;
|
|
7
4
|
exports.isSafeSegment = isSafeSegment;
|
|
@@ -10,15 +7,10 @@ exports.parseManifest = parseManifest;
|
|
|
10
7
|
exports.cleanLabel = cleanLabel;
|
|
11
8
|
exports.displayName = displayName;
|
|
12
9
|
exports.parseFrontmatter = parseFrontmatter;
|
|
13
|
-
// One path segment: starts alphanumeric, then alphanumerics, dot, dash or
|
|
14
|
-
// underscore. Rejects "", ".", "..", slashes, backslashes, absolute paths,
|
|
15
|
-
// drive letters, NUL and whitespace.
|
|
16
10
|
const SAFE_SEGMENT = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
17
11
|
function isSafeSegment(value) {
|
|
18
12
|
return typeof value === "string" && SAFE_SEGMENT.test(value) && !value.includes("..");
|
|
19
13
|
}
|
|
20
|
-
// Skill dir names come from SKILL.md frontmatter and may contain inner spaces
|
|
21
|
-
// (the server allows `[A-Za-z0-9][A-Za-z0-9._ -]*`); still one safe segment.
|
|
22
14
|
const SAFE_SKILL_NAME = /^[A-Za-z0-9][A-Za-z0-9._ -]{0,127}$/;
|
|
23
15
|
function isSafeSkillName(value) {
|
|
24
16
|
return typeof value === "string" && SAFE_SKILL_NAME.test(value) && !value.includes("..") && value.trim() === value;
|
|
@@ -49,9 +41,6 @@ function fileList(value, field, safe) {
|
|
|
49
41
|
return { name: entry.name, content: entry.content, ...(artifactId ? { artifactId } : {}) };
|
|
50
42
|
});
|
|
51
43
|
}
|
|
52
|
-
/** Validate a manifest from the server. Throws ManifestError on anything
|
|
53
|
-
* unsafe or malformed — a partial install of a tampered pack is worse than
|
|
54
|
-
* none. */
|
|
55
44
|
function parseManifest(input) {
|
|
56
45
|
let raw = input;
|
|
57
46
|
if (typeof raw === "string") {
|
|
@@ -104,23 +93,20 @@ function parseManifest(input) {
|
|
|
104
93
|
...(cleanLabel(m.icon, 16) ? { icon: cleanLabel(m.icon, 16) } : {}),
|
|
105
94
|
};
|
|
106
95
|
}
|
|
107
|
-
/** Short display-only label from the server: printable, no control chars. */
|
|
108
96
|
function cleanLabel(value, max) {
|
|
109
97
|
if (typeof value !== "string")
|
|
110
98
|
return undefined;
|
|
111
99
|
const clean = value
|
|
112
|
-
.replace(/\u001b\[[0-9;?]*[ -\/]*[@-~]/g, "")
|
|
100
|
+
.replace(/\u001b\[[0-9;?]*[ -\/]*[@-~]/g, "")
|
|
113
101
|
.replace(/[\u0000-\u001f\u007f-\u009f]/g, "")
|
|
114
102
|
.trim();
|
|
115
103
|
return clean ? [...clean].slice(0, max).join("") : undefined;
|
|
116
104
|
}
|
|
117
|
-
/** "🧰 Backend starter" when an icon is set. */
|
|
118
105
|
function displayName(pack) {
|
|
119
106
|
const icon = cleanLabel(pack.icon, 8);
|
|
120
107
|
const name = pack.name || pack.slug;
|
|
121
108
|
return icon ? `${icon} ${name}` : name;
|
|
122
109
|
}
|
|
123
|
-
/** Parse leading `---` YAML-ish frontmatter (flat `key: value` lines only). */
|
|
124
110
|
function parseFrontmatter(content) {
|
|
125
111
|
const match = content.match(/^?---\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n|$)/);
|
|
126
112
|
if (!match)
|
package/dist/packs/paths.js
CHANGED
|
@@ -44,8 +44,6 @@ exports.shimPath = shimPath;
|
|
|
44
44
|
exports.lastSyncPath = lastSyncPath;
|
|
45
45
|
exports.statusCachePath = statusCachePath;
|
|
46
46
|
exports.lastNagPath = lastNagPath;
|
|
47
|
-
// Where starter packs live on disk. Resolved per call (not at import) so tests
|
|
48
|
-
// and `CODIEDEV_CONFIG_DIR` overrides take effect without module reloads.
|
|
49
47
|
const os = __importStar(require("os"));
|
|
50
48
|
const path = __importStar(require("path"));
|
|
51
49
|
exports.MARKETPLACE_NAME = "codiedev-packs";
|
|
@@ -60,10 +58,6 @@ function pluginsDir(root) {
|
|
|
60
58
|
function pluginDir(root, slug) {
|
|
61
59
|
return path.join(pluginsDir(root), slug);
|
|
62
60
|
}
|
|
63
|
-
/** Codex, Copilot and Cursor read a "portable" copy of each plugin: agent
|
|
64
|
-
* `model:` levels (opus/sonnet/haiku) are Claude Code aliases, so those tools
|
|
65
|
-
* get the line removed and use their own default. Same marketplace name, its
|
|
66
|
-
* own root. */
|
|
67
61
|
function portableRoot(root) {
|
|
68
62
|
return path.join(root, "portable");
|
|
69
63
|
}
|
|
@@ -76,11 +70,9 @@ function registryPath(root) {
|
|
|
76
70
|
function shimPath(root) {
|
|
77
71
|
return path.join(root, "codie-hook-shim.mjs");
|
|
78
72
|
}
|
|
79
|
-
/** Stamp of the last background `pack install --quiet` spawn. */
|
|
80
73
|
function lastSyncPath(root) {
|
|
81
74
|
return path.join(root, ".last-sync");
|
|
82
75
|
}
|
|
83
|
-
/** Cached `pack status`, written by every sync/status run, read by the nag. */
|
|
84
76
|
function statusCachePath(root) {
|
|
85
77
|
return path.join(root, "status-cache.json");
|
|
86
78
|
}
|
package/dist/packs/shim.js
CHANGED
|
@@ -38,13 +38,8 @@ exports.unsupportedShimEvents = unsupportedShimEvents;
|
|
|
38
38
|
exports.shimPacks = shimPacks;
|
|
39
39
|
exports.generateShimSource = generateShimSource;
|
|
40
40
|
exports.writeShim = writeShim;
|
|
41
|
-
// Generates the OpenCode plugin that runs starter-pack Claude hooks inside
|
|
42
|
-
// Codie. Stock OpenCode cannot load a Claude plugin's hooks.json, so this shim
|
|
43
|
-
// translates OpenCode plugin events into Claude hook invocations (Claude-style
|
|
44
|
-
// JSON on stdin, exit 2 on PreToolUse blocks the tool).
|
|
45
41
|
const fs = __importStar(require("fs"));
|
|
46
42
|
const store_1 = require("./store");
|
|
47
|
-
// Only events with an OpenCode equivalent are wired; others are dropped.
|
|
48
43
|
exports.SHIM_EVENTS = ["SessionStart", "PreToolUse", "PostToolUse", "Stop"];
|
|
49
44
|
function normalizeHooks(hooks) {
|
|
50
45
|
const out = {};
|
|
@@ -79,7 +74,6 @@ function normalizeHooks(hooks) {
|
|
|
79
74
|
}
|
|
80
75
|
return out;
|
|
81
76
|
}
|
|
82
|
-
/** Per pack, the hook events in its hooks.json the shim cannot wire. */
|
|
83
77
|
function unsupportedShimEvents(packs) {
|
|
84
78
|
const out = new Map();
|
|
85
79
|
for (const pack of packs) {
|
|
@@ -210,8 +204,6 @@ export const CodiedevPackHooks = async (ctx = {}) => {
|
|
|
210
204
|
};
|
|
211
205
|
`;
|
|
212
206
|
}
|
|
213
|
-
/** Write (or remove, when no pack has wireable hooks) the shim. Returns the
|
|
214
|
-
* path when a shim exists afterwards. */
|
|
215
207
|
function writeShim(file, packs) {
|
|
216
208
|
if (shimPacks(packs).length === 0) {
|
|
217
209
|
fs.rmSync(file, { force: true });
|
package/dist/packs/store.js
CHANGED
|
@@ -43,8 +43,6 @@ exports.readRegistry = readRegistry;
|
|
|
43
43
|
exports.writeRegistry = writeRegistry;
|
|
44
44
|
exports.marketplaceDocument = marketplaceDocument;
|
|
45
45
|
exports.writeMarketplace = writeMarketplace;
|
|
46
|
-
// On-disk layout for installed packs: the Claude-format plugin dir, the local
|
|
47
|
-
// marketplace that every harness reads, and the installed.json registry.
|
|
48
46
|
const fs = __importStar(require("fs"));
|
|
49
47
|
const skillMarker_1 = require("../skillMarker");
|
|
50
48
|
const path = __importStar(require("path"));
|
|
@@ -52,7 +50,6 @@ const paths_1 = require("./paths");
|
|
|
52
50
|
function pluginVersion(version) {
|
|
53
51
|
return `${version}.0.0`;
|
|
54
52
|
}
|
|
55
|
-
/** Write a file via temp + rename so readers never see a partial file. */
|
|
56
53
|
function writeFileAtomic(file, content, mode = 0o644) {
|
|
57
54
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
58
55
|
const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
@@ -60,8 +57,6 @@ function writeFileAtomic(file, content, mode = 0o644) {
|
|
|
60
57
|
fs.renameSync(tmp, file);
|
|
61
58
|
}
|
|
62
59
|
exports.AGENT_LEVELS = new Set(["opus", "sonnet", "haiku"]);
|
|
63
|
-
/** Agent file for tools other than Claude Code: drop a `model:` line unless it
|
|
64
|
-
* is a full `provider/model` id (levels and `inherit` are Claude aliases). */
|
|
65
60
|
function portableAgentContent(content) {
|
|
66
61
|
const fm = content.match(/^(\uFEFF?---\r?\n)([\s\S]*?)(\r?\n---[ \t]*(?:\r?\n|$))/);
|
|
67
62
|
if (!fm)
|
|
@@ -75,7 +70,6 @@ function portableAgentContent(content) {
|
|
|
75
70
|
return content;
|
|
76
71
|
return fm[1] + kept.join("\n") + fm[3] + content.slice(fm[0].length);
|
|
77
72
|
}
|
|
78
|
-
/** The full file set for a pack's plugin dir, relative path → content. */
|
|
79
73
|
function pluginFiles(manifest, options = {}) {
|
|
80
74
|
const files = {};
|
|
81
75
|
files[path.join(".claude-plugin", "plugin.json")] = JSON.stringify({
|
|
@@ -84,7 +78,6 @@ function pluginFiles(manifest, options = {}) {
|
|
|
84
78
|
description: manifest.description || manifest.name,
|
|
85
79
|
}, null, 2) + "\n";
|
|
86
80
|
for (const skill of manifest.skills) {
|
|
87
|
-
// Identity marker so the skill's runs attribute to this exact artifact.
|
|
88
81
|
files[path.join("skills", skill.name, "SKILL.md")] = (0, skillMarker_1.stampSkillMarker)(skill.content, skill.artifactId);
|
|
89
82
|
}
|
|
90
83
|
for (const agent of manifest.agents) {
|
|
@@ -101,9 +94,6 @@ function assertInside(parent, child) {
|
|
|
101
94
|
throw new Error(`refusing to write outside the pack dir: ${child}`);
|
|
102
95
|
}
|
|
103
96
|
}
|
|
104
|
-
/** Build the plugin dir in a sibling temp dir and swap it into place, so a
|
|
105
|
-
* failed write never leaves a half-updated plugin and stale files (a removed
|
|
106
|
-
* skill, hooks that were cleared) never linger. */
|
|
107
97
|
function writePluginDir(root, manifest, options = {}) {
|
|
108
98
|
const target = (0, paths_1.pluginDir)(root, manifest.slug);
|
|
109
99
|
const parent = (0, paths_1.pluginsDir)(root);
|
|
@@ -140,7 +130,6 @@ function readRegistry(root) {
|
|
|
140
130
|
}
|
|
141
131
|
}
|
|
142
132
|
catch {
|
|
143
|
-
// Missing or corrupt registry → start fresh.
|
|
144
133
|
}
|
|
145
134
|
return { packs: {} };
|
|
146
135
|
}
|
|
@@ -161,7 +150,6 @@ function marketplaceDocument(entries) {
|
|
|
161
150
|
})),
|
|
162
151
|
};
|
|
163
152
|
}
|
|
164
|
-
/** Rewrite marketplace.json atomically with one entry per pack. */
|
|
165
153
|
function writeMarketplace(root, entries) {
|
|
166
154
|
writeFileAtomic((0, paths_1.marketplacePath)(root), JSON.stringify(marketplaceDocument(entries), null, 2) + "\n");
|
|
167
155
|
}
|