agent-insights 0.0.16 → 0.0.19

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
@@ -74,7 +74,7 @@ If the browser did not open, visit:
74
74
  return { code, codeVerifier };
75
75
  }
76
76
  function listenForCallback(expectedState, timeoutMs) {
77
- return new Promise((resolve, reject) => {
77
+ return new Promise((resolve2, reject) => {
78
78
  const server = createServer((req, res) => {
79
79
  const url = new URL(req.url ?? "/", `http://localhost:${CALLBACK_PORT}`);
80
80
  if (url.pathname !== "/callback") {
@@ -121,7 +121,7 @@ function listenForCallback(expectedState, timeoutMs) {
121
121
  return;
122
122
  }
123
123
  finish(
124
- () => resolve(code),
124
+ () => resolve2(code),
125
125
  html("\u2713 Logged in! You can close this tab."),
126
126
  200
127
127
  );
@@ -599,16 +599,16 @@ async function runCursorWrapper(opts) {
599
599
  process.exitCode = code;
600
600
  }
601
601
  function spawnCursor(path) {
602
- return new Promise((resolve) => {
602
+ return new Promise((resolve2) => {
603
603
  const child = spawn("cursor", [path], {
604
604
  stdio: "inherit",
605
605
  env: process.env
606
606
  });
607
607
  child.on("error", (err) => {
608
608
  log.fail(`failed to launch cursor: ${err.message}`);
609
- resolve(127);
609
+ resolve2(127);
610
610
  });
611
- child.on("exit", (code) => resolve(code ?? 0));
611
+ child.on("exit", (code) => resolve2(code ?? 0));
612
612
  });
613
613
  }
614
614
  function emit(event) {
@@ -626,6 +626,33 @@ import { rm } from "fs/promises";
626
626
  import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
627
627
  import { homedir as homedir2 } from "os";
628
628
  import { dirname as dirname2, join as join2 } from "path";
629
+
630
+ // src/util/hook-command.ts
631
+ import { realpathSync } from "fs";
632
+ function resolve() {
633
+ const node = process.execPath;
634
+ let script = process.argv[1] ?? "";
635
+ try {
636
+ script = realpathSync(script);
637
+ } catch {
638
+ }
639
+ return { node, script };
640
+ }
641
+ function quote(s) {
642
+ if (s.length === 0) return "''";
643
+ if (!/[\s'"\\$`<>|&;()*?#~]/.test(s)) return s;
644
+ return `'${s.replace(/'/g, "'\\''")}'`;
645
+ }
646
+ function hookCommandString(event) {
647
+ const { node, script } = resolve();
648
+ return `${quote(node)} ${quote(script)} hook ${event}`;
649
+ }
650
+ function hookCommandArgv(event) {
651
+ const { node, script } = resolve();
652
+ return { node, script, args: ["hook", event] };
653
+ }
654
+
655
+ // src/adapters/claude-code.ts
629
656
  var HOOK_COMMAND_NAME = "agent-insights";
630
657
  var HOOK_MAP = {
631
658
  SessionStart: "session.start",
@@ -720,7 +747,8 @@ function resolveClaudePath(repoRoot, scope) {
720
747
  }
721
748
  function isAgentInsightsCommand(cmd) {
722
749
  if (!cmd) return false;
723
- return cmd.startsWith(`${HOOK_COMMAND_NAME} hook`);
750
+ if (cmd.startsWith(`${HOOK_COMMAND_NAME} hook`)) return true;
751
+ return /\bagent-insights\b.*\bcli\.js\b.*\bhook\b/.test(cmd);
724
752
  }
725
753
  function isHookCommand(value) {
726
754
  if (!value || typeof value !== "object") return false;
@@ -763,7 +791,7 @@ function removeAgentInsightsMatchers(matchers) {
763
791
  return result;
764
792
  }
765
793
  function addAgentInsightsHook(matchers, event) {
766
- const command = `${HOOK_COMMAND_NAME} hook ${event}`;
794
+ const command = hookCommandString(event);
767
795
  const entry = { type: "command", command };
768
796
  for (const group of matchers) {
769
797
  if (group.matcher === "") {
@@ -789,6 +817,7 @@ function asString(v) {
789
817
  }
790
818
 
791
819
  // src/adapters/codex.ts
820
+ import { readdirSync } from "fs";
792
821
  import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
793
822
  import { homedir as homedir3 } from "os";
794
823
  import { dirname as dirname3, join as join3 } from "path";
@@ -813,7 +842,7 @@ var codexAdapter = {
813
842
  const data = payload.data ?? {};
814
843
  const sessionId = asString2(data["session_id"]) ?? asString2(data["sessionId"]);
815
844
  const toolName = asString2(data["tool_name"]) ?? asString2(data["toolName"]) ?? asString2(data["tool"]?.["name"]);
816
- const transcriptPath = asString2(data["transcript_path"]) ?? asString2(data["transcriptPath"]);
845
+ const transcriptPath = asString2(data["transcript_path"]) ?? asString2(data["transcriptPath"]) ?? (type === "session.end" && sessionId ? findCodexTranscript(sessionId, defaultSessionsRoot()) : void 0);
817
846
  return {
818
847
  type,
819
848
  ...sessionId !== void 0 ? { sessionId } : {},
@@ -875,7 +904,8 @@ function resolveCodexPath(repoRoot, scope) {
875
904
  }
876
905
  function isAgentInsightsCommand2(cmd) {
877
906
  if (!cmd) return false;
878
- return cmd.startsWith(`${HOOK_COMMAND_NAME2} hook`);
907
+ if (cmd.startsWith(`${HOOK_COMMAND_NAME2} hook`)) return true;
908
+ return /\bagent-insights\b.*\bcli\.js\b.*\bhook\b/.test(cmd);
879
909
  }
880
910
  function isHookCommand2(value) {
881
911
  if (!value || typeof value !== "object") return false;
@@ -913,7 +943,7 @@ function removeAgentInsightsMatchers2(matchers) {
913
943
  return result;
914
944
  }
915
945
  function addAgentInsightsHook2(matchers, event) {
916
- const command = `${HOOK_COMMAND_NAME2} hook ${event}`;
946
+ const command = hookCommandString(event);
917
947
  const entry = { type: "command", command };
918
948
  for (const group of matchers) {
919
949
  if (group.matcher === "") {
@@ -937,6 +967,49 @@ async function readJson2(path) {
937
967
  function asString2(v) {
938
968
  return typeof v === "string" && v.length > 0 ? v : void 0;
939
969
  }
970
+ function defaultSessionsRoot() {
971
+ return join3(homedir3(), ".codex", "sessions");
972
+ }
973
+ function findCodexTranscript(sessionId, root) {
974
+ const suffix = `-${sessionId}.jsonl`;
975
+ const MAX_DAYS = 7;
976
+ let scanned = 0;
977
+ let years;
978
+ try {
979
+ years = readdirSync(root).filter((s) => /^\d{4}$/.test(s)).sort().reverse();
980
+ } catch {
981
+ return void 0;
982
+ }
983
+ for (const y of years) {
984
+ let months;
985
+ try {
986
+ months = readdirSync(join3(root, y)).filter((s) => /^\d{2}$/.test(s)).sort().reverse();
987
+ } catch {
988
+ continue;
989
+ }
990
+ for (const m of months) {
991
+ let days;
992
+ try {
993
+ days = readdirSync(join3(root, y, m)).filter((s) => /^\d{2}$/.test(s)).sort().reverse();
994
+ } catch {
995
+ continue;
996
+ }
997
+ for (const d of days) {
998
+ if (++scanned > MAX_DAYS) return void 0;
999
+ const dir = join3(root, y, m, d);
1000
+ let files;
1001
+ try {
1002
+ files = readdirSync(dir);
1003
+ } catch {
1004
+ continue;
1005
+ }
1006
+ const match = files.find((f) => f.endsWith(suffix));
1007
+ if (match) return join3(dir, match);
1008
+ }
1009
+ }
1010
+ }
1011
+ return void 0;
1012
+ }
940
1013
 
941
1014
  // src/adapters/cursor.ts
942
1015
  import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
@@ -992,7 +1065,7 @@ var cursorAdapter = {
992
1065
  const existing = (hooks[event] ?? []).filter(
993
1066
  (h) => !isAgentInsightsCommand3(h.command)
994
1067
  );
995
- existing.push({ command: `${HOOK_COMMAND_NAME3} hook ${event}` });
1068
+ existing.push({ command: hookCommandString(event) });
996
1069
  hooks[event] = existing;
997
1070
  }
998
1071
  next.hooks = hooks;
@@ -1038,7 +1111,8 @@ function resolveCursorPath(repoRoot, scope) {
1038
1111
  }
1039
1112
  function isAgentInsightsCommand3(cmd) {
1040
1113
  if (!cmd) return false;
1041
- return cmd.startsWith(`${HOOK_COMMAND_NAME3} hook`);
1114
+ if (cmd.startsWith(`${HOOK_COMMAND_NAME3} hook`)) return true;
1115
+ return /\bagent-insights\b.*\bcli\.js\b.*\bhook\b/.test(cmd);
1042
1116
  }
1043
1117
  async function readJson3(path) {
1044
1118
  try {
@@ -1067,6 +1141,7 @@ var HOOK_MAP4 = {
1067
1141
  var PI_HOOK_EVENTS = Object.keys(HOOK_MAP4);
1068
1142
  var EXTENSION_MARKER = "// installed-by: agent-insights";
1069
1143
  function extensionSource() {
1144
+ const { node, script } = hookCommandArgv("Placeholder");
1070
1145
  return `${EXTENSION_MARKER}
1071
1146
  // Generated by \`agent-insights init\`. Edit-with-caution: it's overwritten on every install.
1072
1147
 
@@ -1074,10 +1149,12 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
1074
1149
  import { spawn } from "node:child_process";
1075
1150
 
1076
1151
  const EVENTS = ${JSON.stringify(PI_HOOK_EVENTS)} as const;
1152
+ const NODE_BIN = ${JSON.stringify(node)};
1153
+ const CLI_SCRIPT = ${JSON.stringify(script)};
1077
1154
 
1078
1155
  function emit(event: string, payload: Record<string, unknown>): void {
1079
1156
  try {
1080
- const child = spawn("agent-insights", ["hook", event], {
1157
+ const child = spawn(NODE_BIN, [CLI_SCRIPT, "hook", event], {
1081
1158
  stdio: ["pipe", "ignore", "ignore"],
1082
1159
  detached: true,
1083
1160
  });
@@ -1557,7 +1634,7 @@ function buildEvent(adapter, mapped) {
1557
1634
  var STDIN_TIMEOUT_MS = 200;
1558
1635
  async function readStdinSafely() {
1559
1636
  if (process.stdin.isTTY) return "";
1560
- return new Promise((resolve) => {
1637
+ return new Promise((resolve2) => {
1561
1638
  let buf = "";
1562
1639
  let settled = false;
1563
1640
  const finish = () => {
@@ -1571,7 +1648,7 @@ async function readStdinSafely() {
1571
1648
  process.stdin.unref();
1572
1649
  } catch {
1573
1650
  }
1574
- resolve(buf);
1651
+ resolve2(buf);
1575
1652
  };
1576
1653
  const idle = setTimeout(finish, STDIN_TIMEOUT_MS);
1577
1654
  idle.unref();
@@ -1737,6 +1814,9 @@ async function promptChoices(opts) {
1737
1814
  bypassSecret = opts.bypassSecret;
1738
1815
  } else {
1739
1816
  const existing = await loadBypassSecret();
1817
+ log.hint(
1818
+ `Generate one at ${kleur3.underline("https://vercel.com/vercel-labs/agent-insights/settings/deployment-protection#protection-bypass-for-automation")}`
1819
+ );
1740
1820
  const answer = await safePrompt(
1741
1821
  () => password({
1742
1822
  message: existing ? "Vercel deployment-protection bypass secret (Enter to keep existing, '-' to clear):" : "Vercel deployment-protection bypass secret (Enter to skip):",
@@ -1917,7 +1997,7 @@ function yn(v) {
1917
1997
  var program = new Command();
1918
1998
  program.name("agent-insights").description(
1919
1999
  "Internal CLI for AI coding agent observability (Claude Code, Cursor)."
1920
- ).version("0.0.16");
2000
+ ).version("0.0.19");
1921
2001
  program.command("login").description("Authenticate with Vercel (Sign in with Vercel).").action(async () => {
1922
2002
  await runLogin();
1923
2003
  });