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.
Files changed (154) hide show
  1. package/README.md +12 -5
  2. package/dist/backup/cache.js +1 -5
  3. package/dist/backup/match.js +0 -6
  4. package/dist/backup/run.js +3 -35
  5. package/dist/captureExclusions.js +0 -12
  6. package/dist/captureLog.js +0 -28
  7. package/dist/captureReadiness.js +0 -58
  8. package/dist/captureSignals.js +0 -11
  9. package/dist/cli.js +11 -33
  10. package/dist/cliSession.js +3 -60
  11. package/dist/codexHookTrust.js +0 -28
  12. package/dist/codexLimitScan.js +0 -107
  13. package/dist/codie.js +64 -57
  14. package/dist/codieBrandInstall.js +0 -18
  15. package/dist/codieLauncher.js +1 -72
  16. package/dist/codieRuntime.js +27 -32
  17. package/dist/codieRuntimeInstall.js +11 -43
  18. package/dist/codieUsage.js +0 -49
  19. package/dist/commands/agentTemplates.generated.js +136 -0
  20. package/dist/commands/agents.js +1088 -0
  21. package/dist/commands/agentsSdk.generated.js +7 -0
  22. package/dist/commands/ask.js +0 -3
  23. package/dist/commands/capture.js +0 -2
  24. package/dist/commands/createTicket.js +0 -10
  25. package/dist/commands/doctor.js +2 -72
  26. package/dist/commands/evals.js +3 -9
  27. package/dist/commands/inbox.js +0 -2
  28. package/dist/commands/library.js +0 -3
  29. package/dist/commands/pack.js +0 -29
  30. package/dist/commands/ping.js +0 -2
  31. package/dist/commands/pull.js +0 -9
  32. package/dist/commands/push.js +0 -12
  33. package/dist/commands/search.js +0 -4
  34. package/dist/commands/send.js +0 -5
  35. package/dist/commands/share.js +0 -4
  36. package/dist/commands/shared.js +0 -35
  37. package/dist/commands/traces.js +0 -13
  38. package/dist/commands/tracesLabel.js +0 -8
  39. package/dist/configDir.js +1 -18
  40. package/dist/connect.js +3 -75
  41. package/dist/connectFlow.js +0 -15
  42. package/dist/copilotHooks.js +0 -67
  43. package/dist/copilotInstallation.js +0 -1
  44. package/dist/cursorHooks.js +1 -11
  45. package/dist/cursorLifecycle.js +1 -7
  46. package/dist/detection.js +0 -30
  47. package/dist/harnessDirs.js +0 -19
  48. package/dist/hook.js +43 -293
  49. package/dist/inboxFormat.js +0 -24
  50. package/dist/launchContext.js +0 -50
  51. package/dist/launcher.js +0 -33
  52. package/dist/limitEvent.js +2 -34
  53. package/dist/managedPi.js +2 -50
  54. package/dist/mcp.js +0 -48
  55. package/dist/nativeSteering.js +1 -4
  56. package/dist/packs/codie.js +0 -15
  57. package/dist/packs/harnesses.js +1 -38
  58. package/dist/packs/hookGate.js +0 -33
  59. package/dist/packs/install.js +0 -20
  60. package/dist/packs/manifest.js +1 -15
  61. package/dist/packs/paths.js +0 -8
  62. package/dist/packs/shim.js +0 -8
  63. package/dist/packs/store.js +0 -12
  64. package/dist/packs/sync.js +0 -20
  65. package/dist/piHooks.js +4 -45
  66. package/dist/piRuntime.js +0 -18
  67. package/dist/repoResolver.js +0 -19
  68. package/dist/secret.js +0 -3
  69. package/dist/selfUpdate.js +2 -77
  70. package/dist/skillMarker.js +0 -14
  71. package/dist/subagents.js +0 -18
  72. package/dist/teamSkillContext.js +0 -1
  73. package/dist/transcriptModels.js +0 -8
  74. package/dist/upgradeNudge.js +1 -30
  75. package/dist/utils.js +165 -768
  76. package/dist/version.js +0 -10
  77. package/dist/versionCheck.js +0 -33
  78. package/package.json +13 -8
  79. package/dist/backup/cache.d.ts +0 -14
  80. package/dist/backup/match.d.ts +0 -2
  81. package/dist/backup/run.d.ts +0 -25
  82. package/dist/captureExclusions.d.ts +0 -30
  83. package/dist/captureLog.d.ts +0 -20
  84. package/dist/captureReadiness.d.ts +0 -65
  85. package/dist/captureSignals.d.ts +0 -47
  86. package/dist/cli.d.ts +0 -15
  87. package/dist/cliSession.d.ts +0 -108
  88. package/dist/codexHookTrust.d.ts +0 -49
  89. package/dist/codexLimitScan.d.ts +0 -64
  90. package/dist/codie.d.ts +0 -2
  91. package/dist/codieBrandInstall.d.ts +0 -11
  92. package/dist/codieLauncher.d.ts +0 -87
  93. package/dist/codieRuntime.d.ts +0 -35
  94. package/dist/codieRuntimeInstall.d.ts +0 -56
  95. package/dist/codieUsage.d.ts +0 -64
  96. package/dist/commands/ask.d.ts +0 -1
  97. package/dist/commands/capture.d.ts +0 -14
  98. package/dist/commands/createTicket.d.ts +0 -27
  99. package/dist/commands/delete.d.ts +0 -1
  100. package/dist/commands/doctor.d.ts +0 -9
  101. package/dist/commands/evals.d.ts +0 -3
  102. package/dist/commands/inbox.d.ts +0 -3
  103. package/dist/commands/library.d.ts +0 -2
  104. package/dist/commands/note.d.ts +0 -1
  105. package/dist/commands/pack.d.ts +0 -54
  106. package/dist/commands/ping.d.ts +0 -1
  107. package/dist/commands/pull.d.ts +0 -2
  108. package/dist/commands/push.d.ts +0 -33
  109. package/dist/commands/search.d.ts +0 -2
  110. package/dist/commands/send.d.ts +0 -2
  111. package/dist/commands/share.d.ts +0 -2
  112. package/dist/commands/shared.d.ts +0 -64
  113. package/dist/commands/traces.d.ts +0 -72
  114. package/dist/commands/tracesLabel.d.ts +0 -24
  115. package/dist/configDir.d.ts +0 -10
  116. package/dist/connect.d.ts +0 -1
  117. package/dist/connectFlow.d.ts +0 -34
  118. package/dist/copilotHooks.d.ts +0 -85
  119. package/dist/copilotInstallation.d.ts +0 -10
  120. package/dist/cursorHooks.d.ts +0 -13
  121. package/dist/cursorLifecycle.d.ts +0 -2
  122. package/dist/detection.d.ts +0 -30
  123. package/dist/harnessDirs.d.ts +0 -15
  124. package/dist/hook.d.ts +0 -6
  125. package/dist/inboxFormat.d.ts +0 -38
  126. package/dist/launchContext.d.ts +0 -46
  127. package/dist/launcher.d.ts +0 -25
  128. package/dist/limitEvent.d.ts +0 -15
  129. package/dist/limitEventReporter.d.ts +0 -21
  130. package/dist/managedPi.d.ts +0 -48
  131. package/dist/mcp.d.ts +0 -12
  132. package/dist/nativeSteering.d.ts +0 -5
  133. package/dist/packs/codie.d.ts +0 -45
  134. package/dist/packs/harnesses.d.ts +0 -74
  135. package/dist/packs/hookGate.d.ts +0 -53
  136. package/dist/packs/install.d.ts +0 -46
  137. package/dist/packs/manifest.d.ts +0 -52
  138. package/dist/packs/paths.d.ts +0 -17
  139. package/dist/packs/shim.d.ts +0 -26
  140. package/dist/packs/store.d.ts +0 -42
  141. package/dist/packs/sync.d.ts +0 -40
  142. package/dist/piHooks.d.ts +0 -22
  143. package/dist/piRuntime.d.ts +0 -26
  144. package/dist/repoResolver.d.ts +0 -17
  145. package/dist/secret.d.ts +0 -1
  146. package/dist/selfUpdate.d.ts +0 -64
  147. package/dist/skillMarker.d.ts +0 -6
  148. package/dist/subagents.d.ts +0 -36
  149. package/dist/teamSkillContext.d.ts +0 -9
  150. package/dist/transcriptModels.d.ts +0 -20
  151. package/dist/upgradeNudge.d.ts +0 -24
  152. package/dist/utils.d.ts +0 -396
  153. package/dist/version.d.ts +0 -1
  154. package/dist/versionCheck.d.ts +0 -68
@@ -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 { /* incomplete transcript records are ignored */ }
21
+ catch { }
25
22
  }
26
23
  return { interrupts: Math.max(interrupts.size, abortedTurns.size), rejections: rejections.size };
27
24
  }
@@ -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") }
@@ -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); // follows links
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)),
@@ -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`);
@@ -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);
@@ -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, "") // ANSI CSI sequences
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)
@@ -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
  }
@@ -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 });
@@ -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
  }