codiedev 0.10.0-beta.5 → 0.10.0-beta.7

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 (44) hide show
  1. package/README.md +4 -4
  2. package/dist/captureSignals.js +2 -0
  3. package/dist/cli.js +38 -50
  4. package/dist/codexHookTrust.js +67 -4
  5. package/dist/codie.js +23 -74
  6. package/dist/codieLauncher.js +18 -22
  7. package/dist/commands/agentTemplates.generated.js +136 -0
  8. package/dist/commands/agents.js +1068 -0
  9. package/dist/commands/agentsSdk.generated.js +7 -0
  10. package/dist/commands/doctor.js +12 -38
  11. package/dist/commands/evals.js +187 -0
  12. package/dist/commands/pack.js +1 -1
  13. package/dist/commands/traces.js +79 -15
  14. package/dist/commands/tracesLabel.js +348 -0
  15. package/dist/connect.js +11 -52
  16. package/dist/copilotHooks.js +0 -4
  17. package/dist/cursorHooks.js +0 -15
  18. package/dist/harnessDirs.js +4 -0
  19. package/dist/hook.js +33 -197
  20. package/dist/limitEventReporter.js +1 -1
  21. package/dist/managedPi.js +240 -0
  22. package/dist/mcp.js +0 -307
  23. package/dist/packs/harnesses.js +40 -3
  24. package/dist/packs/install.js +2 -1
  25. package/dist/piHooks.js +216 -0
  26. package/dist/piRuntime.js +120 -0
  27. package/dist/selfUpdate.js +47 -2
  28. package/dist/utils.js +232 -115
  29. package/package.json +5 -7
  30. package/dist/codieStartup.js +0 -27
  31. package/dist/commands/promote.js +0 -53
  32. package/dist/commands/react.js +0 -38
  33. package/dist/commands/reverseTicket.js +0 -444
  34. package/dist/commands/security.js +0 -156
  35. package/dist/prUrl.js +0 -28
  36. package/dist/security.js +0 -417
  37. package/dist/securityDeepScan.js +0 -235
  38. package/dist/securityDoctor.js +0 -61
  39. package/dist/securityFeature.js +0 -6
  40. package/dist/securityInstall.js +0 -232
  41. package/dist/securityInventory.js +0 -566
  42. package/dist/securityPilot.js +0 -59
  43. package/dist/securityPolicy.js +0 -181
  44. package/dist/securitySession.js +0 -72
