@node9/proxy 1.28.0 → 1.29.0
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/README.md +3 -3
- package/dist/cli.js +1094 -118
- package/dist/cli.mjs +1094 -118
- package/dist/dashboard.mjs +10 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7190,6 +7190,12 @@ async function setupClaude() {
|
|
|
7190
7190
|
}
|
|
7191
7191
|
}
|
|
7192
7192
|
async function setupGemini() {
|
|
7193
|
+
console.log(
|
|
7194
|
+
import_chalk.default.yellow(
|
|
7195
|
+
" \u26A0\uFE0F Gemini CLI stops serving AI Pro/Ultra and free tiers on 2026-06-18\n (replaced by Antigravity). If you use agy, run: node9 agents add antigravity"
|
|
7196
|
+
)
|
|
7197
|
+
);
|
|
7198
|
+
console.log("");
|
|
7193
7199
|
seedMcpPinsIfMissing();
|
|
7194
7200
|
const homeDir2 = import_os12.default.homedir();
|
|
7195
7201
|
const settingsPath = import_path15.default.join(homeDir2, ".gemini", "settings.json");
|
|
@@ -7287,6 +7293,355 @@ async function setupGemini() {
|
|
|
7287
7293
|
printDaemonTip();
|
|
7288
7294
|
}
|
|
7289
7295
|
}
|
|
7296
|
+
async function setupAntigravity() {
|
|
7297
|
+
seedMcpPinsIfMissing();
|
|
7298
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7299
|
+
const hooksPath = import_path15.default.join(homeDir2, ".gemini", "config", "hooks.json");
|
|
7300
|
+
const mcpPath = import_path15.default.join(homeDir2, ".gemini", "config", "mcp_config.json");
|
|
7301
|
+
const hooksFile = readJson(hooksPath) ?? {};
|
|
7302
|
+
const mcpConfig = readJson(mcpPath) ?? {};
|
|
7303
|
+
const servers = mcpConfig.mcpServers ?? {};
|
|
7304
|
+
let hooksChanged = false;
|
|
7305
|
+
let anythingChanged = false;
|
|
7306
|
+
if (!hooksFile.hooks) hooksFile.hooks = {};
|
|
7307
|
+
const hasPreHook = hooksFile.hooks.PreToolUse?.some(
|
|
7308
|
+
(m) => m.hooks.some((h) => isNode9Hook(h.command))
|
|
7309
|
+
);
|
|
7310
|
+
if (!hasPreHook) {
|
|
7311
|
+
if (!Array.isArray(hooksFile.hooks.PreToolUse)) hooksFile.hooks.PreToolUse = [];
|
|
7312
|
+
hooksFile.hooks.PreToolUse.push({
|
|
7313
|
+
matcher: ".*",
|
|
7314
|
+
hooks: [
|
|
7315
|
+
{
|
|
7316
|
+
name: "node9-check",
|
|
7317
|
+
type: "command",
|
|
7318
|
+
command: fullPathCommand("check --agent antigravity"),
|
|
7319
|
+
timeout: 600
|
|
7320
|
+
}
|
|
7321
|
+
]
|
|
7322
|
+
});
|
|
7323
|
+
console.log(import_chalk.default.green(" \u2705 PreToolUse hook added \u2192 node9 check"));
|
|
7324
|
+
hooksChanged = true;
|
|
7325
|
+
anythingChanged = true;
|
|
7326
|
+
} else if (hooksFile.hooks.PreToolUse) {
|
|
7327
|
+
for (const matcher of hooksFile.hooks.PreToolUse) {
|
|
7328
|
+
for (const h of matcher.hooks) {
|
|
7329
|
+
const cmd = h.command ?? "";
|
|
7330
|
+
if (isNode9Hook(cmd) && needsRewrite(cmd)) {
|
|
7331
|
+
h.command = fullPathCommand("check --agent antigravity");
|
|
7332
|
+
console.log(import_chalk.default.yellow(" \u{1F527} PreToolUse hook repaired (stale path \u2192 current binary)"));
|
|
7333
|
+
hooksChanged = true;
|
|
7334
|
+
anythingChanged = true;
|
|
7335
|
+
}
|
|
7336
|
+
}
|
|
7337
|
+
}
|
|
7338
|
+
}
|
|
7339
|
+
const hasPostHook = hooksFile.hooks.PostToolUse?.some(
|
|
7340
|
+
(m) => m.hooks.some((h) => isNode9Hook(h.command))
|
|
7341
|
+
);
|
|
7342
|
+
if (!hasPostHook) {
|
|
7343
|
+
if (!Array.isArray(hooksFile.hooks.PostToolUse)) hooksFile.hooks.PostToolUse = [];
|
|
7344
|
+
hooksFile.hooks.PostToolUse.push({
|
|
7345
|
+
matcher: ".*",
|
|
7346
|
+
hooks: [
|
|
7347
|
+
{
|
|
7348
|
+
name: "node9-log",
|
|
7349
|
+
type: "command",
|
|
7350
|
+
command: fullPathCommand("log --agent antigravity"),
|
|
7351
|
+
timeout: 600
|
|
7352
|
+
}
|
|
7353
|
+
]
|
|
7354
|
+
});
|
|
7355
|
+
console.log(import_chalk.default.green(" \u2705 PostToolUse hook added \u2192 node9 log"));
|
|
7356
|
+
hooksChanged = true;
|
|
7357
|
+
anythingChanged = true;
|
|
7358
|
+
} else if (hooksFile.hooks.PostToolUse) {
|
|
7359
|
+
for (const matcher of hooksFile.hooks.PostToolUse) {
|
|
7360
|
+
for (const h of matcher.hooks) {
|
|
7361
|
+
const cmd = h.command ?? "";
|
|
7362
|
+
if (isNode9Hook(cmd) && needsRewrite(cmd)) {
|
|
7363
|
+
h.command = fullPathCommand("log --agent antigravity");
|
|
7364
|
+
console.log(import_chalk.default.yellow(" \u{1F527} PostToolUse hook repaired (stale path \u2192 current binary)"));
|
|
7365
|
+
hooksChanged = true;
|
|
7366
|
+
anythingChanged = true;
|
|
7367
|
+
}
|
|
7368
|
+
}
|
|
7369
|
+
}
|
|
7370
|
+
}
|
|
7371
|
+
if (hooksChanged) {
|
|
7372
|
+
writeJson(hooksPath, hooksFile);
|
|
7373
|
+
console.log("");
|
|
7374
|
+
}
|
|
7375
|
+
if (!hasNode9McpServer(servers)) {
|
|
7376
|
+
servers["node9"] = NODE9_MCP_SERVER_ENTRY;
|
|
7377
|
+
mcpConfig.mcpServers = servers;
|
|
7378
|
+
writeJson(mcpPath, mcpConfig);
|
|
7379
|
+
console.log(import_chalk.default.green(" \u2705 node9 MCP server added \u2192 node9 mcp-server"));
|
|
7380
|
+
anythingChanged = true;
|
|
7381
|
+
}
|
|
7382
|
+
const legacySettings = readJson(import_path15.default.join(homeDir2, ".gemini", "settings.json"));
|
|
7383
|
+
const legacyHasNode9 = ["BeforeTool", "AfterTool"].some(
|
|
7384
|
+
(ev) => legacySettings?.hooks?.[ev]?.some((m) => m.hooks.some((h) => isNode9Hook(h.command)))
|
|
7385
|
+
);
|
|
7386
|
+
if (legacyHasNode9) {
|
|
7387
|
+
console.log(
|
|
7388
|
+
import_chalk.default.yellow(
|
|
7389
|
+
" \u26A0\uFE0F Found node9 hooks for the legacy Gemini CLI in ~/.gemini/settings.json.\n Gemini CLI stops serving AI Pro/Ultra and free tiers on 2026-06-18.\n Keep them only if you still use Gemini CLI (e.g. enterprise Code Assist)."
|
|
7390
|
+
)
|
|
7391
|
+
);
|
|
7392
|
+
const clean = await (0, import_prompts.confirm)({
|
|
7393
|
+
message: "Remove the legacy Gemini CLI hooks?",
|
|
7394
|
+
default: false
|
|
7395
|
+
});
|
|
7396
|
+
if (clean) {
|
|
7397
|
+
teardownGemini();
|
|
7398
|
+
anythingChanged = true;
|
|
7399
|
+
}
|
|
7400
|
+
console.log("");
|
|
7401
|
+
}
|
|
7402
|
+
const serversToWrap = [];
|
|
7403
|
+
for (const [name, server] of Object.entries(servers)) {
|
|
7404
|
+
if (!server.command || server.command === "node9") continue;
|
|
7405
|
+
serversToWrap.push({ name, upstream: [server.command, ...server.args ?? []].join(" ") });
|
|
7406
|
+
}
|
|
7407
|
+
if (serversToWrap.length > 0) {
|
|
7408
|
+
console.log(import_chalk.default.bold("The following existing entries will be modified:\n"));
|
|
7409
|
+
console.log(import_chalk.default.white(` ${mcpPath}`));
|
|
7410
|
+
for (const { name, upstream } of serversToWrap) {
|
|
7411
|
+
console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
|
|
7412
|
+
}
|
|
7413
|
+
console.log("");
|
|
7414
|
+
const proceed = await (0, import_prompts.confirm)({ message: "Wrap these MCP servers?", default: true });
|
|
7415
|
+
if (proceed) {
|
|
7416
|
+
for (const { name, upstream } of serversToWrap) {
|
|
7417
|
+
servers[name] = {
|
|
7418
|
+
...servers[name],
|
|
7419
|
+
command: "node9",
|
|
7420
|
+
args: ["mcp", "--upstream", upstream]
|
|
7421
|
+
};
|
|
7422
|
+
}
|
|
7423
|
+
mcpConfig.mcpServers = servers;
|
|
7424
|
+
writeJson(mcpPath, mcpConfig);
|
|
7425
|
+
console.log(import_chalk.default.green(`
|
|
7426
|
+
\u2705 ${serversToWrap.length} MCP server(s) wrapped`));
|
|
7427
|
+
anythingChanged = true;
|
|
7428
|
+
} else {
|
|
7429
|
+
console.log(import_chalk.default.yellow(" Skipped MCP server wrapping."));
|
|
7430
|
+
}
|
|
7431
|
+
console.log("");
|
|
7432
|
+
}
|
|
7433
|
+
if (!anythingChanged && serversToWrap.length === 0) {
|
|
7434
|
+
console.log(import_chalk.default.blue("\u2139\uFE0F Node9 is already fully configured for Antigravity."));
|
|
7435
|
+
printDaemonTip();
|
|
7436
|
+
return;
|
|
7437
|
+
}
|
|
7438
|
+
if (anythingChanged) {
|
|
7439
|
+
console.log(import_chalk.default.green.bold("\u{1F6E1}\uFE0F Node9 is now protecting Antigravity!"));
|
|
7440
|
+
console.log(
|
|
7441
|
+
import_chalk.default.gray(
|
|
7442
|
+
" Covers both the agy CLI and the Antigravity IDE (shared ~/.gemini/config).\n Restart agy / the IDE for changes to take effect."
|
|
7443
|
+
)
|
|
7444
|
+
);
|
|
7445
|
+
printDaemonTip();
|
|
7446
|
+
}
|
|
7447
|
+
}
|
|
7448
|
+
function teardownAntigravity() {
|
|
7449
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7450
|
+
const hooksPath = import_path15.default.join(homeDir2, ".gemini", "config", "hooks.json");
|
|
7451
|
+
const mcpPath = import_path15.default.join(homeDir2, ".gemini", "config", "mcp_config.json");
|
|
7452
|
+
let changed = false;
|
|
7453
|
+
const hooksFile = readJson(hooksPath);
|
|
7454
|
+
if (hooksFile?.hooks) {
|
|
7455
|
+
for (const event of ["PreToolUse", "PostToolUse"]) {
|
|
7456
|
+
const before = hooksFile.hooks[event]?.length ?? 0;
|
|
7457
|
+
hooksFile.hooks[event] = hooksFile.hooks[event]?.filter(
|
|
7458
|
+
(m) => !m.hooks.some((h) => isNode9Hook(h.command))
|
|
7459
|
+
);
|
|
7460
|
+
if ((hooksFile.hooks[event]?.length ?? 0) < before) changed = true;
|
|
7461
|
+
if (hooksFile.hooks[event]?.length === 0) delete hooksFile.hooks[event];
|
|
7462
|
+
}
|
|
7463
|
+
if (changed) {
|
|
7464
|
+
writeJson(hooksPath, hooksFile);
|
|
7465
|
+
console.log(
|
|
7466
|
+
import_chalk.default.green(" \u2705 Removed PreToolUse / PostToolUse hooks from ~/.gemini/config/hooks.json")
|
|
7467
|
+
);
|
|
7468
|
+
} else {
|
|
7469
|
+
console.log(import_chalk.default.blue(" \u2139\uFE0F No Node9 hooks found in ~/.gemini/config/hooks.json"));
|
|
7470
|
+
}
|
|
7471
|
+
} else {
|
|
7472
|
+
console.log(import_chalk.default.blue(" \u2139\uFE0F ~/.gemini/config/hooks.json not found \u2014 nothing to remove"));
|
|
7473
|
+
}
|
|
7474
|
+
const mcpConfig = readJson(mcpPath);
|
|
7475
|
+
if (mcpConfig?.mcpServers) {
|
|
7476
|
+
let mcpChanged = false;
|
|
7477
|
+
if (removeNode9McpServer(mcpConfig.mcpServers)) {
|
|
7478
|
+
mcpChanged = true;
|
|
7479
|
+
console.log(
|
|
7480
|
+
import_chalk.default.green(" \u2705 Removed node9 MCP server entry from ~/.gemini/config/mcp_config.json")
|
|
7481
|
+
);
|
|
7482
|
+
}
|
|
7483
|
+
for (const [name, server] of Object.entries(mcpConfig.mcpServers)) {
|
|
7484
|
+
const args = server.args;
|
|
7485
|
+
if (server.command === "node9" && Array.isArray(args) && args[0] === "mcp" && args[1] === "--upstream" && typeof args[2] === "string") {
|
|
7486
|
+
const [originalCmd, ...originalArgs] = args[2].split(" ");
|
|
7487
|
+
mcpConfig.mcpServers[name] = {
|
|
7488
|
+
...server,
|
|
7489
|
+
command: originalCmd,
|
|
7490
|
+
args: originalArgs.length ? originalArgs : void 0
|
|
7491
|
+
};
|
|
7492
|
+
mcpChanged = true;
|
|
7493
|
+
}
|
|
7494
|
+
}
|
|
7495
|
+
if (mcpChanged) {
|
|
7496
|
+
writeJson(mcpPath, mcpConfig);
|
|
7497
|
+
console.log(import_chalk.default.green(" \u2705 Unwrapped MCP servers in ~/.gemini/config/mcp_config.json"));
|
|
7498
|
+
}
|
|
7499
|
+
}
|
|
7500
|
+
}
|
|
7501
|
+
async function setupCopilot() {
|
|
7502
|
+
seedMcpPinsIfMissing();
|
|
7503
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7504
|
+
const hooksPath = import_path15.default.join(homeDir2, ".copilot", "hooks", "node9.json");
|
|
7505
|
+
const mcpPath = import_path15.default.join(homeDir2, ".copilot", "mcp-config.json");
|
|
7506
|
+
const hooksFile = readJson(hooksPath) ?? { version: 1 };
|
|
7507
|
+
if (!hooksFile.version) hooksFile.version = 1;
|
|
7508
|
+
if (!hooksFile.hooks) hooksFile.hooks = {};
|
|
7509
|
+
const mcpConfig = readJson(mcpPath) ?? {};
|
|
7510
|
+
const servers = mcpConfig.mcpServers ?? {};
|
|
7511
|
+
let hooksChanged = false;
|
|
7512
|
+
let anythingChanged = false;
|
|
7513
|
+
const addHook = (event, subcommand) => {
|
|
7514
|
+
const arr = Array.isArray(hooksFile.hooks[event]) ? hooksFile.hooks[event] : [];
|
|
7515
|
+
const present = arr.some((h) => isNode9Hook(h.command));
|
|
7516
|
+
if (!present) {
|
|
7517
|
+
arr.push({ type: "command", command: fullPathCommand(subcommand), timeoutSec: 600 });
|
|
7518
|
+
hooksFile.hooks[event] = arr;
|
|
7519
|
+
console.log(import_chalk.default.green(` \u2705 ${event} hook added \u2192 node9 ${subcommand.split(" ")[0]}`));
|
|
7520
|
+
hooksChanged = true;
|
|
7521
|
+
anythingChanged = true;
|
|
7522
|
+
} else {
|
|
7523
|
+
for (const h of arr) {
|
|
7524
|
+
if (h.command && isNode9Hook(h.command) && needsRewrite(h.command)) {
|
|
7525
|
+
h.command = fullPathCommand(subcommand);
|
|
7526
|
+
console.log(import_chalk.default.yellow(` \u{1F527} ${event} hook repaired (stale path \u2192 current binary)`));
|
|
7527
|
+
hooksChanged = true;
|
|
7528
|
+
anythingChanged = true;
|
|
7529
|
+
}
|
|
7530
|
+
}
|
|
7531
|
+
}
|
|
7532
|
+
};
|
|
7533
|
+
addHook("PreToolUse", "check --agent copilot");
|
|
7534
|
+
addHook("PostToolUse", "log --agent copilot");
|
|
7535
|
+
addHook("UserPromptSubmit", "check --agent copilot");
|
|
7536
|
+
if (hooksChanged) {
|
|
7537
|
+
writeJson(hooksPath, hooksFile);
|
|
7538
|
+
console.log("");
|
|
7539
|
+
}
|
|
7540
|
+
if (!hasNode9McpServer(servers)) {
|
|
7541
|
+
servers["node9"] = NODE9_MCP_SERVER_ENTRY;
|
|
7542
|
+
mcpConfig.mcpServers = servers;
|
|
7543
|
+
writeJson(mcpPath, mcpConfig);
|
|
7544
|
+
console.log(import_chalk.default.green(" \u2705 node9 MCP server added \u2192 node9 mcp-server"));
|
|
7545
|
+
anythingChanged = true;
|
|
7546
|
+
}
|
|
7547
|
+
const serversToWrap = [];
|
|
7548
|
+
for (const [name, server] of Object.entries(servers)) {
|
|
7549
|
+
if (!server.command || server.command === "node9") continue;
|
|
7550
|
+
serversToWrap.push({ name, upstream: [server.command, ...server.args ?? []].join(" ") });
|
|
7551
|
+
}
|
|
7552
|
+
if (serversToWrap.length > 0) {
|
|
7553
|
+
console.log(import_chalk.default.bold("The following existing entries will be modified:\n"));
|
|
7554
|
+
console.log(import_chalk.default.white(` ${mcpPath}`));
|
|
7555
|
+
for (const { name, upstream } of serversToWrap) {
|
|
7556
|
+
console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
|
|
7557
|
+
}
|
|
7558
|
+
console.log("");
|
|
7559
|
+
const proceed = await (0, import_prompts.confirm)({ message: "Wrap these MCP servers?", default: true });
|
|
7560
|
+
if (proceed) {
|
|
7561
|
+
for (const { name, upstream } of serversToWrap) {
|
|
7562
|
+
servers[name] = {
|
|
7563
|
+
...servers[name],
|
|
7564
|
+
command: "node9",
|
|
7565
|
+
args: ["mcp", "--upstream", upstream]
|
|
7566
|
+
};
|
|
7567
|
+
}
|
|
7568
|
+
mcpConfig.mcpServers = servers;
|
|
7569
|
+
writeJson(mcpPath, mcpConfig);
|
|
7570
|
+
console.log(import_chalk.default.green(`
|
|
7571
|
+
\u2705 ${serversToWrap.length} MCP server(s) wrapped`));
|
|
7572
|
+
anythingChanged = true;
|
|
7573
|
+
} else {
|
|
7574
|
+
console.log(import_chalk.default.yellow(" Skipped MCP server wrapping."));
|
|
7575
|
+
}
|
|
7576
|
+
console.log("");
|
|
7577
|
+
}
|
|
7578
|
+
if (!anythingChanged) {
|
|
7579
|
+
console.log(import_chalk.default.blue("\u2139\uFE0F Node9 is already fully configured for GitHub Copilot CLI."));
|
|
7580
|
+
printDaemonTip();
|
|
7581
|
+
return;
|
|
7582
|
+
}
|
|
7583
|
+
console.log(import_chalk.default.green.bold("\u{1F6E1}\uFE0F Node9 is now protecting GitHub Copilot CLI!"));
|
|
7584
|
+
console.log(import_chalk.default.gray(" Restart Copilot CLI for changes to take effect."));
|
|
7585
|
+
printDaemonTip();
|
|
7586
|
+
}
|
|
7587
|
+
function teardownCopilot() {
|
|
7588
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7589
|
+
const hooksPath = import_path15.default.join(homeDir2, ".copilot", "hooks", "node9.json");
|
|
7590
|
+
const mcpPath = import_path15.default.join(homeDir2, ".copilot", "mcp-config.json");
|
|
7591
|
+
const hooksFile = readJson(hooksPath);
|
|
7592
|
+
let changed = false;
|
|
7593
|
+
if (hooksFile?.hooks) {
|
|
7594
|
+
for (const event of ["PreToolUse", "PostToolUse", "UserPromptSubmit"]) {
|
|
7595
|
+
const before = hooksFile.hooks[event]?.length ?? 0;
|
|
7596
|
+
hooksFile.hooks[event] = hooksFile.hooks[event]?.filter((h) => !isNode9Hook(h.command));
|
|
7597
|
+
if ((hooksFile.hooks[event]?.length ?? 0) < before) changed = true;
|
|
7598
|
+
if (hooksFile.hooks[event]?.length === 0) delete hooksFile.hooks[event];
|
|
7599
|
+
}
|
|
7600
|
+
if (changed) {
|
|
7601
|
+
if (Object.keys(hooksFile.hooks).length === 0) {
|
|
7602
|
+
try {
|
|
7603
|
+
import_fs13.default.unlinkSync(hooksPath);
|
|
7604
|
+
console.log(import_chalk.default.green(" \u2705 Removed ~/.copilot/hooks/node9.json"));
|
|
7605
|
+
} catch {
|
|
7606
|
+
writeJson(hooksPath, hooksFile);
|
|
7607
|
+
}
|
|
7608
|
+
} else {
|
|
7609
|
+
writeJson(hooksPath, hooksFile);
|
|
7610
|
+
console.log(import_chalk.default.green(" \u2705 Removed Node9 hooks from ~/.copilot/hooks/node9.json"));
|
|
7611
|
+
}
|
|
7612
|
+
} else {
|
|
7613
|
+
console.log(import_chalk.default.blue(" \u2139\uFE0F No Node9 hooks found in ~/.copilot/hooks/node9.json"));
|
|
7614
|
+
}
|
|
7615
|
+
} else {
|
|
7616
|
+
console.log(import_chalk.default.blue(" \u2139\uFE0F ~/.copilot/hooks/node9.json not found \u2014 nothing to remove"));
|
|
7617
|
+
}
|
|
7618
|
+
const mcpConfig = readJson(mcpPath);
|
|
7619
|
+
if (mcpConfig?.mcpServers) {
|
|
7620
|
+
let mcpChanged = false;
|
|
7621
|
+
if (removeNode9McpServer(mcpConfig.mcpServers)) {
|
|
7622
|
+
mcpChanged = true;
|
|
7623
|
+
console.log(
|
|
7624
|
+
import_chalk.default.green(" \u2705 Removed node9 MCP server entry from ~/.copilot/mcp-config.json")
|
|
7625
|
+
);
|
|
7626
|
+
}
|
|
7627
|
+
for (const [name, server] of Object.entries(mcpConfig.mcpServers)) {
|
|
7628
|
+
const args = server.args;
|
|
7629
|
+
if (server.command === "node9" && Array.isArray(args) && args[0] === "mcp" && args[1] === "--upstream" && typeof args[2] === "string") {
|
|
7630
|
+
const [originalCmd, ...originalArgs] = args[2].split(" ");
|
|
7631
|
+
mcpConfig.mcpServers[name] = {
|
|
7632
|
+
...server,
|
|
7633
|
+
command: originalCmd,
|
|
7634
|
+
args: originalArgs.length ? originalArgs : void 0
|
|
7635
|
+
};
|
|
7636
|
+
mcpChanged = true;
|
|
7637
|
+
}
|
|
7638
|
+
}
|
|
7639
|
+
if (mcpChanged) {
|
|
7640
|
+
writeJson(mcpPath, mcpConfig);
|
|
7641
|
+
console.log(import_chalk.default.green(" \u2705 Unwrapped MCP servers in ~/.copilot/mcp-config.json"));
|
|
7642
|
+
}
|
|
7643
|
+
}
|
|
7644
|
+
}
|
|
7290
7645
|
function claudeDesktopConfigPath(homeDir2 = import_os12.default.homedir()) {
|
|
7291
7646
|
if (process.platform === "darwin") {
|
|
7292
7647
|
return import_path15.default.join(
|
|
@@ -7334,7 +7689,23 @@ function detectAgents(homeDir2 = import_os12.default.homedir()) {
|
|
|
7334
7689
|
const desktopPath = claudeDesktopConfigPath(homeDir2);
|
|
7335
7690
|
return {
|
|
7336
7691
|
claude: exists(import_path15.default.join(homeDir2, ".claude")) || exists(import_path15.default.join(homeDir2, ".claude.json")),
|
|
7337
|
-
|
|
7692
|
+
// Antigravity (agy) shares the ~/.gemini root, so a bare
|
|
7693
|
+
// `exists(~/.gemini)` would report the (EOL'd) Gemini CLI as
|
|
7694
|
+
// installed on every agy machine — and `node9 init` would then
|
|
7695
|
+
// write BeforeTool hooks into settings.json, a file agy ignores,
|
|
7696
|
+
// while reporting the machine protected (silent protection gap,
|
|
7697
|
+
// verified live on a machine with both installed). Gemini CLI
|
|
7698
|
+
// creates ~/.gemini/settings.json on first run; agy does not touch
|
|
7699
|
+
// it (it uses antigravity-cli/settings.json) — that file is the
|
|
7700
|
+
// legacy-CLI discriminator.
|
|
7701
|
+
gemini: exists(import_path15.default.join(homeDir2, ".gemini", "settings.json")) || binaryInPath("gemini"),
|
|
7702
|
+
// agy creates ~/.gemini/antigravity-cli/ on first launch; the IDE
|
|
7703
|
+
// creates antigravity-ide/. PATH fallback covers installed-but-
|
|
7704
|
+
// never-launched (same class as opencode #186).
|
|
7705
|
+
antigravity: exists(import_path15.default.join(homeDir2, ".gemini", "antigravity-cli")) || exists(import_path15.default.join(homeDir2, ".gemini", "antigravity-ide")) || binaryInPath("agy"),
|
|
7706
|
+
// GitHub Copilot CLI creates ~/.copilot on first launch; PATH
|
|
7707
|
+
// fallback covers installed-but-never-launched (same as opencode #186).
|
|
7708
|
+
copilot: exists(import_path15.default.join(homeDir2, ".copilot")) || binaryInPath("copilot"),
|
|
7338
7709
|
cursor: exists(import_path15.default.join(homeDir2, ".cursor")),
|
|
7339
7710
|
codex: exists(import_path15.default.join(homeDir2, ".codex")),
|
|
7340
7711
|
windsurf: exists(import_path15.default.join(homeDir2, ".codeium", "windsurf")),
|
|
@@ -8335,6 +8706,18 @@ function getAgentsStatus(homeDir2 = import_os12.default.homedir()) {
|
|
|
8335
8706
|
const settings = readJson(import_path15.default.join(homeDir2, ".gemini", "settings.json"));
|
|
8336
8707
|
return !!settings?.hooks?.BeforeTool?.some((m) => m.hooks.some((h) => isNode9Hook(h.command)));
|
|
8337
8708
|
})();
|
|
8709
|
+
const antigravityWired = (() => {
|
|
8710
|
+
const hooksFile = readJson(
|
|
8711
|
+
import_path15.default.join(homeDir2, ".gemini", "config", "hooks.json")
|
|
8712
|
+
);
|
|
8713
|
+
return !!hooksFile?.hooks?.PreToolUse?.some((m) => m.hooks.some((h) => isNode9Hook(h.command)));
|
|
8714
|
+
})();
|
|
8715
|
+
const copilotWired = (() => {
|
|
8716
|
+
const hooksFile = readJson(
|
|
8717
|
+
import_path15.default.join(homeDir2, ".copilot", "hooks", "node9.json")
|
|
8718
|
+
);
|
|
8719
|
+
return !!hooksFile?.hooks?.PreToolUse?.some((h) => isNode9Hook(h.command));
|
|
8720
|
+
})();
|
|
8338
8721
|
const cursorWired = (() => {
|
|
8339
8722
|
const cfg = readJson(import_path15.default.join(homeDir2, ".cursor", "mcp.json"));
|
|
8340
8723
|
return !!(cfg?.mcpServers && hasNode9McpServer(cfg.mcpServers));
|
|
@@ -8368,6 +8751,20 @@ function getAgentsStatus(homeDir2 = import_os12.default.homedir()) {
|
|
|
8368
8751
|
wired: geminiWired,
|
|
8369
8752
|
mode: detected.gemini ? "hooks" : null
|
|
8370
8753
|
},
|
|
8754
|
+
{
|
|
8755
|
+
name: "antigravity",
|
|
8756
|
+
label: "Antigravity",
|
|
8757
|
+
installed: detected.antigravity,
|
|
8758
|
+
wired: antigravityWired,
|
|
8759
|
+
mode: detected.antigravity ? "hooks" : null
|
|
8760
|
+
},
|
|
8761
|
+
{
|
|
8762
|
+
name: "copilot",
|
|
8763
|
+
label: "GitHub Copilot",
|
|
8764
|
+
installed: detected.copilot,
|
|
8765
|
+
wired: copilotWired,
|
|
8766
|
+
mode: detected.copilot ? "hooks" : null
|
|
8767
|
+
},
|
|
8371
8768
|
{
|
|
8372
8769
|
name: "cursor",
|
|
8373
8770
|
label: "Cursor",
|
|
@@ -8485,7 +8882,84 @@ var init_setup = __esm({
|
|
|
8485
8882
|
}
|
|
8486
8883
|
});
|
|
8487
8884
|
|
|
8885
|
+
// src/utils/hook-payload.ts
|
|
8886
|
+
function extractToolName(payload, defaultValue = "") {
|
|
8887
|
+
return payload.tool_name ?? payload.name ?? payload.toolCall?.name ?? defaultValue;
|
|
8888
|
+
}
|
|
8889
|
+
function extractToolInput(payload) {
|
|
8890
|
+
return payload.tool_input ?? payload.args ?? payload.toolCall?.args ?? {};
|
|
8891
|
+
}
|
|
8892
|
+
function canonicalToolName(name) {
|
|
8893
|
+
switch (name) {
|
|
8894
|
+
// Hermes Agent
|
|
8895
|
+
case "terminal":
|
|
8896
|
+
return "Bash";
|
|
8897
|
+
case "write_file":
|
|
8898
|
+
return "Write";
|
|
8899
|
+
case "patch":
|
|
8900
|
+
return "Edit";
|
|
8901
|
+
case "read_file":
|
|
8902
|
+
return "Read";
|
|
8903
|
+
case "search_files":
|
|
8904
|
+
return "Grep";
|
|
8905
|
+
// Antigravity (agy) — shell tool renamed from Gemini's run_shell_command
|
|
8906
|
+
case "run_command":
|
|
8907
|
+
return "Bash";
|
|
8908
|
+
default:
|
|
8909
|
+
return name;
|
|
8910
|
+
}
|
|
8911
|
+
}
|
|
8912
|
+
function agentLabelFromFlag(flag) {
|
|
8913
|
+
if (typeof flag !== "string") return void 0;
|
|
8914
|
+
switch (flag.toLowerCase()) {
|
|
8915
|
+
case "antigravity":
|
|
8916
|
+
case "agy":
|
|
8917
|
+
return "Antigravity";
|
|
8918
|
+
case "copilot":
|
|
8919
|
+
return "GitHub Copilot";
|
|
8920
|
+
default:
|
|
8921
|
+
return void 0;
|
|
8922
|
+
}
|
|
8923
|
+
}
|
|
8924
|
+
function canonicalToolInput(rawToolName, input) {
|
|
8925
|
+
if (rawToolName !== "run_command") return input;
|
|
8926
|
+
if (typeof input !== "object" || input === null || Array.isArray(input)) return input;
|
|
8927
|
+
const args = input;
|
|
8928
|
+
if (typeof args.CommandLine !== "string") return input;
|
|
8929
|
+
const { CommandLine, Cwd, ...rest } = args;
|
|
8930
|
+
const canonical = { ...rest, command: CommandLine };
|
|
8931
|
+
if (typeof Cwd === "string" && Cwd.length > 0) canonical.cwd = Cwd;
|
|
8932
|
+
return canonical;
|
|
8933
|
+
}
|
|
8934
|
+
var init_hook_payload = __esm({
|
|
8935
|
+
"src/utils/hook-payload.ts"() {
|
|
8936
|
+
"use strict";
|
|
8937
|
+
}
|
|
8938
|
+
});
|
|
8939
|
+
|
|
8488
8940
|
// src/scan-summary.ts
|
|
8941
|
+
function agentDisplayName(agent) {
|
|
8942
|
+
return AGENT_LONG[agent] ?? "Claude Code";
|
|
8943
|
+
}
|
|
8944
|
+
function agentBadgeText(agent, width = 10) {
|
|
8945
|
+
return `[${AGENT_SHORT[agent] ?? "Claude"}]`.padEnd(width);
|
|
8946
|
+
}
|
|
8947
|
+
function agentColorName(agent) {
|
|
8948
|
+
switch (agent) {
|
|
8949
|
+
case "gemini":
|
|
8950
|
+
return "blue";
|
|
8951
|
+
case "codex":
|
|
8952
|
+
return "magenta";
|
|
8953
|
+
case "antigravity":
|
|
8954
|
+
return "yellow";
|
|
8955
|
+
case "copilot":
|
|
8956
|
+
return "green";
|
|
8957
|
+
case "shell":
|
|
8958
|
+
return "yellow";
|
|
8959
|
+
default:
|
|
8960
|
+
return "cyan";
|
|
8961
|
+
}
|
|
8962
|
+
}
|
|
8489
8963
|
function buildScanSummary(agents) {
|
|
8490
8964
|
const stats = {
|
|
8491
8965
|
sessions: 0,
|
|
@@ -8662,12 +9136,29 @@ function fullCommandOf(input) {
|
|
|
8662
9136
|
const raw = input.command ?? input.query ?? input.file_path ?? JSON.stringify(input);
|
|
8663
9137
|
return String(raw).replace(/\s+/g, " ").trim();
|
|
8664
9138
|
}
|
|
9139
|
+
var AGENT_SHORT, AGENT_LONG;
|
|
8665
9140
|
var init_scan_summary = __esm({
|
|
8666
9141
|
"src/scan-summary.ts"() {
|
|
8667
9142
|
"use strict";
|
|
8668
9143
|
init_shields();
|
|
8669
9144
|
init_dist();
|
|
8670
9145
|
init_dist();
|
|
9146
|
+
AGENT_SHORT = {
|
|
9147
|
+
claude: "Claude",
|
|
9148
|
+
gemini: "Gemini",
|
|
9149
|
+
codex: "Codex",
|
|
9150
|
+
antigravity: "Agy",
|
|
9151
|
+
copilot: "Copilot",
|
|
9152
|
+
shell: "Shell"
|
|
9153
|
+
};
|
|
9154
|
+
AGENT_LONG = {
|
|
9155
|
+
claude: "Claude Code",
|
|
9156
|
+
gemini: "Gemini CLI",
|
|
9157
|
+
codex: "Codex",
|
|
9158
|
+
antigravity: "Antigravity",
|
|
9159
|
+
copilot: "GitHub Copilot",
|
|
9160
|
+
shell: "Shell"
|
|
9161
|
+
};
|
|
8671
9162
|
}
|
|
8672
9163
|
});
|
|
8673
9164
|
|
|
@@ -10308,6 +10799,34 @@ function countScanFiles() {
|
|
|
10308
10799
|
} catch {
|
|
10309
10800
|
}
|
|
10310
10801
|
}
|
|
10802
|
+
for (const surface of ["antigravity-cli", "antigravity-ide"]) {
|
|
10803
|
+
const brainDir = import_path22.default.join(import_os19.default.homedir(), ".gemini", surface, "brain");
|
|
10804
|
+
if (!import_fs20.default.existsSync(brainDir)) continue;
|
|
10805
|
+
try {
|
|
10806
|
+
for (const conv of import_fs20.default.readdirSync(brainDir)) {
|
|
10807
|
+
const convPath = import_path22.default.join(brainDir, conv);
|
|
10808
|
+
try {
|
|
10809
|
+
if (!import_fs20.default.statSync(convPath).isDirectory()) continue;
|
|
10810
|
+
const logsDir = import_path22.default.join(convPath, ".system_generated", "logs");
|
|
10811
|
+
if (import_fs20.default.existsSync(import_path22.default.join(logsDir, "transcript_full.jsonl")) || import_fs20.default.existsSync(import_path22.default.join(logsDir, "transcript.jsonl"))) {
|
|
10812
|
+
total += 1;
|
|
10813
|
+
}
|
|
10814
|
+
} catch {
|
|
10815
|
+
continue;
|
|
10816
|
+
}
|
|
10817
|
+
}
|
|
10818
|
+
} catch {
|
|
10819
|
+
}
|
|
10820
|
+
}
|
|
10821
|
+
const copilotDir = import_path22.default.join(import_os19.default.homedir(), ".copilot", "session-state");
|
|
10822
|
+
if (import_fs20.default.existsSync(copilotDir)) {
|
|
10823
|
+
try {
|
|
10824
|
+
for (const sid of import_fs20.default.readdirSync(copilotDir)) {
|
|
10825
|
+
if (import_fs20.default.existsSync(import_path22.default.join(copilotDir, sid, "events.jsonl"))) total += 1;
|
|
10826
|
+
}
|
|
10827
|
+
} catch {
|
|
10828
|
+
}
|
|
10829
|
+
}
|
|
10311
10830
|
const codexDir = import_path22.default.join(import_os19.default.homedir(), ".codex", "sessions");
|
|
10312
10831
|
if (import_fs20.default.existsSync(codexDir)) {
|
|
10313
10832
|
try {
|
|
@@ -10678,33 +11197,248 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
10678
11197
|
if (!import_fs20.default.existsSync(chatsDir)) continue;
|
|
10679
11198
|
let chatFiles;
|
|
10680
11199
|
try {
|
|
10681
|
-
chatFiles = import_fs20.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
11200
|
+
chatFiles = import_fs20.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
11201
|
+
} catch {
|
|
11202
|
+
continue;
|
|
11203
|
+
}
|
|
11204
|
+
for (const chatFile of chatFiles) {
|
|
11205
|
+
result.filesScanned++;
|
|
11206
|
+
onProgress?.(result.filesScanned);
|
|
11207
|
+
const sessionId = chatFile.replace(/\.json$/, "");
|
|
11208
|
+
let raw;
|
|
11209
|
+
try {
|
|
11210
|
+
raw = import_fs20.default.readFileSync(import_path22.default.join(chatsDir, chatFile), "utf-8");
|
|
11211
|
+
} catch {
|
|
11212
|
+
continue;
|
|
11213
|
+
}
|
|
11214
|
+
const sessionCalls = [];
|
|
11215
|
+
let session;
|
|
11216
|
+
try {
|
|
11217
|
+
session = JSON.parse(raw);
|
|
11218
|
+
} catch {
|
|
11219
|
+
continue;
|
|
11220
|
+
}
|
|
11221
|
+
result.sessions++;
|
|
11222
|
+
for (const msg of session.messages ?? []) {
|
|
11223
|
+
onLine?.();
|
|
11224
|
+
if (msg.type === "user") {
|
|
11225
|
+
const content = msg.content;
|
|
11226
|
+
const text = Array.isArray(content) ? content.map((c) => c.text ?? "").join("\n") : typeof content === "string" ? content : "";
|
|
11227
|
+
if (text) {
|
|
11228
|
+
const dlpMatch = scanArgs({ text });
|
|
11229
|
+
if (dlpMatch) {
|
|
11230
|
+
const k = dlpKey(dlpMatch.patternName, dlpMatch.redactedSample, projLabel);
|
|
11231
|
+
if (!dedup.dlpKeys.has(k)) {
|
|
11232
|
+
dedup.dlpKeys.add(k);
|
|
11233
|
+
result.dlpFindings.push({
|
|
11234
|
+
patternName: dlpMatch.patternName,
|
|
11235
|
+
redactedSample: dlpMatch.redactedSample,
|
|
11236
|
+
toolName: "user-prompt",
|
|
11237
|
+
timestamp: msg.timestamp ?? "",
|
|
11238
|
+
project: projLabel,
|
|
11239
|
+
sessionId,
|
|
11240
|
+
agent: "gemini"
|
|
11241
|
+
});
|
|
11242
|
+
}
|
|
11243
|
+
}
|
|
11244
|
+
}
|
|
11245
|
+
continue;
|
|
11246
|
+
}
|
|
11247
|
+
if (msg.type !== "gemini") continue;
|
|
11248
|
+
if (startDate && msg.timestamp && new Date(msg.timestamp) < startDate) continue;
|
|
11249
|
+
if (msg.timestamp) {
|
|
11250
|
+
if (!result.firstDate || msg.timestamp < result.firstDate)
|
|
11251
|
+
result.firstDate = msg.timestamp;
|
|
11252
|
+
if (!result.lastDate || msg.timestamp > result.lastDate) result.lastDate = msg.timestamp;
|
|
11253
|
+
}
|
|
11254
|
+
const tokens = msg.tokens;
|
|
11255
|
+
const model = msg.model;
|
|
11256
|
+
if (tokens && model) {
|
|
11257
|
+
const p = geminiModelPrice(model);
|
|
11258
|
+
if (p) {
|
|
11259
|
+
const nonCached = Math.max(0, tokens.input - tokens.cached);
|
|
11260
|
+
result.totalCostUSD += nonCached * p.i + tokens.cached * p.cr + tokens.output * p.o;
|
|
11261
|
+
}
|
|
11262
|
+
}
|
|
11263
|
+
for (const tc of msg.toolCalls ?? []) {
|
|
11264
|
+
result.totalToolCalls++;
|
|
11265
|
+
const toolName = tc.name ?? "";
|
|
11266
|
+
const toolNameLower = toolName.toLowerCase();
|
|
11267
|
+
const input = tc.args ?? {};
|
|
11268
|
+
sessionCalls.push({ toolName, input, timestamp: msg.timestamp ?? "" });
|
|
11269
|
+
if (toolNameLower === "run_shell_command" || toolNameLower === "shell") {
|
|
11270
|
+
result.bashCalls++;
|
|
11271
|
+
}
|
|
11272
|
+
const rawCmd = String(input.command ?? "").trimStart();
|
|
11273
|
+
if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd))
|
|
11274
|
+
continue;
|
|
11275
|
+
const dlpMatch = scanArgs(input);
|
|
11276
|
+
if (dlpMatch) {
|
|
11277
|
+
const k = dlpKey(dlpMatch.patternName, dlpMatch.redactedSample, projLabel);
|
|
11278
|
+
if (!dedup.dlpKeys.has(k)) {
|
|
11279
|
+
dedup.dlpKeys.add(k);
|
|
11280
|
+
result.dlpFindings.push({
|
|
11281
|
+
patternName: dlpMatch.patternName,
|
|
11282
|
+
redactedSample: dlpMatch.redactedSample,
|
|
11283
|
+
toolName,
|
|
11284
|
+
timestamp: msg.timestamp ?? "",
|
|
11285
|
+
project: projLabel,
|
|
11286
|
+
sessionId,
|
|
11287
|
+
agent: "gemini"
|
|
11288
|
+
});
|
|
11289
|
+
}
|
|
11290
|
+
}
|
|
11291
|
+
let astFsMatched = false;
|
|
11292
|
+
const astRanForBash = toolNameLower === "run_shell_command" || toolNameLower === "shell";
|
|
11293
|
+
if (astRanForBash) {
|
|
11294
|
+
astFsMatched = pushFsOpAstFinding(
|
|
11295
|
+
String(input.command ?? ""),
|
|
11296
|
+
toolName,
|
|
11297
|
+
input,
|
|
11298
|
+
msg.timestamp ?? "",
|
|
11299
|
+
projLabel,
|
|
11300
|
+
sessionId,
|
|
11301
|
+
"gemini",
|
|
11302
|
+
result,
|
|
11303
|
+
dedup
|
|
11304
|
+
);
|
|
11305
|
+
}
|
|
11306
|
+
let ruleMatched = astFsMatched;
|
|
11307
|
+
for (const source of ruleSources) {
|
|
11308
|
+
const { rule } = source;
|
|
11309
|
+
if (rule.verdict === "allow") continue;
|
|
11310
|
+
if (rule.tool && !matchesPattern(toolNameLower, rule.tool)) continue;
|
|
11311
|
+
if (astRanForBash && rule.name && AST_FS_REGEX_RULES.has(rule.name)) continue;
|
|
11312
|
+
if (!evaluateSmartConditions(input, rule)) continue;
|
|
11313
|
+
const inputPreview = preview(input, 120);
|
|
11314
|
+
const k = findingKey(rule.name, inputPreview, projLabel);
|
|
11315
|
+
if (!dedup.findingsKeys.has(k)) {
|
|
11316
|
+
dedup.findingsKeys.add(k);
|
|
11317
|
+
result.findings.push({
|
|
11318
|
+
source,
|
|
11319
|
+
toolName,
|
|
11320
|
+
input,
|
|
11321
|
+
timestamp: msg.timestamp ?? "",
|
|
11322
|
+
project: projLabel,
|
|
11323
|
+
sessionId,
|
|
11324
|
+
agent: "gemini"
|
|
11325
|
+
});
|
|
11326
|
+
}
|
|
11327
|
+
ruleMatched = true;
|
|
11328
|
+
break;
|
|
11329
|
+
}
|
|
11330
|
+
const isShellTool = ["bash", "execute_bash", "run_shell_command", "shell"].includes(
|
|
11331
|
+
toolNameLower
|
|
11332
|
+
);
|
|
11333
|
+
if (!ruleMatched && isShellTool) {
|
|
11334
|
+
const shellVerdict = detectDangerousShellExec(String(input.command ?? ""));
|
|
11335
|
+
if (shellVerdict) {
|
|
11336
|
+
const astRule = {
|
|
11337
|
+
name: `ast:bash-safe:${shellVerdict}-shell-exec-remote`,
|
|
11338
|
+
tool: "bash",
|
|
11339
|
+
conditions: [],
|
|
11340
|
+
verdict: shellVerdict,
|
|
11341
|
+
reason: `Shell execution of remote download detected by AST analysis (bash-safe)`
|
|
11342
|
+
};
|
|
11343
|
+
const inputPreview = preview(input, 120);
|
|
11344
|
+
const k = findingKey(astRule.name, inputPreview, projLabel);
|
|
11345
|
+
if (!dedup.findingsKeys.has(k)) {
|
|
11346
|
+
dedup.findingsKeys.add(k);
|
|
11347
|
+
result.findings.push({
|
|
11348
|
+
source: {
|
|
11349
|
+
shieldName: "bash-safe",
|
|
11350
|
+
shieldLabel: "bash-safe (AST)",
|
|
11351
|
+
sourceType: "shield",
|
|
11352
|
+
rule: astRule
|
|
11353
|
+
},
|
|
11354
|
+
toolName,
|
|
11355
|
+
input,
|
|
11356
|
+
timestamp: msg.timestamp ?? "",
|
|
11357
|
+
project: projLabel,
|
|
11358
|
+
sessionId,
|
|
11359
|
+
agent: "gemini"
|
|
11360
|
+
});
|
|
11361
|
+
}
|
|
11362
|
+
}
|
|
11363
|
+
}
|
|
11364
|
+
}
|
|
11365
|
+
}
|
|
11366
|
+
result.loopFindings.push(...detectLoops(sessionCalls, projLabel, sessionId, "gemini"));
|
|
11367
|
+
}
|
|
11368
|
+
}
|
|
11369
|
+
return result;
|
|
11370
|
+
}
|
|
11371
|
+
function antigravityBrainDirs() {
|
|
11372
|
+
return ["antigravity-cli", "antigravity-ide"].map((surface) => import_path22.default.join(import_os19.default.homedir(), ".gemini", surface, "brain")).filter((p) => import_fs20.default.existsSync(p));
|
|
11373
|
+
}
|
|
11374
|
+
function antigravityTranscriptPath(convPath) {
|
|
11375
|
+
const logsDir = import_path22.default.join(convPath, ".system_generated", "logs");
|
|
11376
|
+
for (const name of ["transcript_full.jsonl", "transcript.jsonl"]) {
|
|
11377
|
+
const p = import_path22.default.join(logsDir, name);
|
|
11378
|
+
if (import_fs20.default.existsSync(p)) return p;
|
|
11379
|
+
}
|
|
11380
|
+
return null;
|
|
11381
|
+
}
|
|
11382
|
+
function scanAntigravityHistory(startDate, onProgress, onLine) {
|
|
11383
|
+
const result = {
|
|
11384
|
+
filesScanned: 0,
|
|
11385
|
+
sessions: 0,
|
|
11386
|
+
totalToolCalls: 0,
|
|
11387
|
+
bashCalls: 0,
|
|
11388
|
+
findings: [],
|
|
11389
|
+
dlpFindings: [],
|
|
11390
|
+
loopFindings: [],
|
|
11391
|
+
totalCostUSD: 0,
|
|
11392
|
+
// transcripts carry no token/model data
|
|
11393
|
+
firstDate: null,
|
|
11394
|
+
lastDate: null,
|
|
11395
|
+
sessionsWithEarlySecrets: 0
|
|
11396
|
+
};
|
|
11397
|
+
const dedup = emptyScanDedup();
|
|
11398
|
+
const brainDirs = antigravityBrainDirs();
|
|
11399
|
+
if (brainDirs.length === 0) return result;
|
|
11400
|
+
const ruleSources = buildRuleSources();
|
|
11401
|
+
for (const brainDir of brainDirs) {
|
|
11402
|
+
let convDirs;
|
|
11403
|
+
try {
|
|
11404
|
+
convDirs = import_fs20.default.readdirSync(brainDir);
|
|
10682
11405
|
} catch {
|
|
10683
11406
|
continue;
|
|
10684
11407
|
}
|
|
10685
|
-
for (const
|
|
10686
|
-
|
|
10687
|
-
onProgress?.(result.filesScanned);
|
|
10688
|
-
const sessionId = chatFile.replace(/\.json$/, "");
|
|
10689
|
-
let raw;
|
|
11408
|
+
for (const conv of convDirs) {
|
|
11409
|
+
const convPath = import_path22.default.join(brainDir, conv);
|
|
10690
11410
|
try {
|
|
10691
|
-
|
|
11411
|
+
if (!import_fs20.default.statSync(convPath).isDirectory()) continue;
|
|
10692
11412
|
} catch {
|
|
10693
11413
|
continue;
|
|
10694
11414
|
}
|
|
10695
|
-
const
|
|
10696
|
-
|
|
11415
|
+
const transcriptFile = antigravityTranscriptPath(convPath);
|
|
11416
|
+
if (!transcriptFile) continue;
|
|
11417
|
+
result.filesScanned++;
|
|
11418
|
+
onProgress?.(result.filesScanned);
|
|
11419
|
+
let raw;
|
|
10697
11420
|
try {
|
|
10698
|
-
|
|
11421
|
+
raw = import_fs20.default.readFileSync(transcriptFile, "utf-8");
|
|
10699
11422
|
} catch {
|
|
10700
11423
|
continue;
|
|
10701
11424
|
}
|
|
11425
|
+
const sessionId = conv;
|
|
11426
|
+
let projLabel = conv.slice(0, 8);
|
|
11427
|
+
const sessionCalls = [];
|
|
10702
11428
|
result.sessions++;
|
|
10703
|
-
for (const
|
|
11429
|
+
for (const line of raw.split("\n")) {
|
|
11430
|
+
if (!line.trim()) continue;
|
|
10704
11431
|
onLine?.();
|
|
10705
|
-
|
|
10706
|
-
|
|
10707
|
-
|
|
11432
|
+
let step;
|
|
11433
|
+
try {
|
|
11434
|
+
step = JSON.parse(line);
|
|
11435
|
+
} catch {
|
|
11436
|
+
continue;
|
|
11437
|
+
}
|
|
11438
|
+
const timestamp = step.created_at ?? "";
|
|
11439
|
+
if (startDate && timestamp && new Date(timestamp) < startDate) continue;
|
|
11440
|
+
if (step.type === "USER_INPUT") {
|
|
11441
|
+
const text = typeof step.content === "string" ? step.content : "";
|
|
10708
11442
|
if (text) {
|
|
10709
11443
|
const dlpMatch = scanArgs({ text });
|
|
10710
11444
|
if (dlpMatch) {
|
|
@@ -10715,40 +11449,34 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
10715
11449
|
patternName: dlpMatch.patternName,
|
|
10716
11450
|
redactedSample: dlpMatch.redactedSample,
|
|
10717
11451
|
toolName: "user-prompt",
|
|
10718
|
-
timestamp
|
|
11452
|
+
timestamp,
|
|
10719
11453
|
project: projLabel,
|
|
10720
11454
|
sessionId,
|
|
10721
|
-
agent: "
|
|
11455
|
+
agent: "antigravity"
|
|
10722
11456
|
});
|
|
10723
11457
|
}
|
|
10724
11458
|
}
|
|
10725
11459
|
}
|
|
10726
11460
|
continue;
|
|
10727
11461
|
}
|
|
10728
|
-
if (
|
|
10729
|
-
if (
|
|
10730
|
-
|
|
10731
|
-
if (!result.
|
|
10732
|
-
result.firstDate = msg.timestamp;
|
|
10733
|
-
if (!result.lastDate || msg.timestamp > result.lastDate) result.lastDate = msg.timestamp;
|
|
10734
|
-
}
|
|
10735
|
-
const tokens = msg.tokens;
|
|
10736
|
-
const model = msg.model;
|
|
10737
|
-
if (tokens && model) {
|
|
10738
|
-
const p = geminiModelPrice(model);
|
|
10739
|
-
if (p) {
|
|
10740
|
-
const nonCached = Math.max(0, tokens.input - tokens.cached);
|
|
10741
|
-
result.totalCostUSD += nonCached * p.i + tokens.cached * p.cr + tokens.output * p.o;
|
|
10742
|
-
}
|
|
11462
|
+
if (!Array.isArray(step.tool_calls) || step.tool_calls.length === 0) continue;
|
|
11463
|
+
if (timestamp) {
|
|
11464
|
+
if (!result.firstDate || timestamp < result.firstDate) result.firstDate = timestamp;
|
|
11465
|
+
if (!result.lastDate || timestamp > result.lastDate) result.lastDate = timestamp;
|
|
10743
11466
|
}
|
|
10744
|
-
for (const tc of
|
|
11467
|
+
for (const tc of step.tool_calls) {
|
|
10745
11468
|
result.totalToolCalls++;
|
|
10746
11469
|
const toolName = tc.name ?? "";
|
|
10747
11470
|
const toolNameLower = toolName.toLowerCase();
|
|
10748
|
-
const input = tc.args ?? {};
|
|
10749
|
-
sessionCalls.push({ toolName, input, timestamp
|
|
10750
|
-
|
|
11471
|
+
const input = canonicalToolInput(toolName, tc.args ?? {});
|
|
11472
|
+
sessionCalls.push({ toolName, input, timestamp });
|
|
11473
|
+
const isShellTool = toolNameLower === "run_command";
|
|
11474
|
+
if (isShellTool) {
|
|
10751
11475
|
result.bashCalls++;
|
|
11476
|
+
const cwd = String(input.cwd ?? "");
|
|
11477
|
+
if (cwd && projLabel === conv.slice(0, 8)) {
|
|
11478
|
+
projLabel = stripTerminalEscapes(cwd).replace(import_os19.default.homedir(), "~").slice(0, 40);
|
|
11479
|
+
}
|
|
10752
11480
|
}
|
|
10753
11481
|
const rawCmd = String(input.command ?? "").trimStart();
|
|
10754
11482
|
if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd))
|
|
@@ -10762,24 +11490,23 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
10762
11490
|
patternName: dlpMatch.patternName,
|
|
10763
11491
|
redactedSample: dlpMatch.redactedSample,
|
|
10764
11492
|
toolName,
|
|
10765
|
-
timestamp
|
|
11493
|
+
timestamp,
|
|
10766
11494
|
project: projLabel,
|
|
10767
11495
|
sessionId,
|
|
10768
|
-
agent: "
|
|
11496
|
+
agent: "antigravity"
|
|
10769
11497
|
});
|
|
10770
11498
|
}
|
|
10771
11499
|
}
|
|
10772
11500
|
let astFsMatched = false;
|
|
10773
|
-
|
|
10774
|
-
if (astRanForBash) {
|
|
11501
|
+
if (isShellTool) {
|
|
10775
11502
|
astFsMatched = pushFsOpAstFinding(
|
|
10776
11503
|
String(input.command ?? ""),
|
|
10777
11504
|
toolName,
|
|
10778
11505
|
input,
|
|
10779
|
-
|
|
11506
|
+
timestamp,
|
|
10780
11507
|
projLabel,
|
|
10781
11508
|
sessionId,
|
|
10782
|
-
"
|
|
11509
|
+
"antigravity",
|
|
10783
11510
|
result,
|
|
10784
11511
|
dedup
|
|
10785
11512
|
);
|
|
@@ -10788,8 +11515,9 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
10788
11515
|
for (const source of ruleSources) {
|
|
10789
11516
|
const { rule } = source;
|
|
10790
11517
|
if (rule.verdict === "allow") continue;
|
|
10791
|
-
|
|
10792
|
-
if (
|
|
11518
|
+
const ruleToolName = isShellTool ? "bash" : toolNameLower;
|
|
11519
|
+
if (rule.tool && !matchesPattern(ruleToolName, rule.tool)) continue;
|
|
11520
|
+
if (isShellTool && rule.name && AST_FS_REGEX_RULES.has(rule.name)) continue;
|
|
10793
11521
|
if (!evaluateSmartConditions(input, rule)) continue;
|
|
10794
11522
|
const inputPreview = preview(input, 120);
|
|
10795
11523
|
const k = findingKey(rule.name, inputPreview, projLabel);
|
|
@@ -10799,18 +11527,15 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
10799
11527
|
source,
|
|
10800
11528
|
toolName,
|
|
10801
11529
|
input,
|
|
10802
|
-
timestamp
|
|
11530
|
+
timestamp,
|
|
10803
11531
|
project: projLabel,
|
|
10804
11532
|
sessionId,
|
|
10805
|
-
agent: "
|
|
11533
|
+
agent: "antigravity"
|
|
10806
11534
|
});
|
|
10807
11535
|
}
|
|
10808
11536
|
ruleMatched = true;
|
|
10809
11537
|
break;
|
|
10810
11538
|
}
|
|
10811
|
-
const isShellTool = ["bash", "execute_bash", "run_shell_command", "shell"].includes(
|
|
10812
|
-
toolNameLower
|
|
10813
|
-
);
|
|
10814
11539
|
if (!ruleMatched && isShellTool) {
|
|
10815
11540
|
const shellVerdict = detectDangerousShellExec(String(input.command ?? ""));
|
|
10816
11541
|
if (shellVerdict) {
|
|
@@ -10834,18 +11559,201 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
10834
11559
|
},
|
|
10835
11560
|
toolName,
|
|
10836
11561
|
input,
|
|
10837
|
-
timestamp
|
|
11562
|
+
timestamp,
|
|
10838
11563
|
project: projLabel,
|
|
10839
11564
|
sessionId,
|
|
10840
|
-
agent: "
|
|
11565
|
+
agent: "antigravity"
|
|
10841
11566
|
});
|
|
10842
11567
|
}
|
|
10843
11568
|
}
|
|
10844
11569
|
}
|
|
10845
11570
|
}
|
|
10846
11571
|
}
|
|
10847
|
-
result.loopFindings.push(...detectLoops(sessionCalls, projLabel, sessionId, "
|
|
11572
|
+
result.loopFindings.push(...detectLoops(sessionCalls, projLabel, sessionId, "antigravity"));
|
|
11573
|
+
}
|
|
11574
|
+
}
|
|
11575
|
+
return result;
|
|
11576
|
+
}
|
|
11577
|
+
function scanCopilotHistory(startDate, onProgress, onLine) {
|
|
11578
|
+
const sessionDir = import_path22.default.join(import_os19.default.homedir(), ".copilot", "session-state");
|
|
11579
|
+
const result = {
|
|
11580
|
+
filesScanned: 0,
|
|
11581
|
+
sessions: 0,
|
|
11582
|
+
totalToolCalls: 0,
|
|
11583
|
+
bashCalls: 0,
|
|
11584
|
+
findings: [],
|
|
11585
|
+
dlpFindings: [],
|
|
11586
|
+
loopFindings: [],
|
|
11587
|
+
totalCostUSD: 0,
|
|
11588
|
+
// event logs carry no token/cost rollup
|
|
11589
|
+
firstDate: null,
|
|
11590
|
+
lastDate: null,
|
|
11591
|
+
sessionsWithEarlySecrets: 0
|
|
11592
|
+
};
|
|
11593
|
+
const dedup = emptyScanDedup();
|
|
11594
|
+
if (!import_fs20.default.existsSync(sessionDir)) return result;
|
|
11595
|
+
let sessionIds;
|
|
11596
|
+
try {
|
|
11597
|
+
sessionIds = import_fs20.default.readdirSync(sessionDir);
|
|
11598
|
+
} catch {
|
|
11599
|
+
return result;
|
|
11600
|
+
}
|
|
11601
|
+
const ruleSources = buildRuleSources();
|
|
11602
|
+
for (const sessionId of sessionIds) {
|
|
11603
|
+
const eventsPath = import_path22.default.join(sessionDir, sessionId, "events.jsonl");
|
|
11604
|
+
if (!import_fs20.default.existsSync(eventsPath)) continue;
|
|
11605
|
+
result.filesScanned++;
|
|
11606
|
+
onProgress?.(result.filesScanned);
|
|
11607
|
+
let raw;
|
|
11608
|
+
try {
|
|
11609
|
+
raw = import_fs20.default.readFileSync(eventsPath, "utf-8");
|
|
11610
|
+
} catch {
|
|
11611
|
+
continue;
|
|
11612
|
+
}
|
|
11613
|
+
let projLabel = sessionId.slice(0, 8);
|
|
11614
|
+
const sessionCalls = [];
|
|
11615
|
+
result.sessions++;
|
|
11616
|
+
for (const line of raw.split("\n")) {
|
|
11617
|
+
if (!line.trim()) continue;
|
|
11618
|
+
onLine?.();
|
|
11619
|
+
let ev;
|
|
11620
|
+
try {
|
|
11621
|
+
ev = JSON.parse(line);
|
|
11622
|
+
} catch {
|
|
11623
|
+
continue;
|
|
11624
|
+
}
|
|
11625
|
+
const timestamp = ev.timestamp ?? "";
|
|
11626
|
+
if (ev.type === "session.start") {
|
|
11627
|
+
const cwd = ev.data?.context?.cwd;
|
|
11628
|
+
if (typeof cwd === "string" && cwd) {
|
|
11629
|
+
projLabel = stripTerminalEscapes(cwd).replace(import_os19.default.homedir(), "~").slice(0, 40);
|
|
11630
|
+
}
|
|
11631
|
+
continue;
|
|
11632
|
+
}
|
|
11633
|
+
if (startDate && timestamp && new Date(timestamp) < startDate) continue;
|
|
11634
|
+
if (ev.type === "user.message") {
|
|
11635
|
+
const text = ev.data?.content ?? ev.data?.text ?? "";
|
|
11636
|
+
if (typeof text === "string" && text) {
|
|
11637
|
+
const dlpMatch2 = scanArgs({ text });
|
|
11638
|
+
if (dlpMatch2) {
|
|
11639
|
+
const k = dlpKey(dlpMatch2.patternName, dlpMatch2.redactedSample, projLabel);
|
|
11640
|
+
if (!dedup.dlpKeys.has(k)) {
|
|
11641
|
+
dedup.dlpKeys.add(k);
|
|
11642
|
+
result.dlpFindings.push({
|
|
11643
|
+
patternName: dlpMatch2.patternName,
|
|
11644
|
+
redactedSample: dlpMatch2.redactedSample,
|
|
11645
|
+
toolName: "user-prompt",
|
|
11646
|
+
timestamp,
|
|
11647
|
+
project: projLabel,
|
|
11648
|
+
sessionId,
|
|
11649
|
+
agent: "copilot"
|
|
11650
|
+
});
|
|
11651
|
+
}
|
|
11652
|
+
}
|
|
11653
|
+
}
|
|
11654
|
+
continue;
|
|
11655
|
+
}
|
|
11656
|
+
if (ev.type !== "tool.execution_start") continue;
|
|
11657
|
+
const toolName = ev.data?.toolName ?? "";
|
|
11658
|
+
const toolNameLower = toolName.toLowerCase();
|
|
11659
|
+
const input = ev.data?.arguments ?? {};
|
|
11660
|
+
result.totalToolCalls++;
|
|
11661
|
+
sessionCalls.push({ toolName, input, timestamp });
|
|
11662
|
+
const isShellTool = toolNameLower === "bash" || toolNameLower === "shell";
|
|
11663
|
+
if (isShellTool) result.bashCalls++;
|
|
11664
|
+
if (timestamp) {
|
|
11665
|
+
if (!result.firstDate || timestamp < result.firstDate) result.firstDate = timestamp;
|
|
11666
|
+
if (!result.lastDate || timestamp > result.lastDate) result.lastDate = timestamp;
|
|
11667
|
+
}
|
|
11668
|
+
const rawCmd = String(input.command ?? "").trimStart();
|
|
11669
|
+
if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd)) continue;
|
|
11670
|
+
const dlpMatch = scanArgs(input);
|
|
11671
|
+
if (dlpMatch) {
|
|
11672
|
+
const k = dlpKey(dlpMatch.patternName, dlpMatch.redactedSample, projLabel);
|
|
11673
|
+
if (!dedup.dlpKeys.has(k)) {
|
|
11674
|
+
dedup.dlpKeys.add(k);
|
|
11675
|
+
result.dlpFindings.push({
|
|
11676
|
+
patternName: dlpMatch.patternName,
|
|
11677
|
+
redactedSample: dlpMatch.redactedSample,
|
|
11678
|
+
toolName,
|
|
11679
|
+
timestamp,
|
|
11680
|
+
project: projLabel,
|
|
11681
|
+
sessionId,
|
|
11682
|
+
agent: "copilot"
|
|
11683
|
+
});
|
|
11684
|
+
}
|
|
11685
|
+
}
|
|
11686
|
+
let astFsMatched = false;
|
|
11687
|
+
if (isShellTool) {
|
|
11688
|
+
astFsMatched = pushFsOpAstFinding(
|
|
11689
|
+
String(input.command ?? ""),
|
|
11690
|
+
toolName,
|
|
11691
|
+
input,
|
|
11692
|
+
timestamp,
|
|
11693
|
+
projLabel,
|
|
11694
|
+
sessionId,
|
|
11695
|
+
"copilot",
|
|
11696
|
+
result,
|
|
11697
|
+
dedup
|
|
11698
|
+
);
|
|
11699
|
+
}
|
|
11700
|
+
let ruleMatched = astFsMatched;
|
|
11701
|
+
for (const source of ruleSources) {
|
|
11702
|
+
const { rule } = source;
|
|
11703
|
+
if (rule.verdict === "allow") continue;
|
|
11704
|
+
if (rule.tool && !matchesPattern(toolNameLower, rule.tool)) continue;
|
|
11705
|
+
if (isShellTool && rule.name && AST_FS_REGEX_RULES.has(rule.name)) continue;
|
|
11706
|
+
if (!evaluateSmartConditions(input, rule)) continue;
|
|
11707
|
+
const inputPreview = preview(input, 120);
|
|
11708
|
+
const k = findingKey(rule.name, inputPreview, projLabel);
|
|
11709
|
+
if (!dedup.findingsKeys.has(k)) {
|
|
11710
|
+
dedup.findingsKeys.add(k);
|
|
11711
|
+
result.findings.push({
|
|
11712
|
+
source,
|
|
11713
|
+
toolName,
|
|
11714
|
+
input,
|
|
11715
|
+
timestamp,
|
|
11716
|
+
project: projLabel,
|
|
11717
|
+
sessionId,
|
|
11718
|
+
agent: "copilot"
|
|
11719
|
+
});
|
|
11720
|
+
}
|
|
11721
|
+
ruleMatched = true;
|
|
11722
|
+
break;
|
|
11723
|
+
}
|
|
11724
|
+
if (!ruleMatched && isShellTool) {
|
|
11725
|
+
const shellVerdict = detectDangerousShellExec(String(input.command ?? ""));
|
|
11726
|
+
if (shellVerdict) {
|
|
11727
|
+
const astRule = {
|
|
11728
|
+
name: `ast:bash-safe:${shellVerdict}-shell-exec-remote`,
|
|
11729
|
+
tool: "bash",
|
|
11730
|
+
conditions: [],
|
|
11731
|
+
verdict: shellVerdict,
|
|
11732
|
+
reason: `Shell execution of remote download detected by AST analysis (bash-safe)`
|
|
11733
|
+
};
|
|
11734
|
+
const inputPreview = preview(input, 120);
|
|
11735
|
+
const k = findingKey(astRule.name, inputPreview, projLabel);
|
|
11736
|
+
if (!dedup.findingsKeys.has(k)) {
|
|
11737
|
+
dedup.findingsKeys.add(k);
|
|
11738
|
+
result.findings.push({
|
|
11739
|
+
source: {
|
|
11740
|
+
shieldName: "bash-safe",
|
|
11741
|
+
shieldLabel: "bash-safe (AST)",
|
|
11742
|
+
sourceType: "shield",
|
|
11743
|
+
rule: astRule
|
|
11744
|
+
},
|
|
11745
|
+
toolName,
|
|
11746
|
+
input,
|
|
11747
|
+
timestamp,
|
|
11748
|
+
project: projLabel,
|
|
11749
|
+
sessionId,
|
|
11750
|
+
agent: "copilot"
|
|
11751
|
+
});
|
|
11752
|
+
}
|
|
11753
|
+
}
|
|
11754
|
+
}
|
|
10848
11755
|
}
|
|
11756
|
+
result.loopFindings.push(...detectLoops(sessionCalls, projLabel, sessionId, "copilot"));
|
|
10849
11757
|
}
|
|
10850
11758
|
return result;
|
|
10851
11759
|
}
|
|
@@ -11144,8 +12052,8 @@ function printFindingRow(f, drillDown, showSessionId, previewWidth) {
|
|
|
11144
12052
|
const stale = isStaleFinding(f.timestamp);
|
|
11145
12053
|
const ts = f.timestamp ? import_chalk5.default.dim(fmtTs(f.timestamp) + " ") : "";
|
|
11146
12054
|
const proj = import_chalk5.default.dim(f.project.slice(0, 22).padEnd(22) + " ");
|
|
11147
|
-
const agentLabel2 = f.agent
|
|
11148
|
-
const agentBadge = stale ? import_chalk5.default.dim(agentLabel2) :
|
|
12055
|
+
const agentLabel2 = agentBadgeText(f.agent);
|
|
12056
|
+
const agentBadge = stale ? import_chalk5.default.dim(agentLabel2) : import_chalk5.default[agentColorName(f.agent)](agentLabel2);
|
|
11149
12057
|
let cmdText;
|
|
11150
12058
|
if (drillDown) {
|
|
11151
12059
|
cmdText = f.fullCommand;
|
|
@@ -11708,16 +12616,35 @@ function registerScanCommand(program2) {
|
|
|
11708
12616
|
(done) => onProgress(claudeScan.filesScanned + done),
|
|
11709
12617
|
onLine
|
|
11710
12618
|
);
|
|
11711
|
-
const
|
|
12619
|
+
const antigravityScan = scanAntigravityHistory(
|
|
11712
12620
|
startDate,
|
|
11713
12621
|
(done) => onProgress(claudeScan.filesScanned + geminiScan.filesScanned + done),
|
|
11714
12622
|
onLine
|
|
11715
12623
|
);
|
|
11716
|
-
const
|
|
12624
|
+
const copilotScan = scanCopilotHistory(
|
|
12625
|
+
startDate,
|
|
12626
|
+
(done) => onProgress(
|
|
12627
|
+
claudeScan.filesScanned + geminiScan.filesScanned + antigravityScan.filesScanned + done
|
|
12628
|
+
),
|
|
12629
|
+
onLine
|
|
12630
|
+
);
|
|
12631
|
+
const codexScan = scanCodexHistory(
|
|
12632
|
+
startDate,
|
|
12633
|
+
(done) => onProgress(
|
|
12634
|
+
claudeScan.filesScanned + geminiScan.filesScanned + antigravityScan.filesScanned + copilotScan.filesScanned + done
|
|
12635
|
+
),
|
|
12636
|
+
onLine
|
|
12637
|
+
);
|
|
12638
|
+
const scan = mergeScans(
|
|
12639
|
+
mergeScans(mergeScans(mergeScans(claudeScan, geminiScan), antigravityScan), copilotScan),
|
|
12640
|
+
codexScan
|
|
12641
|
+
);
|
|
11717
12642
|
scan.dlpFindings.push(...scanShellConfig());
|
|
11718
12643
|
const summary = buildScanSummary([
|
|
11719
12644
|
{ id: "claude", label: "Claude", icon: "\u{1F916}", scan: claudeScan },
|
|
11720
12645
|
{ id: "gemini", label: "Gemini", icon: "\u264A", scan: geminiScan },
|
|
12646
|
+
{ id: "antigravity", label: "Antigravity", icon: "\u{1F680}", scan: antigravityScan },
|
|
12647
|
+
{ id: "copilot", label: "Copilot", icon: "\u{1F419}", scan: copilotScan },
|
|
11721
12648
|
{ id: "codex", label: "Codex", icon: "\u{1F52E}", scan: codexScan }
|
|
11722
12649
|
]);
|
|
11723
12650
|
if (useTTY) process.stdout.write("\r" + " ".repeat(60) + "\r");
|
|
@@ -11725,7 +12652,7 @@ function registerScanCommand(program2) {
|
|
|
11725
12652
|
console.log(import_chalk5.default.yellow(" No session history found."));
|
|
11726
12653
|
console.log(
|
|
11727
12654
|
import_chalk5.default.gray(
|
|
11728
|
-
" Supported: Claude Code (~/.claude/projects/) \xB7 Gemini CLI (~/.gemini/tmp/)\n"
|
|
12655
|
+
" Supported: Claude Code (~/.claude/projects/) \xB7 Gemini CLI (~/.gemini/tmp/) \xB7 Antigravity (~/.gemini/antigravity-*/brain/) \xB7 Copilot CLI (~/.copilot/session-state/)\n"
|
|
11729
12656
|
)
|
|
11730
12657
|
);
|
|
11731
12658
|
return;
|
|
@@ -11737,6 +12664,12 @@ function registerScanCommand(program2) {
|
|
|
11737
12664
|
breakdownParts.push(import_chalk5.default.cyan(String(claudeScan.sessions)) + import_chalk5.default.dim(" Claude"));
|
|
11738
12665
|
if (geminiScan.sessions > 0)
|
|
11739
12666
|
breakdownParts.push(import_chalk5.default.blue(String(geminiScan.sessions)) + import_chalk5.default.dim(" Gemini"));
|
|
12667
|
+
if (antigravityScan.sessions > 0)
|
|
12668
|
+
breakdownParts.push(
|
|
12669
|
+
import_chalk5.default.yellow(String(antigravityScan.sessions)) + import_chalk5.default.dim(" Antigravity")
|
|
12670
|
+
);
|
|
12671
|
+
if (copilotScan.sessions > 0)
|
|
12672
|
+
breakdownParts.push(import_chalk5.default.green(String(copilotScan.sessions)) + import_chalk5.default.dim(" Copilot"));
|
|
11740
12673
|
if (codexScan.sessions > 0)
|
|
11741
12674
|
breakdownParts.push(import_chalk5.default.magenta(String(codexScan.sessions)) + import_chalk5.default.dim(" Codex"));
|
|
11742
12675
|
const sessionBreakdown = breakdownParts.length > 1 ? import_chalk5.default.dim("(") + breakdownParts.join(import_chalk5.default.dim(" \xB7 ")) + import_chalk5.default.dim(")") : "";
|
|
@@ -11925,7 +12858,7 @@ function registerScanCommand(program2) {
|
|
|
11925
12858
|
const stale = isStaleFinding(f.timestamp);
|
|
11926
12859
|
const ts = f.timestamp ? import_chalk5.default.dim(fmtTs(f.timestamp) + " ") : "";
|
|
11927
12860
|
const proj = import_chalk5.default.dim(f.project.slice(0, 22).padEnd(22) + " ");
|
|
11928
|
-
const agentBadge =
|
|
12861
|
+
const agentBadge = import_chalk5.default[agentColorName(f.agent)](agentBadgeText(f.agent));
|
|
11929
12862
|
const sessionSuffix = f.sessionId ? import_chalk5.default.dim(` \u2192 ${f.sessionId.slice(0, 8)}`) : "";
|
|
11930
12863
|
const recurringBadge = recurringPatterns.has(f.patternName) ? import_chalk5.default.red.bold(" \u26A0\uFE0F recurring ") : "";
|
|
11931
12864
|
const patternDisplay = stale ? import_chalk5.default.dim(f.patternName) : import_chalk5.default.yellow(f.patternName);
|
|
@@ -11973,8 +12906,8 @@ function registerScanCommand(program2) {
|
|
|
11973
12906
|
const stale = isStaleFinding(f.timestamp);
|
|
11974
12907
|
const ts = f.timestamp ? import_chalk5.default.dim(fmtTs(f.timestamp) + " ") : "";
|
|
11975
12908
|
const proj = import_chalk5.default.dim(f.project.slice(0, 22).padEnd(22) + " ");
|
|
11976
|
-
const agentLabel2 = f.agent
|
|
11977
|
-
const agentBadge = stale ? import_chalk5.default.dim(agentLabel2) :
|
|
12909
|
+
const agentLabel2 = agentBadgeText(f.agent);
|
|
12910
|
+
const agentBadge = stale ? import_chalk5.default.dim(agentLabel2) : import_chalk5.default[agentColorName(f.agent)](agentLabel2);
|
|
11978
12911
|
const toolDisplay = stale ? import_chalk5.default.dim(f.toolName) : import_chalk5.default.yellow(f.toolName);
|
|
11979
12912
|
const cmdDisplay = stale ? import_chalk5.default.dim(f.commandPreview) : import_chalk5.default.gray(f.commandPreview);
|
|
11980
12913
|
const sessionSuffix = f.sessionId ? import_chalk5.default.dim(` \u2192 ${f.sessionId.slice(0, 8)}`) : "";
|
|
@@ -12112,6 +13045,7 @@ var init_scan = __esm({
|
|
|
12112
13045
|
init_policy();
|
|
12113
13046
|
init_dist();
|
|
12114
13047
|
init_dlp();
|
|
13048
|
+
init_hook_payload();
|
|
12115
13049
|
init_dist();
|
|
12116
13050
|
init_scan_summary();
|
|
12117
13051
|
init_setup();
|
|
@@ -12191,6 +13125,8 @@ var init_scan = __esm({
|
|
|
12191
13125
|
"exec_command",
|
|
12192
13126
|
"shell",
|
|
12193
13127
|
"run_shell_command",
|
|
13128
|
+
"run_command",
|
|
13129
|
+
// Antigravity (agy)
|
|
12194
13130
|
"write",
|
|
12195
13131
|
"edit",
|
|
12196
13132
|
"multiedit"
|
|
@@ -16779,33 +17715,7 @@ function resolveUserSkillRoot(entry, cwd) {
|
|
|
16779
17715
|
// src/cli/commands/check.ts
|
|
16780
17716
|
init_dlp();
|
|
16781
17717
|
init_audit();
|
|
16782
|
-
|
|
16783
|
-
// src/utils/hook-payload.ts
|
|
16784
|
-
function extractToolName(payload, defaultValue = "") {
|
|
16785
|
-
return payload.tool_name ?? payload.name ?? defaultValue;
|
|
16786
|
-
}
|
|
16787
|
-
function extractToolInput(payload) {
|
|
16788
|
-
return payload.tool_input ?? payload.args ?? {};
|
|
16789
|
-
}
|
|
16790
|
-
function canonicalToolName(name) {
|
|
16791
|
-
switch (name) {
|
|
16792
|
-
// Hermes Agent
|
|
16793
|
-
case "terminal":
|
|
16794
|
-
return "Bash";
|
|
16795
|
-
case "write_file":
|
|
16796
|
-
return "Write";
|
|
16797
|
-
case "patch":
|
|
16798
|
-
return "Edit";
|
|
16799
|
-
case "read_file":
|
|
16800
|
-
return "Read";
|
|
16801
|
-
case "search_files":
|
|
16802
|
-
return "Grep";
|
|
16803
|
-
default:
|
|
16804
|
-
return name;
|
|
16805
|
-
}
|
|
16806
|
-
}
|
|
16807
|
-
|
|
16808
|
-
// src/cli/commands/check.ts
|
|
17718
|
+
init_hook_payload();
|
|
16809
17719
|
function sanitize2(value) {
|
|
16810
17720
|
return value.replace(/[\x00-\x1F\x7F]/g, "");
|
|
16811
17721
|
}
|
|
@@ -16818,6 +17728,9 @@ function detectAiAgent(payload) {
|
|
|
16818
17728
|
if (payload.turn_id !== void 0) {
|
|
16819
17729
|
return "Codex";
|
|
16820
17730
|
}
|
|
17731
|
+
if (payload.toolCall !== void 0 || payload.conversationId !== void 0) {
|
|
17732
|
+
return "Antigravity";
|
|
17733
|
+
}
|
|
16821
17734
|
if (payload.hook_event_name === "PreToolUse" || payload.hook_event_name === "PostToolUse" || payload.tool_use_id !== void 0 || payload.permission_mode !== void 0) {
|
|
16822
17735
|
return "Claude Code";
|
|
16823
17736
|
}
|
|
@@ -16833,6 +17746,9 @@ function detectAiAgent(payload) {
|
|
|
16833
17746
|
if (process.env.HERMES_SESSION_ID || process.env.HERMES_HOME || process.env.HERMES_INTERACTIVE) {
|
|
16834
17747
|
return "Hermes";
|
|
16835
17748
|
}
|
|
17749
|
+
if (process.env.ANTIGRAVITY_CONVERSATION_ID) {
|
|
17750
|
+
return "Antigravity";
|
|
17751
|
+
}
|
|
16836
17752
|
if (process.env.GEMINI_CLI_VERSION || process.env.GEMINI_API_KEY) {
|
|
16837
17753
|
return "Gemini CLI";
|
|
16838
17754
|
}
|
|
@@ -16848,7 +17764,11 @@ function detectAiAgent(payload) {
|
|
|
16848
17764
|
return "Terminal";
|
|
16849
17765
|
}
|
|
16850
17766
|
function registerCheckCommand(program2) {
|
|
16851
|
-
program2.command("check", { hidden: true }).description("Hook handler \u2014 evaluates a tool call before execution").argument("[data]", "JSON string of the tool call").
|
|
17767
|
+
program2.command("check", { hidden: true }).description("Hook handler \u2014 evaluates a tool call before execution").argument("[data]", "JSON string of the tool call").option(
|
|
17768
|
+
"--agent <name>",
|
|
17769
|
+
"Agent identity override, set by node9-authored hook registrations (e.g. antigravity)"
|
|
17770
|
+
).action(async (data, opts) => {
|
|
17771
|
+
const agentOverride = agentLabelFromFlag(opts?.agent);
|
|
16852
17772
|
const processPayload = async (raw) => {
|
|
16853
17773
|
try {
|
|
16854
17774
|
if (!raw || raw.trim() === "") process.exit(0);
|
|
@@ -16888,7 +17808,7 @@ RAW: ${raw}
|
|
|
16888
17808
|
if (!prompt) process.exit(0);
|
|
16889
17809
|
const dlpMatch = scanArgs({ prompt });
|
|
16890
17810
|
if (!dlpMatch) process.exit(0);
|
|
16891
|
-
const agent2 = detectAiAgent(payload);
|
|
17811
|
+
const agent2 = agentOverride ?? detectAiAgent(payload);
|
|
16892
17812
|
const sessionId2 = typeof payload.session_id === "string" ? payload.session_id : void 0;
|
|
16893
17813
|
appendLocalAudit(
|
|
16894
17814
|
"UserPromptSubmit",
|
|
@@ -16929,7 +17849,8 @@ RAW: ${raw}
|
|
|
16929
17849
|
);
|
|
16930
17850
|
process.exit(2);
|
|
16931
17851
|
}
|
|
16932
|
-
const
|
|
17852
|
+
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
17853
|
+
const safeCwdForConfig = typeof payloadCwd === "string" && import_path33.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
16933
17854
|
const config = getConfig(safeCwdForConfig);
|
|
16934
17855
|
if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
|
|
16935
17856
|
try {
|
|
@@ -16979,9 +17900,10 @@ RAW: ${raw}
|
|
|
16979
17900
|
import_fs32.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
|
|
16980
17901
|
`);
|
|
16981
17902
|
}
|
|
16982
|
-
const
|
|
16983
|
-
const
|
|
16984
|
-
const
|
|
17903
|
+
const rawToolName = sanitize2(extractToolName(payload));
|
|
17904
|
+
const toolName = canonicalToolName(rawToolName);
|
|
17905
|
+
const toolInput = canonicalToolInput(rawToolName, extractToolInput(payload));
|
|
17906
|
+
const agent = agentOverride ?? detectAiAgent(payload);
|
|
16985
17907
|
const mcpMatch = toolName.match(/^mcp__([^_](?:[^_]|_(?!_))*?)__/i);
|
|
16986
17908
|
const mcpServer = mcpMatch?.[1];
|
|
16987
17909
|
const sendBlock = (msg, result2) => {
|
|
@@ -17019,6 +17941,21 @@ RAW: ${raw}
|
|
|
17019
17941
|
msg,
|
|
17020
17942
|
result2?.recoveryCommand
|
|
17021
17943
|
);
|
|
17944
|
+
if (agent === "Antigravity") {
|
|
17945
|
+
process.stdout.write(
|
|
17946
|
+
JSON.stringify({ decision: "deny", reason: aiFeedbackMessage }) + "\n"
|
|
17947
|
+
);
|
|
17948
|
+
process.exit(0);
|
|
17949
|
+
}
|
|
17950
|
+
if (agent === "GitHub Copilot") {
|
|
17951
|
+
process.stdout.write(
|
|
17952
|
+
JSON.stringify({
|
|
17953
|
+
permissionDecision: "deny",
|
|
17954
|
+
permissionDecisionReason: aiFeedbackMessage
|
|
17955
|
+
}) + "\n"
|
|
17956
|
+
);
|
|
17957
|
+
process.exit(0);
|
|
17958
|
+
}
|
|
17022
17959
|
process.stdout.write(
|
|
17023
17960
|
JSON.stringify({
|
|
17024
17961
|
decision: "block",
|
|
@@ -17037,11 +17974,11 @@ RAW: ${raw}
|
|
|
17037
17974
|
sendBlock("Node9: unrecognised hook payload \u2014 tool name missing.");
|
|
17038
17975
|
return;
|
|
17039
17976
|
}
|
|
17040
|
-
const sessionId = typeof payload.session_id === "string" ? payload.session_id : void 0;
|
|
17041
|
-
const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : void 0;
|
|
17977
|
+
const sessionId = typeof payload.session_id === "string" ? payload.session_id : typeof payload.conversationId === "string" ? payload.conversationId : void 0;
|
|
17978
|
+
const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : typeof payload.transcriptPath === "string" ? payload.transcriptPath : void 0;
|
|
17042
17979
|
const meta = { agent, mcpServer, sessionId, transcriptPath };
|
|
17043
17980
|
const skillPinCfg = config.policy.skillPinning;
|
|
17044
|
-
const rawSessionId =
|
|
17981
|
+
const rawSessionId = sessionId ?? "";
|
|
17045
17982
|
const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
|
|
17046
17983
|
if (skillPinCfg.enabled && safeSessionId) {
|
|
17047
17984
|
try {
|
|
@@ -17098,7 +18035,7 @@ RAW: ${raw}
|
|
|
17098
18035
|
return;
|
|
17099
18036
|
}
|
|
17100
18037
|
if (!flag || flag.state !== "verified" && flag.state !== "warned") {
|
|
17101
|
-
const absoluteCwd = typeof
|
|
18038
|
+
const absoluteCwd = typeof payloadCwd === "string" && import_path33.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
17102
18039
|
const extraRoots = skillPinCfg.roots;
|
|
17103
18040
|
const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
|
|
17104
18041
|
const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
|
|
@@ -17164,7 +18101,7 @@ RAW: ${raw}
|
|
|
17164
18101
|
if (shouldSnapshot(toolName, toolInput, config)) {
|
|
17165
18102
|
await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
|
|
17166
18103
|
}
|
|
17167
|
-
const safeCwdForAuth = typeof
|
|
18104
|
+
const safeCwdForAuth = typeof payloadCwd === "string" && import_path33.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
17168
18105
|
const result = await authorizeHeadless(toolName, toolInput, meta, {
|
|
17169
18106
|
cwd: safeCwdForAuth
|
|
17170
18107
|
});
|
|
@@ -17289,6 +18226,7 @@ function containsShellMetachar(token) {
|
|
|
17289
18226
|
}
|
|
17290
18227
|
|
|
17291
18228
|
// src/cli/commands/log.ts
|
|
18229
|
+
init_hook_payload();
|
|
17292
18230
|
var TEST_COMMAND_RE2 = /(?:^|\s)(npm\s+(?:run\s+)?test|npx\s+(?:vitest|jest|mocha)|yarn\s+(?:run\s+)?test|pnpm\s+(?:run\s+)?test|vitest|jest|mocha|pytest|py\.test|cargo\s+test|go\s+test|bundle\s+exec\s+rspec|rspec|phpunit|dotnet\s+test)\b/i;
|
|
17293
18231
|
function detectTestResult(command, output) {
|
|
17294
18232
|
if (!TEST_COMMAND_RE2.test(command)) return null;
|
|
@@ -17307,14 +18245,19 @@ function sanitize3(value) {
|
|
|
17307
18245
|
return value.replace(/[\x00-\x1F\x7F]/g, "");
|
|
17308
18246
|
}
|
|
17309
18247
|
function registerLogCommand(program2) {
|
|
17310
|
-
program2.command("log", { hidden: true }).description("PostToolUse hook \u2014 records executed tool calls").argument("[data]", "JSON string of the tool call").
|
|
18248
|
+
program2.command("log", { hidden: true }).description("PostToolUse hook \u2014 records executed tool calls").argument("[data]", "JSON string of the tool call").option(
|
|
18249
|
+
"--agent <name>",
|
|
18250
|
+
"Agent identity override, set by node9-authored hook registrations (e.g. antigravity)"
|
|
18251
|
+
).action(async (data, opts) => {
|
|
18252
|
+
const agentOverride = agentLabelFromFlag(opts?.agent);
|
|
17311
18253
|
const logPayload = async (raw) => {
|
|
17312
18254
|
try {
|
|
17313
18255
|
if (!raw || raw.trim() === "") process.exit(0);
|
|
17314
18256
|
const payload = JSON.parse(raw);
|
|
18257
|
+
if (payload.toolCall === null) process.exit(0);
|
|
17315
18258
|
const rawToolName = sanitize3(extractToolName(payload, "unknown"));
|
|
17316
18259
|
const tool = canonicalToolName(rawToolName);
|
|
17317
|
-
const rawInput = extractToolInput(payload);
|
|
18260
|
+
const rawInput = canonicalToolInput(rawToolName, extractToolInput(payload));
|
|
17318
18261
|
const metaTag = (() => {
|
|
17319
18262
|
const m = payload.meta;
|
|
17320
18263
|
if (m && typeof m === "object") {
|
|
@@ -17323,7 +18266,7 @@ function registerLogCommand(program2) {
|
|
|
17323
18266
|
}
|
|
17324
18267
|
return void 0;
|
|
17325
18268
|
})();
|
|
17326
|
-
const agent = metaTag !== void 0 ? metaTag : payload.turn_id !== void 0 ? "Codex" : payload.hook_event_name === "pre_tool_call" || payload.hook_event_name === "post_tool_call" ? "Hermes" : payload.hook_event_name === "PreToolUse" || payload.hook_event_name === "PostToolUse" || payload.tool_use_id !== void 0 || payload.permission_mode !== void 0 ? "Claude Code" : payload.hook_event_name === "BeforeTool" || payload.hook_event_name === "AfterTool" || payload.timestamp !== void 0 ? "Gemini CLI" : process.env.HERMES_SESSION_ID || process.env.HERMES_HOME || process.env.HERMES_INTERACTIVE ? "Hermes" : void 0;
|
|
18269
|
+
const agent = agentOverride !== void 0 ? agentOverride : metaTag !== void 0 ? metaTag : payload.turn_id !== void 0 ? "Codex" : payload.toolCall !== void 0 || payload.conversationId !== void 0 ? "Antigravity" : payload.hook_event_name === "pre_tool_call" || payload.hook_event_name === "post_tool_call" ? "Hermes" : payload.hook_event_name === "PreToolUse" || payload.hook_event_name === "PostToolUse" || payload.tool_use_id !== void 0 || payload.permission_mode !== void 0 ? "Claude Code" : payload.hook_event_name === "BeforeTool" || payload.hook_event_name === "AfterTool" || payload.timestamp !== void 0 ? "Gemini CLI" : process.env.HERMES_SESSION_ID || process.env.HERMES_HOME || process.env.HERMES_INTERACTIVE ? "Hermes" : process.env.ANTIGRAVITY_CONVERSATION_ID ? "Antigravity" : void 0;
|
|
17327
18270
|
const entry = {
|
|
17328
18271
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17329
18272
|
tool,
|
|
@@ -17333,7 +18276,8 @@ function registerLogCommand(program2) {
|
|
|
17333
18276
|
};
|
|
17334
18277
|
if (agent) entry.agent = agent;
|
|
17335
18278
|
if (rawToolName !== tool) entry.agentToolName = rawToolName;
|
|
17336
|
-
|
|
18279
|
+
const payloadSessionId = payload.session_id ?? payload.conversationId;
|
|
18280
|
+
if (payloadSessionId) entry.sessionId = payloadSessionId;
|
|
17337
18281
|
const logPath = import_path34.default.join(import_os29.default.homedir(), ".node9", "audit.log");
|
|
17338
18282
|
if (!import_fs33.default.existsSync(import_path34.default.dirname(logPath)))
|
|
17339
18283
|
import_fs33.default.mkdirSync(import_path34.default.dirname(logPath), { recursive: true });
|
|
@@ -17370,7 +18314,8 @@ function registerLogCommand(program2) {
|
|
|
17370
18314
|
}
|
|
17371
18315
|
}
|
|
17372
18316
|
}
|
|
17373
|
-
const
|
|
18317
|
+
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
18318
|
+
const safeCwd = typeof payloadCwd === "string" && import_path34.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
17374
18319
|
const config = getConfig(safeCwd);
|
|
17375
18320
|
if ((tool === "Bash" || tool === "bash") && config.settings.enableUndo !== false) {
|
|
17376
18321
|
const bashCommand = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
@@ -19458,12 +20403,12 @@ function registerInitCommand(program2) {
|
|
|
19458
20403
|
if (found.length === 0) {
|
|
19459
20404
|
console.log(
|
|
19460
20405
|
import_chalk16.default.gray(
|
|
19461
|
-
"No AI agents detected. Install one of the supported agents (Claude Code, Codex, Gemini CLI, Cursor, Windsurf, VSCode, Claude Desktop, Opencode, Pi, or Hermes Agent)."
|
|
20406
|
+
"No AI agents detected. Install one of the supported agents (Claude Code, Codex, Antigravity, Gemini CLI, GitHub Copilot CLI, Cursor, Windsurf, VSCode, Claude Desktop, Opencode, Pi, or Hermes Agent)."
|
|
19462
20407
|
)
|
|
19463
20408
|
);
|
|
19464
20409
|
console.log(
|
|
19465
20410
|
import_chalk16.default.gray(
|
|
19466
|
-
"then run: node9 agents add <claude|codex|gemini|cursor|windsurf|vscode|claudeDesktop|opencode|pi|hermes>"
|
|
20411
|
+
"then run: node9 agents add <claude|codex|antigravity|gemini|copilot|cursor|windsurf|vscode|claudeDesktop|opencode|pi|hermes>"
|
|
19467
20412
|
)
|
|
19468
20413
|
);
|
|
19469
20414
|
return;
|
|
@@ -19477,6 +20422,8 @@ function registerInitCommand(program2) {
|
|
|
19477
20422
|
console.log(import_chalk16.default.bold(`Wiring ${agent}...`));
|
|
19478
20423
|
if (agent === "claude") await setupClaude();
|
|
19479
20424
|
else if (agent === "gemini") await setupGemini();
|
|
20425
|
+
else if (agent === "antigravity") await setupAntigravity();
|
|
20426
|
+
else if (agent === "copilot") await setupCopilot();
|
|
19480
20427
|
else if (agent === "cursor") await setupCursor();
|
|
19481
20428
|
else if (agent === "codex") await setupCodex();
|
|
19482
20429
|
else if (agent === "windsurf") await setupWindsurf();
|
|
@@ -21240,6 +22187,8 @@ init_setup();
|
|
|
21240
22187
|
var SETUP_FN = {
|
|
21241
22188
|
claude: setupClaude,
|
|
21242
22189
|
gemini: setupGemini,
|
|
22190
|
+
antigravity: setupAntigravity,
|
|
22191
|
+
copilot: setupCopilot,
|
|
21243
22192
|
cursor: setupCursor,
|
|
21244
22193
|
codex: setupCodex,
|
|
21245
22194
|
windsurf: setupWindsurf,
|
|
@@ -21252,6 +22201,8 @@ var SETUP_FN = {
|
|
|
21252
22201
|
var TEARDOWN_FN = {
|
|
21253
22202
|
claude: teardownClaude,
|
|
21254
22203
|
gemini: teardownGemini,
|
|
22204
|
+
antigravity: teardownAntigravity,
|
|
22205
|
+
copilot: teardownCopilot,
|
|
21255
22206
|
cursor: teardownCursor,
|
|
21256
22207
|
codex: teardownCodex,
|
|
21257
22208
|
windsurf: teardownWindsurf,
|
|
@@ -21262,6 +22213,10 @@ var TEARDOWN_FN = {
|
|
|
21262
22213
|
hermes: teardownHermes
|
|
21263
22214
|
};
|
|
21264
22215
|
var AGENT_NAMES = Object.keys(SETUP_FN);
|
|
22216
|
+
function resolveAgentName(agent) {
|
|
22217
|
+
const lower = agent.toLowerCase();
|
|
22218
|
+
return lower === "agy" ? "antigravity" : lower;
|
|
22219
|
+
}
|
|
21265
22220
|
function registerAgentsCommand(program2) {
|
|
21266
22221
|
const agents = program2.command("agents").description("List and manage AI agent integrations");
|
|
21267
22222
|
agents.command("list").description("Show all supported agents and their Node9 status").action(() => {
|
|
@@ -21290,9 +22245,16 @@ function registerAgentsCommand(program2) {
|
|
|
21290
22245
|
import_chalk23.default.yellow(` ${unwired.length} agent(s) not yet wired. Run: `) + import_chalk23.default.white(`node9 agents add ${unwired[0].name}`) + "\n"
|
|
21291
22246
|
);
|
|
21292
22247
|
}
|
|
22248
|
+
if (statuses.some((s) => s.name === "gemini" && s.installed)) {
|
|
22249
|
+
console.log(
|
|
22250
|
+
import_chalk23.default.yellow(
|
|
22251
|
+
" \u26A0\uFE0F Gemini CLI stops serving AI Pro/Ultra and free tiers on 2026-06-18.\n"
|
|
22252
|
+
) + import_chalk23.default.gray(" Migrate to Antigravity: ") + import_chalk23.default.white("node9 agents add antigravity") + "\n"
|
|
22253
|
+
);
|
|
22254
|
+
}
|
|
21293
22255
|
});
|
|
21294
22256
|
agents.command("add").description("Wire Node9 into an agent").argument("<agent>", `Agent to wire: ${AGENT_NAMES.join(" | ")}`).action(async (agent) => {
|
|
21295
|
-
const name = agent
|
|
22257
|
+
const name = resolveAgentName(agent);
|
|
21296
22258
|
const fn = SETUP_FN[name];
|
|
21297
22259
|
if (!fn) {
|
|
21298
22260
|
console.error(import_chalk23.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
|
|
@@ -21301,7 +22263,7 @@ function registerAgentsCommand(program2) {
|
|
|
21301
22263
|
await fn();
|
|
21302
22264
|
});
|
|
21303
22265
|
agents.command("remove").description("Remove Node9 from an agent").argument("<agent>", `Agent to unwire: ${AGENT_NAMES.join(" | ")}`).action((agent) => {
|
|
21304
|
-
const name = agent
|
|
22266
|
+
const name = resolveAgentName(agent);
|
|
21305
22267
|
const fn = TEARDOWN_FN[name];
|
|
21306
22268
|
if (!fn) {
|
|
21307
22269
|
console.error(import_chalk23.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
|
|
@@ -21323,6 +22285,7 @@ var import_chalk24 = __toESM(require("chalk"));
|
|
|
21323
22285
|
var import_fs41 = __toESM(require("fs"));
|
|
21324
22286
|
var import_path42 = __toESM(require("path"));
|
|
21325
22287
|
var import_os36 = __toESM(require("os"));
|
|
22288
|
+
init_scan_summary();
|
|
21326
22289
|
var CLAUDE_PRICING3 = {
|
|
21327
22290
|
"claude-opus-4-6": { i: 5e-6, o: 25e-6, cw: 625e-8, cr: 5e-7 },
|
|
21328
22291
|
"claude-opus-4-5": { i: 5e-6, o: 25e-6, cw: 625e-8, cr: 5e-7 },
|
|
@@ -21929,7 +22892,9 @@ function renderList(summaries, totalCost) {
|
|
|
21929
22892
|
const cost = s.costUSD > 0 ? import_chalk24.default.dim(" " + fmtCost3(s.costUSD).padEnd(8)) : " ";
|
|
21930
22893
|
const blocked = s.blockedCalls.length > 0 ? import_chalk24.default.red(" \u{1F6D1} " + String(s.blockedCalls.length)) : "";
|
|
21931
22894
|
const snap = s.hasSnapshot ? import_chalk24.default.green(" \u{1F4F8}") : "";
|
|
21932
|
-
const agentBadge =
|
|
22895
|
+
const agentBadge = import_chalk24.default[agentColorName(s.agent ?? "claude")](
|
|
22896
|
+
" " + agentBadgeText(s.agent ?? "claude", 0)
|
|
22897
|
+
);
|
|
21933
22898
|
const sid = import_chalk24.default.dim(" " + s.sessionId.slice(0, 8));
|
|
21934
22899
|
console.log(
|
|
21935
22900
|
` ${timeStr} ${prompt} ${tools}${cost}${blocked}${snap}${agentBadge}${sid}${dateRange}`
|
|
@@ -21949,7 +22914,7 @@ function renderDetail(s) {
|
|
|
21949
22914
|
);
|
|
21950
22915
|
console.log(import_chalk24.default.bold(" Project ") + import_chalk24.default.white(s.projectLabel));
|
|
21951
22916
|
if (s.agent) {
|
|
21952
|
-
const agentLabel2 =
|
|
22917
|
+
const agentLabel2 = import_chalk24.default[agentColorName(s.agent)](agentDisplayName(s.agent));
|
|
21953
22918
|
console.log(import_chalk24.default.bold(" Agent ") + agentLabel2);
|
|
21954
22919
|
}
|
|
21955
22920
|
console.log(import_chalk24.default.bold(" When ") + import_chalk24.default.white(fmtDateTime(s.startTime)));
|
|
@@ -22586,12 +23551,14 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
22586
23551
|
});
|
|
22587
23552
|
program.command("addto", { hidden: true }).description("Integrate Node9 with an AI agent").addHelpText(
|
|
22588
23553
|
"after",
|
|
22589
|
-
"\n Supported targets: claude gemini cursor codex windsurf vscode hud"
|
|
23554
|
+
"\n Supported targets: claude antigravity copilot gemini cursor codex windsurf vscode hud"
|
|
22590
23555
|
).argument(
|
|
22591
23556
|
"<target>",
|
|
22592
|
-
"The agent to protect: claude | gemini | cursor | codex | windsurf | vscode | hud"
|
|
23557
|
+
"The agent to protect: claude | antigravity | copilot | gemini | cursor | codex | windsurf | vscode | hud"
|
|
22593
23558
|
).action(async (target) => {
|
|
22594
23559
|
if (target === "gemini") return await setupGemini();
|
|
23560
|
+
if (target === "antigravity" || target === "agy") return await setupAntigravity();
|
|
23561
|
+
if (target === "copilot") return await setupCopilot();
|
|
22595
23562
|
if (target === "claude") return await setupClaude();
|
|
22596
23563
|
if (target === "cursor") return await setupCursor();
|
|
22597
23564
|
if (target === "codex") return await setupCodex();
|
|
@@ -22601,17 +23568,17 @@ program.command("addto", { hidden: true }).description("Integrate Node9 with an
|
|
|
22601
23568
|
if (target === "hud") return setupHud();
|
|
22602
23569
|
console.error(
|
|
22603
23570
|
import_chalk30.default.red(
|
|
22604
|
-
`Unknown target: "${target}". Supported: claude, gemini, cursor, codex, windsurf, vscode, hermes, hud`
|
|
23571
|
+
`Unknown target: "${target}". Supported: claude, antigravity, copilot, gemini, cursor, codex, windsurf, vscode, hermes, hud`
|
|
22605
23572
|
)
|
|
22606
23573
|
);
|
|
22607
23574
|
process.exit(1);
|
|
22608
23575
|
});
|
|
22609
23576
|
program.command("setup", { hidden: true }).description('Alias for "addto" \u2014 integrate Node9 with an AI agent').addHelpText(
|
|
22610
23577
|
"after",
|
|
22611
|
-
"\n Supported targets: claude gemini cursor codex windsurf vscode hud"
|
|
23578
|
+
"\n Supported targets: claude antigravity copilot gemini cursor codex windsurf vscode hud"
|
|
22612
23579
|
).argument(
|
|
22613
23580
|
"[target]",
|
|
22614
|
-
"The agent to protect: claude | gemini | cursor | codex | windsurf | vscode | hud"
|
|
23581
|
+
"The agent to protect: claude | antigravity | copilot | gemini | cursor | codex | windsurf | vscode | hud"
|
|
22615
23582
|
).action(async (target) => {
|
|
22616
23583
|
if (!target) {
|
|
22617
23584
|
console.log(import_chalk30.default.cyan("\n\u{1F6E1}\uFE0F Node9 Setup \u2014 integrate with your AI agent\n"));
|
|
@@ -22619,6 +23586,8 @@ program.command("setup", { hidden: true }).description('Alias for "addto" \u2014
|
|
|
22619
23586
|
console.log(" Targets:");
|
|
22620
23587
|
console.log(" " + import_chalk30.default.green("claude") + " \u2014 Claude Code (hook mode)");
|
|
22621
23588
|
console.log(" " + import_chalk30.default.green("gemini") + " \u2014 Gemini CLI (hook mode)");
|
|
23589
|
+
console.log(" " + import_chalk30.default.green("antigravity") + " \u2014 Antigravity / agy (hook mode)");
|
|
23590
|
+
console.log(" " + import_chalk30.default.green("copilot") + " \u2014 GitHub Copilot CLI (hook mode)");
|
|
22622
23591
|
console.log(" " + import_chalk30.default.green("cursor") + " \u2014 Cursor (MCP proxy)");
|
|
22623
23592
|
console.log(" " + import_chalk30.default.green("codex") + " \u2014 OpenAI Codex CLI (MCP proxy)");
|
|
22624
23593
|
console.log(" " + import_chalk30.default.green("windsurf") + " \u2014 Windsurf (MCP proxy)");
|
|
@@ -22632,6 +23601,8 @@ program.command("setup", { hidden: true }).description('Alias for "addto" \u2014
|
|
|
22632
23601
|
}
|
|
22633
23602
|
const t = target.toLowerCase();
|
|
22634
23603
|
if (t === "gemini") return await setupGemini();
|
|
23604
|
+
if (t === "antigravity" || t === "agy") return await setupAntigravity();
|
|
23605
|
+
if (t === "copilot") return await setupCopilot();
|
|
22635
23606
|
if (t === "claude") return await setupClaude();
|
|
22636
23607
|
if (t === "cursor") return await setupCursor();
|
|
22637
23608
|
if (t === "codex") return await setupCodex();
|
|
@@ -22641,21 +23612,23 @@ program.command("setup", { hidden: true }).description('Alias for "addto" \u2014
|
|
|
22641
23612
|
if (t === "hud") return setupHud();
|
|
22642
23613
|
console.error(
|
|
22643
23614
|
import_chalk30.default.red(
|
|
22644
|
-
`Unknown target: "${target}". Supported: claude, gemini, cursor, codex, windsurf, vscode, hermes, hud`
|
|
23615
|
+
`Unknown target: "${target}". Supported: claude, antigravity, copilot, gemini, cursor, codex, windsurf, vscode, hermes, hud`
|
|
22645
23616
|
)
|
|
22646
23617
|
);
|
|
22647
23618
|
process.exit(1);
|
|
22648
23619
|
});
|
|
22649
23620
|
program.command("removefrom", { hidden: true }).description("Remove Node9 hooks from an AI agent configuration").addHelpText(
|
|
22650
23621
|
"after",
|
|
22651
|
-
"\n Supported targets: claude gemini cursor codex windsurf vscode hud"
|
|
23622
|
+
"\n Supported targets: claude antigravity copilot gemini cursor codex windsurf vscode hud"
|
|
22652
23623
|
).argument(
|
|
22653
23624
|
"<target>",
|
|
22654
|
-
"The agent to remove from: claude | gemini | cursor | codex | windsurf | vscode | hud"
|
|
23625
|
+
"The agent to remove from: claude | antigravity | copilot | gemini | cursor | codex | windsurf | vscode | hud"
|
|
22655
23626
|
).action((target) => {
|
|
22656
23627
|
let fn;
|
|
22657
23628
|
if (target === "claude") fn = teardownClaude;
|
|
22658
23629
|
else if (target === "gemini") fn = teardownGemini;
|
|
23630
|
+
else if (target === "antigravity" || target === "agy") fn = teardownAntigravity;
|
|
23631
|
+
else if (target === "copilot") fn = teardownCopilot;
|
|
22659
23632
|
else if (target === "cursor") fn = teardownCursor;
|
|
22660
23633
|
else if (target === "codex") fn = teardownCodex;
|
|
22661
23634
|
else if (target === "windsurf") fn = teardownWindsurf;
|
|
@@ -22665,7 +23638,7 @@ program.command("removefrom", { hidden: true }).description("Remove Node9 hooks
|
|
|
22665
23638
|
else {
|
|
22666
23639
|
console.error(
|
|
22667
23640
|
import_chalk30.default.red(
|
|
22668
|
-
`Unknown target: "${target}". Supported: claude, gemini, cursor, codex, windsurf, vscode, hermes, hud`
|
|
23641
|
+
`Unknown target: "${target}". Supported: claude, antigravity, copilot, gemini, cursor, codex, windsurf, vscode, hermes, hud`
|
|
22669
23642
|
)
|
|
22670
23643
|
);
|
|
22671
23644
|
process.exit(1);
|
|
@@ -22922,6 +23895,9 @@ program.command("resume").description("Re-enable Node9 protection immediately").
|
|
|
22922
23895
|
var HOOK_BASED_AGENTS = {
|
|
22923
23896
|
claude: "claude",
|
|
22924
23897
|
gemini: "gemini",
|
|
23898
|
+
antigravity: "antigravity",
|
|
23899
|
+
agy: "antigravity",
|
|
23900
|
+
copilot: "copilot",
|
|
22925
23901
|
cursor: "cursor"
|
|
22926
23902
|
};
|
|
22927
23903
|
program.argument("[command...]", "The agent command to run (e.g., gemini)").action(async (commandArgs) => {
|