codiedev 0.9.70 → 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";
@@ -594,7 +597,8 @@ async function main() {
594
597
  if (process.argv[2] === "discover" ||
595
598
  process.argv[2] === "discover-codex" ||
596
599
  process.argv[2] === "discover-codie" ||
597
- process.argv[2] === "discover-copilot") {
600
+ process.argv[2] === "discover-copilot" ||
601
+ process.argv[2] === "discover-pi") {
598
602
  // A Codex block leaves no hook of its own, so this prompt is the first
599
603
  // chance to report it. Runs before runDiscover, which exits the process.
600
604
  if (process.argv[2] === "discover-codex") {
@@ -620,10 +624,11 @@ async function main() {
620
624
  if (process.argv[2] === "session-start" ||
621
625
  process.argv[2] === "session-start-cursor" ||
622
626
  process.argv[2] === "session-start-copilot" ||
623
- process.argv[2] === "session-start-opencode") {
627
+ process.argv[2] === "session-start-opencode" ||
628
+ process.argv[2] === "session-start-pi") {
624
629
  // --- starter packs: hourly detached `pack install --quiet` + daily nudge ---
625
630
  (0, sync_1.maybeSpawnPackSync)({ connected: Boolean((0, utils_1.readConfig)()), cli: path.join(__dirname, "cli.js") });
626
- 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)();
627
632
  // Claude Code adds SessionStart stdout to the session context.
628
633
  if (packNag && process.argv[2] === "session-start")
629
634
  process.stdout.write(`${packNag}\n`);
@@ -634,7 +639,9 @@ async function main() {
634
639
  ? "cursor"
635
640
  : process.argv[2] === "session-start-copilot"
636
641
  ? "copilot"
637
- : "claude-code");
642
+ : process.argv[2] === "session-start-pi"
643
+ ? "pi"
644
+ : "claude-code");
638
645
  if ((0, utils_1.readConfig)() && (process.argv[2] === "session-start-cursor" || process.argv[2] === "session-start-copilot")) {
639
646
  const source = process.argv[2] === "session-start-cursor" ? "cursor" : "copilot";
640
647
  const { TEAM_SKILL_CONTEXT, teamSkillSessionOutput } = await Promise.resolve().then(() => __importStar(require("./teamSkillContext")));
@@ -656,6 +663,9 @@ async function main() {
656
663
  else if ((process.argv[2] ?? "").endsWith("-copilot")) {
657
664
  (0, utils_1.ensureCopilotCodiedevHooksInstalled)();
658
665
  }
666
+ else if (/-pi(?:-final)?$/.test(process.argv[2] ?? "")) {
667
+ (0, utils_1.ensurePiExtensionInstalled)();
668
+ }
659
669
  else {
660
670
  (0, utils_1.ensureAllCodiedevHooksInstalled)();
661
671
  }
@@ -680,7 +690,7 @@ async function main() {
680
690
  // extension) where SessionEnd may never come — the silent zero-capture bug.
681
691
  // Same detached capture-finish child as SessionEnd, marked non-final so the
682
692
  // server renews the session lease instead of summarizing immediately.
683
- 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") {
684
694
  if (transcript_path && !(0, utils_1.isCodexRolloutPath)(transcript_path)) {
685
695
  try {
686
696
  (0, utils_1.dispatchCaptureFinish)({
@@ -688,7 +698,9 @@ async function main() {
688
698
  ? "capture-cursor"
689
699
  : process.argv[2] === "backup-copilot"
690
700
  ? "capture-copilot"
691
- : "capture",
701
+ : process.argv[2] === "backup-pi"
702
+ ? "capture-pi"
703
+ : "capture",
692
704
  session_id,
693
705
  transcript_path,
694
706
  cwd,
@@ -865,7 +877,10 @@ async function runCaptureFinishInner(input, config, session_id, transcript_path,
865
877
  transcriptContent = normalized.content;
866
878
  copilotSubagents = normalized.subagents.count > 0 ? normalized.subagents : undefined;
867
879
  }
868
- 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") {
869
884
  try {
870
885
  await (0, limitEventReporter_1.reportTranscriptLimitEvent)({ config, source: mode, sessionId: session_id, transcript: transcriptContent });
871
886
  }
@@ -906,7 +921,9 @@ async function runCaptureFinishInner(input, config, session_id, transcript_path,
906
921
  ? "empty-cursor-transcript"
907
922
  : parserMode === "copilot" && (0, copilotHooks_1.isCopilotTranscriptEmpty)(rawTranscriptContent)
908
923
  ? "empty-copilot-transcript"
909
- : null;
924
+ : parserMode === "pi" && (0, piHooks_1.isPiTranscriptEmpty)(rawTranscriptContent)
925
+ ? "empty-pi-transcript"
926
+ : null;
910
927
  if (emptyReason) {
911
928
  (0, captureLog_1.appendCaptureLog)({
912
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;