package/README.md CHANGED
@@ -18,7 +18,7 @@ The CLI will prompt you for an API token (get one at https://codiedev.com/portal
18
18
 
19
19
  - **Claude Code** — `SessionEnd` hook in `~/.claude/settings.json`
20
20
  - **Codex** — `Stop` hook in `~/.codex/hooks.json`
21
- - **Cursor** — native session, prompt-security, tool-security, backup, and capture hooks in `~/.cursor/hooks.json`
21
+ - **Cursor** — native session, subagent/tool observation, backup, and capture hooks in `~/.cursor/hooks.json`
22
22
  - **OpenCode / Codie** — plugin in `~/.config/opencode/plugins/codiedev.js`
23
23
 
24
24
  Installed clients are wired automatically. The OpenCode adapter is staged even
@@ -57,9 +57,9 @@ Codex doesn't currently expose a `SessionEnd` event, so the hook runs on `Stop`
57
57
 
58
58
  ## Cursor note
59
59
 
60
- Cursor uses its native hook events for session start/end, prompt blocking,
61
- pre/post-tool security, and stop-time backup. Cursor's `beforeSubmitPrompt`
62
- cannot inject dynamic context today, so task-specific discovery is not claimed.
60
+ Cursor uses its native hook events for session start/end, tool and subagent
61
+ observation, and stop-time backup. Cursor's `beforeSubmitPrompt` cannot inject
62
+ dynamic context today, so task-specific discovery is not claimed.
63
63
  Cursor sessions keep their source
64
64
  label and real transcript statistics through the shared capture pipeline.
65
65
 
@@ -102,6 +102,8 @@ function parseCaptureSignals(content, source) {
102
102
  }
103
103
  if (e.type === "copilot.skill_invoked")
104
104
  addSkill(invocations, e.skill);
105
+ if (e.type === "pi.skill_invoked")
106
+ addSkill(invocations, e.skill);
105
107
  if (e.type === "copilot.usage_summary") {
106
108
  if (typeof e.premiumRequests === "number" && e.premiumRequests >= 0)
107
109
  premiumRequests = e.premiumRequests;
package/dist/cli.js CHANGED
@@ -9,19 +9,17 @@ const ask_1 = require("./commands/ask");
9
9
  const ping_1 = require("./commands/ping");
10
10
  const inbox_1 = require("./commands/inbox");
11
11
  const note_1 = require("./commands/note");
12
- const promote_1 = require("./commands/promote");
13
- const reverseTicket_1 = require("./commands/reverseTicket");
14
12
  const createTicket_1 = require("./commands/createTicket");
15
13
  const doctor_1 = require("./commands/doctor");
16
14
  const search_1 = require("./commands/search");
17
15
  const library_1 = require("./commands/library");
18
16
  const share_1 = require("./commands/share");
19
17
  const send_1 = require("./commands/send");
20
- const react_1 = require("./commands/react");
21
18
  const capture_1 = require("./commands/capture");
22
- const security_1 = require("./commands/security");
23
19
  const pack_1 = require("./commands/pack");
24
20
  const traces_1 = require("./commands/traces");
21
+ const agents_1 = require("./commands/agents");
22
+ const evals_1 = require("./commands/evals");
25
23
  const hookGate_1 = require("./packs/hookGate");
26
24
  const sync_1 = require("./packs/sync");
27
25
  const version_1 = require("./version");
@@ -34,14 +32,8 @@ Codiedev CLI
34
32
 
35
33
  Connect:
36
34
  codiedev connect Link Claude Code / Codex / Cursor /
37
- GitHub Copilot to your org
38
- codiedev doctor Verify setup, capture, and Agent Security
39
- codiedev security pilot Run safe synthetic policy checks
40
- codiedev security inventory Inventory MCPs, skills, hooks, plugins,
41
- instructions, and editor extensions
42
- codiedev security scan --deep Run installed open-source scanners too
43
- codiedev security sync Fetch administrator policy locally
44
- codiedev security rollback --yes Restore pre-update hook configuration
35
+ GitHub Copilot / pi to your org
36
+ codiedev doctor Verify setup and capture
45
37
 
46
38
  Harness:
47
39
  codie Launch the governed Codie harness.
@@ -61,14 +53,6 @@ Artifacts:
61
53
  team's collective memory. Returns an
62
54
  LLM-synthesized answer with citations
63
55
  pointing at sessions + artifacts.
64
- codiedev promote <artifact-id> Promote an auto-extracted artifact
65
- to an authored one
66
- codiedev reverse-ticket [<pr-url>] Generate a Jira ticket draft.
67
- No URL = branch mode (uses your current
68
- local git branch, no PR needed).
69
- Draft lands in /portal/agentic-ticketing.
70
- codiedev reverse-ticket --base <ref> Override the base ref in branch mode
71
- (defaults to origin/main).
72
56
  codiedev create-ticket [<prompt>] Forward-write a scoped ticket plan.
73
57
  Claude investigates the codebase, asks
74
58
  "single repo or multiple? where?", then
@@ -89,19 +73,27 @@ Messaging:
89
73
 
90
74
  Starter packs:
91
75
  codiedev pack list Packs assigned to your team
92
- codiedev pack install [slug] [--harness claude,codex,copilot,cursor,codie]
76
+ codiedev pack install [slug] [--harness claude,codex,copilot,cursor,codie,pi]
93
77
  [--dry-run] [--json]
94
78
  Install a pack (or all) into every
95
79
  detected tool
96
80
  codiedev pack status Installed packs, up to date or not
97
81
 
98
82
  Traces (agents on the gateway):
83
+ codiedev agents init | deploy | run | runs | show | secrets | webhook
84
+ Deploy agents and run them in fresh sandboxes
85
+ (codiedev agents help)
99
86
  codiedev traces agents Agents you maintain, with saved test cases
100
- codiedev traces cases <agent> [--suite name] [--model id]
101
- Pull an agent's test cases (or one suite)
87
+ codiedev traces cases <agent> [--dataset name [--version n]] [--model id]
88
+ Pull an agent's test cases (or one dataset)
102
89
  into this repo for your coding agent to
103
90
  run, optionally on another model
104
91
  codiedev traces report <results.json> Send the results back to Traces
92
+ codiedev traces overview | runs | run | score | scores | score-kinds | queue | judge | import | add-example | versions | save-version
93
+ Agents, runs, failures, scores, review queues,
94
+ automatic scoring and datasets (codiedev traces help)
95
+ codiedev evals report <run.json> File one variant's eval scores under an experiment
96
+ codiedev evals last <subject> Latest experiment on a subject + its champion
105
97
 
106
98
  Discovery:
107
99
  codiedev search "<query>" Semantic search across the team's
@@ -110,9 +102,6 @@ Discovery:
110
102
  [--type T] [--tag X] [--limit N]
111
103
  List artifacts in your workspace
112
104
 
113
- Feed:
114
- codiedev react <postId> <emoji> Toggle a reaction on a feed post
115
-
116
105
  Privacy:
117
106
  codiedev ignore <path> Never capture this folder or its children
118
107
  codiedev unignore <path> Stop ignoring a folder
@@ -168,6 +157,8 @@ status sync never weakens it.
168
157
  const COMMAND_HELP = {
169
158
  pack: pack_1.PACK_HELP,
170
159
  traces: traces_1.TRACES_HELP,
160
+ agents: agents_1.AGENTS_HELP,
161
+ evals: evals_1.EVALS_HELP,
171
162
  connect: `
172
163
  codiedev connect — link your agent CLI to Codiedev
173
164
 
@@ -177,9 +168,11 @@ codiedev connect — link your agent CLI to Codiedev
177
168
  - ~/.claude/CLAUDE.md instructions (teaches Claude the commands)
178
169
  - ~/.codex/hooks.json hook (same, for Codex)
179
170
  - ~/.codex/AGENTS.md instructions (same, for Codex)
180
- - ~/.cursor/hooks.json hooks (session, prompt, security, capture)
171
+ - ~/.cursor/hooks.json hooks (session, backup, capture)
181
172
  - ~/.cursor/rules/codiedev.mdc (teaches Cursor the commands)
182
173
  - ~/.copilot/hooks/codiedev.json (GitHub Copilot: VS Code + CLI capture)
174
+ - ~/.pi/agent/extensions/codiedev.ts (pi: session, prompt, capture)
175
+ - ~/.pi/agent/AGENTS.md (teaches pi the commands)
183
176
 
184
177
  Re-run anytime to swap accounts or refresh the instruction block.
185
178
 
@@ -285,20 +278,6 @@ codiedev note — capture a passing thought, linked to your session
285
278
  unignore: IGNORE_HELP,
286
279
  ignored: IGNORE_HELP,
287
280
  capture: IGNORE_HELP,
288
- promote: `
289
- codiedev promote — promote an auto-extracted artifact to authored
290
-
291
- Usage:
292
- codiedev promote <artifact-id> [--key filename.md]
293
-
294
- The session-capture pipeline auto-extracts spec/bugfix/decision
295
- artifacts from each agent session. Promote turns one of those into
296
- a first-class authored artifact your team can ping, pull, and
297
- update versions of.
298
-
299
- Find artifact-ids in the portal under Knowledge → Memory, or via
300
- the portal search.
301
- `.trim(),
302
281
  "create-ticket": `
303
282
  codiedev create-ticket — forward-write a scoped ticket plan
304
283
 
@@ -424,6 +403,16 @@ Run 'codiedev help <command>' for each, or see the quick list:
424
403
 
425
404
  Tokens are per-user. Rotate any time by revoking + creating a new one.
426
405
  `.trim();
406
+ const REMOVED_COMMANDS = {
407
+ promote: "Share an auto-saved spec with 'Promote to team' in the portal's My artifacts list.",
408
+ "reverse-ticket": "Use 'codiedev create-ticket' to draft Jira tickets.",
409
+ reverseTicket: "Use 'codiedev create-ticket' to draft Jira tickets.",
410
+ react: "React to feed posts in the portal.",
411
+ };
412
+ function removedCommand(command) {
413
+ console.error(`'codiedev ${command}' has been removed. ${REMOVED_COMMANDS[command] ?? ""}`.trim());
414
+ process.exit(1);
415
+ }
427
416
  async function main() {
428
417
  const [, , command, ...rest] = process.argv;
429
418
  if (command === "hook-gate") {
@@ -476,9 +465,6 @@ async function main() {
476
465
  case "verify":
477
466
  await (0, doctor_1.runDoctor)(rest);
478
467
  return;
479
- case "security":
480
- await (0, security_1.runSecurityCommand)(rest);
481
- return;
482
468
  case "push":
483
469
  await (0, push_1.runPush)(rest);
484
470
  return;
@@ -511,11 +497,10 @@ async function main() {
511
497
  await (0, note_1.runNote)(rest);
512
498
  return;
513
499
  case "promote":
514
- await (0, promote_1.runPromote)(rest);
515
- return;
516
500
  case "reverse-ticket":
517
501
  case "reverseTicket":
518
- await (0, reverseTicket_1.runReverseTicket)(rest);
502
+ case "react":
503
+ removedCommand(command);
519
504
  return;
520
505
  case "create-ticket":
521
506
  case "createTicket":
@@ -531,15 +516,18 @@ async function main() {
531
516
  case "traces":
532
517
  await (0, traces_1.runTraces)(rest);
533
518
  return;
519
+ case "agents":
520
+ await (0, agents_1.runAgents)(rest);
521
+ return;
522
+ case "evals":
523
+ await (0, evals_1.runEvals)(rest);
524
+ return;
534
525
  case "share":
535
526
  await (0, share_1.runShare)(rest);
536
527
  return;
537
528
  case "send":
538
529
  await (0, send_1.runSend)(rest);
539
530
  return;
540
- case "react":
541
- await (0, react_1.runReact)(rest);
542
- return;
543
531
  case "ignore":
544
532
  case "unignore":
545
533
  case "ignored":
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.codexPluginContentHash = codexPluginContentHash;
36
37
  exports.codexCommandHookHash = codexCommandHookHash;
37
38
  exports.codiedevCodexHookTrustEntries = codiedevCodexHookTrustEntries;
38
39
  exports.writeCodexHookTrust = writeCodexHookTrust;
@@ -69,6 +70,42 @@ const MATCHER_EVENTS = new Set([
69
70
  "SubagentStart",
70
71
  "SubagentStop",
71
72
  ]);
73
+ function codexPluginContentHash(root) {
74
+ const hash = crypto.createHash("sha256");
75
+ hash.update("codex-plugin-bundle-v1");
76
+ const u64 = (n) => {
77
+ const b = Buffer.alloc(8);
78
+ b.writeBigUInt64LE(BigInt(n));
79
+ return b;
80
+ };
81
+ const pending = [root];
82
+ while (pending.length) {
83
+ const current = pending.pop();
84
+ const relative = path.relative(root, current).split(path.sep).join("/");
85
+ const name = path.posix.basename(relative);
86
+ if (name === "__pycache__" || name === ".venv" || name.endsWith(".pyc") || name.endsWith(".egg-info"))
87
+ continue;
88
+ const nameBytes = Buffer.from(relative, "utf8");
89
+ hash.update(u64(nameBytes.length));
90
+ hash.update(nameBytes);
91
+ const stat = fs.lstatSync(current);
92
+ if (stat.isDirectory()) {
93
+ hash.update("directory");
94
+ const entries = fs.readdirSync(current).sort((a, b) => Buffer.compare(Buffer.from(a), Buffer.from(b)));
95
+ for (const entry of entries.reverse())
96
+ pending.push(path.join(current, entry));
97
+ }
98
+ else if (stat.isFile()) {
99
+ hash.update("file");
100
+ hash.update(u64(stat.size));
101
+ hash.update(fs.readFileSync(current));
102
+ }
103
+ else {
104
+ throw new Error(`unsupported plugin entry type: ${current}`);
105
+ }
106
+ }
107
+ return `sha256:${hash.digest("hex")}`;
108
+ }
72
109
  function canonicalize(value) {
73
110
  if (Array.isArray(value))
74
111
  return value.map(canonicalize);
@@ -155,6 +192,27 @@ function codiedevCodexHookTrustEntries(hooksPath, hooksFile) {
155
192
  }
156
193
  return entries;
157
194
  }
195
+ function stripBlockKeepingForeign(text, begin, end) {
196
+ const foreign = [];
197
+ const stripped = text.replace(new RegExp(`\\n?${begin}\\n([\\s\\S]*?)${end}\\n?`, "g"), (_match, body) => {
198
+ let table = null;
199
+ const flush = () => {
200
+ if (table && table.join("").trim())
201
+ foreign.push(table.join("\n").trimEnd());
202
+ };
203
+ for (const line of body.split("\n")) {
204
+ if (/^\s*\[/.test(line)) {
205
+ flush();
206
+ table = /^\s*\[hooks\.state\./.test(line) ? null : [];
207
+ }
208
+ if (table)
209
+ table.push(line);
210
+ }
211
+ flush();
212
+ return "\n";
213
+ });
214
+ return foreign.length ? `${stripped.trimEnd()}\n\n${foreign.join("\n\n")}\n` : stripped;
215
+ }
158
216
  function tableHeader(key) {
159
217
  return `[hooks.state.${JSON.stringify(key)}]`;
160
218
  }
@@ -176,7 +234,7 @@ function removeTable(lines, header) {
176
234
  function writeCodexHookTrust(configPath, hooksPath, hooksFile) {
177
235
  const entries = codiedevCodexHookTrustEntries(hooksPath, hooksFile);
178
236
  let existing = fs.existsSync(configPath) ? fs.readFileSync(configPath, "utf8") : "";
179
- existing = existing.replace(new RegExp(`\\n?${TRUST_BEGIN}\\n[\\s\\S]*?${TRUST_END}\\n?`, "g"), "\n");
237
+ existing = stripBlockKeepingForeign(existing, TRUST_BEGIN, TRUST_END);
180
238
  let lines = existing.split("\n");
181
239
  for (const entry of entries)
182
240
  lines = removeTable(lines, tableHeader(entry.key));
@@ -225,11 +283,14 @@ function inspectCodexHookTrust(configPath, hooksPath, hooksFile, requiredSubcomm
225
283
  }
226
284
  const PACK_TRUST_BEGIN = "# codiedev-pack-trust:begin";
227
285
  const PACK_TRUST_END = "# codiedev-pack-trust:end";
228
- function packCodexHookTrustEntries(hooksPath, hooksFile) {
286
+ function packCodexHookTrustEntries(hooksPath, hooksFile, plugin) {
229
287
  const events = hooksFile?.hooks;
230
288
  if (!events || typeof events !== "object")
231
289
  return [];
232
- const source = normalizedHooksPath(hooksPath);
290
+ const source = plugin
291
+ ? `${plugin.id}:${path.relative(plugin.root, hooksPath).split(path.sep).join("/")}`
292
+ : normalizedHooksPath(hooksPath);
293
+ const contentHash = plugin ? codexPluginContentHash(plugin.root) : undefined;
233
294
  const entries = [];
234
295
  for (const [eventName, groupsValue] of Object.entries(events)) {
235
296
  const eventLabel = EVENT_LABELS[eventName];
@@ -248,6 +309,7 @@ function packCodexHookTrustEntries(hooksPath, hooksFile) {
248
309
  eventName,
249
310
  command: handler.command,
250
311
  currentHash: codexCommandHookHash(eventName, group, handler),
312
+ ...(contentHash ? { contentHash } : {}),
251
313
  });
252
314
  });
253
315
  });
@@ -256,7 +318,7 @@ function packCodexHookTrustEntries(hooksPath, hooksFile) {
256
318
  }
257
319
  function writeCodexPackHookTrust(configPath, entries) {
258
320
  let existing = fs.existsSync(configPath) ? fs.readFileSync(configPath, "utf8") : "";
259
- existing = existing.replace(new RegExp(`\\n?${PACK_TRUST_BEGIN}\\n[\\s\\S]*?${PACK_TRUST_END}\\n?`, "g"), "\n");
321
+ existing = stripBlockKeepingForeign(existing, PACK_TRUST_BEGIN, PACK_TRUST_END);
260
322
  let lines = existing.split("\n");
261
323
  for (const entry of entries)
262
324
  lines = removeTable(lines, tableHeader(entry.key));
@@ -274,6 +336,7 @@ function writeCodexPackHookTrust(configPath, entries) {
274
336
  tableHeader(entry.key),
275
337
  "enabled = true",
276
338
  `trusted_hash = ${JSON.stringify(entry.currentHash)}`,
339
+ ...(entry.contentHash ? [`trusted_content_hash = ${JSON.stringify(entry.contentHash)}`] : []),
277
340
  "",
278
341
  ]).join("\n");
279
342
  const next = `${base}${base ? "\n\n" : ""}${PACK_TRUST_BEGIN}\n${trustBlock}${PACK_TRUST_END}\n`;
package/dist/codie.js CHANGED
@@ -45,10 +45,10 @@ const codieBrandInstall_1 = require("./codieBrandInstall");
45
45
  const codieUsage_1 = require("./codieUsage");
46
46
  const codieRuntime_1 = require("./codieRuntime");
47
47
  const codieRuntimeInstall_1 = require("./codieRuntimeInstall");
48
- const codieStartup_1 = require("./codieStartup");
49
48
  const upgradeNudge_1 = require("./upgradeNudge");
50
49
  const codie_1 = require("./packs/codie");
51
50
  const paths_1 = require("./packs/paths");
51
+ const managedPi_1 = require("./managedPi");
52
52
  const USAGE_SETTLE_MS = 1200;
53
53
  function git(args) {
54
54
  const result = (0, child_process_1.spawnSync)("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
@@ -166,68 +166,8 @@ async function runNonInteractive(runtime, runtimeArgs, env) {
166
166
  process.once("SIGINT", forwardInterrupt);
167
167
  process.once("SIGTERM", forwardTermination);
168
168
  return await new Promise((resolve, reject) => {
169
- let blockReason;
170
- const errorPrefixes = [Buffer.from("\x1b[91m\x1b[1mError:"), Buffer.from("Error: {")];
171
- const retainedPrefixBytes = Math.max(...errorPrefixes.map((prefix) => prefix.length)) - 1;
172
- const createOutputGate = (write) => {
173
- let tail = Buffer.alloc(0);
174
- let possibleError;
175
- return {
176
- push(chunk, blocked) {
177
- if (blocked) {
178
- if (possibleError)
179
- possibleError.push(Buffer.from(chunk));
180
- return;
181
- }
182
- if (possibleError) {
183
- possibleError.push(Buffer.from(chunk));
184
- return;
185
- }
186
- const combined = Buffer.concat([tail, chunk]);
187
- let errorStart = -1;
188
- for (const prefix of errorPrefixes) {
189
- const index = combined.indexOf(prefix);
190
- if (index >= 0 && (errorStart < 0 || index < errorStart))
191
- errorStart = index;
192
- }
193
- if (errorStart >= 0) {
194
- if (errorStart > 0)
195
- write(combined.subarray(0, errorStart));
196
- possibleError = [combined.subarray(errorStart)];
197
- tail = Buffer.alloc(0);
198
- return;
199
- }
200
- const flushBytes = Math.max(0, combined.length - retainedPrefixBytes);
201
- if (flushBytes > 0)
202
- write(combined.subarray(0, flushBytes));
203
- tail = combined.subarray(flushBytes);
204
- },
205
- finish(blocked) {
206
- if (tail.length > 0)
207
- write(tail);
208
- const heldError = possibleError ? Buffer.concat(possibleError).toString() : "";
209
- const genericBlockError = heldError.includes("UnknownError") &&
210
- heldError.includes("Unexpected server error");
211
- if (heldError && (!blocked || !genericBlockError))
212
- write(heldError);
213
- },
214
- };
215
- };
216
- const stdoutGate = createOutputGate((chunk) => process.stdout.write(chunk));
217
- const stderrGate = createOutputGate((chunk) => process.stderr.write(chunk));
218
- child.stdout?.on("data", (chunk) => {
219
- stdoutGate.push(Buffer.from(chunk), Boolean(blockReason));
220
- });
221
- child.stderr?.on("data", (chunk) => {
222
- const text = chunk.toString();
223
- const reason = (0, codieLauncher_1.extractCodieSecurityBlock)(text);
224
- if (reason) {
225
- blockReason = reason;
226
- signalChild("SIGTERM");
227
- return;
228
- }
229
- stderrGate.push(Buffer.from(chunk), Boolean(blockReason));
230
- });
169
+ child.stdout?.on("data", (chunk) => process.stdout.write(chunk));
170
+ child.stderr?.on("data", (chunk) => process.stderr.write(chunk));
231
171
  child.once("error", (error) => {
232
172
  if (child.stdin)
233
173
  process.stdin.unpipe(child.stdin);
@@ -240,11 +180,6 @@ async function runNonInteractive(runtime, runtimeArgs, env) {
240
180
  process.stdin.unpipe(child.stdin);
241
181
  process.removeListener("SIGINT", forwardInterrupt);
242
182
  process.removeListener("SIGTERM", forwardTermination);
243
- stdoutGate.finish(Boolean(blockReason));
244
- stderrGate.finish(Boolean(blockReason));
245
- if (blockReason) {
246
- console.error(`Codie Security blocked this action:\n${blockReason}`);
247
- }
248
183
  resolve(status);
249
184
  });
250
185
  });
@@ -263,12 +198,28 @@ async function main() {
263
198
  process.exitCode = update.status ?? 0;
264
199
  return;
265
200
  }
266
- const policyRefresh = await (0, codieStartup_1.refreshCodieSecurityPolicy)(connected);
267
- if (policyRefresh.status === "cached") {
268
- console.error(`codie: security policy refresh failed; using the cached policy (${policyRefresh.error})`);
269
- }
270
201
  const gatewayUrl = process.env.CODIEDEV_GATEWAY_URL || "https://gateway.codiedev.com/api/v1";
271
202
  const catalog = await (0, codieLauncher_1.fetchApprovedCatalog)({ baseUrl: gatewayUrl, key });
203
+ if (process.argv[2] === "--pi") {
204
+ let skillPaths = [];
205
+ try {
206
+ const approved = new Set(catalog.map((model) => (0, codieLauncher_1.bareModel)(model.id)).filter(Boolean));
207
+ skillPaths = (0, codie_1.codiePackConfig)((0, paths_1.packsRoot)(), { approvedModels: approved, catalog }).skillPaths;
208
+ }
209
+ catch (error) {
210
+ console.error(`codie: skipping starter packs (${error instanceof Error ? error.message : error})`);
211
+ }
212
+ try {
213
+ process.exitCode = (0, managedPi_1.runManagedPi)({
214
+ args: process.argv.slice(3), key, gatewayUrl, catalog, stateDir: (0, configDir_1.codiedevStateDir)(), skillPaths,
215
+ });
216
+ }
217
+ catch (error) {
218
+ console.error(`codie: ${error instanceof Error ? error.message : String(error)}`);
219
+ process.exitCode = error instanceof managedPi_1.ManagedPiArgError ? 2 : 1;
220
+ }
221
+ return;
222
+ }
272
223
  const parsed = (0, codieLauncher_1.parseCodieArgs)(process.argv.slice(2));
273
224
  if (parsed.args.length === 1 && parsed.args[0] === "models") {
274
225
  console.log("Codiedev approved models\n");
@@ -343,8 +294,6 @@ async function main() {
343
294
  };
344
295
  const runtimeArgs = (0, codieLauncher_1.withCodieWorkingDirectory)(parsed.args, process.cwd());
345
296
  const nonInteractiveRun = runtimeArgs[0] === "run";
346
- if (nonInteractiveRun)
347
- env.CODIEDEV_SECURITY_BLOCK_OUTPUT = "marker";
348
297
  if (nonInteractiveRun) {
349
298
  const reportCost = Boolean(process.stderr.isTTY);
350
299
  const startedAt = Date.now();
@@ -33,10 +33,9 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.HIDDEN_WORDMARK = exports.CODIEDEV_WORDMARK = exports.LEGACY_CODIEDEV_WORDMARK = exports.STOCK_WORDMARK = exports.BRAND_PLUGIN_SPEC = exports.USAGE_MODULE_PLACEHOLDER = exports.CODIE_SECURITY_BLOCK_MARKER = void 0;
36
+ exports.HIDDEN_WORDMARK = exports.CODIEDEV_WORDMARK = exports.LEGACY_CODIEDEV_WORDMARK = exports.STOCK_WORDMARK = exports.BRAND_PLUGIN_SPEC = exports.USAGE_MODULE_PLACEHOLDER = void 0;
37
37
  exports.usableModelCost = usableModelCost;
38
38
  exports.usableModelLimit = usableModelLimit;
39
- exports.extractCodieSecurityBlock = extractCodieSecurityBlock;
40
39
  exports.withCodieWorkingDirectory = withCodieWorkingDirectory;
41
40
  exports.bareModel = bareModel;
42
41
  exports.buildCodieConfig = buildCodieConfig;
@@ -83,22 +82,6 @@ function usableModelLimit(value) {
83
82
  return undefined;
84
83
  return { context, output };
85
84
  }
86
- exports.CODIE_SECURITY_BLOCK_MARKER = "__CODIEDEV_SECURITY_BLOCK__";
87
- function extractCodieSecurityBlock(stderr) {
88
- for (const line of stderr.split(/\r?\n/)) {
89
- const markerIndex = line.indexOf(exports.CODIE_SECURITY_BLOCK_MARKER);
90
- if (markerIndex < 0)
91
- continue;
92
- try {
93
- const parsed = JSON.parse(line.slice(markerIndex + exports.CODIE_SECURITY_BLOCK_MARKER.length));
94
- if (typeof parsed?.reason === "string" && parsed.reason.trim())
95
- return parsed.reason.trim();
96
- }
97
- catch {
98
- }
99
- }
100
- return undefined;
101
- }
102
85
  function withCodieWorkingDirectory(args, cwd) {
103
86
  if (args[0] !== "run")
104
87
  return args;
@@ -305,20 +288,33 @@ function resolveCapturePlugin({ homeDir, existsSync, }) {
305
288
  }
306
289
  return (0, url_1.pathToFileURL)(capturePath).href;
307
290
  }
308
- async function fetchApprovedCatalog({ baseUrl, key, fetchImpl = fetch, }) {
291
+ class CatalogRejected extends Error {
292
+ }
293
+ async function fetchApprovedCatalog({ baseUrl, key, fetchImpl = fetch, retryDelayMs = 1_000, }) {
294
+ try {
295
+ return await fetchCatalogOnce(baseUrl, key, fetchImpl);
296
+ }
297
+ catch (error) {
298
+ if (error instanceof CatalogRejected)
299
+ throw error;
300
+ await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
301
+ return fetchCatalogOnce(baseUrl, key, fetchImpl);
302
+ }
303
+ }
304
+ async function fetchCatalogOnce(baseUrl, key, fetchImpl) {
309
305
  const controller = new AbortController();
310
- const timeout = setTimeout(() => controller.abort(), 5000);
306
+ const timeout = setTimeout(() => controller.abort(), 10_000);
311
307
  try {
312
308
  const response = await fetchImpl(`${cleanBaseUrl(baseUrl)}/models`, {
313
309
  headers: { Authorization: `Bearer ${key}` },
314
310
  signal: controller.signal,
315
311
  });
316
312
  if (response.status === 403) {
317
- throw new Error("The Codie harness is not enabled for your company yet. Ask your Codiedev admin to turn it on — " +
313
+ throw new CatalogRejected("The Codie harness is not enabled for your company yet. Ask your Codiedev admin to turn it on — " +
318
314
  "your session capture keeps working in the meantime.");
319
315
  }
320
316
  if (response.status === 401) {
321
- throw new Error("Your Codiedev token was rejected. Run `codiedev connect` to relink this machine.");
317
+ throw new CatalogRejected("Your Codiedev token was rejected. Run `codiedev connect` to relink this machine.");
322
318
  }
323
319
  if (!response.ok)
324
320
  throw new Error(`model catalog returned ${response.status}`);