agent-insights 0.0.13 → 0.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- type AgentName = "claude-code" | "cursor" | "opencode" | "codex" | "unknown";
1
+ type AgentName = "claude-code" | "cursor" | "opencode" | "codex" | "pi" | "unknown";
2
2
  type AgentEventType = "session.start" | "session.end" | "user.prompt.submit" | "tool.start" | "tool.end" | "tool.failure" | "permission.request" | "permission.denied" | "subagent.start" | "subagent.end" | "agent.stop" | "notification" | "context.compact.start" | "context.compact.end" | "error";
3
3
  type AgentOutcome = "success" | "error" | "cancelled" | "unknown";
4
4
  type AgentEvent = {
@@ -82,7 +82,7 @@ type AgentInsightsConfig = {
82
82
  exporter: ExporterConfig;
83
83
  transcriptStore: TranscriptStoreConfig;
84
84
  sessionAnalysis: SessionAnalysisConfig;
85
- agents: Record<"claudeCode" | "cursor", AgentConfig>;
85
+ agents: Record<"claudeCode" | "cursor" | "codex" | "pi", AgentConfig>;
86
86
  privacy: {
87
87
  capturePrompts: false;
88
88
  captureMessages: false;
@@ -94,7 +94,7 @@ declare function defaultConfig(): AgentInsightsConfig;
94
94
  declare function loadConfig(): Promise<AgentInsightsConfig | undefined>;
95
95
  declare function saveConfig(cfg: AgentInsightsConfig): Promise<void>;
96
96
 
97
- type AgentId = "claude-code" | "cursor";
97
+ type AgentId = "claude-code" | "cursor" | "codex" | "pi";
98
98
  type HookPayload = {
99
99
  /** Native event name as emitted by the agent (e.g. `SessionStart`). */
100
100
  event: string;
package/dist/index.js CHANGED
@@ -95,6 +95,33 @@ function sanitizeInner(value) {
95
95
  import { mkdir, readFile, writeFile } from "fs/promises";
96
96
  import { homedir } from "os";
97
97
  import { dirname, join } from "path";
98
+
99
+ // src/util/hook-command.ts
100
+ import { realpathSync } from "fs";
101
+ function resolve() {
102
+ const node = process.execPath;
103
+ let script = process.argv[1] ?? "";
104
+ try {
105
+ script = realpathSync(script);
106
+ } catch {
107
+ }
108
+ return { node, script };
109
+ }
110
+ function quote(s) {
111
+ if (s.length === 0) return "''";
112
+ if (!/[\s'"\\$`<>|&;()*?#~]/.test(s)) return s;
113
+ return `'${s.replace(/'/g, "'\\''")}'`;
114
+ }
115
+ function hookCommandString(event) {
116
+ const { node, script } = resolve();
117
+ return `${quote(node)} ${quote(script)} hook ${event}`;
118
+ }
119
+ function hookCommandArgv(event) {
120
+ const { node, script } = resolve();
121
+ return { node, script, args: ["hook", event] };
122
+ }
123
+
124
+ // src/adapters/claude-code.ts
98
125
  var HOOK_COMMAND_NAME = "agent-insights";
99
126
  var HOOK_MAP = {
100
127
  SessionStart: "session.start",
@@ -189,7 +216,8 @@ function resolveClaudePath(repoRoot, scope) {
189
216
  }
190
217
  function isAgentInsightsCommand(cmd) {
191
218
  if (!cmd) return false;
192
- return cmd.startsWith(`${HOOK_COMMAND_NAME} hook`);
219
+ if (cmd.startsWith(`${HOOK_COMMAND_NAME} hook`)) return true;
220
+ return /\bagent-insights\b.*\bcli\.js\b.*\bhook\b/.test(cmd);
193
221
  }
194
222
  function isHookCommand(value) {
195
223
  if (!value || typeof value !== "object") return false;
@@ -232,7 +260,7 @@ function removeAgentInsightsMatchers(matchers) {
232
260
  return result;
233
261
  }
234
262
  function addAgentInsightsHook(matchers, event) {
235
- const command = `${HOOK_COMMAND_NAME} hook ${event}`;
263
+ const command = hookCommandString(event);
236
264
  const entry = { type: "command", command };
237
265
  for (const group of matchers) {
238
266
  if (group.matcher === "") {
@@ -257,12 +285,163 @@ function asString(v) {
257
285
  return typeof v === "string" && v.length > 0 ? v : void 0;
258
286
  }
259
287
 
260
- // src/adapters/cursor.ts
288
+ // src/adapters/codex.ts
261
289
  import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
262
290
  import { homedir as homedir2 } from "os";
263
291
  import { dirname as dirname2, join as join2 } from "path";
264
292
  var HOOK_COMMAND_NAME2 = "agent-insights";
265
293
  var HOOK_MAP2 = {
294
+ SessionStart: "session.start",
295
+ UserPromptSubmit: "user.prompt.submit",
296
+ PreToolUse: "tool.start",
297
+ PostToolUse: "tool.end",
298
+ PermissionRequest: "permission.request",
299
+ Stop: "session.end"
300
+ };
301
+ var CODEX_HOOK_EVENTS = Object.keys(HOOK_MAP2);
302
+ var codexAdapter = {
303
+ id: "codex",
304
+ agent: "codex",
305
+ label: "Codex",
306
+ settingsFile: ".codex/hooks.json",
307
+ map(payload) {
308
+ const type = HOOK_MAP2[payload.event];
309
+ if (!type) return void 0;
310
+ const data = payload.data ?? {};
311
+ const sessionId = asString2(data["session_id"]) ?? asString2(data["sessionId"]);
312
+ const toolName = asString2(data["tool_name"]) ?? asString2(data["toolName"]) ?? asString2(data["tool"]?.["name"]);
313
+ const transcriptPath = asString2(data["transcript_path"]) ?? asString2(data["transcriptPath"]);
314
+ return {
315
+ type,
316
+ ...sessionId !== void 0 ? { sessionId } : {},
317
+ ...toolName !== void 0 ? { toolName } : {},
318
+ ...transcriptPath !== void 0 ? { transcriptPath } : {}
319
+ };
320
+ },
321
+ async install(repoRoot, scope = "global") {
322
+ const path = resolveCodexPath(repoRoot, scope);
323
+ const settings = await readJson2(path);
324
+ const next = { ...settings ?? {} };
325
+ const hooks = {};
326
+ for (const [event, raw] of Object.entries(next.hooks ?? {})) {
327
+ hooks[event] = normalizeEventHooks2(raw);
328
+ }
329
+ for (const event of CODEX_HOOK_EVENTS) {
330
+ const withoutInsights = removeAgentInsightsMatchers2(hooks[event] ?? []);
331
+ hooks[event] = addAgentInsightsHook2(withoutInsights, event);
332
+ }
333
+ next.hooks = hooks;
334
+ await mkdir2(dirname2(path), { recursive: true });
335
+ await writeFile2(path, `${JSON.stringify(next, null, 2)}
336
+ `, "utf8");
337
+ return { written: true, path };
338
+ },
339
+ async uninstall(repoRoot, scope = "global") {
340
+ const path = resolveCodexPath(repoRoot, scope);
341
+ const settings = await readJson2(path);
342
+ if (!settings?.hooks) return { removed: false, path };
343
+ const hooks = {};
344
+ let touched = false;
345
+ for (const [event, raw] of Object.entries(settings.hooks)) {
346
+ const before = normalizeEventHooks2(raw);
347
+ const after = removeAgentInsightsMatchers2(before);
348
+ if (after.length !== before.length || JSON.stringify(after) !== JSON.stringify(before)) {
349
+ touched = true;
350
+ }
351
+ if (after.length > 0) hooks[event] = after;
352
+ }
353
+ settings.hooks = hooks;
354
+ await writeFile2(path, `${JSON.stringify(settings, null, 2)}
355
+ `, "utf8");
356
+ return { removed: touched, path };
357
+ },
358
+ async isInstalled(repoRoot, scope = "global") {
359
+ const settings = await readJson2(
360
+ resolveCodexPath(repoRoot, scope)
361
+ );
362
+ if (!settings?.hooks) return false;
363
+ return Object.values(settings.hooks).some(
364
+ (raw) => normalizeEventHooks2(raw).some(
365
+ (group) => group.hooks.some((h) => isAgentInsightsCommand2(h.command))
366
+ )
367
+ );
368
+ }
369
+ };
370
+ function resolveCodexPath(repoRoot, scope) {
371
+ return scope === "global" ? join2(homedir2(), ".codex", "hooks.json") : join2(repoRoot, ".codex", "hooks.json");
372
+ }
373
+ function isAgentInsightsCommand2(cmd) {
374
+ if (!cmd) return false;
375
+ if (cmd.startsWith(`${HOOK_COMMAND_NAME2} hook`)) return true;
376
+ return /\bagent-insights\b.*\bcli\.js\b.*\bhook\b/.test(cmd);
377
+ }
378
+ function isHookCommand2(value) {
379
+ if (!value || typeof value !== "object") return false;
380
+ const entry = value;
381
+ return entry.type === "command" && typeof entry.command === "string";
382
+ }
383
+ function normalizeEventHooks2(raw) {
384
+ const groups = [];
385
+ for (const entry of raw) {
386
+ if (!entry || typeof entry !== "object") continue;
387
+ const record = entry;
388
+ if (Array.isArray(record.hooks)) {
389
+ const commands = record.hooks.filter(isHookCommand2);
390
+ if (commands.length === 0) continue;
391
+ groups.push({
392
+ matcher: typeof record.matcher === "string" ? record.matcher : "",
393
+ hooks: commands
394
+ });
395
+ continue;
396
+ }
397
+ if (isHookCommand2(record)) {
398
+ groups.push({ matcher: "", hooks: [record] });
399
+ }
400
+ }
401
+ return groups;
402
+ }
403
+ function removeAgentInsightsMatchers2(matchers) {
404
+ const result = [];
405
+ for (const group of matchers) {
406
+ const hooks = group.hooks.filter(
407
+ (h) => !isAgentInsightsCommand2(h.command)
408
+ );
409
+ if (hooks.length > 0) result.push({ ...group, hooks });
410
+ }
411
+ return result;
412
+ }
413
+ function addAgentInsightsHook2(matchers, event) {
414
+ const command = hookCommandString(event);
415
+ const entry = { type: "command", command };
416
+ for (const group of matchers) {
417
+ if (group.matcher === "") {
418
+ if (!group.hooks.some((h) => h.command === command)) {
419
+ group.hooks.push(entry);
420
+ }
421
+ return matchers;
422
+ }
423
+ }
424
+ return [...matchers, { matcher: "", hooks: [entry] }];
425
+ }
426
+ async function readJson2(path) {
427
+ try {
428
+ const raw = await readFile2(path, "utf8");
429
+ return JSON.parse(raw);
430
+ } catch (err) {
431
+ if (err.code === "ENOENT") return void 0;
432
+ throw err;
433
+ }
434
+ }
435
+ function asString2(v) {
436
+ return typeof v === "string" && v.length > 0 ? v : void 0;
437
+ }
438
+
439
+ // src/adapters/cursor.ts
440
+ import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
441
+ import { homedir as homedir3 } from "os";
442
+ import { dirname as dirname3, join as join3 } from "path";
443
+ var HOOK_COMMAND_NAME3 = "agent-insights";
444
+ var HOOK_MAP3 = {
266
445
  sessionStart: "session.start",
267
446
  sessionEnd: "session.end",
268
447
  beforeSubmitPrompt: "user.prompt.submit",
@@ -279,19 +458,19 @@ var HOOK_MAP2 = {
279
458
  afterFileEdit: "tool.end",
280
459
  workspaceOpen: "session.start"
281
460
  };
282
- var CURSOR_HOOK_EVENTS = Object.keys(HOOK_MAP2);
461
+ var CURSOR_HOOK_EVENTS = Object.keys(HOOK_MAP3);
283
462
  var cursorAdapter = {
284
463
  id: "cursor",
285
464
  agent: "cursor",
286
465
  label: "Cursor",
287
466
  settingsFile: ".cursor/hooks.json",
288
467
  map(payload) {
289
- const type = HOOK_MAP2[payload.event];
468
+ const type = HOOK_MAP3[payload.event];
290
469
  if (!type) return void 0;
291
470
  const data = payload.data ?? {};
292
- const sessionId = asString2(data["session_id"]) ?? asString2(data["sessionId"]) ?? asString2(data["conversation_id"]);
293
- const toolName = asString2(data["tool_name"]) ?? asString2(data["toolName"]);
294
- const transcriptPath = asString2(data["transcript_path"]) ?? asString2(data["transcriptPath"]) ?? asString2(process.env.CURSOR_TRANSCRIPT_PATH);
471
+ const sessionId = asString3(data["session_id"]) ?? asString3(data["sessionId"]) ?? asString3(data["conversation_id"]);
472
+ const toolName = asString3(data["tool_name"]) ?? asString3(data["toolName"]);
473
+ const transcriptPath = asString3(data["transcript_path"]) ?? asString3(data["transcriptPath"]) ?? asString3(process.env.CURSOR_TRANSCRIPT_PATH);
295
474
  return {
296
475
  type,
297
476
  ...sessionId !== void 0 ? { sessionId } : {},
@@ -301,7 +480,7 @@ var cursorAdapter = {
301
480
  },
302
481
  async install(repoRoot, scope = "global") {
303
482
  const path = resolveCursorPath(repoRoot, scope);
304
- const settings = await readJson2(path);
483
+ const settings = await readJson3(path);
305
484
  const next = {
306
485
  version: 1,
307
486
  ...settings ?? {}
@@ -309,26 +488,26 @@ var cursorAdapter = {
309
488
  const hooks = { ...next.hooks ?? {} };
310
489
  for (const event of CURSOR_HOOK_EVENTS) {
311
490
  const existing = (hooks[event] ?? []).filter(
312
- (h) => !isAgentInsightsCommand2(h.command)
491
+ (h) => !isAgentInsightsCommand3(h.command)
313
492
  );
314
- existing.push({ command: `${HOOK_COMMAND_NAME2} hook ${event}` });
493
+ existing.push({ command: hookCommandString(event) });
315
494
  hooks[event] = existing;
316
495
  }
317
496
  next.hooks = hooks;
318
- await mkdir2(dirname2(path), { recursive: true });
319
- await writeFile2(path, `${JSON.stringify(next, null, 2)}
497
+ await mkdir3(dirname3(path), { recursive: true });
498
+ await writeFile3(path, `${JSON.stringify(next, null, 2)}
320
499
  `, "utf8");
321
500
  return { written: true, path };
322
501
  },
323
502
  async uninstall(repoRoot, scope = "global") {
324
503
  const path = resolveCursorPath(repoRoot, scope);
325
- const settings = await readJson2(path);
504
+ const settings = await readJson3(path);
326
505
  if (!settings?.hooks) return { removed: false, path };
327
506
  const hooks = { ...settings.hooks };
328
507
  let touched = false;
329
508
  for (const [event, entries] of Object.entries(hooks)) {
330
509
  const filtered = entries.filter(
331
- (h) => !isAgentInsightsCommand2(h.command)
510
+ (h) => !isAgentInsightsCommand3(h.command)
332
511
  );
333
512
  if (filtered.length !== entries.length) touched = true;
334
513
  if (filtered.length === 0) {
@@ -338,44 +517,164 @@ var cursorAdapter = {
338
517
  }
339
518
  }
340
519
  settings.hooks = hooks;
341
- await writeFile2(path, `${JSON.stringify(settings, null, 2)}
520
+ await writeFile3(path, `${JSON.stringify(settings, null, 2)}
342
521
  `, "utf8");
343
522
  return { removed: touched, path };
344
523
  },
345
524
  async isInstalled(repoRoot, scope = "global") {
346
- const settings = await readJson2(
525
+ const settings = await readJson3(
347
526
  resolveCursorPath(repoRoot, scope)
348
527
  );
349
528
  if (!settings?.hooks) return false;
350
529
  return Object.values(settings.hooks).some(
351
- (entries) => entries.some((h) => isAgentInsightsCommand2(h.command))
530
+ (entries) => entries.some((h) => isAgentInsightsCommand3(h.command))
352
531
  );
353
532
  }
354
533
  };
355
534
  function resolveCursorPath(repoRoot, scope) {
356
- return scope === "global" ? join2(homedir2(), ".cursor", "hooks.json") : join2(repoRoot, ".cursor", "hooks.json");
535
+ return scope === "global" ? join3(homedir3(), ".cursor", "hooks.json") : join3(repoRoot, ".cursor", "hooks.json");
357
536
  }
358
- function isAgentInsightsCommand2(cmd) {
537
+ function isAgentInsightsCommand3(cmd) {
359
538
  if (!cmd) return false;
360
- return cmd.startsWith(`${HOOK_COMMAND_NAME2} hook`);
539
+ if (cmd.startsWith(`${HOOK_COMMAND_NAME3} hook`)) return true;
540
+ return /\bagent-insights\b.*\bcli\.js\b.*\bhook\b/.test(cmd);
361
541
  }
362
- async function readJson2(path) {
542
+ async function readJson3(path) {
363
543
  try {
364
- const raw = await readFile2(path, "utf8");
544
+ const raw = await readFile3(path, "utf8");
365
545
  return JSON.parse(raw);
366
546
  } catch (err) {
367
547
  if (err.code === "ENOENT") return void 0;
368
548
  throw err;
369
549
  }
370
550
  }
371
- function asString2(v) {
551
+ function asString3(v) {
552
+ return typeof v === "string" && v.length > 0 ? v : void 0;
553
+ }
554
+
555
+ // src/adapters/pi.ts
556
+ import { mkdir as mkdir4, readFile as readFile4, unlink, writeFile as writeFile4 } from "fs/promises";
557
+ import { homedir as homedir4 } from "os";
558
+ import { dirname as dirname4, join as join4 } from "path";
559
+ var EXTENSION_FILENAME = "agent-insights.ts";
560
+ var HOOK_MAP4 = {
561
+ session_start: "session.start",
562
+ session_shutdown: "session.end",
563
+ tool_call: "tool.start",
564
+ tool_result: "tool.end"
565
+ };
566
+ var PI_HOOK_EVENTS = Object.keys(HOOK_MAP4);
567
+ var EXTENSION_MARKER = "// installed-by: agent-insights";
568
+ function extensionSource() {
569
+ const { node, script } = hookCommandArgv("Placeholder");
570
+ return `${EXTENSION_MARKER}
571
+ // Generated by \`agent-insights init\`. Edit-with-caution: it's overwritten on every install.
572
+
573
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
574
+ import { spawn } from "node:child_process";
575
+
576
+ const EVENTS = ${JSON.stringify(PI_HOOK_EVENTS)} as const;
577
+ const NODE_BIN = ${JSON.stringify(node)};
578
+ const CLI_SCRIPT = ${JSON.stringify(script)};
579
+
580
+ function emit(event: string, payload: Record<string, unknown>): void {
581
+ try {
582
+ const child = spawn(NODE_BIN, [CLI_SCRIPT, "hook", event], {
583
+ stdio: ["pipe", "ignore", "ignore"],
584
+ detached: true,
585
+ });
586
+ child.on("error", () => {});
587
+ child.stdin.end(JSON.stringify(payload));
588
+ child.unref();
589
+ } catch {
590
+ // best-effort
591
+ }
592
+ }
593
+
594
+ export default function (pi: ExtensionAPI) {
595
+ for (const event of EVENTS) {
596
+ pi.on(event as never, async (raw: unknown, ctx: { sessionManager?: { getSessionFile?: () => string | undefined; getSessionId?: () => string | undefined } }) => {
597
+ const transcript_path = ctx.sessionManager?.getSessionFile?.();
598
+ const session_id = ctx.sessionManager?.getSessionId?.();
599
+ const e = (raw ?? {}) as Record<string, unknown>;
600
+ emit(event, {
601
+ ...(session_id ? { session_id } : {}),
602
+ ...(transcript_path ? { transcript_path } : {}),
603
+ ...("toolName" in e && typeof e.toolName === "string"
604
+ ? { tool_name: e.toolName }
605
+ : {}),
606
+ ...("reason" in e ? { reason: e.reason } : {}),
607
+ });
608
+ });
609
+ }
610
+ }
611
+ `;
612
+ }
613
+ var piAdapter = {
614
+ id: "pi",
615
+ agent: "pi",
616
+ label: "Pi",
617
+ settingsFile: ".pi/extensions/agent-insights.ts",
618
+ map(payload) {
619
+ const type = HOOK_MAP4[payload.event];
620
+ if (!type) return void 0;
621
+ const data = payload.data ?? {};
622
+ const sessionId = asString4(data["session_id"]) ?? asString4(data["sessionId"]);
623
+ const toolName = asString4(data["tool_name"]) ?? asString4(data["toolName"]);
624
+ const transcriptPath = asString4(data["transcript_path"]) ?? asString4(data["transcriptPath"]);
625
+ return {
626
+ type,
627
+ ...sessionId !== void 0 ? { sessionId } : {},
628
+ ...toolName !== void 0 ? { toolName } : {},
629
+ ...transcriptPath !== void 0 ? { transcriptPath } : {}
630
+ };
631
+ },
632
+ async install(repoRoot, scope = "global") {
633
+ const path = resolvePath(repoRoot, scope);
634
+ await mkdir4(dirname4(path), { recursive: true });
635
+ await writeFile4(path, extensionSource(), "utf8");
636
+ return { written: true, path };
637
+ },
638
+ async uninstall(repoRoot, scope = "global") {
639
+ const path = resolvePath(repoRoot, scope);
640
+ try {
641
+ const raw = await readFile4(path, "utf8");
642
+ if (!raw.includes(EXTENSION_MARKER)) {
643
+ return { removed: false, path };
644
+ }
645
+ await unlink(path);
646
+ return { removed: true, path };
647
+ } catch (err) {
648
+ if (err.code === "ENOENT") {
649
+ return { removed: false, path };
650
+ }
651
+ throw err;
652
+ }
653
+ },
654
+ async isInstalled(repoRoot, scope = "global") {
655
+ const path = resolvePath(repoRoot, scope);
656
+ try {
657
+ const raw = await readFile4(path, "utf8");
658
+ return raw.includes(EXTENSION_MARKER);
659
+ } catch (err) {
660
+ if (err.code === "ENOENT") return false;
661
+ throw err;
662
+ }
663
+ }
664
+ };
665
+ function resolvePath(repoRoot, scope) {
666
+ return scope === "global" ? join4(homedir4(), ".pi", "agent", "extensions", EXTENSION_FILENAME) : join4(repoRoot, ".pi", "extensions", EXTENSION_FILENAME);
667
+ }
668
+ function asString4(v) {
372
669
  return typeof v === "string" && v.length > 0 ? v : void 0;
373
670
  }
374
671
 
375
672
  // src/adapters/registry.ts
376
673
  var adapters = {
377
674
  "claude-code": claudeCodeAdapter,
378
- cursor: cursorAdapter
675
+ cursor: cursorAdapter,
676
+ codex: codexAdapter,
677
+ pi: piAdapter
379
678
  };
380
679
  var adapterList = Object.values(adapters);
381
680
  function getAdapter(id) {
@@ -383,8 +682,8 @@ function getAdapter(id) {
383
682
  }
384
683
 
385
684
  // src/config/config.ts
386
- import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
387
- import { dirname as dirname3 } from "path";
685
+ import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
686
+ import { dirname as dirname5 } from "path";
388
687
 
389
688
  // src/config/analyzer.ts
390
689
  var DEFAULT_ANALYZER_URL = "https://agent-insights.labs.vercel.dev";
@@ -393,25 +692,25 @@ function getAnalyzerUrl() {
393
692
  }
394
693
 
395
694
  // src/config/paths.ts
396
- import { homedir as homedir3 } from "os";
397
- import { join as join3 } from "path";
695
+ import { homedir as homedir5 } from "os";
696
+ import { join as join5 } from "path";
398
697
  function configRoot() {
399
- return process.env.AGENT_INSIGHTS_HOME ?? join3(homedir3(), ".agent-insights");
698
+ return process.env.AGENT_INSIGHTS_HOME ?? join5(homedir5(), ".agent-insights");
400
699
  }
401
700
  function configFile() {
402
- return join3(configRoot(), "config.json");
701
+ return join5(configRoot(), "config.json");
403
702
  }
404
703
  function authFile() {
405
- return join3(configRoot(), "auth.json");
704
+ return join5(configRoot(), "auth.json");
406
705
  }
407
706
  function bypassSecretFile() {
408
- return join3(configRoot(), "bypass-secret");
707
+ return join5(configRoot(), "bypass-secret");
409
708
  }
410
709
  function sessionCacheDir() {
411
- return join3(configRoot(), "session-cache");
710
+ return join5(configRoot(), "session-cache");
412
711
  }
413
712
  function logsDir() {
414
- return join3(configRoot(), "logs");
713
+ return join5(configRoot(), "logs");
415
714
  }
416
715
 
417
716
  // src/config/config.ts
@@ -448,7 +747,9 @@ function defaultConfig() {
448
747
  },
449
748
  agents: {
450
749
  claudeCode: { enabled: false },
451
- cursor: { enabled: false }
750
+ cursor: { enabled: false },
751
+ codex: { enabled: false },
752
+ pi: { enabled: false }
452
753
  },
453
754
  privacy: {
454
755
  capturePrompts: false,
@@ -460,7 +761,7 @@ function defaultConfig() {
460
761
  }
461
762
  async function loadConfig() {
462
763
  try {
463
- const raw = await readFile3(configFile(), "utf8");
764
+ const raw = await readFile5(configFile(), "utf8");
464
765
  const parsed = JSON.parse(raw);
465
766
  return mergeConfig(defaultConfig(), parsed);
466
767
  } catch (err) {
@@ -470,13 +771,13 @@ async function loadConfig() {
470
771
  }
471
772
  async function saveConfig(cfg) {
472
773
  await ensureDirs();
473
- await writeFile3(configFile(), `${JSON.stringify(cfg, null, 2)}
774
+ await writeFile5(configFile(), `${JSON.stringify(cfg, null, 2)}
474
775
  `, "utf8");
475
776
  }
476
777
  async function ensureDirs() {
477
- await mkdir3(dirname3(configFile()), { recursive: true });
478
- await mkdir3(sessionCacheDir(), { recursive: true });
479
- await mkdir3(logsDir(), { recursive: true });
778
+ await mkdir5(dirname5(configFile()), { recursive: true });
779
+ await mkdir5(sessionCacheDir(), { recursive: true });
780
+ await mkdir5(logsDir(), { recursive: true });
480
781
  }
481
782
  function mergeConfig(base, patch) {
482
783
  return {
@@ -495,20 +796,22 @@ function mergeConfig(base, patch) {
495
796
  ...base.agents.claudeCode,
496
797
  ...patch.agents?.claudeCode ?? {}
497
798
  },
498
- cursor: { ...base.agents.cursor, ...patch.agents?.cursor ?? {} }
799
+ cursor: { ...base.agents.cursor, ...patch.agents?.cursor ?? {} },
800
+ codex: { ...base.agents.codex, ...patch.agents?.codex ?? {} },
801
+ pi: { ...base.agents.pi, ...patch.agents?.pi ?? {} }
499
802
  },
500
803
  privacy: base.privacy
501
804
  };
502
805
  }
503
806
 
504
807
  // src/transcript/store.ts
505
- import { readFile as readFile6 } from "fs/promises";
808
+ import { readFile as readFile8 } from "fs/promises";
506
809
  import { put } from "@vercel/blob";
507
810
 
508
811
  // src/auth/store.ts
509
- import { chmod, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
510
- import { dirname as dirname4 } from "path";
511
- import { mkdir as mkdir4 } from "fs/promises";
812
+ import { chmod, readFile as readFile6, writeFile as writeFile6 } from "fs/promises";
813
+ import { dirname as dirname6 } from "path";
814
+ import { mkdir as mkdir6 } from "fs/promises";
512
815
 
513
816
  // src/auth/oauth.ts
514
817
  import { createHash as createHash2, randomBytes } from "crypto";
@@ -540,7 +843,7 @@ async function refreshAccessToken(refreshToken) {
540
843
  var REFRESH_BUFFER_MS = 6e4;
541
844
  async function loadAuth() {
542
845
  try {
543
- const raw = await readFile4(authFile(), "utf8");
846
+ const raw = await readFile6(authFile(), "utf8");
544
847
  const parsed = JSON.parse(raw);
545
848
  if (typeof parsed.accessToken === "string" && parsed.accessToken.length > 0) {
546
849
  return parsed;
@@ -553,8 +856,8 @@ async function loadAuth() {
553
856
  }
554
857
  async function saveAuth(state) {
555
858
  const path = authFile();
556
- await mkdir4(dirname4(path), { recursive: true });
557
- await writeFile4(path, `${JSON.stringify(state, null, 2)}
859
+ await mkdir6(dirname6(path), { recursive: true });
860
+ await writeFile6(path, `${JSON.stringify(state, null, 2)}
558
861
  `, {
559
862
  encoding: "utf8",
560
863
  mode: 384
@@ -565,9 +868,9 @@ async function saveAuth(state) {
565
868
  }
566
869
  }
567
870
  async function clearAuth() {
568
- const { unlink: unlink2 } = await import("fs/promises");
871
+ const { unlink: unlink3 } = await import("fs/promises");
569
872
  try {
570
- await unlink2(authFile());
873
+ await unlink3(authFile());
571
874
  } catch (err) {
572
875
  if (err.code !== "ENOENT") throw err;
573
876
  }
@@ -598,13 +901,13 @@ async function getValidToken() {
598
901
  }
599
902
 
600
903
  // src/config/bypass.ts
601
- import { chmod as chmod2, mkdir as mkdir5, readFile as readFile5, unlink, writeFile as writeFile5 } from "fs/promises";
602
- import { dirname as dirname5 } from "path";
904
+ import { chmod as chmod2, mkdir as mkdir7, readFile as readFile7, unlink as unlink2, writeFile as writeFile7 } from "fs/promises";
905
+ import { dirname as dirname7 } from "path";
603
906
  async function loadBypassSecret() {
604
907
  const fromEnv = process.env.AGENT_INSIGHTS_BYPASS_SECRET || process.env.VERCEL_AUTOMATION_BYPASS_SECRET;
605
908
  if (fromEnv) return fromEnv;
606
909
  try {
607
- const raw = (await readFile5(bypassSecretFile(), "utf8")).trim();
910
+ const raw = (await readFile7(bypassSecretFile(), "utf8")).trim();
608
911
  return raw || void 0;
609
912
  } catch (err) {
610
913
  if (err.code === "ENOENT") return void 0;
@@ -636,7 +939,7 @@ var BlobTranscriptStore = class {
636
939
  token;
637
940
  prefix;
638
941
  async upload(input) {
639
- const body = await readFile6(input.transcriptPath);
942
+ const body = await readFile8(input.transcriptPath);
640
943
  const requestedPath = buildPathname(
641
944
  this.prefix,
642
945
  input.userHash,
@@ -667,7 +970,7 @@ var AnalyzerTranscriptStore = class {
667
970
  "transcript store: not logged in \u2014 run `agent-insights login`"
668
971
  );
669
972
  }
670
- const body = await readFile6(input.transcriptPath);
973
+ const body = await readFile8(input.transcriptPath);
671
974
  const url = new URL("/api/sessions/upload", this.analyzerUrl).toString();
672
975
  const headers = await withBypassHeader({
673
976
  authorization: `Bearer ${token}`,