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 +96 -16
- package/dist/cli.js.map +1 -1
- package/dist/index.js +85 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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((
|
|
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
|
-
() =>
|
|
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((
|
|
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
|
-
|
|
609
|
+
resolve2(127);
|
|
610
610
|
});
|
|
611
|
-
child.on("exit", (code) =>
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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:
|
|
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
|
-
|
|
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(
|
|
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((
|
|
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
|
-
|
|
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.
|
|
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
|
});
|