codiedev 0.9.69 → 0.9.71

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.
@@ -110,6 +110,10 @@ function parseCaptureSignals(content, source) {
110
110
  // whether the user or the agent invoked it.
111
111
  if (e.type === "copilot.skill_invoked")
112
112
  addSkill(invocations, e.skill);
113
+ // pi (normalized): a `/skill:name` expansion or the agent reading a
114
+ // listed skill's SKILL.md, which is how pi runs skills.
115
+ if (e.type === "pi.skill_invoked")
116
+ addSkill(invocations, e.skill);
113
117
  if (e.type === "copilot.usage_summary") {
114
118
  if (typeof e.premiumRequests === "number" && e.premiumRequests >= 0)
115
119
  premiumRequests = e.premiumRequests;
package/dist/cli.js CHANGED
@@ -44,7 +44,7 @@ Codiedev CLI
44
44
 
45
45
  Connect:
46
46
  codiedev connect Link Claude Code / Codex / Cursor /
47
- GitHub Copilot to your org
47
+ GitHub Copilot / pi to your org
48
48
  codiedev doctor Verify your setup after connecting
49
49
 
50
50
  Harness:
@@ -85,7 +85,7 @@ Messaging:
85
85
 
86
86
  Starter packs:
87
87
  codiedev pack list Packs assigned to your team
88
- codiedev pack install [slug] [--harness claude,codex,copilot,cursor,codie]
88
+ codiedev pack install [slug] [--harness claude,codex,copilot,cursor,codie,pi]
89
89
  [--dry-run] [--json]
90
90
  Install a pack (or all) into every
91
91
  detected tool
@@ -164,6 +164,8 @@ codiedev connect — link your agent CLI to Codiedev
164
164
  - ~/.cursor/hooks.json hooks (session, prompt, security, capture)
165
165
  - ~/.cursor/rules/codiedev.mdc (teaches Cursor the commands)
166
166
  - ~/.copilot/hooks/codiedev.json (GitHub Copilot: VS Code + CLI capture)
167
+ - ~/.pi/agent/extensions/codiedev.ts (pi: session, prompt, security, capture)
168
+ - ~/.pi/agent/AGENTS.md (teaches pi the commands)
167
169
 
168
170
  Re-run anytime to swap accounts or refresh the instruction block.
169
171
 
package/dist/codie.js CHANGED
@@ -58,6 +58,7 @@ const codieRuntimeInstall_1 = require("./codieRuntimeInstall");
58
58
  const upgradeNudge_1 = require("./upgradeNudge");
59
59
  const codie_1 = require("./packs/codie");
60
60
  const paths_1 = require("./packs/paths");
61
+ const managedPi_1 = require("./managedPi");
61
62
  // How long to let the gateway finish booking the last request before asking
62
63
  // what the session cost.
63
64
  const USAGE_SETTLE_MS = 1200;
@@ -187,6 +188,30 @@ async function main() {
187
188
  }
188
189
  const gatewayUrl = process.env.CODIEDEV_GATEWAY_URL || "https://gateway.codiedev.com/api/v1";
189
190
  const catalog = await (0, codieLauncher_1.fetchApprovedCatalog)({ baseUrl: gatewayUrl, key });
191
+ // `codie --pi [args]`: pi instead of the OpenCode engine, on the same
192
+ // approved catalog and gateway key (see managedPi.ts).
193
+ if (process.argv[2] === "--pi") {
194
+ let skillPaths = [];
195
+ try {
196
+ const approved = new Set(catalog.map((model) => (0, codieLauncher_1.bareModel)(model.id)).filter(Boolean));
197
+ skillPaths = (0, codie_1.codiePackConfig)((0, paths_1.packsRoot)(), { approvedModels: approved, catalog }).skillPaths;
198
+ }
199
+ catch (error) {
200
+ console.error(`codie: skipping starter packs (${error instanceof Error ? error.message : error})`);
201
+ }
202
+ try {
203
+ process.exitCode = (0, managedPi_1.runManagedPi)({
204
+ args: process.argv.slice(3), key, gatewayUrl, catalog, stateDir: (0, configDir_1.codiedevStateDir)(), skillPaths,
205
+ // This release line has no Agent Security hooks.
206
+ agentSecurityEnabled: false,
207
+ });
208
+ }
209
+ catch (error) {
210
+ console.error(`codie: ${error instanceof Error ? error.message : String(error)}`);
211
+ process.exitCode = error instanceof managedPi_1.ManagedPiArgError ? 2 : 1;
212
+ }
213
+ return;
214
+ }
190
215
  const parsed = (0, codieLauncher_1.parseCodieArgs)(process.argv.slice(2));
191
216
  if (parsed.args.length === 1 && parsed.args[0] === "models") {
192
217
  console.log("Codiedev approved models\n");
@@ -47,6 +47,7 @@ const upgradeNudge_1 = require("../upgradeNudge");
47
47
  const captureReadiness_1 = require("../captureReadiness");
48
48
  const captureLog_1 = require("../captureLog");
49
49
  const copilotInstallation_1 = require("../copilotInstallation");
50
+ const piHooks_1 = require("../piHooks");
50
51
  const harnessDirs_1 = require("../harnessDirs");
51
52
  const CLAUDE_DIR = (0, harnessDirs_1.claudeConfigDir)();
52
53
  const CLAUDE_SETTINGS_PATH = path.join(CLAUDE_DIR, "settings.json");
@@ -496,6 +497,16 @@ async function runDoctor(_args) {
496
497
  else {
497
498
  checks.push({ name: "GitHub Copilot", status: "warn", detail: "not installed on this machine" });
498
499
  }
500
+ if ((0, utils_1.piInstalled)()) {
501
+ const extension = (0, piHooks_1.inspectPiExtension)();
502
+ checks.push({ name: "pi capture extension", status: extension.status === "pass" ? "pass" : "fail", detail: extension.detail });
503
+ checks.push({ name: "pi agent instructions",
504
+ status: hasCodiedevInstructions((0, utils_1.piInstructionsPath)()) ? "pass" : "fail",
505
+ detail: hasCodiedevInstructions((0, utils_1.piInstructionsPath)()) ? (0, harnessDirs_1.displayPath)((0, utils_1.piInstructionsPath)()) : "missing — re-run `codiedev connect`" });
506
+ }
507
+ else {
508
+ checks.push({ name: "pi", status: "warn", detail: "not installed on this machine" });
509
+ }
499
510
  report(checks);
500
511
  const failures = checks.filter((c) => c.status === "fail");
501
512
  if (failures.length > 0) {
@@ -51,4 +51,4 @@ export declare function runExport(config: CodiedevConfig, args: PackArgs): Promi
51
51
  commit?: string;
52
52
  }>;
53
53
  export declare function runApply(config: CodiedevConfig, args: PackArgs): Promise<Record<string, unknown>>;
54
- export declare const PACK_HELP = "Usage:\n codiedev pack list Packs assigned to your team\n codiedev pack install [slug] [--harness claude,codex,copilot,cursor,codie] [--dry-run] [--json] [--quiet]\n Install one pack, or every pack that applies\n codiedev pack status [--json] Installed packs and whether they're up to date\n codiedev pack export <slug> --out <dir> [--git] [--manifest]\n Write the pack as a Claude-format plugin folder plus\n .claude-plugin/marketplace.json (commit it for CI).\n --git inits the folder and commits; --manifest writes\n an editable <slug>.pack.md instead\n codiedev pack apply <pack.md> Create or update a pack from a pack.md\n\nCursor: packs are copied to ~/.cursor/plugins/local/codiedev-<slug>/. A Cursor\nteam admin can disable \"user local plugin imports\"; then Cursor ignores them.\n\nAuto-update: session starts run `codiedev pack install --quiet` in the background\nabout once an hour. Opt out with CODIEDEV_PACK_AUTOSYNC=0.\n\nHooks for specific skills only: codiedev hook-gate --skills a,b --cmd-b64 <base64url of the command>\n(the pack editor writes this; the command runs via /bin/sh, or cmd.exe on Windows)\n\nCI: set CODIEDEV_TOKEN to a pack CI key (cdvci_\u2026, from the pack's page in the portal).\nNo `codiedev connect` or config file is needed. CI mode (a cdvci_ key, or CI=true)\nnever auto-syncs, reports or prunes, installs the one pack the key can see, defaults\n--harness to claude when it's on PATH, and exits non-zero unless every requested tool\ngot the pack. Skills from a pack are /<pack-slug>:<skill> in Claude Code.\n\n GitLab CI (.gitlab-ci.yml; add CODIEDEV_TOKEN and ANTHROPIC_API_KEY as masked\n CI/CD variables):\n pack-scan:\n image: node:22\n script:\n - npm i -g codiedev @anthropic-ai/claude-code\n - codiedev pack install --harness claude\n - claude -p \"/platform-starter:healthcare-scan\" --output-format text\n\n GitHub Actions (repository secrets CODIEDEV_TOKEN and ANTHROPIC_API_KEY):\n - uses: actions/setup-node@v4\n with: { node-version: 22 }\n - run: npm i -g codiedev @anthropic-ai/claude-code\n - run: codiedev pack install --harness claude\n env:\n CODIEDEV_TOKEN: ${{ secrets.CODIEDEV_TOKEN }}\n - run: claude -p \"/platform-starter:healthcare-scan\" --output-format text\n env:\n ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}\n\n Or vendor the plugin into the repo instead of installing at build time:\n codiedev pack export <slug> --out .codiedev/packs";
54
+ export declare const PACK_HELP = "Usage:\n codiedev pack list Packs assigned to your team\n codiedev pack install [slug] [--harness claude,codex,copilot,cursor,codie,pi] [--dry-run] [--json] [--quiet]\n Install one pack, or every pack that applies\n codiedev pack status [--json] Installed packs and whether they're up to date\n codiedev pack export <slug> --out <dir> [--git] [--manifest]\n Write the pack as a Claude-format plugin folder plus\n .claude-plugin/marketplace.json (commit it for CI).\n --git inits the folder and commits; --manifest writes\n an editable <slug>.pack.md instead\n codiedev pack apply <pack.md> Create or update a pack from a pack.md\n\nCursor: packs are copied to ~/.cursor/plugins/local/codiedev-<slug>/. A Cursor\nteam admin can disable \"user local plugin imports\"; then Cursor ignores them.\n\nAuto-update: session starts run `codiedev pack install --quiet` in the background\nabout once an hour. Opt out with CODIEDEV_PACK_AUTOSYNC=0.\n\nHooks for specific skills only: codiedev hook-gate --skills a,b --cmd-b64 <base64url of the command>\n(the pack editor writes this; the command runs via /bin/sh, or cmd.exe on Windows)\n\nCI: set CODIEDEV_TOKEN to a pack CI key (cdvci_\u2026, from the pack's page in the portal).\nNo `codiedev connect` or config file is needed. CI mode (a cdvci_ key, or CI=true)\nnever auto-syncs, reports or prunes, installs the one pack the key can see, defaults\n--harness to claude when it's on PATH, and exits non-zero unless every requested tool\ngot the pack. Skills from a pack are /<pack-slug>:<skill> in Claude Code.\n\n GitLab CI (.gitlab-ci.yml; add CODIEDEV_TOKEN and ANTHROPIC_API_KEY as masked\n CI/CD variables):\n pack-scan:\n image: node:22\n script:\n - npm i -g codiedev @anthropic-ai/claude-code\n - codiedev pack install --harness claude\n - claude -p \"/platform-starter:healthcare-scan\" --output-format text\n\n GitHub Actions (repository secrets CODIEDEV_TOKEN and ANTHROPIC_API_KEY):\n - uses: actions/setup-node@v4\n with: { node-version: 22 }\n - run: npm i -g codiedev @anthropic-ai/claude-code\n - run: codiedev pack install --harness claude\n env:\n CODIEDEV_TOKEN: ${{ secrets.CODIEDEV_TOKEN }}\n - run: claude -p \"/platform-starter:healthcare-scan\" --output-format text\n env:\n ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}\n\n Or vendor the plugin into the repo instead of installing at build time:\n codiedev pack export <slug> --out .codiedev/packs";
@@ -93,7 +93,7 @@ function ciHarnesses(args, env, home) {
93
93
  }
94
94
  const USAGE = `Usage:
95
95
  codiedev pack list Packs assigned to your team
96
- codiedev pack install [slug] [--harness claude,codex,copilot,cursor,codie] [--dry-run] [--json] [--quiet]
96
+ codiedev pack install [slug] [--harness claude,codex,copilot,cursor,codie,pi] [--dry-run] [--json] [--quiet]
97
97
  Install one pack, or every pack that applies
98
98
  codiedev pack status [--json] Installed packs and whether they're up to date
99
99
  codiedev pack export <slug> --out <dir> [--git] [--manifest]
package/dist/connect.js CHANGED
@@ -274,11 +274,13 @@ async function runConnect(args = []) {
274
274
  const hasCursor = (0, utils_1.cursorInstalled)();
275
275
  const hasOpenCode = (0, utils_1.openCodeInstalled)();
276
276
  const hasCopilot = (0, utils_1.copilotInstalled)();
277
+ const hasPi = (0, utils_1.piInstalled)();
277
278
  (0, shared_1.recordInstallEvent)(config, { step: "detect", target: "claude-code", ok: hasClaude });
278
279
  (0, shared_1.recordInstallEvent)(config, { step: "detect", target: "codex", ok: hasCodex });
279
280
  (0, shared_1.recordInstallEvent)(config, { step: "detect", target: "cursor", ok: hasCursor });
280
281
  (0, shared_1.recordInstallEvent)(config, { step: "detect", target: "opencode", ok: hasOpenCode });
281
282
  (0, shared_1.recordInstallEvent)(config, { step: "detect", target: "copilot", ok: hasCopilot });
283
+ (0, shared_1.recordInstallEvent)(config, { step: "detect", target: "pi", ok: hasPi });
282
284
  const installed = [];
283
285
  // Machine-readable target keys reported back to the backend via
284
286
  // /api/cli/markInstalled so the portal's "Connected" state reflects
@@ -323,6 +325,12 @@ async function runConnect(args = []) {
323
325
  runInstall("copilot-hook", () => (0, utils_1.installCopilotHook)(), `GitHub Copilot (VS Code + CLI) sessionStart + agentStop backup + sessionEnd capture hooks (${(0, utils_1.copilotHooksPath)()})`, "copilot-hook");
324
326
  runInstall("copilot-instructions", utils_1.installCopilotInstructions, "GitHub Copilot CLI team artifact instructions", "copilot-instructions");
325
327
  }
328
+ // Staged like OpenCode's adapter: dormant until pi starts, so installing pi
329
+ // later needs no second `connect`.
330
+ runInstall("pi-extension", () => (0, utils_1.installPiExtension)(), `pi session start + prompt guard + capture extension (${(0, harnessDirs_1.displayPath)((0, utils_1.piExtensionPath)())})`, "pi-extension");
331
+ if (hasPi) {
332
+ runInstall("pi-instructions", utils_1.installPiInstructions, `pi agent instructions (${(0, harnessDirs_1.displayPath)((0, utils_1.piInstructionsPath)())})`, "pi-instructions");
333
+ }
326
334
  // Always stage the adapter. It is dormant until OpenCode starts, which lets
327
335
  // a user connect Claude Code today and install the Codie harness tomorrow
328
336
  // without needing a second setup ritual.
@@ -349,7 +357,7 @@ async function runConnect(args = []) {
349
357
  });
350
358
  }
351
359
  }
352
- if (!hasClaude && !hasCodex && !hasCursor && !hasOpenCode && !hasCopilot) {
360
+ if (!hasClaude && !hasCodex && !hasCursor && !hasOpenCode && !hasCopilot && !hasPi) {
353
361
  console.warn("\nNo existing AI client detected; the Codie/OpenCode adapter is ready for a later install.");
354
362
  console.warn("If you just installed Claude Code, launch it once (so ~/.claude is created),");
355
363
  console.warn("then re-run `npx codiedev connect` to wire up the capture hook.");
@@ -6,6 +6,9 @@ export declare function claudeUserConfigPath(env?: NodeJS.ProcessEnv, home?: str
6
6
  export declare function codexHome(env?: NodeJS.ProcessEnv, home?: string): string;
7
7
  /** OpenCode: `$XDG_CONFIG_HOME/opencode` or ~/.config/opencode. */
8
8
  export declare function openCodeConfigDir(env?: NodeJS.ProcessEnv, home?: string): string;
9
+ /** pi: `$PI_CODING_AGENT_DIR` or ~/.pi/agent. Holds extensions/, skills/,
10
+ * sessions/ and the global AGENTS.md. */
11
+ export declare function piAgentDir(env?: NodeJS.ProcessEnv, home?: string): string;
9
12
  /** `~`-abbreviated path for user-facing output. */
10
13
  export declare function displayPath(p: string, home?: string): string;
11
14
  export declare function claudeConfigDirInUse(dir?: string, exists?: (p: string) => boolean): boolean;
@@ -37,6 +37,7 @@ exports.claudeConfigDir = claudeConfigDir;
37
37
  exports.claudeUserConfigPath = claudeUserConfigPath;
38
38
  exports.codexHome = codexHome;
39
39
  exports.openCodeConfigDir = openCodeConfigDir;
40
+ exports.piAgentDir = piAgentDir;
40
41
  exports.displayPath = displayPath;
41
42
  exports.claudeConfigDirInUse = claudeConfigDirInUse;
42
43
  exports.codexHomeInUse = codexHomeInUse;
@@ -72,6 +73,11 @@ function codexHome(env = process.env, home = os.homedir()) {
72
73
  function openCodeConfigDir(env = process.env, home = os.homedir()) {
73
74
  return path.join(override(env.XDG_CONFIG_HOME) ?? path.join(home, ".config"), "opencode");
74
75
  }
76
+ /** pi: `$PI_CODING_AGENT_DIR` or ~/.pi/agent. Holds extensions/, skills/,
77
+ * sessions/ and the global AGENTS.md. */
78
+ function piAgentDir(env = process.env, home = os.homedir()) {
79
+ return override(env.PI_CODING_AGENT_DIR) ?? path.join(home, ".pi", "agent");
80
+ }
75
81
  /** `~`-abbreviated path for user-facing output. */
76
82
  function displayPath(p, home = os.homedir()) {
77
83
  return p === home || p.startsWith(home + path.sep) ? "~" + p.slice(home.length) : p;
package/dist/hook.js CHANGED
@@ -59,6 +59,7 @@ const subagents_1 = require("./subagents");
59
59
  const captureExclusions_1 = require("./captureExclusions");
60
60
  const cursorHooks_1 = require("./cursorHooks");
61
61
  const copilotHooks_1 = require("./copilotHooks");
62
+ const piHooks_1 = require("./piHooks");
62
63
  // Pure builder for the discovery additionalContext. Returns null when there are
63
64
  // no matches. The suggested `codiedev pull` command carries the EXACT top key
64
65
  // (e.g. "pr-push.md") rather than a "<key>" placeholder — otherwise agents
@@ -432,6 +433,8 @@ function resolveMode(arg) {
432
433
  return "copilot";
433
434
  if (arg === "capture-opencode" || arg === "capture-opencode-final")
434
435
  return "opencode";
436
+ if (arg === "capture-pi" || arg === "capture-pi-final")
437
+ return "pi";
435
438
  if (arg === "capture-desktop" || arg === "capture-desktop-final")
436
439
  return "desktop";
437
440
  return "claude-code";
@@ -546,6 +549,7 @@ async function main() {
546
549
  // which is what makes a pnpm install safe to upgrade.
547
550
  if (migrated.length === 0)
548
551
  (0, selfUpdate_1.maybeSpawnSelfUpdate)(process.argv[1]);
552
+ (0, selfUpdate_1.maybeRefreshInstructions)();
549
553
  let hookInput = {};
550
554
  try {
551
555
  const raw = await readStdin();
@@ -593,7 +597,8 @@ async function main() {
593
597
  if (process.argv[2] === "discover" ||
594
598
  process.argv[2] === "discover-codex" ||
595
599
  process.argv[2] === "discover-codie" ||
596
- process.argv[2] === "discover-copilot") {
600
+ process.argv[2] === "discover-copilot" ||
601
+ process.argv[2] === "discover-pi") {
597
602
  // A Codex block leaves no hook of its own, so this prompt is the first
598
603
  // chance to report it. Runs before runDiscover, which exits the process.
599
604
  if (process.argv[2] === "discover-codex") {
@@ -619,10 +624,11 @@ async function main() {
619
624
  if (process.argv[2] === "session-start" ||
620
625
  process.argv[2] === "session-start-cursor" ||
621
626
  process.argv[2] === "session-start-copilot" ||
622
- process.argv[2] === "session-start-opencode") {
627
+ process.argv[2] === "session-start-opencode" ||
628
+ process.argv[2] === "session-start-pi") {
623
629
  // --- starter packs: hourly detached `pack install --quiet` + daily nudge ---
624
630
  (0, sync_1.maybeSpawnPackSync)({ connected: Boolean((0, utils_1.readConfig)()), cli: path.join(__dirname, "cli.js") });
625
- const packNag = process.argv[2] === "session-start-opencode" ? null : (0, sync_1.packNagLine)();
631
+ const packNag = process.argv[2] === "session-start-opencode" || process.argv[2] === "session-start-pi" ? null : (0, sync_1.packNagLine)();
626
632
  // Claude Code adds SessionStart stdout to the session context.
627
633
  if (packNag && process.argv[2] === "session-start")
628
634
  process.stdout.write(`${packNag}\n`);
@@ -633,7 +639,9 @@ async function main() {
633
639
  ? "cursor"
634
640
  : process.argv[2] === "session-start-copilot"
635
641
  ? "copilot"
636
- : "claude-code");
642
+ : process.argv[2] === "session-start-pi"
643
+ ? "pi"
644
+ : "claude-code");
637
645
  if ((0, utils_1.readConfig)() && (process.argv[2] === "session-start-cursor" || process.argv[2] === "session-start-copilot")) {
638
646
  const source = process.argv[2] === "session-start-cursor" ? "cursor" : "copilot";
639
647
  const { TEAM_SKILL_CONTEXT, teamSkillSessionOutput } = await Promise.resolve().then(() => __importStar(require("./teamSkillContext")));
@@ -655,6 +663,9 @@ async function main() {
655
663
  else if ((process.argv[2] ?? "").endsWith("-copilot")) {
656
664
  (0, utils_1.ensureCopilotCodiedevHooksInstalled)();
657
665
  }
666
+ else if (/-pi(?:-final)?$/.test(process.argv[2] ?? "")) {
667
+ (0, utils_1.ensurePiExtensionInstalled)();
668
+ }
658
669
  else {
659
670
  (0, utils_1.ensureAllCodiedevHooksInstalled)();
660
671
  }
@@ -679,7 +690,7 @@ async function main() {
679
690
  // extension) where SessionEnd may never come — the silent zero-capture bug.
680
691
  // Same detached capture-finish child as SessionEnd, marked non-final so the
681
692
  // server renews the session lease instead of summarizing immediately.
682
- if (process.argv[2] === "backup" || process.argv[2] === "backup-cursor" || process.argv[2] === "backup-copilot") {
693
+ if (process.argv[2] === "backup" || process.argv[2] === "backup-cursor" || process.argv[2] === "backup-copilot" || process.argv[2] === "backup-pi") {
683
694
  if (transcript_path && !(0, utils_1.isCodexRolloutPath)(transcript_path)) {
684
695
  try {
685
696
  (0, utils_1.dispatchCaptureFinish)({
@@ -687,7 +698,9 @@ async function main() {
687
698
  ? "capture-cursor"
688
699
  : process.argv[2] === "backup-copilot"
689
700
  ? "capture-copilot"
690
- : "capture",
701
+ : process.argv[2] === "backup-pi"
702
+ ? "capture-pi"
703
+ : "capture",
691
704
  session_id,
692
705
  transcript_path,
693
706
  cwd,
@@ -864,7 +877,10 @@ async function runCaptureFinishInner(input, config, session_id, transcript_path,
864
877
  transcriptContent = normalized.content;
865
878
  copilotSubagents = normalized.subagents.count > 0 ? normalized.subagents : undefined;
866
879
  }
867
- if (mode === "cursor" || mode === "copilot") {
880
+ else if (parserMode === "pi") {
881
+ transcriptContent = (0, piHooks_1.normalizePiTranscript)(transcriptContent);
882
+ }
883
+ if (mode === "cursor" || mode === "copilot" || mode === "pi") {
868
884
  try {
869
885
  await (0, limitEventReporter_1.reportTranscriptLimitEvent)({ config, source: mode, sessionId: session_id, transcript: transcriptContent });
870
886
  }
@@ -905,7 +921,9 @@ async function runCaptureFinishInner(input, config, session_id, transcript_path,
905
921
  ? "empty-cursor-transcript"
906
922
  : parserMode === "copilot" && (0, copilotHooks_1.isCopilotTranscriptEmpty)(rawTranscriptContent)
907
923
  ? "empty-copilot-transcript"
908
- : null;
924
+ : parserMode === "pi" && (0, piHooks_1.isPiTranscriptEmpty)(rawTranscriptContent)
925
+ ? "empty-pi-transcript"
926
+ : null;
909
927
  if (emptyReason) {
910
928
  (0, captureLog_1.appendCaptureLog)({
911
929
  stage: "capture-finish",
@@ -1,5 +1,5 @@
1
1
  import { type LimitEvent } from "./limitEvent";
2
- export type LimitEventSource = "claude-code" | "codex" | "cursor" | "copilot";
2
+ export type LimitEventSource = "claude-code" | "codex" | "cursor" | "copilot" | "pi";
3
3
  export type LimitEventPayload = LimitEvent & {
4
4
  source: LimitEventSource;
5
5
  sessionId?: string;
@@ -76,7 +76,7 @@ function postLimitEvent(config, payload, timeoutMs = 5_000) {
76
76
  async function reportTranscriptLimitEvent(args) {
77
77
  const parse = args.source === "codex"
78
78
  ? limitEvent_1.parseCodexLimitEventFromTranscript
79
- : args.source === "cursor" || args.source === "copilot" ? limitEvent_1.parseNativeLimitEventFromTranscript : limitEvent_1.parseLimitEventFromTranscript;
79
+ : args.source === "cursor" || args.source === "copilot" || args.source === "pi" ? limitEvent_1.parseNativeLimitEventFromTranscript : limitEvent_1.parseLimitEventFromTranscript;
80
80
  const parsed = parse(args.transcript);
81
81
  if (!parsed && !args.emitMinimalOnMiss)
82
82
  return false;
@@ -0,0 +1,47 @@
1
+ import { type CatalogModel } from "./codieLauncher";
2
+ export declare const PI_PROVIDER_ID = "codiedev";
3
+ /** Env vars pi reads provider credentials from (`pi --help`, pi 0.73). */
4
+ export declare const PI_PROVIDER_ENV: string[];
5
+ export declare const GUARD_FILE = "codie-guard.ts";
6
+ export declare const CAPTURE_FILE = "codiedev-capture.ts";
7
+ /** Where the guard points every other provider: a loopback port nothing
8
+ * listens on, so a request (and whatever key it carries) never leaves the
9
+ * machine. */
10
+ export declare const BLOCKED_BASE_URL = "http://127.0.0.1:9/blocked-by-codiedev";
11
+ /** The pi extension that keeps a managed session on Codiedev models and tags
12
+ * each gateway request with the session, repo and skills, so gateway billing
13
+ * joins the captured pi session (same headers as the OpenCode metadata
14
+ * plugin, assets/git-refs.mjs). */
15
+ export declare const GUARD_SOURCE: string;
16
+ export declare function managedPiAgentDir(stateDir: string): string;
17
+ /** pi's models.json entry for the gateway. The key is read from
18
+ * CODIEDEV_GATEWAY_KEY at request time (pi resolves an env var name). */
19
+ export declare function piProviderConfig(gatewayUrl: string, catalog: CatalogModel[]): Record<string, unknown>;
20
+ /** Rewrite everything Codiedev owns in the managed agent dir. Sessions (and
21
+ * anything else pi keeps there) are left alone. Returns the extensions to load. */
22
+ export declare function prepareManagedPiDir(opts: {
23
+ agentDir: string;
24
+ gatewayUrl: string;
25
+ catalog: CatalogModel[];
26
+ model?: string;
27
+ skillPaths?: string[];
28
+ agentSecurityEnabled: boolean;
29
+ }): string[];
30
+ /** The child env: no provider credentials, pi pointed at the managed dir. */
31
+ export declare function managedPiEnv(env: NodeJS.ProcessEnv, agentDir: string, key: string, platform?: NodeJS.Platform): NodeJS.ProcessEnv;
32
+ export declare class ManagedPiArgError extends Error {
33
+ }
34
+ /** Refuse what would bring other credentials or code into the session, then
35
+ * pin extension loading to the managed extensions. */
36
+ export declare function managedPiArgs(args: string[], extensions: string[]): string[];
37
+ export declare function runManagedPi(opts: {
38
+ args: string[];
39
+ key: string;
40
+ gatewayUrl: string;
41
+ catalog: CatalogModel[];
42
+ stateDir: string;
43
+ skillPaths?: string[];
44
+ agentSecurityEnabled: boolean;
45
+ env?: NodeJS.ProcessEnv;
46
+ bin?: string;
47
+ }): number;