agent-insights 0.0.13 → 0.0.16

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/cli.js CHANGED
@@ -225,15 +225,15 @@ __export(store_exports, {
225
225
  loadEmail: () => loadEmail,
226
226
  saveAuth: () => saveAuth
227
227
  });
228
- import { chmod, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
229
- import { dirname as dirname4 } from "path";
230
- import { mkdir as mkdir4 } from "fs/promises";
228
+ import { chmod, readFile as readFile6, writeFile as writeFile6 } from "fs/promises";
229
+ import { dirname as dirname6 } from "path";
230
+ import { mkdir as mkdir6 } from "fs/promises";
231
231
  async function loadEmail() {
232
232
  return (await loadAuth())?.email;
233
233
  }
234
234
  async function loadAuth() {
235
235
  try {
236
- const raw = await readFile4(authFile(), "utf8");
236
+ const raw = await readFile6(authFile(), "utf8");
237
237
  const parsed = JSON.parse(raw);
238
238
  if (typeof parsed.accessToken === "string" && parsed.accessToken.length > 0) {
239
239
  return parsed;
@@ -246,8 +246,8 @@ async function loadAuth() {
246
246
  }
247
247
  async function saveAuth(state) {
248
248
  const path = authFile();
249
- await mkdir4(dirname4(path), { recursive: true });
250
- await writeFile4(path, `${JSON.stringify(state, null, 2)}
249
+ await mkdir6(dirname6(path), { recursive: true });
250
+ await writeFile6(path, `${JSON.stringify(state, null, 2)}
251
251
  `, {
252
252
  encoding: "utf8",
253
253
  mode: 384
@@ -258,9 +258,9 @@ async function saveAuth(state) {
258
258
  }
259
259
  }
260
260
  async function clearAuth() {
261
- const { unlink: unlink2 } = await import("fs/promises");
261
+ const { unlink: unlink3 } = await import("fs/promises");
262
262
  try {
263
- await unlink2(authFile());
263
+ await unlink3(authFile());
264
264
  } catch (err) {
265
265
  if (err.code !== "ENOENT") throw err;
266
266
  }
@@ -351,7 +351,9 @@ function defaultConfig() {
351
351
  },
352
352
  agents: {
353
353
  claudeCode: { enabled: false },
354
- cursor: { enabled: false }
354
+ cursor: { enabled: false },
355
+ codex: { enabled: false },
356
+ pi: { enabled: false }
355
357
  },
356
358
  privacy: {
357
359
  capturePrompts: false,
@@ -398,7 +400,9 @@ function mergeConfig(base, patch) {
398
400
  ...base.agents.claudeCode,
399
401
  ...patch.agents?.claudeCode ?? {}
400
402
  },
401
- cursor: { ...base.agents.cursor, ...patch.agents?.cursor ?? {} }
403
+ cursor: { ...base.agents.cursor, ...patch.agents?.cursor ?? {} },
404
+ codex: { ...base.agents.codex, ...patch.agents?.codex ?? {} },
405
+ pi: { ...base.agents.pi, ...patch.agents?.pi ?? {} }
402
406
  },
403
407
  privacy: base.privacy
404
408
  };
@@ -784,12 +788,162 @@ function asString(v) {
784
788
  return typeof v === "string" && v.length > 0 ? v : void 0;
785
789
  }
786
790
 
787
- // src/adapters/cursor.ts
791
+ // src/adapters/codex.ts
788
792
  import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
789
793
  import { homedir as homedir3 } from "os";
790
794
  import { dirname as dirname3, join as join3 } from "path";
791
795
  var HOOK_COMMAND_NAME2 = "agent-insights";
792
796
  var HOOK_MAP2 = {
797
+ SessionStart: "session.start",
798
+ UserPromptSubmit: "user.prompt.submit",
799
+ PreToolUse: "tool.start",
800
+ PostToolUse: "tool.end",
801
+ PermissionRequest: "permission.request",
802
+ Stop: "session.end"
803
+ };
804
+ var CODEX_HOOK_EVENTS = Object.keys(HOOK_MAP2);
805
+ var codexAdapter = {
806
+ id: "codex",
807
+ agent: "codex",
808
+ label: "Codex",
809
+ settingsFile: ".codex/hooks.json",
810
+ map(payload) {
811
+ const type = HOOK_MAP2[payload.event];
812
+ if (!type) return void 0;
813
+ const data = payload.data ?? {};
814
+ const sessionId = asString2(data["session_id"]) ?? asString2(data["sessionId"]);
815
+ const toolName = asString2(data["tool_name"]) ?? asString2(data["toolName"]) ?? asString2(data["tool"]?.["name"]);
816
+ const transcriptPath = asString2(data["transcript_path"]) ?? asString2(data["transcriptPath"]);
817
+ return {
818
+ type,
819
+ ...sessionId !== void 0 ? { sessionId } : {},
820
+ ...toolName !== void 0 ? { toolName } : {},
821
+ ...transcriptPath !== void 0 ? { transcriptPath } : {}
822
+ };
823
+ },
824
+ async install(repoRoot, scope = "global") {
825
+ const path = resolveCodexPath(repoRoot, scope);
826
+ const settings = await readJson2(path);
827
+ const next = { ...settings ?? {} };
828
+ const hooks = {};
829
+ for (const [event, raw] of Object.entries(next.hooks ?? {})) {
830
+ hooks[event] = normalizeEventHooks2(raw);
831
+ }
832
+ for (const event of CODEX_HOOK_EVENTS) {
833
+ const withoutInsights = removeAgentInsightsMatchers2(hooks[event] ?? []);
834
+ hooks[event] = addAgentInsightsHook2(withoutInsights, event);
835
+ }
836
+ next.hooks = hooks;
837
+ await mkdir3(dirname3(path), { recursive: true });
838
+ await writeFile3(path, `${JSON.stringify(next, null, 2)}
839
+ `, "utf8");
840
+ return { written: true, path };
841
+ },
842
+ async uninstall(repoRoot, scope = "global") {
843
+ const path = resolveCodexPath(repoRoot, scope);
844
+ const settings = await readJson2(path);
845
+ if (!settings?.hooks) return { removed: false, path };
846
+ const hooks = {};
847
+ let touched = false;
848
+ for (const [event, raw] of Object.entries(settings.hooks)) {
849
+ const before = normalizeEventHooks2(raw);
850
+ const after = removeAgentInsightsMatchers2(before);
851
+ if (after.length !== before.length || JSON.stringify(after) !== JSON.stringify(before)) {
852
+ touched = true;
853
+ }
854
+ if (after.length > 0) hooks[event] = after;
855
+ }
856
+ settings.hooks = hooks;
857
+ await writeFile3(path, `${JSON.stringify(settings, null, 2)}
858
+ `, "utf8");
859
+ return { removed: touched, path };
860
+ },
861
+ async isInstalled(repoRoot, scope = "global") {
862
+ const settings = await readJson2(
863
+ resolveCodexPath(repoRoot, scope)
864
+ );
865
+ if (!settings?.hooks) return false;
866
+ return Object.values(settings.hooks).some(
867
+ (raw) => normalizeEventHooks2(raw).some(
868
+ (group) => group.hooks.some((h) => isAgentInsightsCommand2(h.command))
869
+ )
870
+ );
871
+ }
872
+ };
873
+ function resolveCodexPath(repoRoot, scope) {
874
+ return scope === "global" ? join3(homedir3(), ".codex", "hooks.json") : join3(repoRoot, ".codex", "hooks.json");
875
+ }
876
+ function isAgentInsightsCommand2(cmd) {
877
+ if (!cmd) return false;
878
+ return cmd.startsWith(`${HOOK_COMMAND_NAME2} hook`);
879
+ }
880
+ function isHookCommand2(value) {
881
+ if (!value || typeof value !== "object") return false;
882
+ const entry = value;
883
+ return entry.type === "command" && typeof entry.command === "string";
884
+ }
885
+ function normalizeEventHooks2(raw) {
886
+ const groups = [];
887
+ for (const entry of raw) {
888
+ if (!entry || typeof entry !== "object") continue;
889
+ const record = entry;
890
+ if (Array.isArray(record.hooks)) {
891
+ const commands = record.hooks.filter(isHookCommand2);
892
+ if (commands.length === 0) continue;
893
+ groups.push({
894
+ matcher: typeof record.matcher === "string" ? record.matcher : "",
895
+ hooks: commands
896
+ });
897
+ continue;
898
+ }
899
+ if (isHookCommand2(record)) {
900
+ groups.push({ matcher: "", hooks: [record] });
901
+ }
902
+ }
903
+ return groups;
904
+ }
905
+ function removeAgentInsightsMatchers2(matchers) {
906
+ const result = [];
907
+ for (const group of matchers) {
908
+ const hooks = group.hooks.filter(
909
+ (h) => !isAgentInsightsCommand2(h.command)
910
+ );
911
+ if (hooks.length > 0) result.push({ ...group, hooks });
912
+ }
913
+ return result;
914
+ }
915
+ function addAgentInsightsHook2(matchers, event) {
916
+ const command = `${HOOK_COMMAND_NAME2} hook ${event}`;
917
+ const entry = { type: "command", command };
918
+ for (const group of matchers) {
919
+ if (group.matcher === "") {
920
+ if (!group.hooks.some((h) => h.command === command)) {
921
+ group.hooks.push(entry);
922
+ }
923
+ return matchers;
924
+ }
925
+ }
926
+ return [...matchers, { matcher: "", hooks: [entry] }];
927
+ }
928
+ async function readJson2(path) {
929
+ try {
930
+ const raw = await readFile3(path, "utf8");
931
+ return JSON.parse(raw);
932
+ } catch (err) {
933
+ if (err.code === "ENOENT") return void 0;
934
+ throw err;
935
+ }
936
+ }
937
+ function asString2(v) {
938
+ return typeof v === "string" && v.length > 0 ? v : void 0;
939
+ }
940
+
941
+ // src/adapters/cursor.ts
942
+ import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
943
+ import { homedir as homedir4 } from "os";
944
+ import { dirname as dirname4, join as join4 } from "path";
945
+ var HOOK_COMMAND_NAME3 = "agent-insights";
946
+ var HOOK_MAP3 = {
793
947
  sessionStart: "session.start",
794
948
  sessionEnd: "session.end",
795
949
  beforeSubmitPrompt: "user.prompt.submit",
@@ -806,19 +960,19 @@ var HOOK_MAP2 = {
806
960
  afterFileEdit: "tool.end",
807
961
  workspaceOpen: "session.start"
808
962
  };
809
- var CURSOR_HOOK_EVENTS = Object.keys(HOOK_MAP2);
963
+ var CURSOR_HOOK_EVENTS = Object.keys(HOOK_MAP3);
810
964
  var cursorAdapter = {
811
965
  id: "cursor",
812
966
  agent: "cursor",
813
967
  label: "Cursor",
814
968
  settingsFile: ".cursor/hooks.json",
815
969
  map(payload) {
816
- const type = HOOK_MAP2[payload.event];
970
+ const type = HOOK_MAP3[payload.event];
817
971
  if (!type) return void 0;
818
972
  const data = payload.data ?? {};
819
- const sessionId = asString2(data["session_id"]) ?? asString2(data["sessionId"]) ?? asString2(data["conversation_id"]);
820
- const toolName = asString2(data["tool_name"]) ?? asString2(data["toolName"]);
821
- const transcriptPath = asString2(data["transcript_path"]) ?? asString2(data["transcriptPath"]) ?? asString2(process.env.CURSOR_TRANSCRIPT_PATH);
973
+ const sessionId = asString3(data["session_id"]) ?? asString3(data["sessionId"]) ?? asString3(data["conversation_id"]);
974
+ const toolName = asString3(data["tool_name"]) ?? asString3(data["toolName"]);
975
+ const transcriptPath = asString3(data["transcript_path"]) ?? asString3(data["transcriptPath"]) ?? asString3(process.env.CURSOR_TRANSCRIPT_PATH);
822
976
  return {
823
977
  type,
824
978
  ...sessionId !== void 0 ? { sessionId } : {},
@@ -828,7 +982,7 @@ var cursorAdapter = {
828
982
  },
829
983
  async install(repoRoot, scope = "global") {
830
984
  const path = resolveCursorPath(repoRoot, scope);
831
- const settings = await readJson2(path);
985
+ const settings = await readJson3(path);
832
986
  const next = {
833
987
  version: 1,
834
988
  ...settings ?? {}
@@ -836,26 +990,26 @@ var cursorAdapter = {
836
990
  const hooks = { ...next.hooks ?? {} };
837
991
  for (const event of CURSOR_HOOK_EVENTS) {
838
992
  const existing = (hooks[event] ?? []).filter(
839
- (h) => !isAgentInsightsCommand2(h.command)
993
+ (h) => !isAgentInsightsCommand3(h.command)
840
994
  );
841
- existing.push({ command: `${HOOK_COMMAND_NAME2} hook ${event}` });
995
+ existing.push({ command: `${HOOK_COMMAND_NAME3} hook ${event}` });
842
996
  hooks[event] = existing;
843
997
  }
844
998
  next.hooks = hooks;
845
- await mkdir3(dirname3(path), { recursive: true });
846
- await writeFile3(path, `${JSON.stringify(next, null, 2)}
999
+ await mkdir4(dirname4(path), { recursive: true });
1000
+ await writeFile4(path, `${JSON.stringify(next, null, 2)}
847
1001
  `, "utf8");
848
1002
  return { written: true, path };
849
1003
  },
850
1004
  async uninstall(repoRoot, scope = "global") {
851
1005
  const path = resolveCursorPath(repoRoot, scope);
852
- const settings = await readJson2(path);
1006
+ const settings = await readJson3(path);
853
1007
  if (!settings?.hooks) return { removed: false, path };
854
1008
  const hooks = { ...settings.hooks };
855
1009
  let touched = false;
856
1010
  for (const [event, entries] of Object.entries(hooks)) {
857
1011
  const filtered = entries.filter(
858
- (h) => !isAgentInsightsCommand2(h.command)
1012
+ (h) => !isAgentInsightsCommand3(h.command)
859
1013
  );
860
1014
  if (filtered.length !== entries.length) touched = true;
861
1015
  if (filtered.length === 0) {
@@ -865,44 +1019,160 @@ var cursorAdapter = {
865
1019
  }
866
1020
  }
867
1021
  settings.hooks = hooks;
868
- await writeFile3(path, `${JSON.stringify(settings, null, 2)}
1022
+ await writeFile4(path, `${JSON.stringify(settings, null, 2)}
869
1023
  `, "utf8");
870
1024
  return { removed: touched, path };
871
1025
  },
872
1026
  async isInstalled(repoRoot, scope = "global") {
873
- const settings = await readJson2(
1027
+ const settings = await readJson3(
874
1028
  resolveCursorPath(repoRoot, scope)
875
1029
  );
876
1030
  if (!settings?.hooks) return false;
877
1031
  return Object.values(settings.hooks).some(
878
- (entries) => entries.some((h) => isAgentInsightsCommand2(h.command))
1032
+ (entries) => entries.some((h) => isAgentInsightsCommand3(h.command))
879
1033
  );
880
1034
  }
881
1035
  };
882
1036
  function resolveCursorPath(repoRoot, scope) {
883
- return scope === "global" ? join3(homedir3(), ".cursor", "hooks.json") : join3(repoRoot, ".cursor", "hooks.json");
1037
+ return scope === "global" ? join4(homedir4(), ".cursor", "hooks.json") : join4(repoRoot, ".cursor", "hooks.json");
884
1038
  }
885
- function isAgentInsightsCommand2(cmd) {
1039
+ function isAgentInsightsCommand3(cmd) {
886
1040
  if (!cmd) return false;
887
- return cmd.startsWith(`${HOOK_COMMAND_NAME2} hook`);
1041
+ return cmd.startsWith(`${HOOK_COMMAND_NAME3} hook`);
888
1042
  }
889
- async function readJson2(path) {
1043
+ async function readJson3(path) {
890
1044
  try {
891
- const raw = await readFile3(path, "utf8");
1045
+ const raw = await readFile4(path, "utf8");
892
1046
  return JSON.parse(raw);
893
1047
  } catch (err) {
894
1048
  if (err.code === "ENOENT") return void 0;
895
1049
  throw err;
896
1050
  }
897
1051
  }
898
- function asString2(v) {
1052
+ function asString3(v) {
1053
+ return typeof v === "string" && v.length > 0 ? v : void 0;
1054
+ }
1055
+
1056
+ // src/adapters/pi.ts
1057
+ import { mkdir as mkdir5, readFile as readFile5, unlink, writeFile as writeFile5 } from "fs/promises";
1058
+ import { homedir as homedir5 } from "os";
1059
+ import { dirname as dirname5, join as join5 } from "path";
1060
+ var EXTENSION_FILENAME = "agent-insights.ts";
1061
+ var HOOK_MAP4 = {
1062
+ session_start: "session.start",
1063
+ session_shutdown: "session.end",
1064
+ tool_call: "tool.start",
1065
+ tool_result: "tool.end"
1066
+ };
1067
+ var PI_HOOK_EVENTS = Object.keys(HOOK_MAP4);
1068
+ var EXTENSION_MARKER = "// installed-by: agent-insights";
1069
+ function extensionSource() {
1070
+ return `${EXTENSION_MARKER}
1071
+ // Generated by \`agent-insights init\`. Edit-with-caution: it's overwritten on every install.
1072
+
1073
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
1074
+ import { spawn } from "node:child_process";
1075
+
1076
+ const EVENTS = ${JSON.stringify(PI_HOOK_EVENTS)} as const;
1077
+
1078
+ function emit(event: string, payload: Record<string, unknown>): void {
1079
+ try {
1080
+ const child = spawn("agent-insights", ["hook", event], {
1081
+ stdio: ["pipe", "ignore", "ignore"],
1082
+ detached: true,
1083
+ });
1084
+ child.on("error", () => {});
1085
+ child.stdin.end(JSON.stringify(payload));
1086
+ child.unref();
1087
+ } catch {
1088
+ // best-effort
1089
+ }
1090
+ }
1091
+
1092
+ export default function (pi: ExtensionAPI) {
1093
+ for (const event of EVENTS) {
1094
+ pi.on(event as never, async (raw: unknown, ctx: { sessionManager?: { getSessionFile?: () => string | undefined; getSessionId?: () => string | undefined } }) => {
1095
+ const transcript_path = ctx.sessionManager?.getSessionFile?.();
1096
+ const session_id = ctx.sessionManager?.getSessionId?.();
1097
+ const e = (raw ?? {}) as Record<string, unknown>;
1098
+ emit(event, {
1099
+ ...(session_id ? { session_id } : {}),
1100
+ ...(transcript_path ? { transcript_path } : {}),
1101
+ ...("toolName" in e && typeof e.toolName === "string"
1102
+ ? { tool_name: e.toolName }
1103
+ : {}),
1104
+ ...("reason" in e ? { reason: e.reason } : {}),
1105
+ });
1106
+ });
1107
+ }
1108
+ }
1109
+ `;
1110
+ }
1111
+ var piAdapter = {
1112
+ id: "pi",
1113
+ agent: "pi",
1114
+ label: "Pi",
1115
+ settingsFile: ".pi/extensions/agent-insights.ts",
1116
+ map(payload) {
1117
+ const type = HOOK_MAP4[payload.event];
1118
+ if (!type) return void 0;
1119
+ const data = payload.data ?? {};
1120
+ const sessionId = asString4(data["session_id"]) ?? asString4(data["sessionId"]);
1121
+ const toolName = asString4(data["tool_name"]) ?? asString4(data["toolName"]);
1122
+ const transcriptPath = asString4(data["transcript_path"]) ?? asString4(data["transcriptPath"]);
1123
+ return {
1124
+ type,
1125
+ ...sessionId !== void 0 ? { sessionId } : {},
1126
+ ...toolName !== void 0 ? { toolName } : {},
1127
+ ...transcriptPath !== void 0 ? { transcriptPath } : {}
1128
+ };
1129
+ },
1130
+ async install(repoRoot, scope = "global") {
1131
+ const path = resolvePath(repoRoot, scope);
1132
+ await mkdir5(dirname5(path), { recursive: true });
1133
+ await writeFile5(path, extensionSource(), "utf8");
1134
+ return { written: true, path };
1135
+ },
1136
+ async uninstall(repoRoot, scope = "global") {
1137
+ const path = resolvePath(repoRoot, scope);
1138
+ try {
1139
+ const raw = await readFile5(path, "utf8");
1140
+ if (!raw.includes(EXTENSION_MARKER)) {
1141
+ return { removed: false, path };
1142
+ }
1143
+ await unlink(path);
1144
+ return { removed: true, path };
1145
+ } catch (err) {
1146
+ if (err.code === "ENOENT") {
1147
+ return { removed: false, path };
1148
+ }
1149
+ throw err;
1150
+ }
1151
+ },
1152
+ async isInstalled(repoRoot, scope = "global") {
1153
+ const path = resolvePath(repoRoot, scope);
1154
+ try {
1155
+ const raw = await readFile5(path, "utf8");
1156
+ return raw.includes(EXTENSION_MARKER);
1157
+ } catch (err) {
1158
+ if (err.code === "ENOENT") return false;
1159
+ throw err;
1160
+ }
1161
+ }
1162
+ };
1163
+ function resolvePath(repoRoot, scope) {
1164
+ return scope === "global" ? join5(homedir5(), ".pi", "agent", "extensions", EXTENSION_FILENAME) : join5(repoRoot, ".pi", "extensions", EXTENSION_FILENAME);
1165
+ }
1166
+ function asString4(v) {
899
1167
  return typeof v === "string" && v.length > 0 ? v : void 0;
900
1168
  }
901
1169
 
902
1170
  // src/adapters/registry.ts
903
1171
  var adapters = {
904
1172
  "claude-code": claudeCodeAdapter,
905
- cursor: cursorAdapter
1173
+ cursor: cursorAdapter,
1174
+ codex: codexAdapter,
1175
+ pi: piAdapter
906
1176
  };
907
1177
  var adapterList = Object.values(adapters);
908
1178
 
@@ -946,18 +1216,18 @@ init_store();
946
1216
 
947
1217
  // src/transcript/store.ts
948
1218
  init_store();
949
- import { readFile as readFile6 } from "fs/promises";
1219
+ import { readFile as readFile8 } from "fs/promises";
950
1220
  import { put } from "@vercel/blob";
951
1221
 
952
1222
  // src/config/bypass.ts
953
1223
  init_paths();
954
- import { chmod as chmod2, mkdir as mkdir5, readFile as readFile5, unlink, writeFile as writeFile5 } from "fs/promises";
955
- import { dirname as dirname5 } from "path";
1224
+ import { chmod as chmod2, mkdir as mkdir7, readFile as readFile7, unlink as unlink2, writeFile as writeFile7 } from "fs/promises";
1225
+ import { dirname as dirname7 } from "path";
956
1226
  async function loadBypassSecret() {
957
1227
  const fromEnv = process.env.AGENT_INSIGHTS_BYPASS_SECRET || process.env.VERCEL_AUTOMATION_BYPASS_SECRET;
958
1228
  if (fromEnv) return fromEnv;
959
1229
  try {
960
- const raw = (await readFile5(bypassSecretFile(), "utf8")).trim();
1230
+ const raw = (await readFile7(bypassSecretFile(), "utf8")).trim();
961
1231
  return raw || void 0;
962
1232
  } catch (err) {
963
1233
  if (err.code === "ENOENT") return void 0;
@@ -966,8 +1236,8 @@ async function loadBypassSecret() {
966
1236
  }
967
1237
  async function saveBypassSecret(secret) {
968
1238
  const path = bypassSecretFile();
969
- await mkdir5(dirname5(path), { recursive: true });
970
- await writeFile5(path, secret.trim(), { encoding: "utf8", mode: 384 });
1239
+ await mkdir7(dirname7(path), { recursive: true });
1240
+ await writeFile7(path, secret.trim(), { encoding: "utf8", mode: 384 });
971
1241
  try {
972
1242
  await chmod2(path, 384);
973
1243
  } catch {
@@ -975,7 +1245,7 @@ async function saveBypassSecret(secret) {
975
1245
  }
976
1246
  async function clearBypassSecret() {
977
1247
  try {
978
- await unlink(bypassSecretFile());
1248
+ await unlink2(bypassSecretFile());
979
1249
  } catch (err) {
980
1250
  if (err.code !== "ENOENT") throw err;
981
1251
  }
@@ -1005,7 +1275,7 @@ var BlobTranscriptStore = class {
1005
1275
  token;
1006
1276
  prefix;
1007
1277
  async upload(input) {
1008
- const body = await readFile6(input.transcriptPath);
1278
+ const body = await readFile8(input.transcriptPath);
1009
1279
  const requestedPath = buildPathname(
1010
1280
  this.prefix,
1011
1281
  input.userHash,
@@ -1036,7 +1306,7 @@ var AnalyzerTranscriptStore = class {
1036
1306
  "transcript store: not logged in \u2014 run `agent-insights login`"
1037
1307
  );
1038
1308
  }
1039
- const body = await readFile6(input.transcriptPath);
1309
+ const body = await readFile8(input.transcriptPath);
1040
1310
  const url = new URL("/api/sessions/upload", this.analyzerUrl).toString();
1041
1311
  const headers = await withBypassHeader({
1042
1312
  authorization: `Bearer ${token}`,
@@ -1155,7 +1425,7 @@ async function runDoctor(opts) {
1155
1425
  }
1156
1426
  }
1157
1427
  for (const adapter of adapterList) {
1158
- const enabled = adapter.id === "claude-code" ? cfg.agents.claudeCode.enabled : cfg.agents.cursor.enabled;
1428
+ const enabled = adapter.id === "claude-code" ? cfg.agents.claudeCode.enabled : adapter.id === "cursor" ? cfg.agents.cursor.enabled : adapter.id === "codex" ? cfg.agents.codex.enabled : cfg.agents.pi.enabled;
1159
1429
  if (!enabled) continue;
1160
1430
  const installed = await adapter.isInstalled(repoRoot, cfg.hooksScope);
1161
1431
  checks.push({
@@ -1401,6 +1671,8 @@ async function runInit(opts) {
1401
1671
  cfg.userConsent.eventTelemetry = choices.telemetry;
1402
1672
  cfg.agents.claudeCode.enabled = choices.agents.has("claude-code");
1403
1673
  cfg.agents.cursor.enabled = choices.agents.has("cursor");
1674
+ cfg.agents.codex.enabled = choices.agents.has("codex");
1675
+ cfg.agents.pi.enabled = choices.agents.has("pi");
1404
1676
  await saveConfig(cfg);
1405
1677
  log.ok(`Wrote config to ${configFile()}`);
1406
1678
  if (choices.bypassSecret !== void 0) {
@@ -1416,8 +1688,7 @@ async function runInit(opts) {
1416
1688
  const repoRoot = process.cwd();
1417
1689
  if (installHooks) {
1418
1690
  for (const adapter of adapterList) {
1419
- const enabled = adapter.id === "claude-code" && cfg.agents.claudeCode.enabled || adapter.id === "cursor" && cfg.agents.cursor.enabled;
1420
- if (!enabled) continue;
1691
+ if (!isAdapterEnabled(cfg, adapter.id)) continue;
1421
1692
  const { path } = await adapter.install(repoRoot, cfg.hooksScope);
1422
1693
  log.ok(`Installed ${adapter.label} hooks \u2192 ${rel(path)}`);
1423
1694
  }
@@ -1497,6 +1768,9 @@ async function safePrompt(run) {
1497
1768
  throw err;
1498
1769
  }
1499
1770
  }
1771
+ var KNOWN_AGENT_IDS = new Set(
1772
+ adapterList.map((a) => a.id)
1773
+ );
1500
1774
  function parseAgents(value) {
1501
1775
  const out = /* @__PURE__ */ new Set();
1502
1776
  const trimmed = (value ?? "").trim();
@@ -1504,9 +1778,9 @@ function parseAgents(value) {
1504
1778
  for (const a of adapterList) out.add(a.id);
1505
1779
  return out;
1506
1780
  }
1507
- const list = (trimmed || "claude-code,cursor").split(",").map((s) => s.trim()).filter(Boolean);
1781
+ const list = (trimmed || adapterList.map((a) => a.id).join(",")).split(",").map((s) => s.trim()).filter(Boolean);
1508
1782
  for (const id of list) {
1509
- if (id === "claude-code" || id === "cursor") out.add(id);
1783
+ if (KNOWN_AGENT_IDS.has(id)) out.add(id);
1510
1784
  else log.warn(`Unknown agent id "${id}" \u2014 skipping.`);
1511
1785
  }
1512
1786
  return out;
@@ -1515,6 +1789,18 @@ function rel(p) {
1515
1789
  const cwd = process.cwd();
1516
1790
  return p.startsWith(cwd) ? p.slice(cwd.length + 1) : p;
1517
1791
  }
1792
+ function isAdapterEnabled(cfg, id) {
1793
+ switch (id) {
1794
+ case "claude-code":
1795
+ return cfg.agents.claudeCode.enabled;
1796
+ case "cursor":
1797
+ return cfg.agents.cursor.enabled;
1798
+ case "codex":
1799
+ return cfg.agents.codex.enabled;
1800
+ case "pi":
1801
+ return cfg.agents.pi.enabled;
1802
+ }
1803
+ }
1518
1804
 
1519
1805
  // src/commands/login.ts
1520
1806
  init_oauth();
@@ -1568,7 +1854,7 @@ async function runLogout() {
1568
1854
 
1569
1855
  // src/commands/status.ts
1570
1856
  import { existsSync } from "fs";
1571
- import { join as join4 } from "path";
1857
+ import { join as join6 } from "path";
1572
1858
  import kleur5 from "kleur";
1573
1859
  init_paths();
1574
1860
  async function runStatus(opts) {
@@ -1594,8 +1880,8 @@ async function runStatus(opts) {
1594
1880
  enabled: cfg.enabled,
1595
1881
  consent: cfg.userConsent,
1596
1882
  vercel: {
1597
- linked: existsSync(join4(repoRoot, ".vercel/project.json")),
1598
- envFile: existsSync(join4(repoRoot, ".env.local"))
1883
+ linked: existsSync(join6(repoRoot, ".vercel/project.json")),
1884
+ envFile: existsSync(join6(repoRoot, ".env.local"))
1599
1885
  },
1600
1886
  adapters: adapterStatus
1601
1887
  });
@@ -1619,9 +1905,9 @@ async function runStatus(opts) {
1619
1905
  log.info("");
1620
1906
  log.info(kleur5.bold("Vercel"));
1621
1907
  log.info(
1622
- ` linked ${yn(existsSync(join4(repoRoot, ".vercel/project.json")))}`
1908
+ ` linked ${yn(existsSync(join6(repoRoot, ".vercel/project.json")))}`
1623
1909
  );
1624
- log.info(` .env.local ${yn(existsSync(join4(repoRoot, ".env.local")))}`);
1910
+ log.info(` .env.local ${yn(existsSync(join6(repoRoot, ".env.local")))}`);
1625
1911
  }
1626
1912
  function yn(v) {
1627
1913
  return v ? kleur5.green("yes") : kleur5.dim("no");
@@ -1631,7 +1917,7 @@ function yn(v) {
1631
1917
  var program = new Command();
1632
1918
  program.name("agent-insights").description(
1633
1919
  "Internal CLI for AI coding agent observability (Claude Code, Cursor)."
1634
- ).version("0.0.13");
1920
+ ).version("0.0.16");
1635
1921
  program.command("login").description("Authenticate with Vercel (Sign in with Vercel).").action(async () => {
1636
1922
  await runLogin();
1637
1923
  });