@node9/proxy 1.21.5 → 1.23.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/dist/cli.js +1146 -812
- package/dist/cli.mjs +1116 -783
- package/dist/dashboard.mjs +8 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -6305,6 +6305,164 @@ var init_core = __esm({
|
|
|
6305
6305
|
}
|
|
6306
6306
|
});
|
|
6307
6307
|
|
|
6308
|
+
// src/mcp-pin.ts
|
|
6309
|
+
function getHomePinsFilePath() {
|
|
6310
|
+
return import_path14.default.join(import_os11.default.homedir(), ".node9", "mcp-pins.json");
|
|
6311
|
+
}
|
|
6312
|
+
function getPinsFilePath() {
|
|
6313
|
+
return getHomePinsFilePath();
|
|
6314
|
+
}
|
|
6315
|
+
function findPinsFilePath(cwd) {
|
|
6316
|
+
const homeDir2 = import_os11.default.homedir();
|
|
6317
|
+
const homePath = getHomePinsFilePath();
|
|
6318
|
+
let current = import_path14.default.resolve(cwd ?? process.cwd());
|
|
6319
|
+
while (true) {
|
|
6320
|
+
if (current === homeDir2) break;
|
|
6321
|
+
const candidate = import_path14.default.join(current, ".node9", "mcp-pins.json");
|
|
6322
|
+
if (import_fs12.default.existsSync(candidate)) {
|
|
6323
|
+
return { path: candidate, source: "repo" };
|
|
6324
|
+
}
|
|
6325
|
+
const next = import_path14.default.dirname(current);
|
|
6326
|
+
if (next === current) break;
|
|
6327
|
+
current = next;
|
|
6328
|
+
}
|
|
6329
|
+
return { path: homePath, source: "home" };
|
|
6330
|
+
}
|
|
6331
|
+
function hashToolDefinitions(tools) {
|
|
6332
|
+
const sorted = [...tools].sort((a, b) => {
|
|
6333
|
+
const nameA = a.name ?? "";
|
|
6334
|
+
const nameB = b.name ?? "";
|
|
6335
|
+
return nameA.localeCompare(nameB);
|
|
6336
|
+
});
|
|
6337
|
+
const canonical = JSON.stringify(sorted);
|
|
6338
|
+
return import_crypto5.default.createHash("sha256").update(canonical).digest("hex");
|
|
6339
|
+
}
|
|
6340
|
+
function getServerKey(upstreamCommand) {
|
|
6341
|
+
return import_crypto5.default.createHash("sha256").update(upstreamCommand).digest("hex").slice(0, 16);
|
|
6342
|
+
}
|
|
6343
|
+
function readPinsFile(filePath) {
|
|
6344
|
+
try {
|
|
6345
|
+
const raw = import_fs12.default.readFileSync(filePath, "utf-8");
|
|
6346
|
+
if (!raw.trim()) {
|
|
6347
|
+
return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
6348
|
+
}
|
|
6349
|
+
const parsed = JSON.parse(raw);
|
|
6350
|
+
if (!parsed.servers || typeof parsed.servers !== "object" || Array.isArray(parsed.servers)) {
|
|
6351
|
+
return { ok: false, reason: "corrupt", detail: "invalid structure: missing servers object" };
|
|
6352
|
+
}
|
|
6353
|
+
return { ok: true, pins: { servers: parsed.servers } };
|
|
6354
|
+
} catch (err2) {
|
|
6355
|
+
if (err2.code === "ENOENT") {
|
|
6356
|
+
return { ok: false, reason: "missing" };
|
|
6357
|
+
}
|
|
6358
|
+
return { ok: false, reason: "corrupt", detail: String(err2) };
|
|
6359
|
+
}
|
|
6360
|
+
}
|
|
6361
|
+
function readMcpPinsSafe() {
|
|
6362
|
+
return readPinsFile(getHomePinsFilePath());
|
|
6363
|
+
}
|
|
6364
|
+
function readMcpPins() {
|
|
6365
|
+
const result = readMcpPinsSafe();
|
|
6366
|
+
if (result.ok) return result.pins;
|
|
6367
|
+
if (result.reason === "missing") return { servers: {} };
|
|
6368
|
+
throw new Error(`[node9] MCP pin file is corrupt: ${result.detail}`);
|
|
6369
|
+
}
|
|
6370
|
+
function writePinsFile(filePath, data) {
|
|
6371
|
+
import_fs12.default.mkdirSync(import_path14.default.dirname(filePath), { recursive: true });
|
|
6372
|
+
const tmp = `${filePath}.${import_crypto5.default.randomBytes(6).toString("hex")}.tmp`;
|
|
6373
|
+
const isHome = filePath === getHomePinsFilePath();
|
|
6374
|
+
import_fs12.default.writeFileSync(tmp, JSON.stringify(data, null, 2), isHome ? { mode: 384 } : {});
|
|
6375
|
+
import_fs12.default.renameSync(tmp, filePath);
|
|
6376
|
+
}
|
|
6377
|
+
function writeMcpPins(data) {
|
|
6378
|
+
writePinsFile(getHomePinsFilePath(), data);
|
|
6379
|
+
}
|
|
6380
|
+
function seedMcpPinsIfMissing() {
|
|
6381
|
+
const filePath = getPinsFilePath();
|
|
6382
|
+
if (import_fs12.default.existsSync(filePath)) return;
|
|
6383
|
+
writeMcpPins({ servers: {} });
|
|
6384
|
+
}
|
|
6385
|
+
function checkPin(serverKey, currentHash, cwd) {
|
|
6386
|
+
const found = findPinsFilePath(cwd);
|
|
6387
|
+
let repoEntry;
|
|
6388
|
+
if (found.source === "repo") {
|
|
6389
|
+
const repoResult = readPinsFile(found.path);
|
|
6390
|
+
if (!repoResult.ok) {
|
|
6391
|
+
return "corrupt";
|
|
6392
|
+
}
|
|
6393
|
+
repoEntry = repoResult.pins.servers[serverKey];
|
|
6394
|
+
}
|
|
6395
|
+
if (repoEntry) {
|
|
6396
|
+
return repoEntry.toolsHash === currentHash ? "match" : "mismatch";
|
|
6397
|
+
}
|
|
6398
|
+
const homeResult = readPinsFile(getHomePinsFilePath());
|
|
6399
|
+
if (!homeResult.ok) {
|
|
6400
|
+
if (homeResult.reason === "missing") return "new";
|
|
6401
|
+
return "corrupt";
|
|
6402
|
+
}
|
|
6403
|
+
const homeEntry = homeResult.pins.servers[serverKey];
|
|
6404
|
+
if (!homeEntry) return "new";
|
|
6405
|
+
return homeEntry.toolsHash === currentHash ? "match" : "mismatch";
|
|
6406
|
+
}
|
|
6407
|
+
function updatePin(serverKey, label, toolsHash, toolNames) {
|
|
6408
|
+
const pins = readMcpPins();
|
|
6409
|
+
pins.servers[serverKey] = {
|
|
6410
|
+
label,
|
|
6411
|
+
toolsHash,
|
|
6412
|
+
toolNames,
|
|
6413
|
+
toolCount: toolNames.length,
|
|
6414
|
+
pinnedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6415
|
+
};
|
|
6416
|
+
writeMcpPins(pins);
|
|
6417
|
+
}
|
|
6418
|
+
function removePin(serverKey) {
|
|
6419
|
+
const pins = readMcpPins();
|
|
6420
|
+
delete pins.servers[serverKey];
|
|
6421
|
+
writeMcpPins(pins);
|
|
6422
|
+
}
|
|
6423
|
+
function clearAllPins() {
|
|
6424
|
+
writeMcpPins({ servers: {} });
|
|
6425
|
+
}
|
|
6426
|
+
function promotePin(serverKey, cwd) {
|
|
6427
|
+
const homePins = readMcpPins();
|
|
6428
|
+
const homeEntry = homePins.servers[serverKey];
|
|
6429
|
+
if (!homeEntry) {
|
|
6430
|
+
throw new Error(
|
|
6431
|
+
`[node9] Server "${serverKey}" is not pinned in ~/.node9/mcp-pins.json. Run \`node9 mcp pin list\` to see what's pinned.`
|
|
6432
|
+
);
|
|
6433
|
+
}
|
|
6434
|
+
const found = findPinsFilePath(cwd);
|
|
6435
|
+
let repoPath;
|
|
6436
|
+
let repoPins;
|
|
6437
|
+
let created = false;
|
|
6438
|
+
if (found.source === "repo") {
|
|
6439
|
+
repoPath = found.path;
|
|
6440
|
+
const result = readPinsFile(repoPath);
|
|
6441
|
+
if (!result.ok) {
|
|
6442
|
+
const detail = result.reason === "corrupt" ? result.detail : "missing";
|
|
6443
|
+
throw new Error(`[node9] Repo pin file at ${repoPath} is unreadable: ${detail}`);
|
|
6444
|
+
}
|
|
6445
|
+
repoPins = result.pins;
|
|
6446
|
+
} else {
|
|
6447
|
+
repoPath = import_path14.default.join(cwd ?? process.cwd(), ".node9", "mcp-pins.json");
|
|
6448
|
+
repoPins = { servers: {} };
|
|
6449
|
+
created = true;
|
|
6450
|
+
}
|
|
6451
|
+
repoPins.servers[serverKey] = { ...homeEntry };
|
|
6452
|
+
writePinsFile(repoPath, repoPins);
|
|
6453
|
+
return { repoPath, created };
|
|
6454
|
+
}
|
|
6455
|
+
var import_fs12, import_path14, import_os11, import_crypto5;
|
|
6456
|
+
var init_mcp_pin = __esm({
|
|
6457
|
+
"src/mcp-pin.ts"() {
|
|
6458
|
+
"use strict";
|
|
6459
|
+
import_fs12 = __toESM(require("fs"));
|
|
6460
|
+
import_path14 = __toESM(require("path"));
|
|
6461
|
+
import_os11 = __toESM(require("os"));
|
|
6462
|
+
import_crypto5 = __toESM(require("crypto"));
|
|
6463
|
+
}
|
|
6464
|
+
});
|
|
6465
|
+
|
|
6308
6466
|
// src/setup.ts
|
|
6309
6467
|
function hasNode9McpServer(servers) {
|
|
6310
6468
|
const entry = servers["node9"];
|
|
@@ -6330,36 +6488,36 @@ function isStaleHookCommand(command) {
|
|
|
6330
6488
|
const tokens = command.split(/\s+/);
|
|
6331
6489
|
for (const tok of tokens) {
|
|
6332
6490
|
if (!tok.startsWith("/")) continue;
|
|
6333
|
-
if (!
|
|
6491
|
+
if (!import_fs13.default.existsSync(tok)) return true;
|
|
6334
6492
|
}
|
|
6335
6493
|
return false;
|
|
6336
6494
|
}
|
|
6337
6495
|
function readJson(filePath) {
|
|
6338
6496
|
try {
|
|
6339
|
-
if (
|
|
6340
|
-
return JSON.parse(
|
|
6497
|
+
if (import_fs13.default.existsSync(filePath)) {
|
|
6498
|
+
return JSON.parse(import_fs13.default.readFileSync(filePath, "utf-8"));
|
|
6341
6499
|
}
|
|
6342
6500
|
} catch {
|
|
6343
6501
|
}
|
|
6344
6502
|
return null;
|
|
6345
6503
|
}
|
|
6346
6504
|
function writeJson(filePath, data) {
|
|
6347
|
-
const dir =
|
|
6348
|
-
if (!
|
|
6349
|
-
|
|
6505
|
+
const dir = import_path15.default.dirname(filePath);
|
|
6506
|
+
if (!import_fs13.default.existsSync(dir)) import_fs13.default.mkdirSync(dir, { recursive: true });
|
|
6507
|
+
import_fs13.default.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n");
|
|
6350
6508
|
}
|
|
6351
6509
|
function isNode9Hook(cmd) {
|
|
6352
6510
|
if (!cmd) return false;
|
|
6353
6511
|
return /(?:^|[\s/\\])node9 (?:check|log)/.test(cmd) || /(?:^|[\s/\\])cli\.js (?:check|log)/.test(cmd);
|
|
6354
6512
|
}
|
|
6355
6513
|
function teardownClaude() {
|
|
6356
|
-
const homeDir2 =
|
|
6357
|
-
const hooksPath =
|
|
6358
|
-
const mcpPath =
|
|
6514
|
+
const homeDir2 = import_os12.default.homedir();
|
|
6515
|
+
const hooksPath = import_path15.default.join(homeDir2, ".claude", "settings.json");
|
|
6516
|
+
const mcpPath = import_path15.default.join(homeDir2, ".claude", ".mcp.json");
|
|
6359
6517
|
let changed = false;
|
|
6360
6518
|
const settings = readJson(hooksPath);
|
|
6361
6519
|
if (settings?.hooks) {
|
|
6362
|
-
for (const event of ["PreToolUse", "PostToolUse"]) {
|
|
6520
|
+
for (const event of ["PreToolUse", "PostToolUse", "UserPromptSubmit"]) {
|
|
6363
6521
|
const before = settings.hooks[event]?.length ?? 0;
|
|
6364
6522
|
settings.hooks[event] = settings.hooks[event]?.filter(
|
|
6365
6523
|
(m) => !m.hooks.some((h) => isNode9Hook(h.command))
|
|
@@ -6403,8 +6561,8 @@ function teardownClaude() {
|
|
|
6403
6561
|
}
|
|
6404
6562
|
}
|
|
6405
6563
|
function teardownGemini() {
|
|
6406
|
-
const homeDir2 =
|
|
6407
|
-
const settingsPath =
|
|
6564
|
+
const homeDir2 = import_os12.default.homedir();
|
|
6565
|
+
const settingsPath = import_path15.default.join(homeDir2, ".gemini", "settings.json");
|
|
6408
6566
|
const settings = readJson(settingsPath);
|
|
6409
6567
|
if (!settings) {
|
|
6410
6568
|
console.log(import_chalk.default.blue(" \u2139\uFE0F ~/.gemini/settings.json not found \u2014 nothing to remove"));
|
|
@@ -6447,8 +6605,8 @@ function teardownGemini() {
|
|
|
6447
6605
|
}
|
|
6448
6606
|
}
|
|
6449
6607
|
function teardownCursor() {
|
|
6450
|
-
const homeDir2 =
|
|
6451
|
-
const mcpPath =
|
|
6608
|
+
const homeDir2 = import_os12.default.homedir();
|
|
6609
|
+
const mcpPath = import_path15.default.join(homeDir2, ".cursor", "mcp.json");
|
|
6452
6610
|
const mcpConfig = readJson(mcpPath);
|
|
6453
6611
|
if (!mcpConfig?.mcpServers) {
|
|
6454
6612
|
console.log(import_chalk.default.blue(" \u2139\uFE0F ~/.cursor/mcp.json not found \u2014 nothing to remove"));
|
|
@@ -6479,9 +6637,10 @@ function teardownCursor() {
|
|
|
6479
6637
|
}
|
|
6480
6638
|
}
|
|
6481
6639
|
async function setupClaude() {
|
|
6482
|
-
|
|
6483
|
-
const
|
|
6484
|
-
const
|
|
6640
|
+
seedMcpPinsIfMissing();
|
|
6641
|
+
const homeDir2 = import_os12.default.homedir();
|
|
6642
|
+
const mcpPath = import_path15.default.join(homeDir2, ".claude", ".mcp.json");
|
|
6643
|
+
const hooksPath = import_path15.default.join(homeDir2, ".claude", "settings.json");
|
|
6485
6644
|
const claudeConfig = readJson(mcpPath) ?? {};
|
|
6486
6645
|
const settings = readJson(hooksPath) ?? {};
|
|
6487
6646
|
const servers = claudeConfig.mcpServers ?? {};
|
|
@@ -6540,6 +6699,33 @@ async function setupClaude() {
|
|
|
6540
6699
|
}
|
|
6541
6700
|
}
|
|
6542
6701
|
}
|
|
6702
|
+
const hasPromptHook = settings.hooks.UserPromptSubmit?.some(
|
|
6703
|
+
(m) => m.hooks.some((h) => isNode9Hook(h.command))
|
|
6704
|
+
);
|
|
6705
|
+
if (!hasPromptHook) {
|
|
6706
|
+
if (!settings.hooks.UserPromptSubmit) settings.hooks.UserPromptSubmit = [];
|
|
6707
|
+
settings.hooks.UserPromptSubmit.push({
|
|
6708
|
+
matcher: ".*",
|
|
6709
|
+
hooks: [{ type: "command", command: fullPathCommand("check"), timeout: 600 }]
|
|
6710
|
+
});
|
|
6711
|
+
console.log(import_chalk.default.green(" \u2705 UserPromptSubmit hook added \u2192 node9 check (prompt DLP)"));
|
|
6712
|
+
hooksChanged = true;
|
|
6713
|
+
anythingChanged = true;
|
|
6714
|
+
} else if (settings.hooks.UserPromptSubmit) {
|
|
6715
|
+
for (const matcher of settings.hooks.UserPromptSubmit) {
|
|
6716
|
+
for (const h of matcher.hooks) {
|
|
6717
|
+
const cmd = h.command ?? "";
|
|
6718
|
+
if (isNode9Hook(cmd) && isStaleHookCommand(cmd)) {
|
|
6719
|
+
h.command = fullPathCommand("check");
|
|
6720
|
+
console.log(
|
|
6721
|
+
import_chalk.default.yellow(" \u{1F527} UserPromptSubmit hook repaired (stale path \u2192 current binary)")
|
|
6722
|
+
);
|
|
6723
|
+
hooksChanged = true;
|
|
6724
|
+
anythingChanged = true;
|
|
6725
|
+
}
|
|
6726
|
+
}
|
|
6727
|
+
}
|
|
6728
|
+
}
|
|
6543
6729
|
if (!hasNode9McpServer(servers)) {
|
|
6544
6730
|
servers["node9"] = NODE9_MCP_SERVER_ENTRY;
|
|
6545
6731
|
claudeConfig.mcpServers = servers;
|
|
@@ -6604,8 +6790,9 @@ async function setupClaude() {
|
|
|
6604
6790
|
}
|
|
6605
6791
|
}
|
|
6606
6792
|
async function setupGemini() {
|
|
6607
|
-
|
|
6608
|
-
const
|
|
6793
|
+
seedMcpPinsIfMissing();
|
|
6794
|
+
const homeDir2 = import_os12.default.homedir();
|
|
6795
|
+
const settingsPath = import_path15.default.join(homeDir2, ".gemini", "settings.json");
|
|
6609
6796
|
const settings = readJson(settingsPath) ?? {};
|
|
6610
6797
|
const servers = settings.mcpServers ?? {};
|
|
6611
6798
|
let hooksChanged = false;
|
|
@@ -6700,9 +6887,9 @@ async function setupGemini() {
|
|
|
6700
6887
|
printDaemonTip();
|
|
6701
6888
|
}
|
|
6702
6889
|
}
|
|
6703
|
-
function claudeDesktopConfigPath(homeDir2 =
|
|
6890
|
+
function claudeDesktopConfigPath(homeDir2 = import_os12.default.homedir()) {
|
|
6704
6891
|
if (process.platform === "darwin") {
|
|
6705
|
-
return
|
|
6892
|
+
return import_path15.default.join(
|
|
6706
6893
|
homeDir2,
|
|
6707
6894
|
"Library",
|
|
6708
6895
|
"Application Support",
|
|
@@ -6711,18 +6898,18 @@ function claudeDesktopConfigPath(homeDir2 = import_os11.default.homedir()) {
|
|
|
6711
6898
|
);
|
|
6712
6899
|
}
|
|
6713
6900
|
if (process.platform === "linux") {
|
|
6714
|
-
return
|
|
6901
|
+
return import_path15.default.join(homeDir2, ".config", "Claude", "claude_desktop_config.json");
|
|
6715
6902
|
}
|
|
6716
6903
|
if (process.platform === "win32") {
|
|
6717
|
-
const appData = process.env.APPDATA ??
|
|
6718
|
-
return
|
|
6904
|
+
const appData = process.env.APPDATA ?? import_path15.default.join(homeDir2, "AppData", "Roaming");
|
|
6905
|
+
return import_path15.default.join(appData, "Claude", "claude_desktop_config.json");
|
|
6719
6906
|
}
|
|
6720
6907
|
return null;
|
|
6721
6908
|
}
|
|
6722
|
-
function detectAgents(homeDir2 =
|
|
6909
|
+
function detectAgents(homeDir2 = import_os12.default.homedir()) {
|
|
6723
6910
|
const exists = (p) => {
|
|
6724
6911
|
try {
|
|
6725
|
-
return
|
|
6912
|
+
return import_fs13.default.existsSync(p);
|
|
6726
6913
|
} catch (err2) {
|
|
6727
6914
|
const code = err2.code;
|
|
6728
6915
|
if (code !== "ENOENT") {
|
|
@@ -6734,18 +6921,19 @@ function detectAgents(homeDir2 = import_os11.default.homedir()) {
|
|
|
6734
6921
|
};
|
|
6735
6922
|
const desktopPath = claudeDesktopConfigPath(homeDir2);
|
|
6736
6923
|
return {
|
|
6737
|
-
claude: exists(
|
|
6738
|
-
gemini: exists(
|
|
6739
|
-
cursor: exists(
|
|
6740
|
-
codex: exists(
|
|
6741
|
-
windsurf: exists(
|
|
6742
|
-
vscode: exists(
|
|
6743
|
-
claudeDesktop: desktopPath !== null && exists(
|
|
6924
|
+
claude: exists(import_path15.default.join(homeDir2, ".claude")) || exists(import_path15.default.join(homeDir2, ".claude.json")),
|
|
6925
|
+
gemini: exists(import_path15.default.join(homeDir2, ".gemini")),
|
|
6926
|
+
cursor: exists(import_path15.default.join(homeDir2, ".cursor")),
|
|
6927
|
+
codex: exists(import_path15.default.join(homeDir2, ".codex")),
|
|
6928
|
+
windsurf: exists(import_path15.default.join(homeDir2, ".codeium", "windsurf")),
|
|
6929
|
+
vscode: exists(import_path15.default.join(homeDir2, ".vscode")),
|
|
6930
|
+
claudeDesktop: desktopPath !== null && exists(import_path15.default.dirname(desktopPath))
|
|
6744
6931
|
};
|
|
6745
6932
|
}
|
|
6746
6933
|
async function setupCursor() {
|
|
6747
|
-
|
|
6748
|
-
const
|
|
6934
|
+
seedMcpPinsIfMissing();
|
|
6935
|
+
const homeDir2 = import_os12.default.homedir();
|
|
6936
|
+
const mcpPath = import_path15.default.join(homeDir2, ".cursor", "mcp.json");
|
|
6749
6937
|
const mcpConfig = readJson(mcpPath) ?? {};
|
|
6750
6938
|
const servers = mcpConfig.mcpServers ?? {};
|
|
6751
6939
|
let anythingChanged = false;
|
|
@@ -6811,24 +6999,95 @@ async function setupCursor() {
|
|
|
6811
6999
|
}
|
|
6812
7000
|
function readToml(filePath) {
|
|
6813
7001
|
try {
|
|
6814
|
-
if (
|
|
6815
|
-
return (0, import_smol_toml.parse)(
|
|
7002
|
+
if (import_fs13.default.existsSync(filePath)) {
|
|
7003
|
+
return (0, import_smol_toml.parse)(import_fs13.default.readFileSync(filePath, "utf-8"));
|
|
6816
7004
|
}
|
|
6817
7005
|
} catch {
|
|
6818
7006
|
}
|
|
6819
7007
|
return null;
|
|
6820
7008
|
}
|
|
6821
7009
|
function writeToml(filePath, data) {
|
|
6822
|
-
const dir =
|
|
6823
|
-
if (!
|
|
6824
|
-
|
|
7010
|
+
const dir = import_path15.default.dirname(filePath);
|
|
7011
|
+
if (!import_fs13.default.existsSync(dir)) import_fs13.default.mkdirSync(dir, { recursive: true });
|
|
7012
|
+
import_fs13.default.writeFileSync(filePath, (0, import_smol_toml.stringify)(data));
|
|
6825
7013
|
}
|
|
6826
7014
|
async function setupCodex() {
|
|
6827
|
-
|
|
6828
|
-
const
|
|
7015
|
+
seedMcpPinsIfMissing();
|
|
7016
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7017
|
+
const configPath = import_path15.default.join(homeDir2, ".codex", "config.toml");
|
|
7018
|
+
const hooksPath = import_path15.default.join(homeDir2, ".codex", "hooks.json");
|
|
6829
7019
|
const config = readToml(configPath) ?? {};
|
|
6830
7020
|
const servers = config.mcp_servers ?? {};
|
|
6831
7021
|
let anythingChanged = false;
|
|
7022
|
+
const hooksFile = readJson(hooksPath) ?? {};
|
|
7023
|
+
if (!hooksFile.hooks) hooksFile.hooks = {};
|
|
7024
|
+
let hooksChanged = false;
|
|
7025
|
+
if (!hooksFile.hooks.PreToolUse) hooksFile.hooks.PreToolUse = [];
|
|
7026
|
+
for (const matcher of CODEX_PRE_TOOL_MATCHERS) {
|
|
7027
|
+
const existing = hooksFile.hooks.PreToolUse.find((m) => m.matcher === matcher);
|
|
7028
|
+
if (!existing) {
|
|
7029
|
+
hooksFile.hooks.PreToolUse.push({
|
|
7030
|
+
matcher,
|
|
7031
|
+
hooks: [{ type: "command", command: fullPathCommand("check"), timeout: 600 }]
|
|
7032
|
+
});
|
|
7033
|
+
hooksChanged = true;
|
|
7034
|
+
} else {
|
|
7035
|
+
for (const h of existing.hooks) {
|
|
7036
|
+
const cmd = h.command ?? "";
|
|
7037
|
+
if (isNode9Hook(cmd) && isStaleHookCommand(cmd)) {
|
|
7038
|
+
h.command = fullPathCommand("check");
|
|
7039
|
+
hooksChanged = true;
|
|
7040
|
+
}
|
|
7041
|
+
}
|
|
7042
|
+
}
|
|
7043
|
+
}
|
|
7044
|
+
if (!hooksFile.hooks.UserPromptSubmit) hooksFile.hooks.UserPromptSubmit = [];
|
|
7045
|
+
const hasPromptHook = hooksFile.hooks.UserPromptSubmit.some(
|
|
7046
|
+
(m) => m.hooks.some((h) => isNode9Hook(h.command))
|
|
7047
|
+
);
|
|
7048
|
+
if (!hasPromptHook) {
|
|
7049
|
+
hooksFile.hooks.UserPromptSubmit.push({
|
|
7050
|
+
hooks: [{ type: "command", command: fullPathCommand("check"), timeout: 600 }]
|
|
7051
|
+
});
|
|
7052
|
+
hooksChanged = true;
|
|
7053
|
+
} else {
|
|
7054
|
+
for (const m of hooksFile.hooks.UserPromptSubmit) {
|
|
7055
|
+
for (const h of m.hooks) {
|
|
7056
|
+
const cmd = h.command ?? "";
|
|
7057
|
+
if (isNode9Hook(cmd) && isStaleHookCommand(cmd)) {
|
|
7058
|
+
h.command = fullPathCommand("check");
|
|
7059
|
+
hooksChanged = true;
|
|
7060
|
+
}
|
|
7061
|
+
}
|
|
7062
|
+
}
|
|
7063
|
+
}
|
|
7064
|
+
if (!hooksFile.hooks.PostToolUse) hooksFile.hooks.PostToolUse = [];
|
|
7065
|
+
const hasPostHook = hooksFile.hooks.PostToolUse.some(
|
|
7066
|
+
(m) => m.hooks.some((h) => isNode9Hook(h.command))
|
|
7067
|
+
);
|
|
7068
|
+
if (!hasPostHook) {
|
|
7069
|
+
hooksFile.hooks.PostToolUse.push({
|
|
7070
|
+
matcher: ".*",
|
|
7071
|
+
hooks: [{ type: "command", command: fullPathCommand("log"), timeout: 600 }]
|
|
7072
|
+
});
|
|
7073
|
+
hooksChanged = true;
|
|
7074
|
+
} else {
|
|
7075
|
+
for (const m of hooksFile.hooks.PostToolUse) {
|
|
7076
|
+
for (const h of m.hooks) {
|
|
7077
|
+
const cmd = h.command ?? "";
|
|
7078
|
+
if (isNode9Hook(cmd) && isStaleHookCommand(cmd)) {
|
|
7079
|
+
h.command = fullPathCommand("log");
|
|
7080
|
+
hooksChanged = true;
|
|
7081
|
+
}
|
|
7082
|
+
}
|
|
7083
|
+
}
|
|
7084
|
+
}
|
|
7085
|
+
if (hooksChanged) {
|
|
7086
|
+
writeJson(hooksPath, hooksFile);
|
|
7087
|
+
console.log(import_chalk.default.green(" \u2705 Codex hooks added \u2192 node9 check / node9 log"));
|
|
7088
|
+
anythingChanged = true;
|
|
7089
|
+
}
|
|
7090
|
+
const hooksInstalled = (hooksFile.hooks?.PreToolUse?.length ?? 0) > 0;
|
|
6832
7091
|
if (!hasNode9McpServer(servers)) {
|
|
6833
7092
|
servers["node9"] = NODE9_MCP_SERVER_ENTRY;
|
|
6834
7093
|
config.mcp_servers = servers;
|
|
@@ -6868,30 +7127,63 @@ async function setupCodex() {
|
|
|
6868
7127
|
}
|
|
6869
7128
|
console.log("");
|
|
6870
7129
|
}
|
|
6871
|
-
|
|
6872
|
-
|
|
6873
|
-
" \u26A0\uFE0F Note: Codex does not yet support native pre-execution hooks.\n MCP proxy wrapping is the only supported protection mode for Codex.\n Native bash and file operations are not monitored."
|
|
6874
|
-
)
|
|
6875
|
-
);
|
|
6876
|
-
console.log("");
|
|
6877
|
-
if (!anythingChanged && serversToWrap.length === 0) {
|
|
7130
|
+
const hooksDisabled = config.features?.hooks === false || config.codex_hooks === false;
|
|
7131
|
+
if (hooksDisabled) {
|
|
6878
7132
|
console.log(
|
|
6879
|
-
import_chalk.default.
|
|
6880
|
-
"\
|
|
7133
|
+
import_chalk.default.yellow(
|
|
7134
|
+
" \u26A0\uFE0F Codex hooks are disabled in ~/.codex/config.toml ([features].hooks = false).\n Re-enable hooks to activate Node9 shield evaluation on Bash, apply_patch,\n MCP tool calls, and prompt submissions. Until then, only MCP proxy wrapping\n is active."
|
|
7135
|
+
)
|
|
7136
|
+
);
|
|
7137
|
+
console.log("");
|
|
7138
|
+
}
|
|
7139
|
+
const printCodexTrustReminder = () => {
|
|
7140
|
+
console.log(
|
|
7141
|
+
import_chalk.default.yellow(
|
|
7142
|
+
" \u279C Open Codex and run /hooks to review and trust the Node9 entries.\n Until trusted, only MCP proxy wrapping is active."
|
|
6881
7143
|
)
|
|
6882
7144
|
);
|
|
7145
|
+
};
|
|
7146
|
+
if (!anythingChanged && serversToWrap.length === 0) {
|
|
7147
|
+
if (hooksInstalled) {
|
|
7148
|
+
console.log(import_chalk.default.blue("\u2139\uFE0F Codex hooks already installed."));
|
|
7149
|
+
printCodexTrustReminder();
|
|
7150
|
+
} else {
|
|
7151
|
+
console.log(
|
|
7152
|
+
import_chalk.default.blue(
|
|
7153
|
+
"\u2139\uFE0F No MCP servers found to wrap. Add MCP servers to ~/.codex/config.toml and re-run."
|
|
7154
|
+
)
|
|
7155
|
+
);
|
|
7156
|
+
}
|
|
6883
7157
|
printDaemonTip();
|
|
6884
7158
|
return;
|
|
6885
7159
|
}
|
|
6886
7160
|
if (anythingChanged) {
|
|
6887
|
-
console.log(import_chalk.default.green.bold("\u{1F6E1}\uFE0F Node9
|
|
7161
|
+
console.log(import_chalk.default.green.bold("\u{1F6E1}\uFE0F Node9 hooks installed for Codex."));
|
|
7162
|
+
printCodexTrustReminder();
|
|
6888
7163
|
console.log(import_chalk.default.gray(" Restart Codex for changes to take effect."));
|
|
6889
7164
|
printDaemonTip();
|
|
6890
7165
|
}
|
|
6891
7166
|
}
|
|
6892
7167
|
function teardownCodex() {
|
|
6893
|
-
const homeDir2 =
|
|
6894
|
-
const configPath =
|
|
7168
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7169
|
+
const configPath = import_path15.default.join(homeDir2, ".codex", "config.toml");
|
|
7170
|
+
const hooksPath = import_path15.default.join(homeDir2, ".codex", "hooks.json");
|
|
7171
|
+
const hooksFile = readJson(hooksPath);
|
|
7172
|
+
if (hooksFile?.hooks) {
|
|
7173
|
+
let hooksChanged = false;
|
|
7174
|
+
for (const event of ["PreToolUse", "PostToolUse", "UserPromptSubmit"]) {
|
|
7175
|
+
const before = hooksFile.hooks[event]?.length ?? 0;
|
|
7176
|
+
hooksFile.hooks[event] = hooksFile.hooks[event]?.filter(
|
|
7177
|
+
(m) => !m.hooks.some((h) => isNode9Hook(h.command))
|
|
7178
|
+
);
|
|
7179
|
+
if ((hooksFile.hooks[event]?.length ?? 0) < before) hooksChanged = true;
|
|
7180
|
+
if (hooksFile.hooks[event]?.length === 0) delete hooksFile.hooks[event];
|
|
7181
|
+
}
|
|
7182
|
+
if (hooksChanged) {
|
|
7183
|
+
writeJson(hooksPath, hooksFile);
|
|
7184
|
+
console.log(import_chalk.default.green(" \u2705 Removed Node9 hooks from ~/.codex/hooks.json"));
|
|
7185
|
+
}
|
|
7186
|
+
}
|
|
6895
7187
|
const config = readToml(configPath);
|
|
6896
7188
|
if (!config?.mcp_servers) {
|
|
6897
7189
|
console.log(import_chalk.default.blue(" \u2139\uFE0F ~/.codex/config.toml not found \u2014 nothing to remove"));
|
|
@@ -6922,8 +7214,8 @@ function teardownCodex() {
|
|
|
6922
7214
|
}
|
|
6923
7215
|
}
|
|
6924
7216
|
function setupHud() {
|
|
6925
|
-
const homeDir2 =
|
|
6926
|
-
const hooksPath =
|
|
7217
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7218
|
+
const hooksPath = import_path15.default.join(homeDir2, ".claude", "settings.json");
|
|
6927
7219
|
const settings = readJson(hooksPath) ?? {};
|
|
6928
7220
|
const hudCommand = fullPathCommand("hud");
|
|
6929
7221
|
const statusLineObj = { type: "command", command: hudCommand };
|
|
@@ -6949,8 +7241,8 @@ function setupHud() {
|
|
|
6949
7241
|
console.log(import_chalk.default.gray(" Restart Claude Code to activate."));
|
|
6950
7242
|
}
|
|
6951
7243
|
function teardownHud() {
|
|
6952
|
-
const homeDir2 =
|
|
6953
|
-
const hooksPath =
|
|
7244
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7245
|
+
const hooksPath = import_path15.default.join(homeDir2, ".claude", "settings.json");
|
|
6954
7246
|
const settings = readJson(hooksPath);
|
|
6955
7247
|
if (!settings) {
|
|
6956
7248
|
console.log(import_chalk.default.blue(" \u2139\uFE0F ~/.claude/settings.json not found \u2014 nothing to remove"));
|
|
@@ -6968,8 +7260,9 @@ function teardownHud() {
|
|
|
6968
7260
|
console.log(import_chalk.default.gray(" Restart Claude Code for changes to take effect."));
|
|
6969
7261
|
}
|
|
6970
7262
|
async function setupWindsurf() {
|
|
6971
|
-
|
|
6972
|
-
const
|
|
7263
|
+
seedMcpPinsIfMissing();
|
|
7264
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7265
|
+
const mcpPath = import_path15.default.join(homeDir2, ".codeium", "windsurf", "mcp_config.json");
|
|
6973
7266
|
const mcpConfig = readJson(mcpPath) ?? {};
|
|
6974
7267
|
const servers = mcpConfig.mcpServers ?? {};
|
|
6975
7268
|
let anythingChanged = false;
|
|
@@ -7029,8 +7322,8 @@ async function setupWindsurf() {
|
|
|
7029
7322
|
}
|
|
7030
7323
|
}
|
|
7031
7324
|
function teardownWindsurf() {
|
|
7032
|
-
const homeDir2 =
|
|
7033
|
-
const mcpPath =
|
|
7325
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7326
|
+
const mcpPath = import_path15.default.join(homeDir2, ".codeium", "windsurf", "mcp_config.json");
|
|
7034
7327
|
const mcpConfig = readJson(mcpPath);
|
|
7035
7328
|
if (!mcpConfig?.mcpServers) {
|
|
7036
7329
|
console.log(
|
|
@@ -7071,8 +7364,9 @@ function hasNode9McpServerVSCode(servers) {
|
|
|
7071
7364
|
return !!entry && entry.command === "node9" && Array.isArray(entry.args) && entry.args[0] === "mcp-server";
|
|
7072
7365
|
}
|
|
7073
7366
|
async function setupVSCode() {
|
|
7074
|
-
|
|
7075
|
-
const
|
|
7367
|
+
seedMcpPinsIfMissing();
|
|
7368
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7369
|
+
const mcpPath = import_path15.default.join(homeDir2, ".vscode", "mcp.json");
|
|
7076
7370
|
const mcpConfig = readJson(mcpPath) ?? {};
|
|
7077
7371
|
const servers = mcpConfig.servers ?? {};
|
|
7078
7372
|
let anythingChanged = false;
|
|
@@ -7133,8 +7427,8 @@ async function setupVSCode() {
|
|
|
7133
7427
|
}
|
|
7134
7428
|
}
|
|
7135
7429
|
function teardownVSCode() {
|
|
7136
|
-
const homeDir2 =
|
|
7137
|
-
const mcpPath =
|
|
7430
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7431
|
+
const mcpPath = import_path15.default.join(homeDir2, ".vscode", "mcp.json");
|
|
7138
7432
|
const mcpConfig = readJson(mcpPath);
|
|
7139
7433
|
if (!mcpConfig?.servers) {
|
|
7140
7434
|
console.log(import_chalk.default.blue(" \u2139\uFE0F ~/.vscode/mcp.json not found \u2014 nothing to remove"));
|
|
@@ -7167,6 +7461,7 @@ function teardownVSCode() {
|
|
|
7167
7461
|
}
|
|
7168
7462
|
}
|
|
7169
7463
|
async function setupClaudeDesktop() {
|
|
7464
|
+
seedMcpPinsIfMissing();
|
|
7170
7465
|
const configPath = claudeDesktopConfigPath();
|
|
7171
7466
|
if (!configPath) {
|
|
7172
7467
|
console.log(import_chalk.default.yellow(" \u26A0\uFE0F Claude Desktop is not supported on this platform."));
|
|
@@ -7265,32 +7560,32 @@ function teardownClaudeDesktop() {
|
|
|
7265
7560
|
console.log(import_chalk.default.blue(" \u2139\uFE0F No Node9-wrapped MCP servers found in Claude Desktop config"));
|
|
7266
7561
|
}
|
|
7267
7562
|
}
|
|
7268
|
-
function getAgentsStatus(homeDir2 =
|
|
7563
|
+
function getAgentsStatus(homeDir2 = import_os12.default.homedir()) {
|
|
7269
7564
|
const detected = detectAgents(homeDir2);
|
|
7270
7565
|
const claudeWired = (() => {
|
|
7271
|
-
const settings = readJson(
|
|
7566
|
+
const settings = readJson(import_path15.default.join(homeDir2, ".claude", "settings.json"));
|
|
7272
7567
|
return !!settings?.hooks?.PreToolUse?.some((m) => m.hooks.some((h) => isNode9Hook(h.command)));
|
|
7273
7568
|
})();
|
|
7274
7569
|
const geminiWired = (() => {
|
|
7275
|
-
const settings = readJson(
|
|
7570
|
+
const settings = readJson(import_path15.default.join(homeDir2, ".gemini", "settings.json"));
|
|
7276
7571
|
return !!settings?.hooks?.BeforeTool?.some((m) => m.hooks.some((h) => isNode9Hook(h.command)));
|
|
7277
7572
|
})();
|
|
7278
7573
|
const cursorWired = (() => {
|
|
7279
|
-
const cfg = readJson(
|
|
7574
|
+
const cfg = readJson(import_path15.default.join(homeDir2, ".cursor", "mcp.json"));
|
|
7280
7575
|
return !!(cfg?.mcpServers && hasNode9McpServer(cfg.mcpServers));
|
|
7281
7576
|
})();
|
|
7282
7577
|
const codexWired = (() => {
|
|
7283
|
-
const cfg = readToml(
|
|
7578
|
+
const cfg = readToml(import_path15.default.join(homeDir2, ".codex", "config.toml"));
|
|
7284
7579
|
return !!(cfg?.mcp_servers && hasNode9McpServer(cfg.mcp_servers));
|
|
7285
7580
|
})();
|
|
7286
7581
|
const windsurfWired = (() => {
|
|
7287
7582
|
const cfg = readJson(
|
|
7288
|
-
|
|
7583
|
+
import_path15.default.join(homeDir2, ".codeium", "windsurf", "mcp_config.json")
|
|
7289
7584
|
);
|
|
7290
7585
|
return !!(cfg?.mcpServers && hasNode9McpServer(cfg.mcpServers));
|
|
7291
7586
|
})();
|
|
7292
7587
|
const vscodeWired = (() => {
|
|
7293
|
-
const cfg = readJson(
|
|
7588
|
+
const cfg = readJson(import_path15.default.join(homeDir2, ".vscode", "mcp.json"));
|
|
7294
7589
|
return !!(cfg?.servers && hasNode9McpServerVSCode(cfg.servers));
|
|
7295
7590
|
})();
|
|
7296
7591
|
return [
|
|
@@ -7350,17 +7645,19 @@ function getAgentsStatus(homeDir2 = import_os11.default.homedir()) {
|
|
|
7350
7645
|
}
|
|
7351
7646
|
];
|
|
7352
7647
|
}
|
|
7353
|
-
var
|
|
7648
|
+
var import_fs13, import_path15, import_os12, import_chalk, import_prompts, import_smol_toml, NODE9_MCP_SERVER_ENTRY, CODEX_PRE_TOOL_MATCHERS;
|
|
7354
7649
|
var init_setup = __esm({
|
|
7355
7650
|
"src/setup.ts"() {
|
|
7356
7651
|
"use strict";
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
7652
|
+
import_fs13 = __toESM(require("fs"));
|
|
7653
|
+
import_path15 = __toESM(require("path"));
|
|
7654
|
+
import_os12 = __toESM(require("os"));
|
|
7360
7655
|
import_chalk = __toESM(require("chalk"));
|
|
7361
7656
|
import_prompts = require("@inquirer/prompts");
|
|
7362
7657
|
import_smol_toml = require("smol-toml");
|
|
7658
|
+
init_mcp_pin();
|
|
7363
7659
|
NODE9_MCP_SERVER_ENTRY = { command: "node9", args: ["mcp-server"] };
|
|
7660
|
+
CODEX_PRE_TOOL_MATCHERS = ["^Bash$", "^apply_patch$", "^mcp__.*"];
|
|
7364
7661
|
}
|
|
7365
7662
|
});
|
|
7366
7663
|
|
|
@@ -7554,79 +7851,79 @@ var init_scan_summary = __esm({
|
|
|
7554
7851
|
function buildSensitivePaths(home, cwd) {
|
|
7555
7852
|
return [
|
|
7556
7853
|
{
|
|
7557
|
-
full:
|
|
7854
|
+
full: import_path16.default.join(home, ".ssh", "id_rsa"),
|
|
7558
7855
|
label: "~/.ssh/id_rsa",
|
|
7559
7856
|
description: "RSA private key \u2014 grants SSH access to your servers",
|
|
7560
7857
|
score: 20
|
|
7561
7858
|
},
|
|
7562
7859
|
{
|
|
7563
|
-
full:
|
|
7860
|
+
full: import_path16.default.join(home, ".ssh", "id_ed25519"),
|
|
7564
7861
|
label: "~/.ssh/id_ed25519",
|
|
7565
7862
|
description: "Ed25519 private key \u2014 grants SSH access to your servers",
|
|
7566
7863
|
score: 20
|
|
7567
7864
|
},
|
|
7568
7865
|
{
|
|
7569
|
-
full:
|
|
7866
|
+
full: import_path16.default.join(home, ".ssh", "id_ecdsa"),
|
|
7570
7867
|
label: "~/.ssh/id_ecdsa",
|
|
7571
7868
|
description: "ECDSA private key \u2014 grants SSH access to your servers",
|
|
7572
7869
|
score: 20
|
|
7573
7870
|
},
|
|
7574
7871
|
{
|
|
7575
|
-
full:
|
|
7872
|
+
full: import_path16.default.join(home, ".aws", "credentials"),
|
|
7576
7873
|
label: "~/.aws/credentials",
|
|
7577
7874
|
description: "AWS access keys \u2014 full cloud account access",
|
|
7578
7875
|
score: 20
|
|
7579
7876
|
},
|
|
7580
7877
|
{
|
|
7581
|
-
full:
|
|
7878
|
+
full: import_path16.default.join(home, ".aws", "config"),
|
|
7582
7879
|
label: "~/.aws/config",
|
|
7583
7880
|
description: "AWS configuration \u2014 account and region settings",
|
|
7584
7881
|
score: 5
|
|
7585
7882
|
},
|
|
7586
7883
|
{
|
|
7587
|
-
full:
|
|
7884
|
+
full: import_path16.default.join(home, ".config", "gcloud", "credentials.db"),
|
|
7588
7885
|
label: "~/.config/gcloud/credentials.db",
|
|
7589
7886
|
description: "Google Cloud credentials",
|
|
7590
7887
|
score: 15
|
|
7591
7888
|
},
|
|
7592
7889
|
{
|
|
7593
|
-
full:
|
|
7890
|
+
full: import_path16.default.join(home, ".docker", "config.json"),
|
|
7594
7891
|
label: "~/.docker/config.json",
|
|
7595
7892
|
description: "Docker registry auth tokens",
|
|
7596
7893
|
score: 10
|
|
7597
7894
|
},
|
|
7598
7895
|
{
|
|
7599
|
-
full:
|
|
7896
|
+
full: import_path16.default.join(home, ".netrc"),
|
|
7600
7897
|
label: "~/.netrc",
|
|
7601
7898
|
description: "FTP/HTTP credentials in plain text",
|
|
7602
7899
|
score: 15
|
|
7603
7900
|
},
|
|
7604
7901
|
{
|
|
7605
|
-
full:
|
|
7902
|
+
full: import_path16.default.join(home, ".npmrc"),
|
|
7606
7903
|
label: "~/.npmrc",
|
|
7607
7904
|
description: "npm auth token \u2014 can publish packages as you",
|
|
7608
7905
|
score: 10
|
|
7609
7906
|
},
|
|
7610
7907
|
{
|
|
7611
|
-
full:
|
|
7908
|
+
full: import_path16.default.join(home, ".node9", "credentials.json"),
|
|
7612
7909
|
label: "~/.node9/credentials.json",
|
|
7613
7910
|
description: "Node9 cloud API key",
|
|
7614
7911
|
score: 10
|
|
7615
7912
|
},
|
|
7616
7913
|
{
|
|
7617
|
-
full:
|
|
7914
|
+
full: import_path16.default.join(cwd, ".env"),
|
|
7618
7915
|
label: ".env (current folder)",
|
|
7619
7916
|
description: "App secrets \u2014 database passwords, API keys",
|
|
7620
7917
|
score: 20
|
|
7621
7918
|
},
|
|
7622
7919
|
{
|
|
7623
|
-
full:
|
|
7920
|
+
full: import_path16.default.join(cwd, ".env.local"),
|
|
7624
7921
|
label: ".env.local (current folder)",
|
|
7625
7922
|
description: "Local overrides \u2014 often contains real credentials",
|
|
7626
7923
|
score: 15
|
|
7627
7924
|
},
|
|
7628
7925
|
{
|
|
7629
|
-
full:
|
|
7926
|
+
full: import_path16.default.join(cwd, ".env.production"),
|
|
7630
7927
|
label: ".env.production (current folder)",
|
|
7631
7928
|
description: "Production secrets",
|
|
7632
7929
|
score: 20
|
|
@@ -7635,7 +7932,7 @@ function buildSensitivePaths(home, cwd) {
|
|
|
7635
7932
|
}
|
|
7636
7933
|
function isReadable(filePath) {
|
|
7637
7934
|
try {
|
|
7638
|
-
|
|
7935
|
+
import_fs14.default.accessSync(filePath, import_fs14.default.constants.R_OK);
|
|
7639
7936
|
return true;
|
|
7640
7937
|
} catch {
|
|
7641
7938
|
return false;
|
|
@@ -7648,13 +7945,13 @@ function scoreLabel(score) {
|
|
|
7648
7945
|
return import_chalk2.default.red.bold(`${score}/100 Critical`);
|
|
7649
7946
|
}
|
|
7650
7947
|
function runBlast() {
|
|
7651
|
-
const home =
|
|
7948
|
+
const home = import_os13.default.homedir();
|
|
7652
7949
|
const cwd = process.cwd();
|
|
7653
7950
|
const paths = buildSensitivePaths(home, cwd);
|
|
7654
7951
|
let scoreDeduction = 0;
|
|
7655
7952
|
const reachable = [];
|
|
7656
7953
|
for (const p of paths) {
|
|
7657
|
-
if (
|
|
7954
|
+
if (import_fs14.default.existsSync(p.full) && isReadable(p.full)) {
|
|
7658
7955
|
reachable.push(p);
|
|
7659
7956
|
scoreDeduction += p.score;
|
|
7660
7957
|
}
|
|
@@ -7672,7 +7969,7 @@ function runBlast() {
|
|
|
7672
7969
|
}
|
|
7673
7970
|
function registerBlastCommand(program2) {
|
|
7674
7971
|
program2.command("blast").description("Map what an AI agent can currently reach on this machine").action(() => {
|
|
7675
|
-
const home =
|
|
7972
|
+
const home = import_os13.default.homedir();
|
|
7676
7973
|
const cwd = process.cwd();
|
|
7677
7974
|
const { reachable, envFindings, score } = runBlast();
|
|
7678
7975
|
console.log("");
|
|
@@ -7719,14 +8016,14 @@ function registerBlastCommand(program2) {
|
|
|
7719
8016
|
console.log("");
|
|
7720
8017
|
});
|
|
7721
8018
|
}
|
|
7722
|
-
var import_chalk2,
|
|
8019
|
+
var import_chalk2, import_fs14, import_path16, import_os13;
|
|
7723
8020
|
var init_blast = __esm({
|
|
7724
8021
|
"src/cli/commands/blast.ts"() {
|
|
7725
8022
|
"use strict";
|
|
7726
8023
|
import_chalk2 = __toESM(require("chalk"));
|
|
7727
|
-
|
|
7728
|
-
|
|
7729
|
-
|
|
8024
|
+
import_fs14 = __toESM(require("fs"));
|
|
8025
|
+
import_path16 = __toESM(require("path"));
|
|
8026
|
+
import_os13 = __toESM(require("os"));
|
|
7730
8027
|
init_dlp();
|
|
7731
8028
|
}
|
|
7732
8029
|
});
|
|
@@ -7854,13 +8151,13 @@ var init_scan_json = __esm({
|
|
|
7854
8151
|
|
|
7855
8152
|
// src/cli/render/scan-history.ts
|
|
7856
8153
|
function defaultHistoryPath() {
|
|
7857
|
-
return
|
|
8154
|
+
return import_path17.default.join(import_os14.default.homedir(), ".node9", "scan-history.json");
|
|
7858
8155
|
}
|
|
7859
8156
|
function readPreviousScan(opts = {}) {
|
|
7860
8157
|
const filePath = opts.path ?? defaultHistoryPath();
|
|
7861
8158
|
try {
|
|
7862
|
-
if (!
|
|
7863
|
-
const raw =
|
|
8159
|
+
if (!import_fs15.default.existsSync(filePath)) return null;
|
|
8160
|
+
const raw = import_fs15.default.readFileSync(filePath, "utf8");
|
|
7864
8161
|
const parsed = JSON.parse(raw);
|
|
7865
8162
|
if (!Array.isArray(parsed) || parsed.length === 0) return null;
|
|
7866
8163
|
const last = parsed[parsed.length - 1];
|
|
@@ -7874,11 +8171,11 @@ function appendScanHistory(record, opts = {}) {
|
|
|
7874
8171
|
const filePath = opts.path ?? defaultHistoryPath();
|
|
7875
8172
|
const cap = opts.cap ?? SCAN_HISTORY_CAP;
|
|
7876
8173
|
try {
|
|
7877
|
-
|
|
8174
|
+
import_fs15.default.mkdirSync(import_path17.default.dirname(filePath), { recursive: true });
|
|
7878
8175
|
let history = [];
|
|
7879
|
-
if (
|
|
8176
|
+
if (import_fs15.default.existsSync(filePath)) {
|
|
7880
8177
|
try {
|
|
7881
|
-
const parsed = JSON.parse(
|
|
8178
|
+
const parsed = JSON.parse(import_fs15.default.readFileSync(filePath, "utf8"));
|
|
7882
8179
|
if (Array.isArray(parsed)) {
|
|
7883
8180
|
history = parsed.filter(isValidRecord);
|
|
7884
8181
|
}
|
|
@@ -7889,7 +8186,7 @@ function appendScanHistory(record, opts = {}) {
|
|
|
7889
8186
|
if (history.length > cap) {
|
|
7890
8187
|
history = history.slice(history.length - cap);
|
|
7891
8188
|
}
|
|
7892
|
-
|
|
8189
|
+
import_fs15.default.writeFileSync(filePath, JSON.stringify(history, null, 2));
|
|
7893
8190
|
} catch (err2) {
|
|
7894
8191
|
process.stderr.write(
|
|
7895
8192
|
`[node9] Warning: could not write scan-history.json: ${err2.message}
|
|
@@ -7911,13 +8208,13 @@ function isValidRecord(x) {
|
|
|
7911
8208
|
const r = x;
|
|
7912
8209
|
return typeof r.timestamp === "string" && typeof r.score === "number" && typeof r.blocked === "number" && typeof r.review === "number" && typeof r.leaks === "number" && typeof r.loops === "number" && typeof r.totalCalls === "number";
|
|
7913
8210
|
}
|
|
7914
|
-
var
|
|
8211
|
+
var import_fs15, import_path17, import_os14, SCAN_HISTORY_CAP;
|
|
7915
8212
|
var init_scan_history = __esm({
|
|
7916
8213
|
"src/cli/render/scan-history.ts"() {
|
|
7917
8214
|
"use strict";
|
|
7918
|
-
|
|
7919
|
-
|
|
7920
|
-
|
|
8215
|
+
import_fs15 = __toESM(require("fs"));
|
|
8216
|
+
import_path17 = __toESM(require("path"));
|
|
8217
|
+
import_os14 = __toESM(require("os"));
|
|
7921
8218
|
SCAN_HISTORY_CAP = 30;
|
|
7922
8219
|
}
|
|
7923
8220
|
});
|
|
@@ -7928,7 +8225,7 @@ function normalizeModel(raw) {
|
|
|
7928
8225
|
}
|
|
7929
8226
|
function readCache() {
|
|
7930
8227
|
try {
|
|
7931
|
-
const raw = JSON.parse(
|
|
8228
|
+
const raw = JSON.parse(import_fs16.default.readFileSync(CACHE_FILE(), "utf-8"));
|
|
7932
8229
|
if (typeof raw.fetchedAt !== "string" || typeof raw.prices !== "object" || raw.prices === null) {
|
|
7933
8230
|
return null;
|
|
7934
8231
|
}
|
|
@@ -7942,18 +8239,18 @@ function readCache() {
|
|
|
7942
8239
|
function writeCache(prices) {
|
|
7943
8240
|
try {
|
|
7944
8241
|
const target = CACHE_FILE();
|
|
7945
|
-
const dir =
|
|
7946
|
-
if (!
|
|
8242
|
+
const dir = import_path18.default.dirname(target);
|
|
8243
|
+
if (!import_fs16.default.existsSync(dir)) import_fs16.default.mkdirSync(dir, { recursive: true });
|
|
7947
8244
|
const tmp = target + ".tmp";
|
|
7948
8245
|
const body = {
|
|
7949
8246
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7950
8247
|
prices
|
|
7951
8248
|
};
|
|
7952
|
-
|
|
7953
|
-
|
|
8249
|
+
import_fs16.default.writeFileSync(tmp, JSON.stringify(body) + "\n", "utf-8");
|
|
8250
|
+
import_fs16.default.renameSync(tmp, target);
|
|
7954
8251
|
} catch (err2) {
|
|
7955
8252
|
try {
|
|
7956
|
-
|
|
8253
|
+
import_fs16.default.appendFileSync(
|
|
7957
8254
|
HOOK_DEBUG_LOG,
|
|
7958
8255
|
`[pricing] cache write failed: ${err2.message}
|
|
7959
8256
|
`
|
|
@@ -8046,13 +8343,13 @@ function pricingFor(model) {
|
|
|
8046
8343
|
lookupCache.set(norm, resolved);
|
|
8047
8344
|
return resolved;
|
|
8048
8345
|
}
|
|
8049
|
-
var
|
|
8346
|
+
var import_fs16, import_path18, import_os15, LITELLM_URL, BUNDLED_PRICING, CACHE_FILE, TTL_MS, memCache, memCacheAt, lookupCache;
|
|
8050
8347
|
var init_litellm = __esm({
|
|
8051
8348
|
"src/pricing/litellm.ts"() {
|
|
8052
8349
|
"use strict";
|
|
8053
|
-
|
|
8054
|
-
|
|
8055
|
-
|
|
8350
|
+
import_fs16 = __toESM(require("fs"));
|
|
8351
|
+
import_path18 = __toESM(require("path"));
|
|
8352
|
+
import_os15 = __toESM(require("os"));
|
|
8056
8353
|
init_audit();
|
|
8057
8354
|
LITELLM_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json";
|
|
8058
8355
|
BUNDLED_PRICING = {
|
|
@@ -8079,7 +8376,7 @@ var init_litellm = __esm({
|
|
|
8079
8376
|
"gemini-2.0-flash": [75e-9, 3e-7, 0, 0],
|
|
8080
8377
|
"gemini-1.5-pro": [125e-8, 5e-6, 0, 0]
|
|
8081
8378
|
};
|
|
8082
|
-
CACHE_FILE = () =>
|
|
8379
|
+
CACHE_FILE = () => import_path18.default.join(import_os15.default.homedir(), ".node9", "model-pricing.json");
|
|
8083
8380
|
TTL_MS = 24 * 60 * 60 * 1e3;
|
|
8084
8381
|
memCache = null;
|
|
8085
8382
|
memCacheAt = 0;
|
|
@@ -8092,10 +8389,10 @@ function decodeProjectDirName(dirName) {
|
|
|
8092
8389
|
return dirName.replace(/-/g, "/");
|
|
8093
8390
|
}
|
|
8094
8391
|
function parseJSONLFile(filePath, fallbackWorkingDir) {
|
|
8095
|
-
const runId =
|
|
8392
|
+
const runId = import_path19.default.basename(filePath, ".jsonl");
|
|
8096
8393
|
let content;
|
|
8097
8394
|
try {
|
|
8098
|
-
content =
|
|
8395
|
+
content = import_fs17.default.readFileSync(filePath, "utf8");
|
|
8099
8396
|
} catch {
|
|
8100
8397
|
return /* @__PURE__ */ new Map();
|
|
8101
8398
|
}
|
|
@@ -8151,34 +8448,34 @@ function parseJSONLFile(filePath, fallbackWorkingDir) {
|
|
|
8151
8448
|
return daily;
|
|
8152
8449
|
}
|
|
8153
8450
|
function collectEntries(sinceMs) {
|
|
8154
|
-
const projectsDir =
|
|
8155
|
-
if (!
|
|
8451
|
+
const projectsDir = import_path19.default.join(import_os16.default.homedir(), ".claude", "projects");
|
|
8452
|
+
if (!import_fs17.default.existsSync(projectsDir)) return [];
|
|
8156
8453
|
const combined = /* @__PURE__ */ new Map();
|
|
8157
8454
|
let dirs;
|
|
8158
8455
|
try {
|
|
8159
|
-
dirs =
|
|
8456
|
+
dirs = import_fs17.default.readdirSync(projectsDir);
|
|
8160
8457
|
} catch {
|
|
8161
8458
|
return [];
|
|
8162
8459
|
}
|
|
8163
8460
|
for (const dir of dirs) {
|
|
8164
|
-
const dirPath =
|
|
8461
|
+
const dirPath = import_path19.default.join(projectsDir, dir);
|
|
8165
8462
|
try {
|
|
8166
|
-
if (!
|
|
8463
|
+
if (!import_fs17.default.statSync(dirPath).isDirectory()) continue;
|
|
8167
8464
|
} catch {
|
|
8168
8465
|
continue;
|
|
8169
8466
|
}
|
|
8170
8467
|
let files;
|
|
8171
8468
|
try {
|
|
8172
|
-
files =
|
|
8469
|
+
files = import_fs17.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
8173
8470
|
} catch {
|
|
8174
8471
|
continue;
|
|
8175
8472
|
}
|
|
8176
8473
|
const fallbackWorkingDir = decodeProjectDirName(dir);
|
|
8177
8474
|
for (const file of files) {
|
|
8178
|
-
const filePath =
|
|
8475
|
+
const filePath = import_path19.default.join(dirPath, file);
|
|
8179
8476
|
if (sinceMs !== void 0) {
|
|
8180
8477
|
try {
|
|
8181
|
-
if (
|
|
8478
|
+
if (import_fs17.default.statSync(filePath).mtimeMs < sinceMs) continue;
|
|
8182
8479
|
} catch {
|
|
8183
8480
|
continue;
|
|
8184
8481
|
}
|
|
@@ -8208,10 +8505,10 @@ async function syncCost() {
|
|
|
8208
8505
|
if (entries.length === 0) return;
|
|
8209
8506
|
let username = "unknown";
|
|
8210
8507
|
try {
|
|
8211
|
-
username =
|
|
8508
|
+
username = import_os16.default.userInfo().username;
|
|
8212
8509
|
} catch {
|
|
8213
8510
|
}
|
|
8214
|
-
const machineId = `${
|
|
8511
|
+
const machineId = `${import_os16.default.hostname()}:${username}`;
|
|
8215
8512
|
try {
|
|
8216
8513
|
const res = await fetch(`${creds.apiUrl}/cost-sync`, {
|
|
8217
8514
|
method: "POST",
|
|
@@ -8220,11 +8517,11 @@ async function syncCost() {
|
|
|
8220
8517
|
signal: AbortSignal.timeout(15e3)
|
|
8221
8518
|
});
|
|
8222
8519
|
if (!res.ok) {
|
|
8223
|
-
|
|
8520
|
+
import_fs17.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
|
|
8224
8521
|
`);
|
|
8225
8522
|
}
|
|
8226
8523
|
} catch (err2) {
|
|
8227
|
-
|
|
8524
|
+
import_fs17.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
|
|
8228
8525
|
`);
|
|
8229
8526
|
}
|
|
8230
8527
|
}
|
|
@@ -8237,13 +8534,13 @@ function startCostSync() {
|
|
|
8237
8534
|
}, SYNC_INTERVAL_MS);
|
|
8238
8535
|
timer.unref();
|
|
8239
8536
|
}
|
|
8240
|
-
var
|
|
8537
|
+
var import_fs17, import_path19, import_os16, SYNC_INTERVAL_MS;
|
|
8241
8538
|
var init_costSync = __esm({
|
|
8242
8539
|
"src/costSync.ts"() {
|
|
8243
8540
|
"use strict";
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8541
|
+
import_fs17 = __toESM(require("fs"));
|
|
8542
|
+
import_path19 = __toESM(require("path"));
|
|
8543
|
+
import_os16 = __toESM(require("os"));
|
|
8247
8544
|
init_config();
|
|
8248
8545
|
init_audit();
|
|
8249
8546
|
init_litellm();
|
|
@@ -8274,7 +8571,7 @@ function freshWatermark() {
|
|
|
8274
8571
|
function loadWatermark() {
|
|
8275
8572
|
let raw;
|
|
8276
8573
|
try {
|
|
8277
|
-
raw =
|
|
8574
|
+
raw = import_fs18.default.readFileSync(WATERMARK_FILE(), "utf-8");
|
|
8278
8575
|
} catch {
|
|
8279
8576
|
return { status: "fresh", wm: freshWatermark() };
|
|
8280
8577
|
}
|
|
@@ -8326,28 +8623,28 @@ function loadWatermark() {
|
|
|
8326
8623
|
function saveWatermark(wm) {
|
|
8327
8624
|
if (wm.schemaVersion > WATERMARK_SCHEMA_VERSION) return;
|
|
8328
8625
|
const target = WATERMARK_FILE();
|
|
8329
|
-
const dir =
|
|
8330
|
-
if (!
|
|
8626
|
+
const dir = import_path20.default.dirname(target);
|
|
8627
|
+
if (!import_fs18.default.existsSync(dir)) import_fs18.default.mkdirSync(dir, { recursive: true });
|
|
8331
8628
|
const tmp = target + ".tmp";
|
|
8332
|
-
|
|
8333
|
-
|
|
8629
|
+
import_fs18.default.writeFileSync(tmp, JSON.stringify(wm, null, 2) + "\n", "utf-8");
|
|
8630
|
+
import_fs18.default.renameSync(tmp, target);
|
|
8334
8631
|
}
|
|
8335
8632
|
function listJsonlFiles() {
|
|
8336
8633
|
const root = PROJECTS_DIR();
|
|
8337
|
-
if (!
|
|
8634
|
+
if (!import_fs18.default.existsSync(root)) return [];
|
|
8338
8635
|
const out = [];
|
|
8339
|
-
for (const entry of
|
|
8636
|
+
for (const entry of import_fs18.default.readdirSync(root, { withFileTypes: true })) {
|
|
8340
8637
|
if (!entry.isDirectory()) continue;
|
|
8341
|
-
const projectDir =
|
|
8638
|
+
const projectDir = import_path20.default.join(root, entry.name);
|
|
8342
8639
|
let inner;
|
|
8343
8640
|
try {
|
|
8344
|
-
inner =
|
|
8641
|
+
inner = import_fs18.default.readdirSync(projectDir, { withFileTypes: true });
|
|
8345
8642
|
} catch {
|
|
8346
8643
|
continue;
|
|
8347
8644
|
}
|
|
8348
8645
|
for (const file of inner) {
|
|
8349
8646
|
if (file.isFile() && file.name.endsWith(".jsonl")) {
|
|
8350
|
-
out.push(
|
|
8647
|
+
out.push(import_path20.default.join(projectDir, file.name));
|
|
8351
8648
|
}
|
|
8352
8649
|
}
|
|
8353
8650
|
}
|
|
@@ -8355,7 +8652,7 @@ function listJsonlFiles() {
|
|
|
8355
8652
|
}
|
|
8356
8653
|
function fileSize(p) {
|
|
8357
8654
|
try {
|
|
8358
|
-
return
|
|
8655
|
+
return import_fs18.default.statSync(p).size;
|
|
8359
8656
|
} catch {
|
|
8360
8657
|
return 0;
|
|
8361
8658
|
}
|
|
@@ -8363,7 +8660,7 @@ function fileSize(p) {
|
|
|
8363
8660
|
async function scanDelta(filePath, fromByte, onLine) {
|
|
8364
8661
|
const size = fileSize(filePath);
|
|
8365
8662
|
if (size <= fromByte) return fromByte;
|
|
8366
|
-
const stream =
|
|
8663
|
+
const stream = import_fs18.default.createReadStream(filePath, {
|
|
8367
8664
|
start: fromByte,
|
|
8368
8665
|
end: size - 1,
|
|
8369
8666
|
highWaterMark: 64 * 1024
|
|
@@ -8475,7 +8772,7 @@ async function tickForensicBroadcast(offsets) {
|
|
|
8475
8772
|
continue;
|
|
8476
8773
|
}
|
|
8477
8774
|
if (size <= offset) continue;
|
|
8478
|
-
const sessionId =
|
|
8775
|
+
const sessionId = import_path20.default.basename(file, ".jsonl");
|
|
8479
8776
|
const newOffset = await scanDelta(file, offset, (obj, lineIndex) => {
|
|
8480
8777
|
out.push(...extractFindingsFromLine(obj, sessionId, lineIndex));
|
|
8481
8778
|
});
|
|
@@ -8534,7 +8831,7 @@ function emptyTick(uploadAs) {
|
|
|
8534
8831
|
function readRawWatermarkPreservingOffsets() {
|
|
8535
8832
|
let raw;
|
|
8536
8833
|
try {
|
|
8537
|
-
raw =
|
|
8834
|
+
raw = import_fs18.default.readFileSync(WATERMARK_FILE(), "utf-8");
|
|
8538
8835
|
} catch {
|
|
8539
8836
|
return null;
|
|
8540
8837
|
}
|
|
@@ -8568,13 +8865,13 @@ async function runActualTick(wm) {
|
|
|
8568
8865
|
if (!known) {
|
|
8569
8866
|
let mtimeMs = 0;
|
|
8570
8867
|
try {
|
|
8571
|
-
mtimeMs =
|
|
8868
|
+
mtimeMs = import_fs18.default.statSync(filePath).mtime.getTime();
|
|
8572
8869
|
} catch {
|
|
8573
8870
|
continue;
|
|
8574
8871
|
}
|
|
8575
8872
|
if (mtimeMs >= watermarkCreatedAt) {
|
|
8576
8873
|
filesNew++;
|
|
8577
|
-
const sessionId2 =
|
|
8874
|
+
const sessionId2 = import_path20.default.basename(filePath, ".jsonl");
|
|
8578
8875
|
const newScannedTo2 = await scanDelta(filePath, 0, (obj, lineIndex) => {
|
|
8579
8876
|
totalToolCalls++;
|
|
8580
8877
|
toolCallsBySession[sessionId2] = (toolCallsBySession[sessionId2] ?? 0) + 1;
|
|
@@ -8592,7 +8889,7 @@ async function runActualTick(wm) {
|
|
|
8592
8889
|
filesSkipped++;
|
|
8593
8890
|
continue;
|
|
8594
8891
|
}
|
|
8595
|
-
const sessionId =
|
|
8892
|
+
const sessionId = import_path20.default.basename(filePath, ".jsonl");
|
|
8596
8893
|
const newScannedTo = await scanDelta(filePath, known.scannedTo, (obj, lineIndex) => {
|
|
8597
8894
|
totalToolCalls++;
|
|
8598
8895
|
toolCallsBySession[sessionId] = (toolCallsBySession[sessionId] ?? 0) + 1;
|
|
@@ -8614,18 +8911,18 @@ async function runActualTick(wm) {
|
|
|
8614
8911
|
schemaFuture: false
|
|
8615
8912
|
};
|
|
8616
8913
|
}
|
|
8617
|
-
var
|
|
8914
|
+
var import_fs18, import_os17, import_path20, import_readline, PROJECTS_DIR, WATERMARK_FILE, MAX_LINE_BYTES, WATERMARK_SCHEMA_VERSION, LONG_OUTPUT_THRESHOLD_BYTES2;
|
|
8618
8915
|
var init_scan_watermark = __esm({
|
|
8619
8916
|
"src/daemon/scan-watermark.ts"() {
|
|
8620
8917
|
"use strict";
|
|
8621
|
-
|
|
8622
|
-
|
|
8623
|
-
|
|
8918
|
+
import_fs18 = __toESM(require("fs"));
|
|
8919
|
+
import_os17 = __toESM(require("os"));
|
|
8920
|
+
import_path20 = __toESM(require("path"));
|
|
8624
8921
|
import_readline = __toESM(require("readline"));
|
|
8625
8922
|
init_dlp();
|
|
8626
8923
|
init_dist();
|
|
8627
|
-
PROJECTS_DIR = () =>
|
|
8628
|
-
WATERMARK_FILE = () =>
|
|
8924
|
+
PROJECTS_DIR = () => import_path20.default.join(import_os17.default.homedir(), ".claude", "projects");
|
|
8925
|
+
WATERMARK_FILE = () => import_path20.default.join(import_os17.default.homedir(), ".node9", "scan-watermark.json");
|
|
8629
8926
|
MAX_LINE_BYTES = 2 * 1024 * 1024;
|
|
8630
8927
|
WATERMARK_SCHEMA_VERSION = 2;
|
|
8631
8928
|
LONG_OUTPUT_THRESHOLD_BYTES2 = LONG_OUTPUT_THRESHOLD_BYTES;
|
|
@@ -8673,40 +8970,40 @@ function parseSinceCutoff(raw, now = /* @__PURE__ */ new Date()) {
|
|
|
8673
8970
|
return now.getTime() - 90 * 864e5;
|
|
8674
8971
|
}
|
|
8675
8972
|
function* iterateJsonlFiles(cutoffMs) {
|
|
8676
|
-
const projectsDir =
|
|
8973
|
+
const projectsDir = import_path21.default.join(import_os18.default.homedir(), ".claude", "projects");
|
|
8677
8974
|
let dirs;
|
|
8678
8975
|
try {
|
|
8679
|
-
dirs =
|
|
8976
|
+
dirs = import_fs19.default.readdirSync(projectsDir);
|
|
8680
8977
|
} catch {
|
|
8681
8978
|
return;
|
|
8682
8979
|
}
|
|
8683
8980
|
for (const dir of dirs) {
|
|
8684
|
-
const dirPath =
|
|
8981
|
+
const dirPath = import_path21.default.join(projectsDir, dir);
|
|
8685
8982
|
let stats;
|
|
8686
8983
|
try {
|
|
8687
|
-
stats =
|
|
8984
|
+
stats = import_fs19.default.statSync(dirPath);
|
|
8688
8985
|
} catch {
|
|
8689
8986
|
continue;
|
|
8690
8987
|
}
|
|
8691
8988
|
if (!stats.isDirectory()) continue;
|
|
8692
8989
|
let files;
|
|
8693
8990
|
try {
|
|
8694
|
-
files =
|
|
8991
|
+
files = import_fs19.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
8695
8992
|
} catch {
|
|
8696
8993
|
continue;
|
|
8697
8994
|
}
|
|
8698
8995
|
for (const file of files) {
|
|
8699
|
-
const filePath =
|
|
8996
|
+
const filePath = import_path21.default.join(dirPath, file);
|
|
8700
8997
|
let mtime = 0;
|
|
8701
8998
|
try {
|
|
8702
|
-
mtime =
|
|
8999
|
+
mtime = import_fs19.default.statSync(filePath).mtimeMs;
|
|
8703
9000
|
} catch {
|
|
8704
9001
|
continue;
|
|
8705
9002
|
}
|
|
8706
9003
|
if (mtime < cutoffMs) continue;
|
|
8707
9004
|
yield {
|
|
8708
9005
|
filePath,
|
|
8709
|
-
sessionId:
|
|
9006
|
+
sessionId: import_path21.default.basename(file, ".jsonl"),
|
|
8710
9007
|
projectDir: dir
|
|
8711
9008
|
};
|
|
8712
9009
|
}
|
|
@@ -8759,7 +9056,7 @@ async function runUploadHistory(opts) {
|
|
|
8759
9056
|
filesScanned++;
|
|
8760
9057
|
let content;
|
|
8761
9058
|
try {
|
|
8762
|
-
content =
|
|
9059
|
+
content = import_fs19.default.readFileSync(filePath, "utf8");
|
|
8763
9060
|
} catch {
|
|
8764
9061
|
continue;
|
|
8765
9062
|
}
|
|
@@ -8845,10 +9142,10 @@ async function runUploadHistory(opts) {
|
|
|
8845
9142
|
const costUrl = creds.apiUrl.endsWith("/policies/sync") ? creds.apiUrl.replace(/\/policies\/sync$/, "/cost-sync") : `${creds.apiUrl.replace(/\/$/, "")}/cost-sync`;
|
|
8846
9143
|
let username = "unknown";
|
|
8847
9144
|
try {
|
|
8848
|
-
username =
|
|
9145
|
+
username = import_os18.default.userInfo().username;
|
|
8849
9146
|
} catch {
|
|
8850
9147
|
}
|
|
8851
|
-
const machineId = `${
|
|
9148
|
+
const machineId = `${import_os18.default.hostname()}:${username}`;
|
|
8852
9149
|
await postJson(costUrl, creds.apiKey, {
|
|
8853
9150
|
machineId,
|
|
8854
9151
|
entries: dailyEntries
|
|
@@ -8898,14 +9195,14 @@ async function postJson(url, apiKey, body) {
|
|
|
8898
9195
|
req.end();
|
|
8899
9196
|
});
|
|
8900
9197
|
}
|
|
8901
|
-
var
|
|
9198
|
+
var import_fs19, import_https, import_os18, import_path21, import_chalk4, FINDING_TO_SIGNAL2;
|
|
8902
9199
|
var init_scan_upload_history = __esm({
|
|
8903
9200
|
"src/scan-upload-history.ts"() {
|
|
8904
9201
|
"use strict";
|
|
8905
|
-
|
|
9202
|
+
import_fs19 = __toESM(require("fs"));
|
|
8906
9203
|
import_https = __toESM(require("https"));
|
|
8907
|
-
|
|
8908
|
-
|
|
9204
|
+
import_os18 = __toESM(require("os"));
|
|
9205
|
+
import_path21 = __toESM(require("path"));
|
|
8909
9206
|
import_chalk4 = __toESM(require("chalk"));
|
|
8910
9207
|
init_dist();
|
|
8911
9208
|
init_config();
|
|
@@ -9151,14 +9448,14 @@ function buildRuleSources() {
|
|
|
9151
9448
|
}
|
|
9152
9449
|
function countScanFiles() {
|
|
9153
9450
|
let total = 0;
|
|
9154
|
-
const claudeDir =
|
|
9155
|
-
if (
|
|
9451
|
+
const claudeDir = import_path22.default.join(import_os19.default.homedir(), ".claude", "projects");
|
|
9452
|
+
if (import_fs20.default.existsSync(claudeDir)) {
|
|
9156
9453
|
try {
|
|
9157
|
-
for (const proj of
|
|
9158
|
-
const p =
|
|
9454
|
+
for (const proj of import_fs20.default.readdirSync(claudeDir)) {
|
|
9455
|
+
const p = import_path22.default.join(claudeDir, proj);
|
|
9159
9456
|
try {
|
|
9160
|
-
if (!
|
|
9161
|
-
total +=
|
|
9457
|
+
if (!import_fs20.default.statSync(p).isDirectory()) continue;
|
|
9458
|
+
total += import_fs20.default.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
|
|
9162
9459
|
} catch {
|
|
9163
9460
|
continue;
|
|
9164
9461
|
}
|
|
@@ -9166,17 +9463,17 @@ function countScanFiles() {
|
|
|
9166
9463
|
} catch {
|
|
9167
9464
|
}
|
|
9168
9465
|
}
|
|
9169
|
-
const geminiDir =
|
|
9170
|
-
if (
|
|
9466
|
+
const geminiDir = import_path22.default.join(import_os19.default.homedir(), ".gemini", "tmp");
|
|
9467
|
+
if (import_fs20.default.existsSync(geminiDir)) {
|
|
9171
9468
|
try {
|
|
9172
|
-
for (const slug of
|
|
9173
|
-
const p =
|
|
9469
|
+
for (const slug of import_fs20.default.readdirSync(geminiDir)) {
|
|
9470
|
+
const p = import_path22.default.join(geminiDir, slug);
|
|
9174
9471
|
try {
|
|
9175
|
-
if (!
|
|
9176
|
-
const chatsDir =
|
|
9177
|
-
if (
|
|
9472
|
+
if (!import_fs20.default.statSync(p).isDirectory()) continue;
|
|
9473
|
+
const chatsDir = import_path22.default.join(p, "chats");
|
|
9474
|
+
if (import_fs20.default.existsSync(chatsDir)) {
|
|
9178
9475
|
try {
|
|
9179
|
-
total +=
|
|
9476
|
+
total += import_fs20.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
|
|
9180
9477
|
} catch {
|
|
9181
9478
|
}
|
|
9182
9479
|
}
|
|
@@ -9187,22 +9484,22 @@ function countScanFiles() {
|
|
|
9187
9484
|
} catch {
|
|
9188
9485
|
}
|
|
9189
9486
|
}
|
|
9190
|
-
const codexDir =
|
|
9191
|
-
if (
|
|
9487
|
+
const codexDir = import_path22.default.join(import_os19.default.homedir(), ".codex", "sessions");
|
|
9488
|
+
if (import_fs20.default.existsSync(codexDir)) {
|
|
9192
9489
|
try {
|
|
9193
|
-
for (const year of
|
|
9194
|
-
const yp =
|
|
9490
|
+
for (const year of import_fs20.default.readdirSync(codexDir)) {
|
|
9491
|
+
const yp = import_path22.default.join(codexDir, year);
|
|
9195
9492
|
try {
|
|
9196
|
-
if (!
|
|
9197
|
-
for (const month of
|
|
9198
|
-
const mp =
|
|
9493
|
+
if (!import_fs20.default.statSync(yp).isDirectory()) continue;
|
|
9494
|
+
for (const month of import_fs20.default.readdirSync(yp)) {
|
|
9495
|
+
const mp = import_path22.default.join(yp, month);
|
|
9199
9496
|
try {
|
|
9200
|
-
if (!
|
|
9201
|
-
for (const day of
|
|
9202
|
-
const dp =
|
|
9497
|
+
if (!import_fs20.default.statSync(mp).isDirectory()) continue;
|
|
9498
|
+
for (const day of import_fs20.default.readdirSync(mp)) {
|
|
9499
|
+
const dp = import_path22.default.join(mp, day);
|
|
9203
9500
|
try {
|
|
9204
|
-
if (!
|
|
9205
|
-
total +=
|
|
9501
|
+
if (!import_fs20.default.statSync(dp).isDirectory()) continue;
|
|
9502
|
+
total += import_fs20.default.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
|
|
9206
9503
|
} catch {
|
|
9207
9504
|
continue;
|
|
9208
9505
|
}
|
|
@@ -9238,7 +9535,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
9238
9535
|
const sessionId = file.replace(/\.jsonl$/, "");
|
|
9239
9536
|
let raw;
|
|
9240
9537
|
try {
|
|
9241
|
-
raw =
|
|
9538
|
+
raw = import_fs20.default.readFileSync(import_path22.default.join(projPath, file), "utf-8");
|
|
9242
9539
|
} catch {
|
|
9243
9540
|
return;
|
|
9244
9541
|
}
|
|
@@ -9290,7 +9587,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
9290
9587
|
if (block.type !== "tool_result") continue;
|
|
9291
9588
|
const filePath = block.tool_use_id ? toolUseFilePaths.get(block.tool_use_id) : void 0;
|
|
9292
9589
|
if (filePath) {
|
|
9293
|
-
const ext =
|
|
9590
|
+
const ext = import_path22.default.extname(filePath).toLowerCase();
|
|
9294
9591
|
if (CODE_EXTENSIONS.has(ext)) continue;
|
|
9295
9592
|
}
|
|
9296
9593
|
const resultText = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => c.text ?? "").join("\n") : null;
|
|
@@ -9347,7 +9644,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
9347
9644
|
const rawCmd = String(input.command ?? "").trimStart();
|
|
9348
9645
|
if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd)) continue;
|
|
9349
9646
|
const inputFilePath = typeof input.file_path === "string" ? input.file_path : "";
|
|
9350
|
-
const inputFileExt = inputFilePath ?
|
|
9647
|
+
const inputFileExt = inputFilePath ? import_path22.default.extname(inputFilePath).toLowerCase() : "";
|
|
9351
9648
|
if (CODE_EXTENSIONS.has(inputFileExt)) continue;
|
|
9352
9649
|
const dlpMatch = scanArgs(input);
|
|
9353
9650
|
if (dlpMatch) {
|
|
@@ -9444,19 +9741,19 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
9444
9741
|
}
|
|
9445
9742
|
}
|
|
9446
9743
|
function processClaudeProject(proj, projectsDir, ruleSources, startDate, result, dedup, onProgress, onLine) {
|
|
9447
|
-
const projPath =
|
|
9744
|
+
const projPath = import_path22.default.join(projectsDir, proj);
|
|
9448
9745
|
try {
|
|
9449
|
-
if (!
|
|
9746
|
+
if (!import_fs20.default.statSync(projPath).isDirectory()) return;
|
|
9450
9747
|
} catch {
|
|
9451
9748
|
return;
|
|
9452
9749
|
}
|
|
9453
|
-
const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(
|
|
9750
|
+
const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(import_os19.default.homedir(), "~")).slice(
|
|
9454
9751
|
0,
|
|
9455
9752
|
40
|
|
9456
9753
|
);
|
|
9457
9754
|
let files;
|
|
9458
9755
|
try {
|
|
9459
|
-
files =
|
|
9756
|
+
files = import_fs20.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
9460
9757
|
} catch {
|
|
9461
9758
|
return;
|
|
9462
9759
|
}
|
|
@@ -9490,12 +9787,12 @@ function emptyClaudeScan() {
|
|
|
9490
9787
|
};
|
|
9491
9788
|
}
|
|
9492
9789
|
function scanClaudeHistory(startDate, onProgress, onLine) {
|
|
9493
|
-
const projectsDir =
|
|
9790
|
+
const projectsDir = import_path22.default.join(import_os19.default.homedir(), ".claude", "projects");
|
|
9494
9791
|
const result = emptyClaudeScan();
|
|
9495
|
-
if (!
|
|
9792
|
+
if (!import_fs20.default.existsSync(projectsDir)) return result;
|
|
9496
9793
|
let projDirs;
|
|
9497
9794
|
try {
|
|
9498
|
-
projDirs =
|
|
9795
|
+
projDirs = import_fs20.default.readdirSync(projectsDir);
|
|
9499
9796
|
} catch {
|
|
9500
9797
|
return result;
|
|
9501
9798
|
}
|
|
@@ -9516,7 +9813,7 @@ function scanClaudeHistory(startDate, onProgress, onLine) {
|
|
|
9516
9813
|
return result;
|
|
9517
9814
|
}
|
|
9518
9815
|
function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
9519
|
-
const tmpDir =
|
|
9816
|
+
const tmpDir = import_path22.default.join(import_os19.default.homedir(), ".gemini", "tmp");
|
|
9520
9817
|
const result = {
|
|
9521
9818
|
filesScanned: 0,
|
|
9522
9819
|
sessions: 0,
|
|
@@ -9531,33 +9828,33 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
9531
9828
|
sessionsWithEarlySecrets: 0
|
|
9532
9829
|
};
|
|
9533
9830
|
const dedup = emptyScanDedup();
|
|
9534
|
-
if (!
|
|
9831
|
+
if (!import_fs20.default.existsSync(tmpDir)) return result;
|
|
9535
9832
|
let slugDirs;
|
|
9536
9833
|
try {
|
|
9537
|
-
slugDirs =
|
|
9834
|
+
slugDirs = import_fs20.default.readdirSync(tmpDir);
|
|
9538
9835
|
} catch {
|
|
9539
9836
|
return result;
|
|
9540
9837
|
}
|
|
9541
9838
|
const ruleSources = buildRuleSources();
|
|
9542
9839
|
for (const slug of slugDirs) {
|
|
9543
|
-
const slugPath =
|
|
9840
|
+
const slugPath = import_path22.default.join(tmpDir, slug);
|
|
9544
9841
|
try {
|
|
9545
|
-
if (!
|
|
9842
|
+
if (!import_fs20.default.statSync(slugPath).isDirectory()) continue;
|
|
9546
9843
|
} catch {
|
|
9547
9844
|
continue;
|
|
9548
9845
|
}
|
|
9549
9846
|
let projLabel = stripTerminalEscapes(slug).slice(0, 40);
|
|
9550
9847
|
try {
|
|
9551
9848
|
projLabel = stripTerminalEscapes(
|
|
9552
|
-
|
|
9553
|
-
).replace(
|
|
9849
|
+
import_fs20.default.readFileSync(import_path22.default.join(slugPath, ".project_root"), "utf-8").trim()
|
|
9850
|
+
).replace(import_os19.default.homedir(), "~").slice(0, 40);
|
|
9554
9851
|
} catch {
|
|
9555
9852
|
}
|
|
9556
|
-
const chatsDir =
|
|
9557
|
-
if (!
|
|
9853
|
+
const chatsDir = import_path22.default.join(slugPath, "chats");
|
|
9854
|
+
if (!import_fs20.default.existsSync(chatsDir)) continue;
|
|
9558
9855
|
let chatFiles;
|
|
9559
9856
|
try {
|
|
9560
|
-
chatFiles =
|
|
9857
|
+
chatFiles = import_fs20.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
9561
9858
|
} catch {
|
|
9562
9859
|
continue;
|
|
9563
9860
|
}
|
|
@@ -9567,7 +9864,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
9567
9864
|
const sessionId = chatFile.replace(/\.json$/, "");
|
|
9568
9865
|
let raw;
|
|
9569
9866
|
try {
|
|
9570
|
-
raw =
|
|
9867
|
+
raw = import_fs20.default.readFileSync(import_path22.default.join(chatsDir, chatFile), "utf-8");
|
|
9571
9868
|
} catch {
|
|
9572
9869
|
continue;
|
|
9573
9870
|
}
|
|
@@ -9729,7 +10026,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
9729
10026
|
return result;
|
|
9730
10027
|
}
|
|
9731
10028
|
function scanCodexHistory(startDate, onProgress, onLine) {
|
|
9732
|
-
const sessionsBase =
|
|
10029
|
+
const sessionsBase = import_path22.default.join(import_os19.default.homedir(), ".codex", "sessions");
|
|
9733
10030
|
const result = {
|
|
9734
10031
|
filesScanned: 0,
|
|
9735
10032
|
sessions: 0,
|
|
@@ -9744,32 +10041,32 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
9744
10041
|
sessionsWithEarlySecrets: 0
|
|
9745
10042
|
};
|
|
9746
10043
|
const dedup = emptyScanDedup();
|
|
9747
|
-
if (!
|
|
10044
|
+
if (!import_fs20.default.existsSync(sessionsBase)) return result;
|
|
9748
10045
|
const jsonlFiles = [];
|
|
9749
10046
|
try {
|
|
9750
|
-
for (const year of
|
|
9751
|
-
const yearPath =
|
|
10047
|
+
for (const year of import_fs20.default.readdirSync(sessionsBase)) {
|
|
10048
|
+
const yearPath = import_path22.default.join(sessionsBase, year);
|
|
9752
10049
|
try {
|
|
9753
|
-
if (!
|
|
10050
|
+
if (!import_fs20.default.statSync(yearPath).isDirectory()) continue;
|
|
9754
10051
|
} catch {
|
|
9755
10052
|
continue;
|
|
9756
10053
|
}
|
|
9757
|
-
for (const month of
|
|
9758
|
-
const monthPath =
|
|
10054
|
+
for (const month of import_fs20.default.readdirSync(yearPath)) {
|
|
10055
|
+
const monthPath = import_path22.default.join(yearPath, month);
|
|
9759
10056
|
try {
|
|
9760
|
-
if (!
|
|
10057
|
+
if (!import_fs20.default.statSync(monthPath).isDirectory()) continue;
|
|
9761
10058
|
} catch {
|
|
9762
10059
|
continue;
|
|
9763
10060
|
}
|
|
9764
|
-
for (const day of
|
|
9765
|
-
const dayPath =
|
|
10061
|
+
for (const day of import_fs20.default.readdirSync(monthPath)) {
|
|
10062
|
+
const dayPath = import_path22.default.join(monthPath, day);
|
|
9766
10063
|
try {
|
|
9767
|
-
if (!
|
|
10064
|
+
if (!import_fs20.default.statSync(dayPath).isDirectory()) continue;
|
|
9768
10065
|
} catch {
|
|
9769
10066
|
continue;
|
|
9770
10067
|
}
|
|
9771
|
-
for (const file of
|
|
9772
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
10068
|
+
for (const file of import_fs20.default.readdirSync(dayPath)) {
|
|
10069
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path22.default.join(dayPath, file));
|
|
9773
10070
|
}
|
|
9774
10071
|
}
|
|
9775
10072
|
}
|
|
@@ -9783,7 +10080,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
9783
10080
|
onProgress?.(result.filesScanned);
|
|
9784
10081
|
let lines;
|
|
9785
10082
|
try {
|
|
9786
|
-
lines =
|
|
10083
|
+
lines = import_fs20.default.readFileSync(filePath, "utf-8").split("\n");
|
|
9787
10084
|
} catch {
|
|
9788
10085
|
continue;
|
|
9789
10086
|
}
|
|
@@ -9809,7 +10106,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
9809
10106
|
sessionId = String(payload["id"] ?? filePath);
|
|
9810
10107
|
startTime = String(payload["timestamp"] ?? "");
|
|
9811
10108
|
const cwd = String(payload["cwd"] ?? "");
|
|
9812
|
-
projLabel = stripTerminalEscapes(cwd.replace(
|
|
10109
|
+
projLabel = stripTerminalEscapes(cwd.replace(import_os19.default.homedir(), "~")).slice(0, 40);
|
|
9813
10110
|
continue;
|
|
9814
10111
|
}
|
|
9815
10112
|
if (entry.type === "event_msg" && payload["type"] === "token_count") {
|
|
@@ -9962,17 +10259,17 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
9962
10259
|
return result;
|
|
9963
10260
|
}
|
|
9964
10261
|
function scanShellConfig() {
|
|
9965
|
-
const home =
|
|
10262
|
+
const home = import_os19.default.homedir();
|
|
9966
10263
|
const configFiles = [".zshrc", ".bashrc", ".bash_profile", ".profile"].map(
|
|
9967
|
-
(f) =>
|
|
10264
|
+
(f) => import_path22.default.join(home, f)
|
|
9968
10265
|
);
|
|
9969
10266
|
const findings = [];
|
|
9970
10267
|
const seen = /* @__PURE__ */ new Set();
|
|
9971
10268
|
for (const filePath of configFiles) {
|
|
9972
|
-
if (!
|
|
10269
|
+
if (!import_fs20.default.existsSync(filePath)) continue;
|
|
9973
10270
|
let lines;
|
|
9974
10271
|
try {
|
|
9975
|
-
lines =
|
|
10272
|
+
lines = import_fs20.default.readFileSync(filePath, "utf-8").split("\n");
|
|
9976
10273
|
} catch {
|
|
9977
10274
|
continue;
|
|
9978
10275
|
}
|
|
@@ -10752,7 +11049,7 @@ function registerScanCommand(program2) {
|
|
|
10752
11049
|
if (!drillDown) {
|
|
10753
11050
|
const useInk2 = !options.classic;
|
|
10754
11051
|
if (useInk2) {
|
|
10755
|
-
const scanInkPath =
|
|
11052
|
+
const scanInkPath = import_path22.default.join(__dirname, "scan-ink.mjs");
|
|
10756
11053
|
const dynamicImport = new Function("id", "return import(id)");
|
|
10757
11054
|
const mod = await dynamicImport(`file://${scanInkPath}`);
|
|
10758
11055
|
const rangeLabel2 = options.all ? "all time" : `last ${options.days ?? 90} days`;
|
|
@@ -10977,14 +11274,14 @@ function registerScanCommand(program2) {
|
|
|
10977
11274
|
}
|
|
10978
11275
|
);
|
|
10979
11276
|
}
|
|
10980
|
-
var import_chalk5,
|
|
11277
|
+
var import_chalk5, import_fs20, import_path22, import_os19, import_string_width2, CLAUDE_PRICING, GEMINI_PRICING, CODE_EXTENSIONS, SELF_OUTPUT_MARKERS, FIXTURE_TOKEN_PATTERNS, TERMINAL_ESCAPE_RE2, LOOP_TOOLS, LOOP_THRESHOLD, LOOP_TIMESPAN_THRESHOLD_MS, STUCK_TOOLS_MIN_WASTE, STUCK_TOOLS_LIMIT, RECURRING_SESSION_THRESHOLD, STALE_AGE_DAYS, classifyRuleSeverity2, narrativeRuleLabel2;
|
|
10981
11278
|
var init_scan = __esm({
|
|
10982
11279
|
"src/cli/commands/scan.ts"() {
|
|
10983
11280
|
"use strict";
|
|
10984
11281
|
import_chalk5 = __toESM(require("chalk"));
|
|
10985
|
-
|
|
10986
|
-
|
|
10987
|
-
|
|
11282
|
+
import_fs20 = __toESM(require("fs"));
|
|
11283
|
+
import_path22 = __toESM(require("path"));
|
|
11284
|
+
import_os19 = __toESM(require("os"));
|
|
10988
11285
|
init_shields();
|
|
10989
11286
|
init_config();
|
|
10990
11287
|
init_policy();
|
|
@@ -11111,11 +11408,11 @@ function commonPathPrefix(paths) {
|
|
|
11111
11408
|
const prefix = common.join("/").replace(/\/?$/, "/");
|
|
11112
11409
|
return prefix.length > 1 ? prefix : null;
|
|
11113
11410
|
}
|
|
11114
|
-
var
|
|
11411
|
+
var import_crypto6, SuggestionTracker;
|
|
11115
11412
|
var init_suggestion_tracker = __esm({
|
|
11116
11413
|
"src/daemon/suggestion-tracker.ts"() {
|
|
11117
11414
|
"use strict";
|
|
11118
|
-
|
|
11415
|
+
import_crypto6 = require("crypto");
|
|
11119
11416
|
SuggestionTracker = class {
|
|
11120
11417
|
events = /* @__PURE__ */ new Map();
|
|
11121
11418
|
threshold;
|
|
@@ -11161,7 +11458,7 @@ var init_suggestion_tracker = __esm({
|
|
|
11161
11458
|
}
|
|
11162
11459
|
} : { type: "ignoredTool", toolName };
|
|
11163
11460
|
return {
|
|
11164
|
-
id: (0,
|
|
11461
|
+
id: (0, import_crypto6.randomUUID)(),
|
|
11165
11462
|
toolName,
|
|
11166
11463
|
allowCount: events.length,
|
|
11167
11464
|
suggestedRule,
|
|
@@ -11175,12 +11472,12 @@ var init_suggestion_tracker = __esm({
|
|
|
11175
11472
|
});
|
|
11176
11473
|
|
|
11177
11474
|
// src/daemon/taint-store.ts
|
|
11178
|
-
var
|
|
11475
|
+
var import_fs21, import_path23, DEFAULT_TTL_MS, TaintStore;
|
|
11179
11476
|
var init_taint_store = __esm({
|
|
11180
11477
|
"src/daemon/taint-store.ts"() {
|
|
11181
11478
|
"use strict";
|
|
11182
|
-
|
|
11183
|
-
|
|
11479
|
+
import_fs21 = __toESM(require("fs"));
|
|
11480
|
+
import_path23 = __toESM(require("path"));
|
|
11184
11481
|
DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
11185
11482
|
TaintStore = class {
|
|
11186
11483
|
records = /* @__PURE__ */ new Map();
|
|
@@ -11245,9 +11542,9 @@ var init_taint_store = __esm({
|
|
|
11245
11542
|
/** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
|
|
11246
11543
|
_resolve(filePath) {
|
|
11247
11544
|
try {
|
|
11248
|
-
return
|
|
11545
|
+
return import_fs21.default.realpathSync.native(import_path23.default.resolve(filePath));
|
|
11249
11546
|
} catch {
|
|
11250
|
-
return
|
|
11547
|
+
return import_path23.default.resolve(filePath);
|
|
11251
11548
|
}
|
|
11252
11549
|
}
|
|
11253
11550
|
};
|
|
@@ -11365,8 +11662,8 @@ var init_session_history = __esm({
|
|
|
11365
11662
|
// src/daemon/state.ts
|
|
11366
11663
|
function loadInsightCounts() {
|
|
11367
11664
|
try {
|
|
11368
|
-
if (!
|
|
11369
|
-
const data = JSON.parse(
|
|
11665
|
+
if (!import_fs22.default.existsSync(INSIGHT_COUNTS_FILE)) return;
|
|
11666
|
+
const data = JSON.parse(import_fs22.default.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
|
|
11370
11667
|
for (const [tool, count] of Object.entries(data)) {
|
|
11371
11668
|
if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
|
|
11372
11669
|
}
|
|
@@ -11405,23 +11702,23 @@ function markRejectionHandlerRegistered() {
|
|
|
11405
11702
|
daemonRejectionHandlerRegistered = true;
|
|
11406
11703
|
}
|
|
11407
11704
|
function atomicWriteSync2(filePath, data, options) {
|
|
11408
|
-
const dir =
|
|
11409
|
-
if (!
|
|
11410
|
-
const tmpPath = `${filePath}.${(0,
|
|
11705
|
+
const dir = import_path24.default.dirname(filePath);
|
|
11706
|
+
if (!import_fs22.default.existsSync(dir)) import_fs22.default.mkdirSync(dir, { recursive: true });
|
|
11707
|
+
const tmpPath = `${filePath}.${(0, import_crypto7.randomUUID)()}.tmp`;
|
|
11411
11708
|
try {
|
|
11412
|
-
|
|
11709
|
+
import_fs22.default.writeFileSync(tmpPath, data, options);
|
|
11413
11710
|
} catch (err2) {
|
|
11414
11711
|
try {
|
|
11415
|
-
|
|
11712
|
+
import_fs22.default.unlinkSync(tmpPath);
|
|
11416
11713
|
} catch {
|
|
11417
11714
|
}
|
|
11418
11715
|
throw err2;
|
|
11419
11716
|
}
|
|
11420
11717
|
try {
|
|
11421
|
-
|
|
11718
|
+
import_fs22.default.renameSync(tmpPath, filePath);
|
|
11422
11719
|
} catch (err2) {
|
|
11423
11720
|
try {
|
|
11424
|
-
|
|
11721
|
+
import_fs22.default.unlinkSync(tmpPath);
|
|
11425
11722
|
} catch {
|
|
11426
11723
|
}
|
|
11427
11724
|
throw err2;
|
|
@@ -11445,16 +11742,16 @@ function appendAuditLog(data) {
|
|
|
11445
11742
|
decision: data.decision,
|
|
11446
11743
|
source: "daemon"
|
|
11447
11744
|
};
|
|
11448
|
-
const dir =
|
|
11449
|
-
if (!
|
|
11450
|
-
|
|
11745
|
+
const dir = import_path24.default.dirname(AUDIT_LOG_FILE);
|
|
11746
|
+
if (!import_fs22.default.existsSync(dir)) import_fs22.default.mkdirSync(dir, { recursive: true });
|
|
11747
|
+
import_fs22.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
11451
11748
|
} catch {
|
|
11452
11749
|
}
|
|
11453
11750
|
}
|
|
11454
11751
|
function getAuditHistory(limit = 20) {
|
|
11455
11752
|
try {
|
|
11456
|
-
if (!
|
|
11457
|
-
const lines =
|
|
11753
|
+
if (!import_fs22.default.existsSync(AUDIT_LOG_FILE)) return [];
|
|
11754
|
+
const lines = import_fs22.default.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
|
|
11458
11755
|
if (lines.length === 1 && lines[0] === "") return [];
|
|
11459
11756
|
return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
|
|
11460
11757
|
} catch {
|
|
@@ -11463,7 +11760,7 @@ function getAuditHistory(limit = 20) {
|
|
|
11463
11760
|
}
|
|
11464
11761
|
function getOrgName() {
|
|
11465
11762
|
try {
|
|
11466
|
-
if (
|
|
11763
|
+
if (import_fs22.default.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
|
|
11467
11764
|
} catch {
|
|
11468
11765
|
}
|
|
11469
11766
|
return null;
|
|
@@ -11471,8 +11768,8 @@ function getOrgName() {
|
|
|
11471
11768
|
function writeGlobalSetting(key, value) {
|
|
11472
11769
|
let config = {};
|
|
11473
11770
|
try {
|
|
11474
|
-
if (
|
|
11475
|
-
config = JSON.parse(
|
|
11771
|
+
if (import_fs22.default.existsSync(GLOBAL_CONFIG_FILE)) {
|
|
11772
|
+
config = JSON.parse(import_fs22.default.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
|
|
11476
11773
|
}
|
|
11477
11774
|
} catch {
|
|
11478
11775
|
}
|
|
@@ -11484,8 +11781,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
11484
11781
|
try {
|
|
11485
11782
|
let trust = { entries: [] };
|
|
11486
11783
|
try {
|
|
11487
|
-
if (
|
|
11488
|
-
trust = JSON.parse(
|
|
11784
|
+
if (import_fs22.default.existsSync(TRUST_FILE2))
|
|
11785
|
+
trust = JSON.parse(import_fs22.default.readFileSync(TRUST_FILE2, "utf-8"));
|
|
11489
11786
|
} catch {
|
|
11490
11787
|
}
|
|
11491
11788
|
trust.entries = trust.entries.filter(
|
|
@@ -11502,8 +11799,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
11502
11799
|
}
|
|
11503
11800
|
function readPersistentDecisions() {
|
|
11504
11801
|
try {
|
|
11505
|
-
if (
|
|
11506
|
-
return JSON.parse(
|
|
11802
|
+
if (import_fs22.default.existsSync(DECISIONS_FILE)) {
|
|
11803
|
+
return JSON.parse(import_fs22.default.readFileSync(DECISIONS_FILE, "utf-8"));
|
|
11507
11804
|
}
|
|
11508
11805
|
} catch {
|
|
11509
11806
|
}
|
|
@@ -11531,7 +11828,7 @@ function estimateToolCost(tool, args) {
|
|
|
11531
11828
|
const filePath = a.file_path ?? a.path;
|
|
11532
11829
|
if (filePath) {
|
|
11533
11830
|
try {
|
|
11534
|
-
const bytes =
|
|
11831
|
+
const bytes = import_fs22.default.statSync(filePath).size;
|
|
11535
11832
|
return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
|
|
11536
11833
|
} catch {
|
|
11537
11834
|
}
|
|
@@ -11582,7 +11879,7 @@ function broadcastForensic(finding) {
|
|
|
11582
11879
|
const severity = CRITICAL_FORENSIC_CATEGORIES.has(finding.type) ? "critical" : "warning";
|
|
11583
11880
|
const event = {
|
|
11584
11881
|
type: "forensic",
|
|
11585
|
-
id: `fnd_${(0,
|
|
11882
|
+
id: `fnd_${(0, import_crypto7.randomUUID)()}`,
|
|
11586
11883
|
ts: Date.now(),
|
|
11587
11884
|
sessionId: finding.sessionId,
|
|
11588
11885
|
category: finding.type,
|
|
@@ -11602,7 +11899,7 @@ function abandonPending() {
|
|
|
11602
11899
|
});
|
|
11603
11900
|
if (autoStarted) {
|
|
11604
11901
|
try {
|
|
11605
|
-
|
|
11902
|
+
import_fs22.default.unlinkSync(DAEMON_PID_FILE);
|
|
11606
11903
|
} catch {
|
|
11607
11904
|
}
|
|
11608
11905
|
setTimeout(() => {
|
|
@@ -11613,8 +11910,8 @@ function abandonPending() {
|
|
|
11613
11910
|
}
|
|
11614
11911
|
function logActivitySocket(msg) {
|
|
11615
11912
|
try {
|
|
11616
|
-
|
|
11617
|
-
|
|
11913
|
+
import_fs22.default.appendFileSync(
|
|
11914
|
+
import_path24.default.join(homeDir, ".node9", "hook-debug.log"),
|
|
11618
11915
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] [activity-socket] ${msg}
|
|
11619
11916
|
`
|
|
11620
11917
|
);
|
|
@@ -11636,13 +11933,13 @@ function shouldRebind(now = Date.now()) {
|
|
|
11636
11933
|
function startActivitySocket() {
|
|
11637
11934
|
bindActivitySocket();
|
|
11638
11935
|
activityHealthInterval = setInterval(() => {
|
|
11639
|
-
if (!
|
|
11936
|
+
if (!import_fs22.default.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
|
|
11640
11937
|
}, ACTIVITY_HEALTH_PROBE_MS);
|
|
11641
11938
|
activityHealthInterval.unref();
|
|
11642
11939
|
process.on("exit", () => {
|
|
11643
11940
|
if (activityHealthInterval) clearInterval(activityHealthInterval);
|
|
11644
11941
|
try {
|
|
11645
|
-
|
|
11942
|
+
import_fs22.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
11646
11943
|
} catch {
|
|
11647
11944
|
}
|
|
11648
11945
|
});
|
|
@@ -11670,7 +11967,7 @@ function attemptRebind(reason) {
|
|
|
11670
11967
|
}
|
|
11671
11968
|
function bindActivitySocket() {
|
|
11672
11969
|
try {
|
|
11673
|
-
|
|
11970
|
+
import_fs22.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
11674
11971
|
} catch {
|
|
11675
11972
|
}
|
|
11676
11973
|
const ACTIVITY_MAX_BYTES = 1024 * 1024;
|
|
@@ -11774,28 +12071,28 @@ function bindActivitySocket() {
|
|
|
11774
12071
|
});
|
|
11775
12072
|
activitySocketServer = unixServer;
|
|
11776
12073
|
}
|
|
11777
|
-
var import_net2,
|
|
12074
|
+
var import_net2, import_fs22, import_path24, import_os20, import_crypto7, homeDir, DAEMON_PID_FILE, DECISIONS_FILE, AUDIT_LOG_FILE, TRUST_FILE2, GLOBAL_CONFIG_FILE, CREDENTIALS_FILE, INSIGHT_COUNTS_FILE, pending, sseClients, suggestionTracker, taintStore, insightCounts, _abandonTimer, _hadBrowserClient, _daemonServer, daemonRejectionHandlerRegistered, AUTO_DENY_MS, TRUST_DURATIONS, autoStarted, ACTIVITY_SOCKET_PATH2, ACTIVITY_RING_SIZE, activityRing, LARGE_RESPONSE_RING_SIZE, largeResponseRing, cachedScanResult, cachedScanTs, SCAN_CACHE_TTL_MS, SECRET_KEY_RE, INPUT_PRICE_PER_1M, OUTPUT_PRICE_PER_1M, BYTES_PER_TOKEN, CRITICAL_FORENSIC_CATEGORIES, WRITE_TOOL_NAMES, ACTIVITY_REBIND_MAX_ATTEMPTS, ACTIVITY_REBIND_WINDOW_MS, ACTIVITY_HEALTH_PROBE_MS, activitySocketServer, activityHealthInterval, activityRebindAttempts, activityCircuitTripped;
|
|
11778
12075
|
var init_state2 = __esm({
|
|
11779
12076
|
"src/daemon/state.ts"() {
|
|
11780
12077
|
"use strict";
|
|
11781
12078
|
import_net2 = __toESM(require("net"));
|
|
11782
|
-
|
|
11783
|
-
|
|
11784
|
-
|
|
11785
|
-
|
|
12079
|
+
import_fs22 = __toESM(require("fs"));
|
|
12080
|
+
import_path24 = __toESM(require("path"));
|
|
12081
|
+
import_os20 = __toESM(require("os"));
|
|
12082
|
+
import_crypto7 = require("crypto");
|
|
11786
12083
|
init_daemon();
|
|
11787
12084
|
init_suggestion_tracker();
|
|
11788
12085
|
init_taint_store();
|
|
11789
12086
|
init_session_counters();
|
|
11790
12087
|
init_session_history();
|
|
11791
|
-
homeDir =
|
|
11792
|
-
DAEMON_PID_FILE =
|
|
11793
|
-
DECISIONS_FILE =
|
|
11794
|
-
AUDIT_LOG_FILE =
|
|
11795
|
-
TRUST_FILE2 =
|
|
11796
|
-
GLOBAL_CONFIG_FILE =
|
|
11797
|
-
CREDENTIALS_FILE =
|
|
11798
|
-
INSIGHT_COUNTS_FILE =
|
|
12088
|
+
homeDir = import_os20.default.homedir();
|
|
12089
|
+
DAEMON_PID_FILE = import_path24.default.join(homeDir, ".node9", "daemon.pid");
|
|
12090
|
+
DECISIONS_FILE = import_path24.default.join(homeDir, ".node9", "decisions.json");
|
|
12091
|
+
AUDIT_LOG_FILE = import_path24.default.join(homeDir, ".node9", "audit.log");
|
|
12092
|
+
TRUST_FILE2 = import_path24.default.join(homeDir, ".node9", "trust.json");
|
|
12093
|
+
GLOBAL_CONFIG_FILE = import_path24.default.join(homeDir, ".node9", "config.json");
|
|
12094
|
+
CREDENTIALS_FILE = import_path24.default.join(homeDir, ".node9", "credentials.json");
|
|
12095
|
+
INSIGHT_COUNTS_FILE = import_path24.default.join(homeDir, ".node9", "insight-counts.json");
|
|
11799
12096
|
pending = /* @__PURE__ */ new Map();
|
|
11800
12097
|
sseClients = /* @__PURE__ */ new Set();
|
|
11801
12098
|
suggestionTracker = new SuggestionTracker(3);
|
|
@@ -11812,7 +12109,7 @@ var init_state2 = __esm({
|
|
|
11812
12109
|
"2h": 2 * 60 * 6e4
|
|
11813
12110
|
};
|
|
11814
12111
|
autoStarted = process.env.NODE9_AUTO_STARTED === "1";
|
|
11815
|
-
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
12112
|
+
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path24.default.join(import_os20.default.tmpdir(), "node9-activity.sock");
|
|
11816
12113
|
ACTIVITY_RING_SIZE = 100;
|
|
11817
12114
|
activityRing = [];
|
|
11818
12115
|
LARGE_RESPONSE_RING_SIZE = 20;
|
|
@@ -11890,8 +12187,8 @@ function readCredentials() {
|
|
|
11890
12187
|
};
|
|
11891
12188
|
}
|
|
11892
12189
|
try {
|
|
11893
|
-
const credPath =
|
|
11894
|
-
const creds = JSON.parse(
|
|
12190
|
+
const credPath = import_path25.default.join(import_os21.default.homedir(), ".node9", "credentials.json");
|
|
12191
|
+
const creds = JSON.parse(import_fs23.default.readFileSync(credPath, "utf-8"));
|
|
11895
12192
|
const profileName = process.env.NODE9_PROFILE ?? "default";
|
|
11896
12193
|
const profile = creds[profileName];
|
|
11897
12194
|
if (typeof profile?.apiKey === "string" && profile.apiKey.length > 0) {
|
|
@@ -11917,7 +12214,7 @@ function readCredentials() {
|
|
|
11917
12214
|
}
|
|
11918
12215
|
function readCachedEtag() {
|
|
11919
12216
|
try {
|
|
11920
|
-
const raw = JSON.parse(
|
|
12217
|
+
const raw = JSON.parse(import_fs23.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
11921
12218
|
return typeof raw.etag === "string" ? raw.etag : void 0;
|
|
11922
12219
|
} catch {
|
|
11923
12220
|
return void 0;
|
|
@@ -11978,9 +12275,9 @@ function extractRules(body) {
|
|
|
11978
12275
|
return [];
|
|
11979
12276
|
}
|
|
11980
12277
|
function writeCache2(cache) {
|
|
11981
|
-
const dir =
|
|
11982
|
-
if (!
|
|
11983
|
-
|
|
12278
|
+
const dir = import_path25.default.dirname(rulesCacheFile());
|
|
12279
|
+
if (!import_fs23.default.existsSync(dir)) import_fs23.default.mkdirSync(dir, { recursive: true });
|
|
12280
|
+
import_fs23.default.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
|
|
11984
12281
|
}
|
|
11985
12282
|
async function syncOnce() {
|
|
11986
12283
|
const creds = readCredentials();
|
|
@@ -12137,7 +12434,7 @@ async function runCloudSync() {
|
|
|
12137
12434
|
}
|
|
12138
12435
|
function getCloudSyncStatus() {
|
|
12139
12436
|
try {
|
|
12140
|
-
const raw = JSON.parse(
|
|
12437
|
+
const raw = JSON.parse(import_fs23.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
12141
12438
|
if (!Array.isArray(raw.rules) || typeof raw.fetchedAt !== "string") return { cached: false };
|
|
12142
12439
|
return {
|
|
12143
12440
|
cached: true,
|
|
@@ -12154,7 +12451,7 @@ function getCloudSyncStatus() {
|
|
|
12154
12451
|
}
|
|
12155
12452
|
function getCloudRules() {
|
|
12156
12453
|
try {
|
|
12157
|
-
const raw = JSON.parse(
|
|
12454
|
+
const raw = JSON.parse(import_fs23.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
12158
12455
|
return Array.isArray(raw.rules) ? raw.rules : null;
|
|
12159
12456
|
} catch {
|
|
12160
12457
|
return null;
|
|
@@ -12188,14 +12485,14 @@ function startForensicBroadcast() {
|
|
|
12188
12485
|
const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
|
|
12189
12486
|
recurring.unref();
|
|
12190
12487
|
}
|
|
12191
|
-
var
|
|
12488
|
+
var import_fs23, import_https2, import_os21, import_path25, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_HOURS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
|
|
12192
12489
|
var init_sync = __esm({
|
|
12193
12490
|
"src/daemon/sync.ts"() {
|
|
12194
12491
|
"use strict";
|
|
12195
|
-
|
|
12492
|
+
import_fs23 = __toESM(require("fs"));
|
|
12196
12493
|
import_https2 = __toESM(require("https"));
|
|
12197
|
-
|
|
12198
|
-
|
|
12494
|
+
import_os21 = __toESM(require("os"));
|
|
12495
|
+
import_path25 = __toESM(require("path"));
|
|
12199
12496
|
init_config();
|
|
12200
12497
|
init_blast();
|
|
12201
12498
|
init_dist();
|
|
@@ -12214,7 +12511,7 @@ var init_sync = __esm({
|
|
|
12214
12511
|
loop: "loops",
|
|
12215
12512
|
"long-output-redacted": "longOutputRedactions"
|
|
12216
12513
|
};
|
|
12217
|
-
rulesCacheFile = () =>
|
|
12514
|
+
rulesCacheFile = () => import_path25.default.join(import_os21.default.homedir(), ".node9", "rules-cache.json");
|
|
12218
12515
|
DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept/policies/sync";
|
|
12219
12516
|
DEFAULT_INTERVAL_HOURS = 5;
|
|
12220
12517
|
MIN_INTERVAL_HOURS = 1;
|
|
@@ -12227,68 +12524,68 @@ var init_sync = __esm({
|
|
|
12227
12524
|
// src/daemon/dlp-scanner.ts
|
|
12228
12525
|
function loadIndex() {
|
|
12229
12526
|
try {
|
|
12230
|
-
return JSON.parse(
|
|
12527
|
+
return JSON.parse(import_fs24.default.readFileSync(INDEX_FILE, "utf-8"));
|
|
12231
12528
|
} catch {
|
|
12232
12529
|
return {};
|
|
12233
12530
|
}
|
|
12234
12531
|
}
|
|
12235
12532
|
function saveIndex(index) {
|
|
12236
12533
|
try {
|
|
12237
|
-
|
|
12534
|
+
import_fs24.default.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
|
|
12238
12535
|
} catch {
|
|
12239
12536
|
}
|
|
12240
12537
|
}
|
|
12241
12538
|
function appendAuditEntry(entry) {
|
|
12242
12539
|
try {
|
|
12243
|
-
|
|
12540
|
+
import_fs24.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
12244
12541
|
} catch {
|
|
12245
12542
|
}
|
|
12246
12543
|
}
|
|
12247
12544
|
function runDlpScan() {
|
|
12248
|
-
if (!
|
|
12545
|
+
if (!import_fs24.default.existsSync(PROJECTS_DIR2)) return;
|
|
12249
12546
|
const index = loadIndex();
|
|
12250
12547
|
let updated = false;
|
|
12251
12548
|
let projDirs;
|
|
12252
12549
|
try {
|
|
12253
|
-
projDirs =
|
|
12550
|
+
projDirs = import_fs24.default.readdirSync(PROJECTS_DIR2);
|
|
12254
12551
|
} catch {
|
|
12255
12552
|
return;
|
|
12256
12553
|
}
|
|
12257
12554
|
for (const proj of projDirs) {
|
|
12258
|
-
const projPath =
|
|
12555
|
+
const projPath = import_path26.default.join(PROJECTS_DIR2, proj);
|
|
12259
12556
|
try {
|
|
12260
|
-
if (!
|
|
12261
|
-
const real =
|
|
12262
|
-
if (!real.startsWith(PROJECTS_DIR2 +
|
|
12557
|
+
if (!import_fs24.default.lstatSync(projPath).isDirectory()) continue;
|
|
12558
|
+
const real = import_fs24.default.realpathSync(projPath);
|
|
12559
|
+
if (!real.startsWith(PROJECTS_DIR2 + import_path26.default.sep) && real !== PROJECTS_DIR2) continue;
|
|
12263
12560
|
} catch {
|
|
12264
12561
|
continue;
|
|
12265
12562
|
}
|
|
12266
12563
|
let files;
|
|
12267
12564
|
try {
|
|
12268
|
-
files =
|
|
12565
|
+
files = import_fs24.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
12269
12566
|
} catch {
|
|
12270
12567
|
continue;
|
|
12271
12568
|
}
|
|
12272
12569
|
for (const file of files) {
|
|
12273
|
-
const filePath =
|
|
12570
|
+
const filePath = import_path26.default.join(projPath, file);
|
|
12274
12571
|
const lastOffset = index[filePath] ?? 0;
|
|
12275
12572
|
let size;
|
|
12276
12573
|
try {
|
|
12277
|
-
size =
|
|
12574
|
+
size = import_fs24.default.statSync(filePath).size;
|
|
12278
12575
|
} catch {
|
|
12279
12576
|
continue;
|
|
12280
12577
|
}
|
|
12281
12578
|
if (size <= lastOffset) continue;
|
|
12282
12579
|
let fd;
|
|
12283
12580
|
try {
|
|
12284
|
-
fd =
|
|
12581
|
+
fd = import_fs24.default.openSync(filePath, "r");
|
|
12285
12582
|
} catch {
|
|
12286
12583
|
continue;
|
|
12287
12584
|
}
|
|
12288
12585
|
try {
|
|
12289
12586
|
const chunkSize = size - lastOffset;
|
|
12290
12587
|
const buf = Buffer.alloc(chunkSize);
|
|
12291
|
-
|
|
12588
|
+
import_fs24.default.readSync(fd, buf, 0, chunkSize, lastOffset);
|
|
12292
12589
|
const chunk = buf.toString("utf-8");
|
|
12293
12590
|
for (const line of chunk.split("\n")) {
|
|
12294
12591
|
if (!line.trim()) continue;
|
|
@@ -12308,7 +12605,7 @@ function runDlpScan() {
|
|
|
12308
12605
|
if (typeof text !== "string") continue;
|
|
12309
12606
|
const match = scanText(text);
|
|
12310
12607
|
if (!match) continue;
|
|
12311
|
-
const projLabel = decodeURIComponent(proj).replace(
|
|
12608
|
+
const projLabel = decodeURIComponent(proj).replace(import_os22.default.homedir(), "~").slice(0, 40);
|
|
12312
12609
|
const ts = entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
12313
12610
|
appendAuditEntry({
|
|
12314
12611
|
ts,
|
|
@@ -12333,7 +12630,7 @@ Run: node9 report --period 30d`
|
|
|
12333
12630
|
updated = true;
|
|
12334
12631
|
} finally {
|
|
12335
12632
|
try {
|
|
12336
|
-
|
|
12633
|
+
import_fs24.default.closeSync(fd);
|
|
12337
12634
|
} catch {
|
|
12338
12635
|
}
|
|
12339
12636
|
}
|
|
@@ -12359,30 +12656,30 @@ function startDlpScanner() {
|
|
|
12359
12656
|
);
|
|
12360
12657
|
timer.unref();
|
|
12361
12658
|
}
|
|
12362
|
-
var
|
|
12659
|
+
var import_fs24, import_path26, import_os22, INDEX_FILE, PROJECTS_DIR2;
|
|
12363
12660
|
var init_dlp_scanner = __esm({
|
|
12364
12661
|
"src/daemon/dlp-scanner.ts"() {
|
|
12365
12662
|
"use strict";
|
|
12366
|
-
|
|
12367
|
-
|
|
12368
|
-
|
|
12663
|
+
import_fs24 = __toESM(require("fs"));
|
|
12664
|
+
import_path26 = __toESM(require("path"));
|
|
12665
|
+
import_os22 = __toESM(require("os"));
|
|
12369
12666
|
init_dlp();
|
|
12370
12667
|
init_native();
|
|
12371
12668
|
init_state2();
|
|
12372
|
-
INDEX_FILE =
|
|
12373
|
-
PROJECTS_DIR2 =
|
|
12669
|
+
INDEX_FILE = import_path26.default.join(import_os22.default.homedir(), ".node9", "dlp-index.json");
|
|
12670
|
+
PROJECTS_DIR2 = import_path26.default.join(import_os22.default.homedir(), ".claude", "projects");
|
|
12374
12671
|
}
|
|
12375
12672
|
});
|
|
12376
12673
|
|
|
12377
12674
|
// src/daemon/mcp-tools.ts
|
|
12378
12675
|
function getMcpToolsFile() {
|
|
12379
|
-
return
|
|
12676
|
+
return import_path27.default.join(import_os23.default.homedir(), ".node9", "mcp-tools.json");
|
|
12380
12677
|
}
|
|
12381
12678
|
function readMcpToolsConfig() {
|
|
12382
12679
|
try {
|
|
12383
12680
|
const file = getMcpToolsFile();
|
|
12384
|
-
if (!
|
|
12385
|
-
const raw =
|
|
12681
|
+
if (!import_fs25.default.existsSync(file)) return {};
|
|
12682
|
+
const raw = import_fs25.default.readFileSync(file, "utf-8");
|
|
12386
12683
|
return JSON.parse(raw);
|
|
12387
12684
|
} catch {
|
|
12388
12685
|
return {};
|
|
@@ -12391,11 +12688,11 @@ function readMcpToolsConfig() {
|
|
|
12391
12688
|
function writeMcpToolsConfig(config) {
|
|
12392
12689
|
try {
|
|
12393
12690
|
const file = getMcpToolsFile();
|
|
12394
|
-
const dir =
|
|
12395
|
-
if (!
|
|
12396
|
-
const tmpPath = `${file}.${
|
|
12397
|
-
|
|
12398
|
-
|
|
12691
|
+
const dir = import_path27.default.dirname(file);
|
|
12692
|
+
if (!import_fs25.default.existsSync(dir)) import_fs25.default.mkdirSync(dir, { recursive: true });
|
|
12693
|
+
const tmpPath = `${file}.${import_os23.default.hostname()}.${process.pid}.tmp`;
|
|
12694
|
+
import_fs25.default.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
|
|
12695
|
+
import_fs25.default.renameSync(tmpPath, file);
|
|
12399
12696
|
} catch (e) {
|
|
12400
12697
|
console.error("Failed to write mcp-tools.json", e);
|
|
12401
12698
|
}
|
|
@@ -12434,13 +12731,13 @@ function approveServer(serverKey, disabledTools) {
|
|
|
12434
12731
|
writeMcpToolsConfig(config);
|
|
12435
12732
|
}
|
|
12436
12733
|
}
|
|
12437
|
-
var
|
|
12734
|
+
var import_fs25, import_path27, import_os23;
|
|
12438
12735
|
var init_mcp_tools = __esm({
|
|
12439
12736
|
"src/daemon/mcp-tools.ts"() {
|
|
12440
12737
|
"use strict";
|
|
12441
|
-
|
|
12442
|
-
|
|
12443
|
-
|
|
12738
|
+
import_fs25 = __toESM(require("fs"));
|
|
12739
|
+
import_path27 = __toESM(require("path"));
|
|
12740
|
+
import_os23 = __toESM(require("os"));
|
|
12444
12741
|
}
|
|
12445
12742
|
});
|
|
12446
12743
|
|
|
@@ -12451,7 +12748,7 @@ function startDaemon() {
|
|
|
12451
12748
|
startForensicBroadcast();
|
|
12452
12749
|
startDlpScanner();
|
|
12453
12750
|
loadInsightCounts();
|
|
12454
|
-
const internalToken = (0,
|
|
12751
|
+
const internalToken = (0, import_crypto8.randomUUID)();
|
|
12455
12752
|
const validToken = (req) => req.headers["x-node9-internal"] === internalToken || req.headers["x-node9-token"] === internalToken;
|
|
12456
12753
|
const IDLE_TIMEOUT_MS = 12 * 60 * 60 * 1e3;
|
|
12457
12754
|
const watchMode = process.env.NODE9_WATCH_MODE === "1";
|
|
@@ -12462,7 +12759,7 @@ function startDaemon() {
|
|
|
12462
12759
|
idleTimer = setTimeout(() => {
|
|
12463
12760
|
if (autoStarted) {
|
|
12464
12761
|
try {
|
|
12465
|
-
|
|
12762
|
+
import_fs26.default.unlinkSync(DAEMON_PID_FILE);
|
|
12466
12763
|
} catch {
|
|
12467
12764
|
}
|
|
12468
12765
|
}
|
|
@@ -12563,7 +12860,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
12563
12860
|
cwd,
|
|
12564
12861
|
localSmartRuleMatched = false
|
|
12565
12862
|
} = JSON.parse(body);
|
|
12566
|
-
const id = fromCLI && typeof activityId === "string" && activityId || (0,
|
|
12863
|
+
const id = fromCLI && typeof activityId === "string" && activityId || (0, import_crypto8.randomUUID)();
|
|
12567
12864
|
const entry = {
|
|
12568
12865
|
id,
|
|
12569
12866
|
toolName,
|
|
@@ -12607,7 +12904,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
12607
12904
|
mcpServer: entry.mcpServer
|
|
12608
12905
|
});
|
|
12609
12906
|
}
|
|
12610
|
-
const projectCwd = typeof cwd === "string" &&
|
|
12907
|
+
const projectCwd = typeof cwd === "string" && import_path28.default.isAbsolute(cwd) ? cwd : void 0;
|
|
12611
12908
|
const projectConfig = getConfig(projectCwd);
|
|
12612
12909
|
const browserEnabled = projectConfig.settings.approvers?.browser !== false;
|
|
12613
12910
|
const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
|
|
@@ -12899,8 +13196,8 @@ data: ${JSON.stringify(item.data)}
|
|
|
12899
13196
|
if (!validToken(req)) return res.writeHead(403).end();
|
|
12900
13197
|
const periodParam = reqUrl.searchParams.get("period") || "7d";
|
|
12901
13198
|
const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
|
|
12902
|
-
const logPath =
|
|
12903
|
-
if (!
|
|
13199
|
+
const logPath = import_path28.default.join(import_os24.default.homedir(), ".node9", "audit.log");
|
|
13200
|
+
if (!import_fs26.default.existsSync(logPath)) {
|
|
12904
13201
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
12905
13202
|
return res.end(
|
|
12906
13203
|
JSON.stringify({
|
|
@@ -12913,7 +13210,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
12913
13210
|
);
|
|
12914
13211
|
}
|
|
12915
13212
|
try {
|
|
12916
|
-
const raw =
|
|
13213
|
+
const raw = import_fs26.default.readFileSync(logPath, "utf-8");
|
|
12917
13214
|
const allEntries = raw.split("\n").flatMap((line) => {
|
|
12918
13215
|
if (!line.trim()) return [];
|
|
12919
13216
|
try {
|
|
@@ -13148,7 +13445,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
13148
13445
|
args: { toolCount: tools.length, status },
|
|
13149
13446
|
decision: "mcp-discovered"
|
|
13150
13447
|
});
|
|
13151
|
-
const id = (0,
|
|
13448
|
+
const id = (0, import_crypto8.randomUUID)();
|
|
13152
13449
|
const entry = {
|
|
13153
13450
|
id,
|
|
13154
13451
|
type: "mcp-discovery",
|
|
@@ -13236,14 +13533,14 @@ data: ${JSON.stringify(item.data)}
|
|
|
13236
13533
|
server.on("error", (e) => {
|
|
13237
13534
|
if (e.code === "EADDRINUSE") {
|
|
13238
13535
|
try {
|
|
13239
|
-
if (
|
|
13240
|
-
const { pid } = JSON.parse(
|
|
13536
|
+
if (import_fs26.default.existsSync(DAEMON_PID_FILE)) {
|
|
13537
|
+
const { pid } = JSON.parse(import_fs26.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
13241
13538
|
process.kill(pid, 0);
|
|
13242
13539
|
return process.exit(0);
|
|
13243
13540
|
}
|
|
13244
13541
|
} catch {
|
|
13245
13542
|
try {
|
|
13246
|
-
|
|
13543
|
+
import_fs26.default.unlinkSync(DAEMON_PID_FILE);
|
|
13247
13544
|
} catch {
|
|
13248
13545
|
}
|
|
13249
13546
|
server.listen(DAEMON_PORT, DAEMON_HOST);
|
|
@@ -13315,15 +13612,15 @@ data: ${JSON.stringify(item.data)}
|
|
|
13315
13612
|
}
|
|
13316
13613
|
startActivitySocket();
|
|
13317
13614
|
}
|
|
13318
|
-
var import_http,
|
|
13615
|
+
var import_http, import_fs26, import_path28, import_os24, import_crypto8, import_child_process2, import_chalk6;
|
|
13319
13616
|
var init_server = __esm({
|
|
13320
13617
|
"src/daemon/server.ts"() {
|
|
13321
13618
|
"use strict";
|
|
13322
13619
|
import_http = __toESM(require("http"));
|
|
13323
|
-
|
|
13324
|
-
|
|
13325
|
-
|
|
13326
|
-
|
|
13620
|
+
import_fs26 = __toESM(require("fs"));
|
|
13621
|
+
import_path28 = __toESM(require("path"));
|
|
13622
|
+
import_os24 = __toESM(require("os"));
|
|
13623
|
+
import_crypto8 = require("crypto");
|
|
13327
13624
|
import_child_process2 = require("child_process");
|
|
13328
13625
|
import_chalk6 = __toESM(require("chalk"));
|
|
13329
13626
|
init_core();
|
|
@@ -13342,8 +13639,8 @@ var init_server = __esm({
|
|
|
13342
13639
|
function resolveNode9Binary() {
|
|
13343
13640
|
try {
|
|
13344
13641
|
const script = process.argv[1];
|
|
13345
|
-
if (typeof script === "string" &&
|
|
13346
|
-
return
|
|
13642
|
+
if (typeof script === "string" && import_path29.default.isAbsolute(script) && import_fs27.default.existsSync(script)) {
|
|
13643
|
+
return import_fs27.default.realpathSync(script);
|
|
13347
13644
|
}
|
|
13348
13645
|
} catch {
|
|
13349
13646
|
}
|
|
@@ -13361,11 +13658,11 @@ function xmlEscape(s) {
|
|
|
13361
13658
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
13362
13659
|
}
|
|
13363
13660
|
function launchdPlist(binaryPath) {
|
|
13364
|
-
const logDir =
|
|
13661
|
+
const logDir = import_path29.default.join(import_os25.default.homedir(), ".node9");
|
|
13365
13662
|
const nodePath = xmlEscape(process.execPath);
|
|
13366
13663
|
const scriptPath = xmlEscape(binaryPath);
|
|
13367
|
-
const outLog = xmlEscape(
|
|
13368
|
-
const errLog = xmlEscape(
|
|
13664
|
+
const outLog = xmlEscape(import_path29.default.join(logDir, "daemon.log"));
|
|
13665
|
+
const errLog = xmlEscape(import_path29.default.join(logDir, "daemon-error.log"));
|
|
13369
13666
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
13370
13667
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
13371
13668
|
<plist version="1.0">
|
|
@@ -13398,9 +13695,9 @@ function launchdPlist(binaryPath) {
|
|
|
13398
13695
|
`;
|
|
13399
13696
|
}
|
|
13400
13697
|
function installLaunchd(binaryPath) {
|
|
13401
|
-
const dir =
|
|
13402
|
-
if (!
|
|
13403
|
-
|
|
13698
|
+
const dir = import_path29.default.dirname(LAUNCHD_PLIST);
|
|
13699
|
+
if (!import_fs27.default.existsSync(dir)) import_fs27.default.mkdirSync(dir, { recursive: true });
|
|
13700
|
+
import_fs27.default.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
|
|
13404
13701
|
(0, import_child_process3.spawnSync)("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
|
|
13405
13702
|
const r = (0, import_child_process3.spawnSync)("launchctl", ["load", "-w", LAUNCHD_PLIST], {
|
|
13406
13703
|
encoding: "utf8",
|
|
@@ -13411,13 +13708,13 @@ function installLaunchd(binaryPath) {
|
|
|
13411
13708
|
}
|
|
13412
13709
|
}
|
|
13413
13710
|
function uninstallLaunchd() {
|
|
13414
|
-
if (
|
|
13711
|
+
if (import_fs27.default.existsSync(LAUNCHD_PLIST)) {
|
|
13415
13712
|
(0, import_child_process3.spawnSync)("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
|
|
13416
|
-
|
|
13713
|
+
import_fs27.default.unlinkSync(LAUNCHD_PLIST);
|
|
13417
13714
|
}
|
|
13418
13715
|
}
|
|
13419
13716
|
function isLaunchdInstalled() {
|
|
13420
|
-
return
|
|
13717
|
+
return import_fs27.default.existsSync(LAUNCHD_PLIST);
|
|
13421
13718
|
}
|
|
13422
13719
|
function systemdUnit(binaryPath) {
|
|
13423
13720
|
return `[Unit]
|
|
@@ -13436,12 +13733,12 @@ WantedBy=default.target
|
|
|
13436
13733
|
`;
|
|
13437
13734
|
}
|
|
13438
13735
|
function installSystemd(binaryPath) {
|
|
13439
|
-
if (!
|
|
13440
|
-
|
|
13736
|
+
if (!import_fs27.default.existsSync(SYSTEMD_UNIT_DIR)) {
|
|
13737
|
+
import_fs27.default.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
|
|
13441
13738
|
}
|
|
13442
|
-
|
|
13739
|
+
import_fs27.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
|
|
13443
13740
|
try {
|
|
13444
|
-
(0, import_child_process3.execFileSync)("loginctl", ["enable-linger",
|
|
13741
|
+
(0, import_child_process3.execFileSync)("loginctl", ["enable-linger", import_os25.default.userInfo().username], { timeout: 3e3 });
|
|
13445
13742
|
} catch {
|
|
13446
13743
|
}
|
|
13447
13744
|
const reload = (0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], {
|
|
@@ -13461,23 +13758,23 @@ function installSystemd(binaryPath) {
|
|
|
13461
13758
|
}
|
|
13462
13759
|
}
|
|
13463
13760
|
function uninstallSystemd() {
|
|
13464
|
-
if (
|
|
13761
|
+
if (import_fs27.default.existsSync(SYSTEMD_UNIT)) {
|
|
13465
13762
|
(0, import_child_process3.spawnSync)("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
|
|
13466
13763
|
encoding: "utf8",
|
|
13467
13764
|
timeout: 5e3
|
|
13468
13765
|
});
|
|
13469
13766
|
(0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
|
|
13470
|
-
|
|
13767
|
+
import_fs27.default.unlinkSync(SYSTEMD_UNIT);
|
|
13471
13768
|
}
|
|
13472
13769
|
}
|
|
13473
13770
|
function isSystemdInstalled() {
|
|
13474
|
-
return
|
|
13771
|
+
return import_fs27.default.existsSync(SYSTEMD_UNIT);
|
|
13475
13772
|
}
|
|
13476
13773
|
function stopRunningDaemon() {
|
|
13477
|
-
const pidFile =
|
|
13478
|
-
if (!
|
|
13774
|
+
const pidFile = import_path29.default.join(import_os25.default.homedir(), ".node9", "daemon.pid");
|
|
13775
|
+
if (!import_fs27.default.existsSync(pidFile)) return;
|
|
13479
13776
|
try {
|
|
13480
|
-
const data = JSON.parse(
|
|
13777
|
+
const data = JSON.parse(import_fs27.default.readFileSync(pidFile, "utf-8"));
|
|
13481
13778
|
const pid = data.pid;
|
|
13482
13779
|
const MAX_PID2 = 4194304;
|
|
13483
13780
|
if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
|
|
@@ -13497,7 +13794,7 @@ function stopRunningDaemon() {
|
|
|
13497
13794
|
}
|
|
13498
13795
|
}
|
|
13499
13796
|
try {
|
|
13500
|
-
|
|
13797
|
+
import_fs27.default.unlinkSync(pidFile);
|
|
13501
13798
|
} catch {
|
|
13502
13799
|
}
|
|
13503
13800
|
} catch {
|
|
@@ -13567,26 +13864,26 @@ function isDaemonServiceInstalled() {
|
|
|
13567
13864
|
if (process.platform === "linux") return isSystemdInstalled();
|
|
13568
13865
|
return false;
|
|
13569
13866
|
}
|
|
13570
|
-
var
|
|
13867
|
+
var import_fs27, import_path29, import_os25, import_child_process3, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
|
|
13571
13868
|
var init_service = __esm({
|
|
13572
13869
|
"src/daemon/service.ts"() {
|
|
13573
13870
|
"use strict";
|
|
13574
|
-
|
|
13575
|
-
|
|
13576
|
-
|
|
13871
|
+
import_fs27 = __toESM(require("fs"));
|
|
13872
|
+
import_path29 = __toESM(require("path"));
|
|
13873
|
+
import_os25 = __toESM(require("os"));
|
|
13577
13874
|
import_child_process3 = require("child_process");
|
|
13578
13875
|
LAUNCHD_LABEL = "ai.node9.daemon";
|
|
13579
|
-
LAUNCHD_PLIST =
|
|
13580
|
-
SYSTEMD_UNIT_DIR =
|
|
13581
|
-
SYSTEMD_UNIT =
|
|
13876
|
+
LAUNCHD_PLIST = import_path29.default.join(import_os25.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
13877
|
+
SYSTEMD_UNIT_DIR = import_path29.default.join(import_os25.default.homedir(), ".config", "systemd", "user");
|
|
13878
|
+
SYSTEMD_UNIT = import_path29.default.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
|
|
13582
13879
|
}
|
|
13583
13880
|
});
|
|
13584
13881
|
|
|
13585
13882
|
// src/daemon/index.ts
|
|
13586
13883
|
function stopDaemon() {
|
|
13587
|
-
if (!
|
|
13884
|
+
if (!import_fs28.default.existsSync(DAEMON_PID_FILE)) return console.log(import_chalk7.default.yellow("Not running."));
|
|
13588
13885
|
try {
|
|
13589
|
-
const data = JSON.parse(
|
|
13886
|
+
const data = JSON.parse(import_fs28.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
13590
13887
|
const pid = data.pid;
|
|
13591
13888
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
13592
13889
|
console.log(import_chalk7.default.gray("Cleaned up invalid PID file."));
|
|
@@ -13598,7 +13895,7 @@ function stopDaemon() {
|
|
|
13598
13895
|
console.log(import_chalk7.default.gray("Cleaned up stale PID file."));
|
|
13599
13896
|
} finally {
|
|
13600
13897
|
try {
|
|
13601
|
-
|
|
13898
|
+
import_fs28.default.unlinkSync(DAEMON_PID_FILE);
|
|
13602
13899
|
} catch {
|
|
13603
13900
|
}
|
|
13604
13901
|
}
|
|
@@ -13607,9 +13904,9 @@ function daemonStatus() {
|
|
|
13607
13904
|
const serviceInstalled = isDaemonServiceInstalled();
|
|
13608
13905
|
const serviceLabel = serviceInstalled ? import_chalk7.default.green("installed (starts on login)") : import_chalk7.default.yellow("not installed \u2014 run: node9 daemon install");
|
|
13609
13906
|
let processStatus;
|
|
13610
|
-
if (
|
|
13907
|
+
if (import_fs28.default.existsSync(DAEMON_PID_FILE)) {
|
|
13611
13908
|
try {
|
|
13612
|
-
const data = JSON.parse(
|
|
13909
|
+
const data = JSON.parse(import_fs28.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
13613
13910
|
const pid = data.pid;
|
|
13614
13911
|
const port = data.port;
|
|
13615
13912
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
@@ -13631,11 +13928,11 @@ function daemonStatus() {
|
|
|
13631
13928
|
console.log(` Service : ${serviceLabel}
|
|
13632
13929
|
`);
|
|
13633
13930
|
}
|
|
13634
|
-
var
|
|
13931
|
+
var import_fs28, import_chalk7, MAX_PID;
|
|
13635
13932
|
var init_daemon2 = __esm({
|
|
13636
13933
|
"src/daemon/index.ts"() {
|
|
13637
13934
|
"use strict";
|
|
13638
|
-
|
|
13935
|
+
import_fs28 = __toESM(require("fs"));
|
|
13639
13936
|
import_chalk7 = __toESM(require("chalk"));
|
|
13640
13937
|
init_server();
|
|
13641
13938
|
init_state2();
|
|
@@ -13676,19 +13973,19 @@ function getModelContextLimit(model) {
|
|
|
13676
13973
|
}
|
|
13677
13974
|
function readSessionUsage() {
|
|
13678
13975
|
const projectsDir = import_path47.default.join(import_os41.default.homedir(), ".claude", "projects");
|
|
13679
|
-
if (!
|
|
13976
|
+
if (!import_fs46.default.existsSync(projectsDir)) return null;
|
|
13680
13977
|
let latestFile = null;
|
|
13681
13978
|
let latestMtime = 0;
|
|
13682
13979
|
try {
|
|
13683
|
-
for (const dir of
|
|
13980
|
+
for (const dir of import_fs46.default.readdirSync(projectsDir)) {
|
|
13684
13981
|
const dirPath = import_path47.default.join(projectsDir, dir);
|
|
13685
13982
|
try {
|
|
13686
|
-
if (!
|
|
13687
|
-
for (const file of
|
|
13983
|
+
if (!import_fs46.default.statSync(dirPath).isDirectory()) continue;
|
|
13984
|
+
for (const file of import_fs46.default.readdirSync(dirPath)) {
|
|
13688
13985
|
if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
|
|
13689
13986
|
const filePath = import_path47.default.join(dirPath, file);
|
|
13690
13987
|
try {
|
|
13691
|
-
const mtime =
|
|
13988
|
+
const mtime = import_fs46.default.statSync(filePath).mtimeMs;
|
|
13692
13989
|
if (mtime > latestMtime) {
|
|
13693
13990
|
latestMtime = mtime;
|
|
13694
13991
|
latestFile = filePath;
|
|
@@ -13703,7 +14000,7 @@ function readSessionUsage() {
|
|
|
13703
14000
|
}
|
|
13704
14001
|
if (!latestFile) return null;
|
|
13705
14002
|
try {
|
|
13706
|
-
const lines =
|
|
14003
|
+
const lines = import_fs46.default.readFileSync(latestFile, "utf-8").split("\n");
|
|
13707
14004
|
let lastModel = "";
|
|
13708
14005
|
let lastInput = 0;
|
|
13709
14006
|
let lastOutput = 0;
|
|
@@ -13803,9 +14100,9 @@ function renderPending(activity) {
|
|
|
13803
14100
|
}
|
|
13804
14101
|
async function ensureDaemon() {
|
|
13805
14102
|
let pidPort = null;
|
|
13806
|
-
if (
|
|
14103
|
+
if (import_fs46.default.existsSync(PID_FILE)) {
|
|
13807
14104
|
try {
|
|
13808
|
-
const { port } = JSON.parse(
|
|
14105
|
+
const { port } = JSON.parse(import_fs46.default.readFileSync(PID_FILE, "utf-8"));
|
|
13809
14106
|
pidPort = port;
|
|
13810
14107
|
} catch {
|
|
13811
14108
|
console.error(import_chalk29.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
@@ -13963,7 +14260,7 @@ function buildRecoveryCardLines(req) {
|
|
|
13963
14260
|
function readApproversFromDisk() {
|
|
13964
14261
|
const configPath = import_path47.default.join(import_os41.default.homedir(), ".node9", "config.json");
|
|
13965
14262
|
try {
|
|
13966
|
-
const raw = JSON.parse(
|
|
14263
|
+
const raw = JSON.parse(import_fs46.default.readFileSync(configPath, "utf-8"));
|
|
13967
14264
|
const settings = raw.settings ?? {};
|
|
13968
14265
|
return settings.approvers ?? {};
|
|
13969
14266
|
} catch {
|
|
@@ -13981,13 +14278,13 @@ function approverStatusLine() {
|
|
|
13981
14278
|
function toggleApprover(channel) {
|
|
13982
14279
|
const configPath = import_path47.default.join(import_os41.default.homedir(), ".node9", "config.json");
|
|
13983
14280
|
try {
|
|
13984
|
-
const raw = JSON.parse(
|
|
14281
|
+
const raw = JSON.parse(import_fs46.default.readFileSync(configPath, "utf-8"));
|
|
13985
14282
|
const settings = raw.settings ?? {};
|
|
13986
14283
|
const approvers = settings.approvers ?? {};
|
|
13987
14284
|
approvers[channel] = approvers[channel] === false;
|
|
13988
14285
|
settings.approvers = approvers;
|
|
13989
14286
|
raw.settings = settings;
|
|
13990
|
-
|
|
14287
|
+
import_fs46.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
|
|
13991
14288
|
} catch (err2) {
|
|
13992
14289
|
process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
|
|
13993
14290
|
`);
|
|
@@ -14159,7 +14456,7 @@ async function startTail(options = {}) {
|
|
|
14159
14456
|
}
|
|
14160
14457
|
postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
|
|
14161
14458
|
try {
|
|
14162
|
-
|
|
14459
|
+
import_fs46.default.appendFileSync(
|
|
14163
14460
|
import_path47.default.join(import_os41.default.homedir(), ".node9", "hook-debug.log"),
|
|
14164
14461
|
`[tail] POST /decision failed: ${String(err2)}
|
|
14165
14462
|
`
|
|
@@ -14226,7 +14523,7 @@ async function startTail(options = {}) {
|
|
|
14226
14523
|
}
|
|
14227
14524
|
const auditLog = import_path47.default.join(import_os41.default.homedir(), ".node9", "audit.log");
|
|
14228
14525
|
try {
|
|
14229
|
-
const unackedDlp =
|
|
14526
|
+
const unackedDlp = import_fs46.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
14230
14527
|
if (unackedDlp > 0) {
|
|
14231
14528
|
console.log("");
|
|
14232
14529
|
console.log(
|
|
@@ -14266,7 +14563,7 @@ async function startTail(options = {}) {
|
|
|
14266
14563
|
if (stallWarned) return;
|
|
14267
14564
|
if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
|
|
14268
14565
|
try {
|
|
14269
|
-
const auditMtime =
|
|
14566
|
+
const auditMtime = import_fs46.default.statSync(auditLog).mtimeMs;
|
|
14270
14567
|
if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
|
|
14271
14568
|
console.log("");
|
|
14272
14569
|
console.log(
|
|
@@ -14451,13 +14748,13 @@ async function startTail(options = {}) {
|
|
|
14451
14748
|
process.exit(1);
|
|
14452
14749
|
});
|
|
14453
14750
|
}
|
|
14454
|
-
var import_http2, import_chalk29,
|
|
14751
|
+
var import_http2, import_chalk29, import_fs46, import_os41, import_path47, import_readline6, import_child_process12, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
|
|
14455
14752
|
var init_tail = __esm({
|
|
14456
14753
|
"src/tui/tail.ts"() {
|
|
14457
14754
|
"use strict";
|
|
14458
14755
|
import_http2 = __toESM(require("http"));
|
|
14459
14756
|
import_chalk29 = __toESM(require("chalk"));
|
|
14460
|
-
|
|
14757
|
+
import_fs46 = __toESM(require("fs"));
|
|
14461
14758
|
import_os41 = __toESM(require("os"));
|
|
14462
14759
|
import_path47 = __toESM(require("path"));
|
|
14463
14760
|
import_readline6 = __toESM(require("readline"));
|
|
@@ -14586,9 +14883,9 @@ function formatTimeLeft(resetsAt) {
|
|
|
14586
14883
|
return ` (${m}m left)`;
|
|
14587
14884
|
}
|
|
14588
14885
|
function safeReadJson(filePath) {
|
|
14589
|
-
if (!
|
|
14886
|
+
if (!import_fs47.default.existsSync(filePath)) return null;
|
|
14590
14887
|
try {
|
|
14591
|
-
return JSON.parse(
|
|
14888
|
+
return JSON.parse(import_fs47.default.readFileSync(filePath, "utf-8"));
|
|
14592
14889
|
} catch {
|
|
14593
14890
|
return null;
|
|
14594
14891
|
}
|
|
@@ -14609,10 +14906,10 @@ function countHooksInFile(filePath) {
|
|
|
14609
14906
|
return Object.keys(cfg.hooks).length;
|
|
14610
14907
|
}
|
|
14611
14908
|
function countRulesInDir(rulesDir) {
|
|
14612
|
-
if (!
|
|
14909
|
+
if (!import_fs47.default.existsSync(rulesDir)) return 0;
|
|
14613
14910
|
let count = 0;
|
|
14614
14911
|
try {
|
|
14615
|
-
for (const entry of
|
|
14912
|
+
for (const entry of import_fs47.default.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
14616
14913
|
if (entry.isDirectory()) {
|
|
14617
14914
|
count += countRulesInDir(import_path48.default.join(rulesDir, entry.name));
|
|
14618
14915
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -14638,7 +14935,7 @@ function countConfigs(cwd) {
|
|
|
14638
14935
|
let hooksCount = 0;
|
|
14639
14936
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
14640
14937
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
14641
|
-
if (
|
|
14938
|
+
if (import_fs47.default.existsSync(import_path48.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
14642
14939
|
rulesCount += countRulesInDir(import_path48.default.join(claudeDir, "rules"));
|
|
14643
14940
|
const userSettings = import_path48.default.join(claudeDir, "settings.json");
|
|
14644
14941
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
@@ -14649,18 +14946,18 @@ function countConfigs(cwd) {
|
|
|
14649
14946
|
userMcpServers.delete(name);
|
|
14650
14947
|
}
|
|
14651
14948
|
if (cwd) {
|
|
14652
|
-
if (
|
|
14653
|
-
if (
|
|
14949
|
+
if (import_fs47.default.existsSync(import_path48.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
14950
|
+
if (import_fs47.default.existsSync(import_path48.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
14654
14951
|
const projectClaudeDir = import_path48.default.join(cwd, ".claude");
|
|
14655
14952
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
14656
14953
|
if (!overlapsUserScope) {
|
|
14657
|
-
if (
|
|
14954
|
+
if (import_fs47.default.existsSync(import_path48.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
14658
14955
|
rulesCount += countRulesInDir(import_path48.default.join(projectClaudeDir, "rules"));
|
|
14659
14956
|
const projSettings = import_path48.default.join(projectClaudeDir, "settings.json");
|
|
14660
14957
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
14661
14958
|
hooksCount += countHooksInFile(projSettings);
|
|
14662
14959
|
}
|
|
14663
|
-
if (
|
|
14960
|
+
if (import_fs47.default.existsSync(import_path48.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
14664
14961
|
const localSettings = import_path48.default.join(projectClaudeDir, "settings.local.json");
|
|
14665
14962
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
14666
14963
|
hooksCount += countHooksInFile(localSettings);
|
|
@@ -14698,11 +14995,11 @@ function readActiveShieldsHud() {
|
|
|
14698
14995
|
}
|
|
14699
14996
|
try {
|
|
14700
14997
|
const shieldsPath = import_path48.default.join(import_os42.default.homedir(), ".node9", "shields.json");
|
|
14701
|
-
if (!
|
|
14998
|
+
if (!import_fs47.default.existsSync(shieldsPath)) {
|
|
14702
14999
|
shieldsCache = { value: [], ts: now };
|
|
14703
15000
|
return [];
|
|
14704
15001
|
}
|
|
14705
|
-
const parsed = JSON.parse(
|
|
15002
|
+
const parsed = JSON.parse(import_fs47.default.readFileSync(shieldsPath, "utf-8"));
|
|
14706
15003
|
if (!Array.isArray(parsed.active)) {
|
|
14707
15004
|
shieldsCache = { value: [], ts: now };
|
|
14708
15005
|
return [];
|
|
@@ -14804,17 +15101,17 @@ function renderContextLine(stdin) {
|
|
|
14804
15101
|
async function main() {
|
|
14805
15102
|
try {
|
|
14806
15103
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
14807
|
-
if (
|
|
15104
|
+
if (import_fs47.default.existsSync(import_path48.default.join(import_os42.default.homedir(), ".node9", "hud-debug"))) {
|
|
14808
15105
|
try {
|
|
14809
15106
|
const logPath = import_path48.default.join(import_os42.default.homedir(), ".node9", "hud-debug.log");
|
|
14810
15107
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
14811
15108
|
let size = 0;
|
|
14812
15109
|
try {
|
|
14813
|
-
size =
|
|
15110
|
+
size = import_fs47.default.statSync(logPath).size;
|
|
14814
15111
|
} catch {
|
|
14815
15112
|
}
|
|
14816
15113
|
if (size < MAX_LOG_SIZE) {
|
|
14817
|
-
|
|
15114
|
+
import_fs47.default.appendFileSync(
|
|
14818
15115
|
logPath,
|
|
14819
15116
|
JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
|
|
14820
15117
|
);
|
|
@@ -14838,8 +15135,8 @@ async function main() {
|
|
|
14838
15135
|
import_path48.default.join(cwd, "node9.config.json"),
|
|
14839
15136
|
import_path48.default.join(import_os42.default.homedir(), ".node9", "config.json")
|
|
14840
15137
|
]) {
|
|
14841
|
-
if (!
|
|
14842
|
-
const cfg = JSON.parse(
|
|
15138
|
+
if (!import_fs47.default.existsSync(configPath)) continue;
|
|
15139
|
+
const cfg = JSON.parse(import_fs47.default.readFileSync(configPath, "utf-8"));
|
|
14843
15140
|
const hud = cfg.settings?.hud;
|
|
14844
15141
|
if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
|
|
14845
15142
|
}
|
|
@@ -14857,11 +15154,11 @@ async function main() {
|
|
|
14857
15154
|
renderOffline();
|
|
14858
15155
|
}
|
|
14859
15156
|
}
|
|
14860
|
-
var
|
|
15157
|
+
var import_fs47, import_path48, import_os42, import_http3, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
|
|
14861
15158
|
var init_hud = __esm({
|
|
14862
15159
|
"src/cli/hud.ts"() {
|
|
14863
15160
|
"use strict";
|
|
14864
|
-
|
|
15161
|
+
import_fs47 = __toESM(require("fs"));
|
|
14865
15162
|
import_path48 = __toESM(require("path"));
|
|
14866
15163
|
import_os42 = __toESM(require("os"));
|
|
14867
15164
|
import_http3 = __toESM(require("http"));
|
|
@@ -14890,7 +15187,7 @@ init_core();
|
|
|
14890
15187
|
init_setup();
|
|
14891
15188
|
init_daemon2();
|
|
14892
15189
|
var import_chalk30 = __toESM(require("chalk"));
|
|
14893
|
-
var
|
|
15190
|
+
var import_fs48 = __toESM(require("fs"));
|
|
14894
15191
|
var import_path49 = __toESM(require("path"));
|
|
14895
15192
|
var import_os43 = __toESM(require("os"));
|
|
14896
15193
|
var import_prompts2 = require("@inquirer/prompts");
|
|
@@ -15074,18 +15371,18 @@ async function runProxy(targetCommand) {
|
|
|
15074
15371
|
|
|
15075
15372
|
// src/cli/daemon-starter.ts
|
|
15076
15373
|
var import_child_process5 = require("child_process");
|
|
15077
|
-
var
|
|
15078
|
-
var
|
|
15374
|
+
var import_path30 = __toESM(require("path"));
|
|
15375
|
+
var import_fs29 = __toESM(require("fs"));
|
|
15079
15376
|
init_daemon();
|
|
15080
15377
|
function isTestingMode() {
|
|
15081
15378
|
return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
|
|
15082
15379
|
}
|
|
15083
15380
|
async function autoStartDaemonAndWait() {
|
|
15084
15381
|
if (isTestingMode()) return false;
|
|
15085
|
-
if (!
|
|
15382
|
+
if (!import_path30.default.isAbsolute(process.argv[1])) return false;
|
|
15086
15383
|
let resolvedArgv1;
|
|
15087
15384
|
try {
|
|
15088
|
-
resolvedArgv1 =
|
|
15385
|
+
resolvedArgv1 = import_fs29.default.realpathSync(process.argv[1]);
|
|
15089
15386
|
} catch {
|
|
15090
15387
|
return false;
|
|
15091
15388
|
}
|
|
@@ -15112,10 +15409,10 @@ async function autoStartDaemonAndWait() {
|
|
|
15112
15409
|
|
|
15113
15410
|
// src/cli/commands/check.ts
|
|
15114
15411
|
var import_chalk9 = __toESM(require("chalk"));
|
|
15115
|
-
var
|
|
15412
|
+
var import_fs32 = __toESM(require("fs"));
|
|
15116
15413
|
var import_child_process7 = require("child_process");
|
|
15117
|
-
var
|
|
15118
|
-
var
|
|
15414
|
+
var import_path33 = __toESM(require("path"));
|
|
15415
|
+
var import_os28 = __toESM(require("os"));
|
|
15119
15416
|
init_orchestrator();
|
|
15120
15417
|
init_daemon();
|
|
15121
15418
|
init_config();
|
|
@@ -15123,12 +15420,12 @@ init_policy();
|
|
|
15123
15420
|
|
|
15124
15421
|
// src/undo.ts
|
|
15125
15422
|
var import_child_process6 = require("child_process");
|
|
15126
|
-
var
|
|
15127
|
-
var
|
|
15423
|
+
var import_crypto9 = __toESM(require("crypto"));
|
|
15424
|
+
var import_fs30 = __toESM(require("fs"));
|
|
15128
15425
|
var import_net3 = __toESM(require("net"));
|
|
15129
|
-
var
|
|
15130
|
-
var
|
|
15131
|
-
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
15426
|
+
var import_path31 = __toESM(require("path"));
|
|
15427
|
+
var import_os26 = __toESM(require("os"));
|
|
15428
|
+
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path31.default.join(import_os26.default.tmpdir(), "node9-activity.sock");
|
|
15132
15429
|
function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
15133
15430
|
try {
|
|
15134
15431
|
const payload = JSON.stringify({
|
|
@@ -15148,22 +15445,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
|
15148
15445
|
} catch {
|
|
15149
15446
|
}
|
|
15150
15447
|
}
|
|
15151
|
-
var SNAPSHOT_STACK_PATH =
|
|
15152
|
-
var UNDO_LATEST_PATH =
|
|
15448
|
+
var SNAPSHOT_STACK_PATH = import_path31.default.join(import_os26.default.homedir(), ".node9", "snapshots.json");
|
|
15449
|
+
var UNDO_LATEST_PATH = import_path31.default.join(import_os26.default.homedir(), ".node9", "undo_latest.txt");
|
|
15153
15450
|
var MAX_SNAPSHOTS = 10;
|
|
15154
15451
|
var GIT_TIMEOUT = 15e3;
|
|
15155
15452
|
function readStack() {
|
|
15156
15453
|
try {
|
|
15157
|
-
if (
|
|
15158
|
-
return JSON.parse(
|
|
15454
|
+
if (import_fs30.default.existsSync(SNAPSHOT_STACK_PATH))
|
|
15455
|
+
return JSON.parse(import_fs30.default.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
|
|
15159
15456
|
} catch {
|
|
15160
15457
|
}
|
|
15161
15458
|
return [];
|
|
15162
15459
|
}
|
|
15163
15460
|
function writeStack(stack) {
|
|
15164
|
-
const dir =
|
|
15165
|
-
if (!
|
|
15166
|
-
|
|
15461
|
+
const dir = import_path31.default.dirname(SNAPSHOT_STACK_PATH);
|
|
15462
|
+
if (!import_fs30.default.existsSync(dir)) import_fs30.default.mkdirSync(dir, { recursive: true });
|
|
15463
|
+
import_fs30.default.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
|
|
15167
15464
|
}
|
|
15168
15465
|
function extractFilePath(args) {
|
|
15169
15466
|
if (!args || typeof args !== "object") return null;
|
|
@@ -15183,12 +15480,12 @@ function buildArgsSummary(tool, args) {
|
|
|
15183
15480
|
return "";
|
|
15184
15481
|
}
|
|
15185
15482
|
function findProjectRoot(filePath) {
|
|
15186
|
-
let dir =
|
|
15483
|
+
let dir = import_path31.default.dirname(filePath);
|
|
15187
15484
|
while (true) {
|
|
15188
|
-
if (
|
|
15485
|
+
if (import_fs30.default.existsSync(import_path31.default.join(dir, ".git")) || import_fs30.default.existsSync(import_path31.default.join(dir, "package.json"))) {
|
|
15189
15486
|
return dir;
|
|
15190
15487
|
}
|
|
15191
|
-
const parent =
|
|
15488
|
+
const parent = import_path31.default.dirname(dir);
|
|
15192
15489
|
if (parent === dir) return process.cwd();
|
|
15193
15490
|
dir = parent;
|
|
15194
15491
|
}
|
|
@@ -15196,7 +15493,7 @@ function findProjectRoot(filePath) {
|
|
|
15196
15493
|
function normalizeCwdForHash(cwd) {
|
|
15197
15494
|
let normalized;
|
|
15198
15495
|
try {
|
|
15199
|
-
normalized =
|
|
15496
|
+
normalized = import_fs30.default.realpathSync(cwd);
|
|
15200
15497
|
} catch {
|
|
15201
15498
|
normalized = cwd;
|
|
15202
15499
|
}
|
|
@@ -15205,17 +15502,17 @@ function normalizeCwdForHash(cwd) {
|
|
|
15205
15502
|
return normalized;
|
|
15206
15503
|
}
|
|
15207
15504
|
function getShadowRepoDir(cwd) {
|
|
15208
|
-
const hash =
|
|
15209
|
-
return
|
|
15505
|
+
const hash = import_crypto9.default.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
|
|
15506
|
+
return import_path31.default.join(import_os26.default.homedir(), ".node9", "snapshots", hash);
|
|
15210
15507
|
}
|
|
15211
15508
|
function cleanOrphanedIndexFiles(shadowDir) {
|
|
15212
15509
|
try {
|
|
15213
15510
|
const cutoff = Date.now() - 6e4;
|
|
15214
|
-
for (const f of
|
|
15511
|
+
for (const f of import_fs30.default.readdirSync(shadowDir)) {
|
|
15215
15512
|
if (f.startsWith("index_")) {
|
|
15216
|
-
const fp =
|
|
15513
|
+
const fp = import_path31.default.join(shadowDir, f);
|
|
15217
15514
|
try {
|
|
15218
|
-
if (
|
|
15515
|
+
if (import_fs30.default.statSync(fp).mtimeMs < cutoff) import_fs30.default.unlinkSync(fp);
|
|
15219
15516
|
} catch {
|
|
15220
15517
|
}
|
|
15221
15518
|
}
|
|
@@ -15227,7 +15524,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
|
|
|
15227
15524
|
const hardcoded = [".git", ".node9"];
|
|
15228
15525
|
const lines = [...hardcoded, ...ignorePaths].join("\n");
|
|
15229
15526
|
try {
|
|
15230
|
-
|
|
15527
|
+
import_fs30.default.writeFileSync(import_path31.default.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
|
|
15231
15528
|
} catch {
|
|
15232
15529
|
}
|
|
15233
15530
|
}
|
|
@@ -15240,25 +15537,25 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
15240
15537
|
timeout: 3e3
|
|
15241
15538
|
});
|
|
15242
15539
|
if (check.status === 0) {
|
|
15243
|
-
const ptPath =
|
|
15540
|
+
const ptPath = import_path31.default.join(shadowDir, "project-path.txt");
|
|
15244
15541
|
try {
|
|
15245
|
-
const stored =
|
|
15542
|
+
const stored = import_fs30.default.readFileSync(ptPath, "utf8").trim();
|
|
15246
15543
|
if (stored === normalizedCwd) return true;
|
|
15247
15544
|
if (process.env.NODE9_DEBUG === "1")
|
|
15248
15545
|
console.error(
|
|
15249
15546
|
`[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
|
|
15250
15547
|
);
|
|
15251
|
-
|
|
15548
|
+
import_fs30.default.rmSync(shadowDir, { recursive: true, force: true });
|
|
15252
15549
|
} catch {
|
|
15253
15550
|
try {
|
|
15254
|
-
|
|
15551
|
+
import_fs30.default.writeFileSync(ptPath, normalizedCwd, "utf8");
|
|
15255
15552
|
} catch {
|
|
15256
15553
|
}
|
|
15257
15554
|
return true;
|
|
15258
15555
|
}
|
|
15259
15556
|
}
|
|
15260
15557
|
try {
|
|
15261
|
-
|
|
15558
|
+
import_fs30.default.mkdirSync(shadowDir, { recursive: true });
|
|
15262
15559
|
} catch {
|
|
15263
15560
|
}
|
|
15264
15561
|
const init = (0, import_child_process6.spawnSync)("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
|
|
@@ -15267,7 +15564,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
15267
15564
|
if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
|
|
15268
15565
|
return false;
|
|
15269
15566
|
}
|
|
15270
|
-
const configFile =
|
|
15567
|
+
const configFile = import_path31.default.join(shadowDir, "config");
|
|
15271
15568
|
(0, import_child_process6.spawnSync)("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
|
|
15272
15569
|
timeout: 3e3
|
|
15273
15570
|
});
|
|
@@ -15275,7 +15572,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
15275
15572
|
timeout: 3e3
|
|
15276
15573
|
});
|
|
15277
15574
|
try {
|
|
15278
|
-
|
|
15575
|
+
import_fs30.default.writeFileSync(import_path31.default.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
|
|
15279
15576
|
} catch {
|
|
15280
15577
|
}
|
|
15281
15578
|
return true;
|
|
@@ -15298,12 +15595,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
15298
15595
|
let indexFile = null;
|
|
15299
15596
|
try {
|
|
15300
15597
|
const rawFilePath = extractFilePath(args);
|
|
15301
|
-
const absFilePath = rawFilePath &&
|
|
15598
|
+
const absFilePath = rawFilePath && import_path31.default.isAbsolute(rawFilePath) ? rawFilePath : null;
|
|
15302
15599
|
const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
|
|
15303
15600
|
const shadowDir = getShadowRepoDir(cwd);
|
|
15304
15601
|
if (!ensureShadowRepo(shadowDir, cwd)) return null;
|
|
15305
15602
|
writeShadowExcludes(shadowDir, ignorePaths);
|
|
15306
|
-
indexFile =
|
|
15603
|
+
indexFile = import_path31.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
|
|
15307
15604
|
const shadowEnv = {
|
|
15308
15605
|
...process.env,
|
|
15309
15606
|
GIT_DIR: shadowDir,
|
|
@@ -15375,7 +15672,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
15375
15672
|
writeStack(stack);
|
|
15376
15673
|
const entry = stack[stack.length - 1];
|
|
15377
15674
|
notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
|
|
15378
|
-
|
|
15675
|
+
import_fs30.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
|
|
15379
15676
|
if (shouldGc) {
|
|
15380
15677
|
(0, import_child_process6.spawn)("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
|
|
15381
15678
|
}
|
|
@@ -15386,7 +15683,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
15386
15683
|
} finally {
|
|
15387
15684
|
if (indexFile) {
|
|
15388
15685
|
try {
|
|
15389
|
-
|
|
15686
|
+
import_fs30.default.unlinkSync(indexFile);
|
|
15390
15687
|
} catch {
|
|
15391
15688
|
}
|
|
15392
15689
|
}
|
|
@@ -15462,9 +15759,9 @@ function applyUndo(hash, cwd) {
|
|
|
15462
15759
|
timeout: GIT_TIMEOUT
|
|
15463
15760
|
}).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
|
|
15464
15761
|
for (const file of [...tracked, ...untracked]) {
|
|
15465
|
-
const fullPath =
|
|
15466
|
-
if (!snapshotFiles.has(file) &&
|
|
15467
|
-
|
|
15762
|
+
const fullPath = import_path31.default.join(dir, file);
|
|
15763
|
+
if (!snapshotFiles.has(file) && import_fs30.default.existsSync(fullPath)) {
|
|
15764
|
+
import_fs30.default.unlinkSync(fullPath);
|
|
15468
15765
|
}
|
|
15469
15766
|
}
|
|
15470
15767
|
return true;
|
|
@@ -15474,17 +15771,17 @@ function applyUndo(hash, cwd) {
|
|
|
15474
15771
|
}
|
|
15475
15772
|
|
|
15476
15773
|
// src/skill-pin.ts
|
|
15477
|
-
var
|
|
15478
|
-
var
|
|
15479
|
-
var
|
|
15480
|
-
var
|
|
15481
|
-
function
|
|
15482
|
-
return
|
|
15774
|
+
var import_fs31 = __toESM(require("fs"));
|
|
15775
|
+
var import_path32 = __toESM(require("path"));
|
|
15776
|
+
var import_os27 = __toESM(require("os"));
|
|
15777
|
+
var import_crypto10 = __toESM(require("crypto"));
|
|
15778
|
+
function getPinsFilePath2() {
|
|
15779
|
+
return import_path32.default.join(import_os27.default.homedir(), ".node9", "skill-pins.json");
|
|
15483
15780
|
}
|
|
15484
15781
|
var MAX_FILES = 5e3;
|
|
15485
15782
|
var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
|
|
15486
15783
|
function sha256Bytes(buf) {
|
|
15487
|
-
return
|
|
15784
|
+
return import_crypto10.default.createHash("sha256").update(buf).digest("hex");
|
|
15488
15785
|
}
|
|
15489
15786
|
function walkDir(root) {
|
|
15490
15787
|
const out = [];
|
|
@@ -15493,18 +15790,18 @@ function walkDir(root) {
|
|
|
15493
15790
|
if (out.length >= MAX_FILES) return;
|
|
15494
15791
|
let entries;
|
|
15495
15792
|
try {
|
|
15496
|
-
entries =
|
|
15793
|
+
entries = import_fs31.default.readdirSync(dir, { withFileTypes: true });
|
|
15497
15794
|
} catch {
|
|
15498
15795
|
return;
|
|
15499
15796
|
}
|
|
15500
15797
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
15501
15798
|
for (const entry of entries) {
|
|
15502
15799
|
if (out.length >= MAX_FILES) return;
|
|
15503
|
-
const full =
|
|
15504
|
-
const rel = relDir ?
|
|
15800
|
+
const full = import_path32.default.join(dir, entry.name);
|
|
15801
|
+
const rel = relDir ? import_path32.default.posix.join(relDir, entry.name) : entry.name;
|
|
15505
15802
|
let lst;
|
|
15506
15803
|
try {
|
|
15507
|
-
lst =
|
|
15804
|
+
lst = import_fs31.default.lstatSync(full);
|
|
15508
15805
|
} catch {
|
|
15509
15806
|
continue;
|
|
15510
15807
|
}
|
|
@@ -15516,7 +15813,7 @@ function walkDir(root) {
|
|
|
15516
15813
|
if (!lst.isFile()) continue;
|
|
15517
15814
|
if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
|
|
15518
15815
|
try {
|
|
15519
|
-
const buf =
|
|
15816
|
+
const buf = import_fs31.default.readFileSync(full);
|
|
15520
15817
|
totalBytes += buf.length;
|
|
15521
15818
|
out.push({ rel, hash: sha256Bytes(buf) });
|
|
15522
15819
|
} catch {
|
|
@@ -15530,32 +15827,32 @@ function walkDir(root) {
|
|
|
15530
15827
|
function hashSkillRoot(absPath) {
|
|
15531
15828
|
let lst;
|
|
15532
15829
|
try {
|
|
15533
|
-
lst =
|
|
15830
|
+
lst = import_fs31.default.lstatSync(absPath);
|
|
15534
15831
|
} catch {
|
|
15535
15832
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
15536
15833
|
}
|
|
15537
15834
|
if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
|
|
15538
15835
|
if (lst.isFile()) {
|
|
15539
15836
|
try {
|
|
15540
|
-
return { exists: true, contentHash: sha256Bytes(
|
|
15837
|
+
return { exists: true, contentHash: sha256Bytes(import_fs31.default.readFileSync(absPath)), fileCount: 1 };
|
|
15541
15838
|
} catch {
|
|
15542
15839
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
15543
15840
|
}
|
|
15544
15841
|
}
|
|
15545
15842
|
if (lst.isDirectory()) {
|
|
15546
15843
|
const entries = walkDir(absPath);
|
|
15547
|
-
const contentHash =
|
|
15844
|
+
const contentHash = import_crypto10.default.createHash("sha256").update(entries.join("\n")).digest("hex");
|
|
15548
15845
|
return { exists: true, contentHash, fileCount: entries.length };
|
|
15549
15846
|
}
|
|
15550
15847
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
15551
15848
|
}
|
|
15552
15849
|
function getRootKey(absPath) {
|
|
15553
|
-
return
|
|
15850
|
+
return import_crypto10.default.createHash("sha256").update(absPath).digest("hex").slice(0, 16);
|
|
15554
15851
|
}
|
|
15555
15852
|
function readSkillPinsSafe() {
|
|
15556
|
-
const filePath =
|
|
15853
|
+
const filePath = getPinsFilePath2();
|
|
15557
15854
|
try {
|
|
15558
|
-
const raw =
|
|
15855
|
+
const raw = import_fs31.default.readFileSync(filePath, "utf-8");
|
|
15559
15856
|
if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
15560
15857
|
const parsed = JSON.parse(raw);
|
|
15561
15858
|
if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
|
|
@@ -15574,18 +15871,18 @@ function readSkillPins() {
|
|
|
15574
15871
|
throw new Error(`[node9] skill pin file is corrupt: ${result.detail}`);
|
|
15575
15872
|
}
|
|
15576
15873
|
function writeSkillPins(data) {
|
|
15577
|
-
const filePath =
|
|
15578
|
-
|
|
15579
|
-
const tmp = `${filePath}.${
|
|
15580
|
-
|
|
15581
|
-
|
|
15874
|
+
const filePath = getPinsFilePath2();
|
|
15875
|
+
import_fs31.default.mkdirSync(import_path32.default.dirname(filePath), { recursive: true });
|
|
15876
|
+
const tmp = `${filePath}.${import_crypto10.default.randomBytes(6).toString("hex")}.tmp`;
|
|
15877
|
+
import_fs31.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
15878
|
+
import_fs31.default.renameSync(tmp, filePath);
|
|
15582
15879
|
}
|
|
15583
|
-
function
|
|
15880
|
+
function removePin2(rootKey) {
|
|
15584
15881
|
const pins = readSkillPins();
|
|
15585
15882
|
delete pins.roots[rootKey];
|
|
15586
15883
|
writeSkillPins(pins);
|
|
15587
15884
|
}
|
|
15588
|
-
function
|
|
15885
|
+
function clearAllPins2() {
|
|
15589
15886
|
writeSkillPins({ roots: {} });
|
|
15590
15887
|
}
|
|
15591
15888
|
function verifyAndPinRoots(roots) {
|
|
@@ -15622,43 +15919,48 @@ function verifyAndPinRoots(roots) {
|
|
|
15622
15919
|
return { kind: "verified" };
|
|
15623
15920
|
}
|
|
15624
15921
|
function defaultSkillRoots(_cwd) {
|
|
15625
|
-
const marketplaces =
|
|
15922
|
+
const marketplaces = import_path32.default.join(import_os27.default.homedir(), ".claude", "plugins", "marketplaces");
|
|
15626
15923
|
const roots = [];
|
|
15627
15924
|
let registries;
|
|
15628
15925
|
try {
|
|
15629
|
-
registries =
|
|
15926
|
+
registries = import_fs31.default.readdirSync(marketplaces, { withFileTypes: true });
|
|
15630
15927
|
} catch {
|
|
15631
15928
|
return [];
|
|
15632
15929
|
}
|
|
15633
15930
|
for (const registry of registries) {
|
|
15634
15931
|
if (!registry.isDirectory()) continue;
|
|
15635
|
-
const pluginsDir =
|
|
15932
|
+
const pluginsDir = import_path32.default.join(marketplaces, registry.name, "plugins");
|
|
15636
15933
|
let plugins;
|
|
15637
15934
|
try {
|
|
15638
|
-
plugins =
|
|
15935
|
+
plugins = import_fs31.default.readdirSync(pluginsDir, { withFileTypes: true });
|
|
15639
15936
|
} catch {
|
|
15640
15937
|
continue;
|
|
15641
15938
|
}
|
|
15642
15939
|
for (const plugin of plugins) {
|
|
15643
15940
|
if (!plugin.isDirectory()) continue;
|
|
15644
|
-
roots.push(
|
|
15941
|
+
roots.push(import_path32.default.join(pluginsDir, plugin.name));
|
|
15645
15942
|
}
|
|
15646
15943
|
}
|
|
15647
15944
|
return roots;
|
|
15648
15945
|
}
|
|
15649
15946
|
function resolveUserSkillRoot(entry, cwd) {
|
|
15650
15947
|
if (!entry) return null;
|
|
15651
|
-
if (entry.startsWith("~/") || entry === "~") return
|
|
15652
|
-
if (
|
|
15653
|
-
if (!cwd || !
|
|
15654
|
-
return
|
|
15948
|
+
if (entry.startsWith("~/") || entry === "~") return import_path32.default.join(import_os27.default.homedir(), entry.slice(1));
|
|
15949
|
+
if (import_path32.default.isAbsolute(entry)) return entry;
|
|
15950
|
+
if (!cwd || !import_path32.default.isAbsolute(cwd)) return null;
|
|
15951
|
+
return import_path32.default.join(cwd, entry);
|
|
15655
15952
|
}
|
|
15656
15953
|
|
|
15657
15954
|
// src/cli/commands/check.ts
|
|
15955
|
+
init_dlp();
|
|
15956
|
+
init_audit();
|
|
15658
15957
|
function sanitize2(value) {
|
|
15659
15958
|
return value.replace(/[\x00-\x1F\x7F]/g, "");
|
|
15660
15959
|
}
|
|
15661
15960
|
function detectAiAgent(payload) {
|
|
15961
|
+
if (payload.turn_id !== void 0) {
|
|
15962
|
+
return "Codex";
|
|
15963
|
+
}
|
|
15662
15964
|
if (payload.hook_event_name === "PreToolUse" || payload.hook_event_name === "PostToolUse" || payload.tool_use_id !== void 0 || payload.permission_mode !== void 0) {
|
|
15663
15965
|
return "Claude Code";
|
|
15664
15966
|
}
|
|
@@ -15693,9 +15995,9 @@ function registerCheckCommand(program2) {
|
|
|
15693
15995
|
} catch (err2) {
|
|
15694
15996
|
const tempConfig = getConfig();
|
|
15695
15997
|
if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
|
|
15696
|
-
const logPath =
|
|
15998
|
+
const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
15697
15999
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
15698
|
-
|
|
16000
|
+
import_fs32.default.appendFileSync(
|
|
15699
16001
|
logPath,
|
|
15700
16002
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
|
|
15701
16003
|
RAW: ${raw}
|
|
@@ -15704,15 +16006,76 @@ RAW: ${raw}
|
|
|
15704
16006
|
}
|
|
15705
16007
|
process.exit(0);
|
|
15706
16008
|
}
|
|
15707
|
-
|
|
16009
|
+
if (payload.hook_event_name === "UserPromptSubmit") {
|
|
16010
|
+
const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
|
|
16011
|
+
if (process.env.NODE9_DEBUG === "1") {
|
|
16012
|
+
try {
|
|
16013
|
+
const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
16014
|
+
if (!import_fs32.default.existsSync(import_path33.default.dirname(logPath)))
|
|
16015
|
+
import_fs32.default.mkdirSync(import_path33.default.dirname(logPath), { recursive: true });
|
|
16016
|
+
const sanitized = JSON.stringify({
|
|
16017
|
+
...payload,
|
|
16018
|
+
prompt: `<redacted, ${prompt.length} bytes>`
|
|
16019
|
+
});
|
|
16020
|
+
import_fs32.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
|
|
16021
|
+
`);
|
|
16022
|
+
} catch {
|
|
16023
|
+
}
|
|
16024
|
+
}
|
|
16025
|
+
if (!prompt) process.exit(0);
|
|
16026
|
+
const dlpMatch = scanArgs({ prompt });
|
|
16027
|
+
if (!dlpMatch) process.exit(0);
|
|
16028
|
+
const agent2 = detectAiAgent(payload);
|
|
16029
|
+
const sessionId2 = typeof payload.session_id === "string" ? payload.session_id : void 0;
|
|
16030
|
+
appendLocalAudit(
|
|
16031
|
+
"UserPromptSubmit",
|
|
16032
|
+
{ prompt },
|
|
16033
|
+
"deny",
|
|
16034
|
+
"dlp-block",
|
|
16035
|
+
{ agent: agent2, sessionId: sessionId2 },
|
|
16036
|
+
true
|
|
16037
|
+
);
|
|
16038
|
+
const reason = `\u{1F6A8} Node9 DLP: ${dlpMatch.patternName} detected in prompt (${dlpMatch.redactedSample}). Prompt was not submitted \u2014 remove the credential and try again.`;
|
|
16039
|
+
try {
|
|
16040
|
+
const ttyFd = import_fs32.default.openSync("/dev/tty", "w");
|
|
16041
|
+
import_fs32.default.writeSync(
|
|
16042
|
+
ttyFd,
|
|
16043
|
+
import_chalk9.default.bgRed.white.bold(`
|
|
16044
|
+
\u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
|
|
16045
|
+
`) + import_chalk9.default.red(` ${dlpMatch.patternName} detected in your prompt.
|
|
16046
|
+
`) + import_chalk9.default.gray(` Match: ${dlpMatch.redactedSample}
|
|
16047
|
+
`) + import_chalk9.default.cyan(` Edit the prompt to remove the credential and resubmit.
|
|
16048
|
+
|
|
16049
|
+
`)
|
|
16050
|
+
);
|
|
16051
|
+
import_fs32.default.closeSync(ttyFd);
|
|
16052
|
+
} catch {
|
|
16053
|
+
}
|
|
16054
|
+
const isCodex = agent2 === "Codex";
|
|
16055
|
+
process.stdout.write(
|
|
16056
|
+
JSON.stringify({
|
|
16057
|
+
decision: "block",
|
|
16058
|
+
reason,
|
|
16059
|
+
systemMessage: reason,
|
|
16060
|
+
hookSpecificOutput: isCodex ? { hookEventName: "UserPromptSubmit" } : {
|
|
16061
|
+
hookEventName: "UserPromptSubmit",
|
|
16062
|
+
permissionDecision: "deny",
|
|
16063
|
+
permissionDecisionReason: reason
|
|
16064
|
+
}
|
|
16065
|
+
}) + "\n"
|
|
16066
|
+
);
|
|
16067
|
+
process.exit(2);
|
|
16068
|
+
}
|
|
16069
|
+
const safeCwdForConfig = typeof payload.cwd === "string" && import_path33.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
|
|
16070
|
+
const config = getConfig(safeCwdForConfig);
|
|
15708
16071
|
if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
|
|
15709
16072
|
try {
|
|
15710
16073
|
const scriptPath = process.argv[1];
|
|
15711
|
-
if (typeof scriptPath !== "string" || !
|
|
16074
|
+
if (typeof scriptPath !== "string" || !import_path33.default.isAbsolute(scriptPath))
|
|
15712
16075
|
throw new Error("node9: argv[1] is not an absolute path");
|
|
15713
|
-
const resolvedScript =
|
|
15714
|
-
const packageDist =
|
|
15715
|
-
if (!resolvedScript.startsWith(packageDist +
|
|
16076
|
+
const resolvedScript = import_fs32.default.realpathSync(scriptPath);
|
|
16077
|
+
const packageDist = import_fs32.default.realpathSync(import_path33.default.resolve(__dirname, "../.."));
|
|
16078
|
+
if (!resolvedScript.startsWith(packageDist + import_path33.default.sep) && resolvedScript !== packageDist)
|
|
15716
16079
|
throw new Error(
|
|
15717
16080
|
`node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
|
|
15718
16081
|
);
|
|
@@ -15734,10 +16097,10 @@ RAW: ${raw}
|
|
|
15734
16097
|
});
|
|
15735
16098
|
d.unref();
|
|
15736
16099
|
} catch (spawnErr) {
|
|
15737
|
-
const logPath =
|
|
16100
|
+
const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
15738
16101
|
const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
|
|
15739
16102
|
try {
|
|
15740
|
-
|
|
16103
|
+
import_fs32.default.appendFileSync(
|
|
15741
16104
|
logPath,
|
|
15742
16105
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
|
|
15743
16106
|
`
|
|
@@ -15747,10 +16110,10 @@ RAW: ${raw}
|
|
|
15747
16110
|
}
|
|
15748
16111
|
}
|
|
15749
16112
|
if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
|
|
15750
|
-
const logPath =
|
|
15751
|
-
if (!
|
|
15752
|
-
|
|
15753
|
-
|
|
16113
|
+
const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
16114
|
+
if (!import_fs32.default.existsSync(import_path33.default.dirname(logPath)))
|
|
16115
|
+
import_fs32.default.mkdirSync(import_path33.default.dirname(logPath), { recursive: true });
|
|
16116
|
+
import_fs32.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
|
|
15754
16117
|
`);
|
|
15755
16118
|
}
|
|
15756
16119
|
const toolName = sanitize2(payload.tool_name ?? payload.name ?? "");
|
|
@@ -15763,8 +16126,8 @@ RAW: ${raw}
|
|
|
15763
16126
|
const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
|
|
15764
16127
|
let ttyFd = null;
|
|
15765
16128
|
try {
|
|
15766
|
-
ttyFd =
|
|
15767
|
-
const writeTty = (line) =>
|
|
16129
|
+
ttyFd = import_fs32.default.openSync("/dev/tty", "w");
|
|
16130
|
+
const writeTty = (line) => import_fs32.default.writeSync(ttyFd, line + "\n");
|
|
15768
16131
|
if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
|
|
15769
16132
|
writeTty(import_chalk9.default.bgRed.white.bold(`
|
|
15770
16133
|
\u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
|
|
@@ -15783,7 +16146,7 @@ RAW: ${raw}
|
|
|
15783
16146
|
} finally {
|
|
15784
16147
|
if (ttyFd !== null)
|
|
15785
16148
|
try {
|
|
15786
|
-
|
|
16149
|
+
import_fs32.default.closeSync(ttyFd);
|
|
15787
16150
|
} catch {
|
|
15788
16151
|
}
|
|
15789
16152
|
}
|
|
@@ -15819,17 +16182,17 @@ RAW: ${raw}
|
|
|
15819
16182
|
const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
|
|
15820
16183
|
if (skillPinCfg.enabled && safeSessionId) {
|
|
15821
16184
|
try {
|
|
15822
|
-
const sessionsDir =
|
|
15823
|
-
const flagPath =
|
|
16185
|
+
const sessionsDir = import_path33.default.join(import_os28.default.homedir(), ".node9", "skill-sessions");
|
|
16186
|
+
const flagPath = import_path33.default.join(sessionsDir, `${safeSessionId}.json`);
|
|
15824
16187
|
let flag = null;
|
|
15825
16188
|
try {
|
|
15826
|
-
flag = JSON.parse(
|
|
16189
|
+
flag = JSON.parse(import_fs32.default.readFileSync(flagPath, "utf-8"));
|
|
15827
16190
|
} catch {
|
|
15828
16191
|
}
|
|
15829
16192
|
const writeFlag = (data2) => {
|
|
15830
16193
|
try {
|
|
15831
|
-
|
|
15832
|
-
|
|
16194
|
+
import_fs32.default.mkdirSync(sessionsDir, { recursive: true });
|
|
16195
|
+
import_fs32.default.writeFileSync(
|
|
15833
16196
|
flagPath,
|
|
15834
16197
|
JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
|
|
15835
16198
|
{ mode: 384 }
|
|
@@ -15840,8 +16203,8 @@ RAW: ${raw}
|
|
|
15840
16203
|
const sendSkillWarn = (detail, recoveryCmd) => {
|
|
15841
16204
|
let ttyFd = null;
|
|
15842
16205
|
try {
|
|
15843
|
-
ttyFd =
|
|
15844
|
-
const w = (line) =>
|
|
16206
|
+
ttyFd = import_fs32.default.openSync("/dev/tty", "w");
|
|
16207
|
+
const w = (line) => import_fs32.default.writeSync(ttyFd, line + "\n");
|
|
15845
16208
|
w(import_chalk9.default.yellow(`
|
|
15846
16209
|
\u26A0\uFE0F Node9: installed skill drift detected`));
|
|
15847
16210
|
w(import_chalk9.default.gray(` ${detail}`));
|
|
@@ -15856,7 +16219,7 @@ RAW: ${raw}
|
|
|
15856
16219
|
} finally {
|
|
15857
16220
|
if (ttyFd !== null)
|
|
15858
16221
|
try {
|
|
15859
|
-
|
|
16222
|
+
import_fs32.default.closeSync(ttyFd);
|
|
15860
16223
|
} catch {
|
|
15861
16224
|
}
|
|
15862
16225
|
}
|
|
@@ -15872,7 +16235,7 @@ RAW: ${raw}
|
|
|
15872
16235
|
return;
|
|
15873
16236
|
}
|
|
15874
16237
|
if (!flag || flag.state !== "verified" && flag.state !== "warned") {
|
|
15875
|
-
const absoluteCwd = typeof payload.cwd === "string" &&
|
|
16238
|
+
const absoluteCwd = typeof payload.cwd === "string" && import_path33.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
|
|
15876
16239
|
const extraRoots = skillPinCfg.roots;
|
|
15877
16240
|
const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
|
|
15878
16241
|
const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
|
|
@@ -15913,10 +16276,10 @@ RAW: ${raw}
|
|
|
15913
16276
|
}
|
|
15914
16277
|
try {
|
|
15915
16278
|
const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
15916
|
-
for (const name of
|
|
15917
|
-
const p =
|
|
16279
|
+
for (const name of import_fs32.default.readdirSync(sessionsDir)) {
|
|
16280
|
+
const p = import_path33.default.join(sessionsDir, name);
|
|
15918
16281
|
try {
|
|
15919
|
-
if (
|
|
16282
|
+
if (import_fs32.default.statSync(p).mtimeMs < cutoff) import_fs32.default.unlinkSync(p);
|
|
15920
16283
|
} catch {
|
|
15921
16284
|
}
|
|
15922
16285
|
}
|
|
@@ -15926,9 +16289,9 @@ RAW: ${raw}
|
|
|
15926
16289
|
} catch (err2) {
|
|
15927
16290
|
if (process.env.NODE9_DEBUG === "1") {
|
|
15928
16291
|
try {
|
|
15929
|
-
const dbg =
|
|
16292
|
+
const dbg = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
15930
16293
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
15931
|
-
|
|
16294
|
+
import_fs32.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
|
|
15932
16295
|
`);
|
|
15933
16296
|
} catch {
|
|
15934
16297
|
}
|
|
@@ -15938,7 +16301,7 @@ RAW: ${raw}
|
|
|
15938
16301
|
if (shouldSnapshot(toolName, toolInput, config)) {
|
|
15939
16302
|
await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
|
|
15940
16303
|
}
|
|
15941
|
-
const safeCwdForAuth = typeof payload.cwd === "string" &&
|
|
16304
|
+
const safeCwdForAuth = typeof payload.cwd === "string" && import_path33.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
|
|
15942
16305
|
const result = await authorizeHeadless(toolName, toolInput, meta, {
|
|
15943
16306
|
cwd: safeCwdForAuth
|
|
15944
16307
|
});
|
|
@@ -15950,12 +16313,12 @@ RAW: ${raw}
|
|
|
15950
16313
|
}
|
|
15951
16314
|
if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
|
|
15952
16315
|
try {
|
|
15953
|
-
const tty =
|
|
15954
|
-
|
|
16316
|
+
const tty = import_fs32.default.openSync("/dev/tty", "w");
|
|
16317
|
+
import_fs32.default.writeSync(
|
|
15955
16318
|
tty,
|
|
15956
16319
|
import_chalk9.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
|
|
15957
16320
|
);
|
|
15958
|
-
|
|
16321
|
+
import_fs32.default.closeSync(tty);
|
|
15959
16322
|
} catch {
|
|
15960
16323
|
}
|
|
15961
16324
|
const daemonReady = await autoStartDaemonAndWait();
|
|
@@ -15982,9 +16345,9 @@ RAW: ${raw}
|
|
|
15982
16345
|
});
|
|
15983
16346
|
} catch (err2) {
|
|
15984
16347
|
if (process.env.NODE9_DEBUG === "1") {
|
|
15985
|
-
const logPath =
|
|
16348
|
+
const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
15986
16349
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
15987
|
-
|
|
16350
|
+
import_fs32.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
|
|
15988
16351
|
`);
|
|
15989
16352
|
}
|
|
15990
16353
|
process.exit(0);
|
|
@@ -16018,9 +16381,9 @@ RAW: ${raw}
|
|
|
16018
16381
|
}
|
|
16019
16382
|
|
|
16020
16383
|
// src/cli/commands/log.ts
|
|
16021
|
-
var
|
|
16022
|
-
var
|
|
16023
|
-
var
|
|
16384
|
+
var import_fs33 = __toESM(require("fs"));
|
|
16385
|
+
var import_path34 = __toESM(require("path"));
|
|
16386
|
+
var import_os29 = __toESM(require("os"));
|
|
16024
16387
|
init_audit();
|
|
16025
16388
|
init_config();
|
|
16026
16389
|
init_daemon();
|
|
@@ -16088,7 +16451,7 @@ function registerLogCommand(program2) {
|
|
|
16088
16451
|
const payload = JSON.parse(raw);
|
|
16089
16452
|
const tool = sanitize3(payload.tool_name ?? payload.name ?? "unknown");
|
|
16090
16453
|
const rawInput = payload.tool_input ?? payload.args ?? {};
|
|
16091
|
-
const agent = 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" : void 0;
|
|
16454
|
+
const agent = payload.turn_id !== void 0 ? "Codex" : 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" : void 0;
|
|
16092
16455
|
const entry = {
|
|
16093
16456
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16094
16457
|
tool,
|
|
@@ -16098,10 +16461,10 @@ function registerLogCommand(program2) {
|
|
|
16098
16461
|
};
|
|
16099
16462
|
if (agent) entry.agent = agent;
|
|
16100
16463
|
if (payload.session_id) entry.sessionId = payload.session_id;
|
|
16101
|
-
const logPath =
|
|
16102
|
-
if (!
|
|
16103
|
-
|
|
16104
|
-
|
|
16464
|
+
const logPath = import_path34.default.join(import_os29.default.homedir(), ".node9", "audit.log");
|
|
16465
|
+
if (!import_fs33.default.existsSync(import_path34.default.dirname(logPath)))
|
|
16466
|
+
import_fs33.default.mkdirSync(import_path34.default.dirname(logPath), { recursive: true });
|
|
16467
|
+
import_fs33.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
|
|
16105
16468
|
if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
|
|
16106
16469
|
const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
16107
16470
|
if (command) {
|
|
@@ -16134,7 +16497,7 @@ function registerLogCommand(program2) {
|
|
|
16134
16497
|
}
|
|
16135
16498
|
}
|
|
16136
16499
|
}
|
|
16137
|
-
const safeCwd = typeof payload.cwd === "string" &&
|
|
16500
|
+
const safeCwd = typeof payload.cwd === "string" && import_path34.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
|
|
16138
16501
|
const config = getConfig(safeCwd);
|
|
16139
16502
|
if ((tool === "Bash" || tool === "bash") && config.settings.enableUndo !== false) {
|
|
16140
16503
|
const bashCommand = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
@@ -16155,9 +16518,9 @@ function registerLogCommand(program2) {
|
|
|
16155
16518
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
16156
16519
|
process.stderr.write(`[Node9] audit log error: ${msg}
|
|
16157
16520
|
`);
|
|
16158
|
-
const debugPath =
|
|
16521
|
+
const debugPath = import_path34.default.join(import_os29.default.homedir(), ".node9", "hook-debug.log");
|
|
16159
16522
|
try {
|
|
16160
|
-
|
|
16523
|
+
import_fs33.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
|
|
16161
16524
|
`);
|
|
16162
16525
|
} catch {
|
|
16163
16526
|
}
|
|
@@ -16557,14 +16920,14 @@ function registerConfigShowCommand(program2) {
|
|
|
16557
16920
|
|
|
16558
16921
|
// src/cli/commands/doctor.ts
|
|
16559
16922
|
var import_chalk11 = __toESM(require("chalk"));
|
|
16560
|
-
var
|
|
16561
|
-
var
|
|
16562
|
-
var
|
|
16923
|
+
var import_fs34 = __toESM(require("fs"));
|
|
16924
|
+
var import_path35 = __toESM(require("path"));
|
|
16925
|
+
var import_os30 = __toESM(require("os"));
|
|
16563
16926
|
var import_child_process8 = require("child_process");
|
|
16564
16927
|
init_daemon();
|
|
16565
16928
|
function registerDoctorCommand(program2, version2) {
|
|
16566
16929
|
program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(() => {
|
|
16567
|
-
const homeDir2 =
|
|
16930
|
+
const homeDir2 = import_os30.default.homedir();
|
|
16568
16931
|
let failures = 0;
|
|
16569
16932
|
function pass(msg) {
|
|
16570
16933
|
console.log(import_chalk11.default.green(" \u2705 ") + msg);
|
|
@@ -16613,10 +16976,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16613
16976
|
);
|
|
16614
16977
|
}
|
|
16615
16978
|
section("Configuration");
|
|
16616
|
-
const globalConfigPath =
|
|
16617
|
-
if (
|
|
16979
|
+
const globalConfigPath = import_path35.default.join(homeDir2, ".node9", "config.json");
|
|
16980
|
+
if (import_fs34.default.existsSync(globalConfigPath)) {
|
|
16618
16981
|
try {
|
|
16619
|
-
JSON.parse(
|
|
16982
|
+
JSON.parse(import_fs34.default.readFileSync(globalConfigPath, "utf-8"));
|
|
16620
16983
|
pass("~/.node9/config.json found and valid");
|
|
16621
16984
|
} catch {
|
|
16622
16985
|
fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
|
|
@@ -16624,10 +16987,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16624
16987
|
} else {
|
|
16625
16988
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
16626
16989
|
}
|
|
16627
|
-
const projectConfigPath =
|
|
16628
|
-
if (
|
|
16990
|
+
const projectConfigPath = import_path35.default.join(process.cwd(), "node9.config.json");
|
|
16991
|
+
if (import_fs34.default.existsSync(projectConfigPath)) {
|
|
16629
16992
|
try {
|
|
16630
|
-
JSON.parse(
|
|
16993
|
+
JSON.parse(import_fs34.default.readFileSync(projectConfigPath, "utf-8"));
|
|
16631
16994
|
pass("node9.config.json found and valid (project)");
|
|
16632
16995
|
} catch {
|
|
16633
16996
|
fail(
|
|
@@ -16636,8 +16999,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16636
16999
|
);
|
|
16637
17000
|
}
|
|
16638
17001
|
}
|
|
16639
|
-
const credsPath =
|
|
16640
|
-
if (
|
|
17002
|
+
const credsPath = import_path35.default.join(homeDir2, ".node9", "credentials.json");
|
|
17003
|
+
if (import_fs34.default.existsSync(credsPath)) {
|
|
16641
17004
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
16642
17005
|
} else {
|
|
16643
17006
|
warn(
|
|
@@ -16646,10 +17009,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16646
17009
|
);
|
|
16647
17010
|
}
|
|
16648
17011
|
section("Agent Hooks");
|
|
16649
|
-
const claudeSettingsPath =
|
|
16650
|
-
if (
|
|
17012
|
+
const claudeSettingsPath = import_path35.default.join(homeDir2, ".claude", "settings.json");
|
|
17013
|
+
if (import_fs34.default.existsSync(claudeSettingsPath)) {
|
|
16651
17014
|
try {
|
|
16652
|
-
const cs = JSON.parse(
|
|
17015
|
+
const cs = JSON.parse(import_fs34.default.readFileSync(claudeSettingsPath, "utf-8"));
|
|
16653
17016
|
const hasHook = cs.hooks?.PreToolUse?.some(
|
|
16654
17017
|
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
16655
17018
|
);
|
|
@@ -16665,10 +17028,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16665
17028
|
} else {
|
|
16666
17029
|
warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
|
|
16667
17030
|
}
|
|
16668
|
-
const geminiSettingsPath =
|
|
16669
|
-
if (
|
|
17031
|
+
const geminiSettingsPath = import_path35.default.join(homeDir2, ".gemini", "settings.json");
|
|
17032
|
+
if (import_fs34.default.existsSync(geminiSettingsPath)) {
|
|
16670
17033
|
try {
|
|
16671
|
-
const gs = JSON.parse(
|
|
17034
|
+
const gs = JSON.parse(import_fs34.default.readFileSync(geminiSettingsPath, "utf-8"));
|
|
16672
17035
|
const hasHook = gs.hooks?.BeforeTool?.some(
|
|
16673
17036
|
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
16674
17037
|
);
|
|
@@ -16684,10 +17047,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16684
17047
|
} else {
|
|
16685
17048
|
warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
|
|
16686
17049
|
}
|
|
16687
|
-
const cursorHooksPath =
|
|
16688
|
-
if (
|
|
17050
|
+
const cursorHooksPath = import_path35.default.join(homeDir2, ".cursor", "hooks.json");
|
|
17051
|
+
if (import_fs34.default.existsSync(cursorHooksPath)) {
|
|
16689
17052
|
try {
|
|
16690
|
-
const cur = JSON.parse(
|
|
17053
|
+
const cur = JSON.parse(import_fs34.default.readFileSync(cursorHooksPath, "utf-8"));
|
|
16691
17054
|
const hasHook = cur.hooks?.preToolUse?.some(
|
|
16692
17055
|
(h) => h.command?.includes("node9") || h.command?.includes("cli.js")
|
|
16693
17056
|
);
|
|
@@ -16727,9 +17090,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16727
17090
|
|
|
16728
17091
|
// src/cli/commands/audit.ts
|
|
16729
17092
|
var import_chalk12 = __toESM(require("chalk"));
|
|
16730
|
-
var
|
|
16731
|
-
var
|
|
16732
|
-
var
|
|
17093
|
+
var import_fs35 = __toESM(require("fs"));
|
|
17094
|
+
var import_path36 = __toESM(require("path"));
|
|
17095
|
+
var import_os31 = __toESM(require("os"));
|
|
16733
17096
|
function formatRelativeTime(timestamp) {
|
|
16734
17097
|
const diff = Date.now() - new Date(timestamp).getTime();
|
|
16735
17098
|
const sec = Math.floor(diff / 1e3);
|
|
@@ -16742,14 +17105,14 @@ function formatRelativeTime(timestamp) {
|
|
|
16742
17105
|
}
|
|
16743
17106
|
function registerAuditCommand(program2) {
|
|
16744
17107
|
program2.command("audit").description("View local execution audit log").option("--tail <n>", "Number of entries to show", "20").option("--tool <pattern>", "Filter by tool name (substring match)").option("--deny", "Show only denied actions").option("--json", "Output raw JSON").action((options) => {
|
|
16745
|
-
const logPath =
|
|
16746
|
-
if (!
|
|
17108
|
+
const logPath = import_path36.default.join(import_os31.default.homedir(), ".node9", "audit.log");
|
|
17109
|
+
if (!import_fs35.default.existsSync(logPath)) {
|
|
16747
17110
|
console.log(
|
|
16748
17111
|
import_chalk12.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
16749
17112
|
);
|
|
16750
17113
|
return;
|
|
16751
17114
|
}
|
|
16752
|
-
const raw =
|
|
17115
|
+
const raw = import_fs35.default.readFileSync(logPath, "utf-8");
|
|
16753
17116
|
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
16754
17117
|
let entries = lines.flatMap((line) => {
|
|
16755
17118
|
try {
|
|
@@ -16805,9 +17168,9 @@ function registerAuditCommand(program2) {
|
|
|
16805
17168
|
var import_chalk13 = __toESM(require("chalk"));
|
|
16806
17169
|
|
|
16807
17170
|
// src/cli/aggregate/report-audit.ts
|
|
16808
|
-
var
|
|
16809
|
-
var
|
|
16810
|
-
var
|
|
17171
|
+
var import_fs36 = __toESM(require("fs"));
|
|
17172
|
+
var import_os32 = __toESM(require("os"));
|
|
17173
|
+
var import_path37 = __toESM(require("path"));
|
|
16811
17174
|
init_costSync();
|
|
16812
17175
|
init_litellm();
|
|
16813
17176
|
var TEST_COMMAND_RE3 = /(?:^|\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;
|
|
@@ -16889,8 +17252,8 @@ function getDateRange(period, now) {
|
|
|
16889
17252
|
}
|
|
16890
17253
|
}
|
|
16891
17254
|
function parseAuditLog(logPath) {
|
|
16892
|
-
if (!
|
|
16893
|
-
const raw =
|
|
17255
|
+
if (!import_fs36.default.existsSync(logPath)) return [];
|
|
17256
|
+
const raw = import_fs36.default.readFileSync(logPath, "utf-8");
|
|
16894
17257
|
return raw.split("\n").flatMap((line) => {
|
|
16895
17258
|
if (!line.trim()) return [];
|
|
16896
17259
|
try {
|
|
@@ -16950,25 +17313,25 @@ function freezeClaudeCost(acc) {
|
|
|
16950
17313
|
};
|
|
16951
17314
|
}
|
|
16952
17315
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
16953
|
-
const projPath =
|
|
17316
|
+
const projPath = import_path37.default.join(projectsDir, proj);
|
|
16954
17317
|
let files;
|
|
16955
17318
|
try {
|
|
16956
|
-
const stat =
|
|
17319
|
+
const stat = import_fs36.default.statSync(projPath);
|
|
16957
17320
|
if (!stat.isDirectory()) return;
|
|
16958
|
-
files =
|
|
17321
|
+
files = import_fs36.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
16959
17322
|
} catch {
|
|
16960
17323
|
return;
|
|
16961
17324
|
}
|
|
16962
17325
|
const startMs = start.getTime();
|
|
16963
17326
|
for (const file of files) {
|
|
16964
|
-
const filePath =
|
|
17327
|
+
const filePath = import_path37.default.join(projPath, file);
|
|
16965
17328
|
try {
|
|
16966
|
-
if (
|
|
17329
|
+
if (import_fs36.default.statSync(filePath).mtimeMs < startMs) continue;
|
|
16967
17330
|
} catch {
|
|
16968
17331
|
continue;
|
|
16969
17332
|
}
|
|
16970
17333
|
try {
|
|
16971
|
-
const raw =
|
|
17334
|
+
const raw = import_fs36.default.readFileSync(filePath, "utf-8");
|
|
16972
17335
|
for (const line of raw.split("\n")) {
|
|
16973
17336
|
if (!line.trim()) continue;
|
|
16974
17337
|
let entry;
|
|
@@ -17018,10 +17381,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
17018
17381
|
}
|
|
17019
17382
|
function loadClaudeCost(start, end, projectsDir) {
|
|
17020
17383
|
const acc = emptyClaudeCostAccumulator();
|
|
17021
|
-
if (!
|
|
17384
|
+
if (!import_fs36.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
|
|
17022
17385
|
let dirs;
|
|
17023
17386
|
try {
|
|
17024
|
-
dirs =
|
|
17387
|
+
dirs = import_fs36.default.readdirSync(projectsDir);
|
|
17025
17388
|
} catch {
|
|
17026
17389
|
return freezeClaudeCost(acc);
|
|
17027
17390
|
}
|
|
@@ -17033,7 +17396,7 @@ function loadClaudeCost(start, end, projectsDir) {
|
|
|
17033
17396
|
function processCodexCostFile(filePath, start, end, acc) {
|
|
17034
17397
|
let lines;
|
|
17035
17398
|
try {
|
|
17036
|
-
lines =
|
|
17399
|
+
lines = import_fs36.default.readFileSync(filePath, "utf-8").split("\n");
|
|
17037
17400
|
} catch {
|
|
17038
17401
|
return;
|
|
17039
17402
|
}
|
|
@@ -17078,31 +17441,31 @@ function processCodexCostFile(filePath, start, end, acc) {
|
|
|
17078
17441
|
}
|
|
17079
17442
|
function listCodexSessionFiles(sessionsBase) {
|
|
17080
17443
|
const jsonlFiles = [];
|
|
17081
|
-
if (!
|
|
17444
|
+
if (!import_fs36.default.existsSync(sessionsBase)) return jsonlFiles;
|
|
17082
17445
|
try {
|
|
17083
|
-
for (const year of
|
|
17084
|
-
const yearPath =
|
|
17446
|
+
for (const year of import_fs36.default.readdirSync(sessionsBase)) {
|
|
17447
|
+
const yearPath = import_path37.default.join(sessionsBase, year);
|
|
17085
17448
|
try {
|
|
17086
|
-
if (!
|
|
17449
|
+
if (!import_fs36.default.statSync(yearPath).isDirectory()) continue;
|
|
17087
17450
|
} catch {
|
|
17088
17451
|
continue;
|
|
17089
17452
|
}
|
|
17090
|
-
for (const month of
|
|
17091
|
-
const monthPath =
|
|
17453
|
+
for (const month of import_fs36.default.readdirSync(yearPath)) {
|
|
17454
|
+
const monthPath = import_path37.default.join(yearPath, month);
|
|
17092
17455
|
try {
|
|
17093
|
-
if (!
|
|
17456
|
+
if (!import_fs36.default.statSync(monthPath).isDirectory()) continue;
|
|
17094
17457
|
} catch {
|
|
17095
17458
|
continue;
|
|
17096
17459
|
}
|
|
17097
|
-
for (const day of
|
|
17098
|
-
const dayPath =
|
|
17460
|
+
for (const day of import_fs36.default.readdirSync(monthPath)) {
|
|
17461
|
+
const dayPath = import_path37.default.join(monthPath, day);
|
|
17099
17462
|
try {
|
|
17100
|
-
if (!
|
|
17463
|
+
if (!import_fs36.default.statSync(dayPath).isDirectory()) continue;
|
|
17101
17464
|
} catch {
|
|
17102
17465
|
continue;
|
|
17103
17466
|
}
|
|
17104
|
-
for (const file of
|
|
17105
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
17467
|
+
for (const file of import_fs36.default.readdirSync(dayPath)) {
|
|
17468
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path37.default.join(dayPath, file));
|
|
17106
17469
|
}
|
|
17107
17470
|
}
|
|
17108
17471
|
}
|
|
@@ -17155,13 +17518,13 @@ function freezeGeminiCost(acc) {
|
|
|
17155
17518
|
function processGeminiCostFile(filePath, projectKey, start, end, acc) {
|
|
17156
17519
|
const startMs = start.getTime();
|
|
17157
17520
|
try {
|
|
17158
|
-
if (
|
|
17521
|
+
if (import_fs36.default.statSync(filePath).mtimeMs < startMs) return;
|
|
17159
17522
|
} catch {
|
|
17160
17523
|
return;
|
|
17161
17524
|
}
|
|
17162
17525
|
let raw;
|
|
17163
17526
|
try {
|
|
17164
|
-
raw =
|
|
17527
|
+
raw = import_fs36.default.readFileSync(filePath, "utf-8");
|
|
17165
17528
|
} catch {
|
|
17166
17529
|
return;
|
|
17167
17530
|
}
|
|
@@ -17210,30 +17573,30 @@ function listGeminiSessionFiles(geminiTmpDir) {
|
|
|
17210
17573
|
const out = [];
|
|
17211
17574
|
let dirs;
|
|
17212
17575
|
try {
|
|
17213
|
-
if (!
|
|
17214
|
-
dirs =
|
|
17576
|
+
if (!import_fs36.default.statSync(geminiTmpDir).isDirectory()) return out;
|
|
17577
|
+
dirs = import_fs36.default.readdirSync(geminiTmpDir);
|
|
17215
17578
|
} catch {
|
|
17216
17579
|
return out;
|
|
17217
17580
|
}
|
|
17218
17581
|
for (const proj of dirs) {
|
|
17219
|
-
const chatsDir =
|
|
17582
|
+
const chatsDir = import_path37.default.join(geminiTmpDir, proj, "chats");
|
|
17220
17583
|
let files;
|
|
17221
17584
|
try {
|
|
17222
|
-
if (!
|
|
17223
|
-
files =
|
|
17585
|
+
if (!import_fs36.default.statSync(chatsDir).isDirectory()) continue;
|
|
17586
|
+
files = import_fs36.default.readdirSync(chatsDir);
|
|
17224
17587
|
} catch {
|
|
17225
17588
|
continue;
|
|
17226
17589
|
}
|
|
17227
17590
|
for (const f of files) {
|
|
17228
17591
|
if (!f.endsWith(".jsonl")) continue;
|
|
17229
|
-
out.push({ projectKey: proj, file:
|
|
17592
|
+
out.push({ projectKey: proj, file: import_path37.default.join(chatsDir, f) });
|
|
17230
17593
|
}
|
|
17231
17594
|
}
|
|
17232
17595
|
return out;
|
|
17233
17596
|
}
|
|
17234
17597
|
function loadGeminiCost(start, end, geminiTmpDir) {
|
|
17235
17598
|
const acc = emptyGeminiAccumulator();
|
|
17236
|
-
if (!
|
|
17599
|
+
if (!import_fs36.default.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
|
|
17237
17600
|
for (const { projectKey, file } of listGeminiSessionFiles(geminiTmpDir)) {
|
|
17238
17601
|
processGeminiCostFile(file, projectKey, start, end, acc);
|
|
17239
17602
|
}
|
|
@@ -17241,11 +17604,11 @@ function loadGeminiCost(start, end, geminiTmpDir) {
|
|
|
17241
17604
|
}
|
|
17242
17605
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
17243
17606
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
17244
|
-
const auditLogPath = opts.auditLogPath ??
|
|
17245
|
-
const claudeProjectsDir = opts.claudeProjectsDir ??
|
|
17246
|
-
const codexSessionsDir = opts.codexSessionsDir ??
|
|
17247
|
-
const geminiTmpDir = opts.geminiTmpDir ??
|
|
17248
|
-
const hasAuditFile =
|
|
17607
|
+
const auditLogPath = opts.auditLogPath ?? import_path37.default.join(import_os32.default.homedir(), ".node9", "audit.log");
|
|
17608
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? import_path37.default.join(import_os32.default.homedir(), ".claude", "projects");
|
|
17609
|
+
const codexSessionsDir = opts.codexSessionsDir ?? import_path37.default.join(import_os32.default.homedir(), ".codex", "sessions");
|
|
17610
|
+
const geminiTmpDir = opts.geminiTmpDir ?? import_path37.default.join(import_os32.default.homedir(), ".gemini", "tmp");
|
|
17611
|
+
const hasAuditFile = import_fs36.default.existsSync(auditLogPath);
|
|
17249
17612
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
|
|
17250
17613
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
17251
17614
|
const { start, end } = getDateRange(period, now);
|
|
@@ -17941,14 +18304,14 @@ function registerDaemonCommand(program2) {
|
|
|
17941
18304
|
|
|
17942
18305
|
// src/cli/commands/status.ts
|
|
17943
18306
|
var import_chalk15 = __toESM(require("chalk"));
|
|
17944
|
-
var
|
|
17945
|
-
var
|
|
17946
|
-
var
|
|
18307
|
+
var import_fs37 = __toESM(require("fs"));
|
|
18308
|
+
var import_path38 = __toESM(require("path"));
|
|
18309
|
+
var import_os33 = __toESM(require("os"));
|
|
17947
18310
|
init_core();
|
|
17948
18311
|
init_daemon();
|
|
17949
18312
|
function readJson2(filePath) {
|
|
17950
18313
|
try {
|
|
17951
|
-
if (
|
|
18314
|
+
if (import_fs37.default.existsSync(filePath)) return JSON.parse(import_fs37.default.readFileSync(filePath, "utf-8"));
|
|
17952
18315
|
} catch {
|
|
17953
18316
|
}
|
|
17954
18317
|
return null;
|
|
@@ -18013,28 +18376,28 @@ function registerStatusCommand(program2) {
|
|
|
18013
18376
|
console.log("");
|
|
18014
18377
|
const modeLabel = settings.mode === "audit" ? import_chalk15.default.blue("audit") : settings.mode === "strict" ? import_chalk15.default.red("strict") : import_chalk15.default.white("standard");
|
|
18015
18378
|
console.log(` Mode: ${modeLabel}`);
|
|
18016
|
-
const projectConfig =
|
|
18017
|
-
const globalConfig =
|
|
18379
|
+
const projectConfig = import_path38.default.join(process.cwd(), "node9.config.json");
|
|
18380
|
+
const globalConfig = import_path38.default.join(import_os33.default.homedir(), ".node9", "config.json");
|
|
18018
18381
|
console.log(
|
|
18019
|
-
` Local: ${
|
|
18382
|
+
` Local: ${import_fs37.default.existsSync(projectConfig) ? import_chalk15.default.green("Active (node9.config.json)") : import_chalk15.default.gray("Not present")}`
|
|
18020
18383
|
);
|
|
18021
18384
|
console.log(
|
|
18022
|
-
` Global: ${
|
|
18385
|
+
` Global: ${import_fs37.default.existsSync(globalConfig) ? import_chalk15.default.green("Active (~/.node9/config.json)") : import_chalk15.default.gray("Not present")}`
|
|
18023
18386
|
);
|
|
18024
18387
|
if (mergedConfig.policy.sandboxPaths.length > 0) {
|
|
18025
18388
|
console.log(
|
|
18026
18389
|
` Sandbox: ${import_chalk15.default.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
|
|
18027
18390
|
);
|
|
18028
18391
|
}
|
|
18029
|
-
const homeDir2 =
|
|
18392
|
+
const homeDir2 = import_os33.default.homedir();
|
|
18030
18393
|
const claudeSettings = readJson2(
|
|
18031
|
-
|
|
18394
|
+
import_path38.default.join(homeDir2, ".claude", "settings.json")
|
|
18032
18395
|
);
|
|
18033
|
-
const claudeConfig = readJson2(
|
|
18396
|
+
const claudeConfig = readJson2(import_path38.default.join(homeDir2, ".claude.json"));
|
|
18034
18397
|
const geminiSettings = readJson2(
|
|
18035
|
-
|
|
18398
|
+
import_path38.default.join(homeDir2, ".gemini", "settings.json")
|
|
18036
18399
|
);
|
|
18037
|
-
const cursorConfig = readJson2(
|
|
18400
|
+
const cursorConfig = readJson2(import_path38.default.join(homeDir2, ".cursor", "mcp.json"));
|
|
18038
18401
|
const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig;
|
|
18039
18402
|
if (agentFound) {
|
|
18040
18403
|
console.log("");
|
|
@@ -18093,9 +18456,9 @@ function registerStatusCommand(program2) {
|
|
|
18093
18456
|
|
|
18094
18457
|
// src/cli/commands/init.ts
|
|
18095
18458
|
var import_chalk16 = __toESM(require("chalk"));
|
|
18096
|
-
var
|
|
18097
|
-
var
|
|
18098
|
-
var
|
|
18459
|
+
var import_fs38 = __toESM(require("fs"));
|
|
18460
|
+
var import_path39 = __toESM(require("path"));
|
|
18461
|
+
var import_os34 = __toESM(require("os"));
|
|
18099
18462
|
var import_https4 = __toESM(require("https"));
|
|
18100
18463
|
init_core();
|
|
18101
18464
|
init_setup();
|
|
@@ -18175,15 +18538,15 @@ function registerInitCommand(program2) {
|
|
|
18175
18538
|
}
|
|
18176
18539
|
console.log("");
|
|
18177
18540
|
}
|
|
18178
|
-
const configPath =
|
|
18179
|
-
if (
|
|
18541
|
+
const configPath = import_path39.default.join(import_os34.default.homedir(), ".node9", "config.json");
|
|
18542
|
+
if (import_fs38.default.existsSync(configPath) && !options.force) {
|
|
18180
18543
|
try {
|
|
18181
|
-
const existing = JSON.parse(
|
|
18544
|
+
const existing = JSON.parse(import_fs38.default.readFileSync(configPath, "utf-8"));
|
|
18182
18545
|
const settings = existing.settings ?? {};
|
|
18183
18546
|
if (settings.mode !== chosenMode) {
|
|
18184
18547
|
settings.mode = chosenMode;
|
|
18185
18548
|
existing.settings = settings;
|
|
18186
|
-
|
|
18549
|
+
import_fs38.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
|
|
18187
18550
|
console.log(import_chalk16.default.green(`\u2705 Mode updated: ${chosenMode}`));
|
|
18188
18551
|
} else {
|
|
18189
18552
|
console.log(import_chalk16.default.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
|
|
@@ -18196,9 +18559,9 @@ function registerInitCommand(program2) {
|
|
|
18196
18559
|
...DEFAULT_CONFIG,
|
|
18197
18560
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
18198
18561
|
};
|
|
18199
|
-
const dir =
|
|
18200
|
-
if (!
|
|
18201
|
-
|
|
18562
|
+
const dir = import_path39.default.dirname(configPath);
|
|
18563
|
+
if (!import_fs38.default.existsSync(dir)) import_fs38.default.mkdirSync(dir, { recursive: true });
|
|
18564
|
+
import_fs38.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
|
|
18202
18565
|
console.log(import_chalk16.default.green(`\u2705 Config created: ${configPath}`));
|
|
18203
18566
|
console.log(import_chalk16.default.gray(` Mode: ${chosenMode}`));
|
|
18204
18567
|
}
|
|
@@ -18296,7 +18659,7 @@ function registerInitCommand(program2) {
|
|
|
18296
18659
|
}
|
|
18297
18660
|
|
|
18298
18661
|
// src/cli/commands/undo.ts
|
|
18299
|
-
var
|
|
18662
|
+
var import_path40 = __toESM(require("path"));
|
|
18300
18663
|
var import_chalk18 = __toESM(require("chalk"));
|
|
18301
18664
|
|
|
18302
18665
|
// src/tui/undo-navigator.ts
|
|
@@ -18455,7 +18818,7 @@ function findMatchingCwd(startDir, history) {
|
|
|
18455
18818
|
let dir = startDir;
|
|
18456
18819
|
while (true) {
|
|
18457
18820
|
if (cwds.has(dir)) return dir;
|
|
18458
|
-
const parent =
|
|
18821
|
+
const parent = import_path40.default.dirname(dir);
|
|
18459
18822
|
if (parent === dir) return null;
|
|
18460
18823
|
dir = parent;
|
|
18461
18824
|
}
|
|
@@ -18588,90 +18951,7 @@ var import_child_process10 = require("child_process");
|
|
|
18588
18951
|
var import_execa3 = require("execa");
|
|
18589
18952
|
init_orchestrator();
|
|
18590
18953
|
init_provenance();
|
|
18591
|
-
|
|
18592
|
-
// src/mcp-pin.ts
|
|
18593
|
-
var import_fs38 = __toESM(require("fs"));
|
|
18594
|
-
var import_path40 = __toESM(require("path"));
|
|
18595
|
-
var import_os34 = __toESM(require("os"));
|
|
18596
|
-
var import_crypto10 = __toESM(require("crypto"));
|
|
18597
|
-
function getPinsFilePath2() {
|
|
18598
|
-
return import_path40.default.join(import_os34.default.homedir(), ".node9", "mcp-pins.json");
|
|
18599
|
-
}
|
|
18600
|
-
function hashToolDefinitions(tools) {
|
|
18601
|
-
const sorted = [...tools].sort((a, b) => {
|
|
18602
|
-
const nameA = a.name ?? "";
|
|
18603
|
-
const nameB = b.name ?? "";
|
|
18604
|
-
return nameA.localeCompare(nameB);
|
|
18605
|
-
});
|
|
18606
|
-
const canonical = JSON.stringify(sorted);
|
|
18607
|
-
return import_crypto10.default.createHash("sha256").update(canonical).digest("hex");
|
|
18608
|
-
}
|
|
18609
|
-
function getServerKey(upstreamCommand) {
|
|
18610
|
-
return import_crypto10.default.createHash("sha256").update(upstreamCommand).digest("hex").slice(0, 16);
|
|
18611
|
-
}
|
|
18612
|
-
function readMcpPinsSafe() {
|
|
18613
|
-
const filePath = getPinsFilePath2();
|
|
18614
|
-
try {
|
|
18615
|
-
const raw = import_fs38.default.readFileSync(filePath, "utf-8");
|
|
18616
|
-
if (!raw.trim()) {
|
|
18617
|
-
return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
18618
|
-
}
|
|
18619
|
-
const parsed = JSON.parse(raw);
|
|
18620
|
-
if (!parsed.servers || typeof parsed.servers !== "object" || Array.isArray(parsed.servers)) {
|
|
18621
|
-
return { ok: false, reason: "corrupt", detail: "invalid structure: missing servers object" };
|
|
18622
|
-
}
|
|
18623
|
-
return { ok: true, pins: { servers: parsed.servers } };
|
|
18624
|
-
} catch (err2) {
|
|
18625
|
-
if (err2.code === "ENOENT") {
|
|
18626
|
-
return { ok: false, reason: "missing" };
|
|
18627
|
-
}
|
|
18628
|
-
return { ok: false, reason: "corrupt", detail: String(err2) };
|
|
18629
|
-
}
|
|
18630
|
-
}
|
|
18631
|
-
function readMcpPins() {
|
|
18632
|
-
const result = readMcpPinsSafe();
|
|
18633
|
-
if (result.ok) return result.pins;
|
|
18634
|
-
if (result.reason === "missing") return { servers: {} };
|
|
18635
|
-
throw new Error(`[node9] MCP pin file is corrupt: ${result.detail}`);
|
|
18636
|
-
}
|
|
18637
|
-
function writeMcpPins(data) {
|
|
18638
|
-
const filePath = getPinsFilePath2();
|
|
18639
|
-
import_fs38.default.mkdirSync(import_path40.default.dirname(filePath), { recursive: true });
|
|
18640
|
-
const tmp = `${filePath}.${import_crypto10.default.randomBytes(6).toString("hex")}.tmp`;
|
|
18641
|
-
import_fs38.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
18642
|
-
import_fs38.default.renameSync(tmp, filePath);
|
|
18643
|
-
}
|
|
18644
|
-
function checkPin(serverKey, currentHash) {
|
|
18645
|
-
const result = readMcpPinsSafe();
|
|
18646
|
-
if (!result.ok) {
|
|
18647
|
-
if (result.reason === "missing") return "new";
|
|
18648
|
-
return "corrupt";
|
|
18649
|
-
}
|
|
18650
|
-
const entry = result.pins.servers[serverKey];
|
|
18651
|
-
if (!entry) return "new";
|
|
18652
|
-
return entry.toolsHash === currentHash ? "match" : "mismatch";
|
|
18653
|
-
}
|
|
18654
|
-
function updatePin(serverKey, label, toolsHash, toolNames) {
|
|
18655
|
-
const pins = readMcpPins();
|
|
18656
|
-
pins.servers[serverKey] = {
|
|
18657
|
-
label,
|
|
18658
|
-
toolsHash,
|
|
18659
|
-
toolNames,
|
|
18660
|
-
toolCount: toolNames.length,
|
|
18661
|
-
pinnedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
18662
|
-
};
|
|
18663
|
-
writeMcpPins(pins);
|
|
18664
|
-
}
|
|
18665
|
-
function removePin2(serverKey) {
|
|
18666
|
-
const pins = readMcpPins();
|
|
18667
|
-
delete pins.servers[serverKey];
|
|
18668
|
-
writeMcpPins(pins);
|
|
18669
|
-
}
|
|
18670
|
-
function clearAllPins2() {
|
|
18671
|
-
writeMcpPins({ servers: {} });
|
|
18672
|
-
}
|
|
18673
|
-
|
|
18674
|
-
// src/mcp-gateway/index.ts
|
|
18954
|
+
init_mcp_pin();
|
|
18675
18955
|
init_mcp_tools();
|
|
18676
18956
|
init_daemon();
|
|
18677
18957
|
function sanitize4(value) {
|
|
@@ -18733,6 +19013,7 @@ function tokenize4(cmd) {
|
|
|
18733
19013
|
return tokens;
|
|
18734
19014
|
}
|
|
18735
19015
|
async function runMcpGateway(upstreamCommand) {
|
|
19016
|
+
const gatewayCwd = process.cwd();
|
|
18736
19017
|
const commandParts = tokenize4(upstreamCommand);
|
|
18737
19018
|
const cmd = commandParts[0];
|
|
18738
19019
|
const cmdArgs = commandParts.slice(1);
|
|
@@ -18955,7 +19236,7 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
18955
19236
|
if (parsed.result && Array.isArray(parsed.result.tools)) {
|
|
18956
19237
|
const tools = parsed.result.tools || [];
|
|
18957
19238
|
const currentHash = hashToolDefinitions(tools);
|
|
18958
|
-
const pinStatus = checkPin(serverKey, currentHash);
|
|
19239
|
+
const pinStatus = checkPin(serverKey, currentHash, gatewayCwd);
|
|
18959
19240
|
const token = getInternalToken();
|
|
18960
19241
|
if (isDaemonRunning() && process.env.NODE9_TESTING !== "1") {
|
|
18961
19242
|
const toolSummary = tools.map((t) => ({ name: t.name, description: t.description }));
|
|
@@ -19840,26 +20121,45 @@ function registerTrustCommand(program2) {
|
|
|
19840
20121
|
|
|
19841
20122
|
// src/cli/commands/mcp-pin.ts
|
|
19842
20123
|
var import_chalk21 = __toESM(require("chalk"));
|
|
20124
|
+
init_mcp_pin();
|
|
20125
|
+
var import_fs40 = __toESM(require("fs"));
|
|
19843
20126
|
function registerMcpPinCommand(program2) {
|
|
19844
20127
|
const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
|
|
19845
20128
|
const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
|
|
19846
20129
|
pinSubCmd.command("list").description("Show all pinned MCP servers and their tool definition hashes").action(() => {
|
|
19847
|
-
const
|
|
19848
|
-
|
|
19849
|
-
|
|
19850
|
-
|
|
19851
|
-
|
|
19852
|
-
|
|
19853
|
-
);
|
|
19854
|
-
|
|
20130
|
+
const found = findPinsFilePath(process.cwd());
|
|
20131
|
+
const homeResult = readMcpPinsSafe();
|
|
20132
|
+
let repoEntries = {};
|
|
20133
|
+
let repoCorrupt = false;
|
|
20134
|
+
if (found.source === "repo") {
|
|
20135
|
+
try {
|
|
20136
|
+
const raw = import_fs40.default.readFileSync(found.path, "utf-8");
|
|
20137
|
+
const parsed = JSON.parse(raw);
|
|
20138
|
+
repoEntries = parsed.servers ?? {};
|
|
20139
|
+
} catch {
|
|
20140
|
+
repoCorrupt = true;
|
|
19855
20141
|
}
|
|
20142
|
+
}
|
|
20143
|
+
if (repoCorrupt) {
|
|
19856
20144
|
console.error(import_chalk21.default.red(`
|
|
19857
|
-
\u274C
|
|
20145
|
+
\u274C Repo pin file at ${found.path} is corrupt or unreadable.`));
|
|
20146
|
+
process.exit(1);
|
|
20147
|
+
}
|
|
20148
|
+
if (!homeResult.ok && homeResult.reason === "corrupt") {
|
|
20149
|
+
console.error(import_chalk21.default.red(`
|
|
20150
|
+
\u274C Home pin file is corrupt: ${homeResult.detail}`));
|
|
19858
20151
|
console.error(import_chalk21.default.yellow(" Run: node9 mcp pin reset\n"));
|
|
19859
20152
|
process.exit(1);
|
|
19860
20153
|
}
|
|
19861
|
-
const
|
|
19862
|
-
|
|
20154
|
+
const homeEntries = homeResult.ok ? homeResult.pins.servers : {};
|
|
20155
|
+
const merged = /* @__PURE__ */ new Map();
|
|
20156
|
+
for (const [key, entry] of Object.entries(homeEntries)) {
|
|
20157
|
+
merged.set(key, { entry, source: "home" });
|
|
20158
|
+
}
|
|
20159
|
+
for (const [key, entry] of Object.entries(repoEntries)) {
|
|
20160
|
+
merged.set(key, { entry, source: "repo" });
|
|
20161
|
+
}
|
|
20162
|
+
if (merged.size === 0) {
|
|
19863
20163
|
console.log(import_chalk21.default.gray("\nNo MCP servers are pinned yet."));
|
|
19864
20164
|
console.log(
|
|
19865
20165
|
import_chalk21.default.gray("Pins are created automatically when the MCP gateway first connects.\n")
|
|
@@ -19867,13 +20167,47 @@ function registerMcpPinCommand(program2) {
|
|
|
19867
20167
|
return;
|
|
19868
20168
|
}
|
|
19869
20169
|
console.log(import_chalk21.default.bold("\n\u{1F512} Pinned MCP Servers\n"));
|
|
19870
|
-
|
|
19871
|
-
|
|
20170
|
+
const showSource = found.source === "repo";
|
|
20171
|
+
for (const [key, { entry, source }] of merged) {
|
|
20172
|
+
const tag = showSource ? ` ${import_chalk21.default.yellow(`[${source}]`)}` : "";
|
|
20173
|
+
console.log(` ${import_chalk21.default.cyan(key)}${tag} ${import_chalk21.default.gray(entry.label)}`);
|
|
19872
20174
|
console.log(` Tools (${entry.toolCount}): ${import_chalk21.default.white(entry.toolNames.join(", "))}`);
|
|
19873
20175
|
console.log(` Hash: ${import_chalk21.default.gray(entry.toolsHash.slice(0, 16))}...`);
|
|
19874
20176
|
console.log(` Pinned: ${import_chalk21.default.gray(entry.pinnedAt)}`);
|
|
19875
20177
|
console.log("");
|
|
19876
20178
|
}
|
|
20179
|
+
if (showSource) {
|
|
20180
|
+
console.log(import_chalk21.default.gray(` [repo] entries come from ${found.path}`));
|
|
20181
|
+
console.log(import_chalk21.default.gray(" [home] entries come from ~/.node9/mcp-pins.json\n"));
|
|
20182
|
+
}
|
|
20183
|
+
});
|
|
20184
|
+
pinSubCmd.command("promote <serverKey>").description(
|
|
20185
|
+
"Copy a pin from ~/.node9/mcp-pins.json into <repo>/.node9/mcp-pins.json so teammates share the same vetted baseline"
|
|
20186
|
+
).action((serverKey) => {
|
|
20187
|
+
try {
|
|
20188
|
+
const { repoPath, created } = promotePin(serverKey, process.cwd());
|
|
20189
|
+
if (created) {
|
|
20190
|
+
console.log(
|
|
20191
|
+
import_chalk21.default.green(
|
|
20192
|
+
`
|
|
20193
|
+
\u2705 Created ${repoPath} with the promoted pin for ${import_chalk21.default.cyan(serverKey)}.`
|
|
20194
|
+
)
|
|
20195
|
+
);
|
|
20196
|
+
} else {
|
|
20197
|
+
console.log(import_chalk21.default.green(`
|
|
20198
|
+
\u2705 Promoted ${import_chalk21.default.cyan(serverKey)} into ${repoPath}.`));
|
|
20199
|
+
}
|
|
20200
|
+
console.log(import_chalk21.default.gray(" Review the change and commit it:"));
|
|
20201
|
+
console.log(import_chalk21.default.cyan(` git add ${repoPath}`));
|
|
20202
|
+
console.log(import_chalk21.default.cyan(` git commit -m "pin ${serverKey} (node9)"`));
|
|
20203
|
+
console.log("");
|
|
20204
|
+
} catch (err2) {
|
|
20205
|
+
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
20206
|
+
console.error(import_chalk21.default.red(`
|
|
20207
|
+
\u274C ${msg}
|
|
20208
|
+
`));
|
|
20209
|
+
process.exit(1);
|
|
20210
|
+
}
|
|
19877
20211
|
});
|
|
19878
20212
|
pinSubCmd.command("update <serverKey>").description(
|
|
19879
20213
|
"Remove a pin so the next gateway connection re-pins with current tool definitions"
|
|
@@ -19895,7 +20229,7 @@ function registerMcpPinCommand(program2) {
|
|
|
19895
20229
|
process.exit(1);
|
|
19896
20230
|
}
|
|
19897
20231
|
const label = pins.servers[serverKey].label;
|
|
19898
|
-
|
|
20232
|
+
removePin(serverKey);
|
|
19899
20233
|
console.log(import_chalk21.default.green(`
|
|
19900
20234
|
\u{1F513} Pin removed for ${import_chalk21.default.cyan(serverKey)}`));
|
|
19901
20235
|
console.log(import_chalk21.default.gray(` Server: ${label}`));
|
|
@@ -19908,7 +20242,7 @@ function registerMcpPinCommand(program2) {
|
|
|
19908
20242
|
return;
|
|
19909
20243
|
}
|
|
19910
20244
|
const count = result.ok ? Object.keys(result.pins.servers).length : "?";
|
|
19911
|
-
|
|
20245
|
+
clearAllPins();
|
|
19912
20246
|
console.log(import_chalk21.default.green(`
|
|
19913
20247
|
\u{1F513} Cleared ${count} MCP pin(s).`));
|
|
19914
20248
|
console.log(import_chalk21.default.gray(" Next connection to each server will re-pin.\n"));
|
|
@@ -20091,7 +20425,7 @@ init_scan();
|
|
|
20091
20425
|
|
|
20092
20426
|
// src/cli/commands/sessions.ts
|
|
20093
20427
|
var import_chalk24 = __toESM(require("chalk"));
|
|
20094
|
-
var
|
|
20428
|
+
var import_fs41 = __toESM(require("fs"));
|
|
20095
20429
|
var import_path42 = __toESM(require("path"));
|
|
20096
20430
|
var import_os36 = __toESM(require("os"));
|
|
20097
20431
|
var CLAUDE_PRICING3 = {
|
|
@@ -20209,7 +20543,7 @@ function loadAuditEntries(auditPath) {
|
|
|
20209
20543
|
const aPath = auditPath ?? import_path42.default.join(import_os36.default.homedir(), ".node9", "audit.log");
|
|
20210
20544
|
let raw;
|
|
20211
20545
|
try {
|
|
20212
|
-
raw =
|
|
20546
|
+
raw = import_fs41.default.readFileSync(aPath, "utf-8");
|
|
20213
20547
|
} catch {
|
|
20214
20548
|
return [];
|
|
20215
20549
|
}
|
|
@@ -20246,7 +20580,7 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
20246
20580
|
}
|
|
20247
20581
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
20248
20582
|
const tmpDir = import_path42.default.join(import_os36.default.homedir(), ".gemini", "tmp");
|
|
20249
|
-
if (!
|
|
20583
|
+
if (!import_fs41.default.existsSync(tmpDir)) return [];
|
|
20250
20584
|
const cutoff = days !== null ? (() => {
|
|
20251
20585
|
const d = /* @__PURE__ */ new Date();
|
|
20252
20586
|
d.setDate(d.getDate() - days);
|
|
@@ -20255,7 +20589,7 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
20255
20589
|
})() : null;
|
|
20256
20590
|
let slugDirs;
|
|
20257
20591
|
try {
|
|
20258
|
-
slugDirs =
|
|
20592
|
+
slugDirs = import_fs41.default.readdirSync(tmpDir);
|
|
20259
20593
|
} catch {
|
|
20260
20594
|
return [];
|
|
20261
20595
|
}
|
|
@@ -20263,27 +20597,27 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
20263
20597
|
for (const slug of slugDirs) {
|
|
20264
20598
|
const slugPath = import_path42.default.join(tmpDir, slug);
|
|
20265
20599
|
try {
|
|
20266
|
-
if (!
|
|
20600
|
+
if (!import_fs41.default.statSync(slugPath).isDirectory()) continue;
|
|
20267
20601
|
} catch {
|
|
20268
20602
|
continue;
|
|
20269
20603
|
}
|
|
20270
20604
|
let projectRoot = import_path42.default.join(import_os36.default.homedir(), slug);
|
|
20271
20605
|
try {
|
|
20272
|
-
projectRoot =
|
|
20606
|
+
projectRoot = import_fs41.default.readFileSync(import_path42.default.join(slugPath, ".project_root"), "utf-8").trim();
|
|
20273
20607
|
} catch {
|
|
20274
20608
|
}
|
|
20275
20609
|
const chatsDir = import_path42.default.join(slugPath, "chats");
|
|
20276
|
-
if (!
|
|
20610
|
+
if (!import_fs41.default.existsSync(chatsDir)) continue;
|
|
20277
20611
|
let chatFiles;
|
|
20278
20612
|
try {
|
|
20279
|
-
chatFiles =
|
|
20613
|
+
chatFiles = import_fs41.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
20280
20614
|
} catch {
|
|
20281
20615
|
continue;
|
|
20282
20616
|
}
|
|
20283
20617
|
for (const chatFile of chatFiles) {
|
|
20284
20618
|
let raw;
|
|
20285
20619
|
try {
|
|
20286
|
-
raw =
|
|
20620
|
+
raw = import_fs41.default.readFileSync(import_path42.default.join(chatsDir, chatFile), "utf-8");
|
|
20287
20621
|
} catch {
|
|
20288
20622
|
continue;
|
|
20289
20623
|
}
|
|
@@ -20364,7 +20698,7 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
20364
20698
|
}
|
|
20365
20699
|
function buildCodexSessions(days, allAuditEntries) {
|
|
20366
20700
|
const sessionsBase = import_path42.default.join(import_os36.default.homedir(), ".codex", "sessions");
|
|
20367
|
-
if (!
|
|
20701
|
+
if (!import_fs41.default.existsSync(sessionsBase)) return [];
|
|
20368
20702
|
const cutoff = days !== null ? (() => {
|
|
20369
20703
|
const d = /* @__PURE__ */ new Date();
|
|
20370
20704
|
d.setDate(d.getDate() - days);
|
|
@@ -20373,28 +20707,28 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
20373
20707
|
})() : null;
|
|
20374
20708
|
const jsonlFiles = [];
|
|
20375
20709
|
try {
|
|
20376
|
-
for (const year of
|
|
20710
|
+
for (const year of import_fs41.default.readdirSync(sessionsBase)) {
|
|
20377
20711
|
const yearPath = import_path42.default.join(sessionsBase, year);
|
|
20378
20712
|
try {
|
|
20379
|
-
if (!
|
|
20713
|
+
if (!import_fs41.default.statSync(yearPath).isDirectory()) continue;
|
|
20380
20714
|
} catch {
|
|
20381
20715
|
continue;
|
|
20382
20716
|
}
|
|
20383
|
-
for (const month of
|
|
20717
|
+
for (const month of import_fs41.default.readdirSync(yearPath)) {
|
|
20384
20718
|
const monthPath = import_path42.default.join(yearPath, month);
|
|
20385
20719
|
try {
|
|
20386
|
-
if (!
|
|
20720
|
+
if (!import_fs41.default.statSync(monthPath).isDirectory()) continue;
|
|
20387
20721
|
} catch {
|
|
20388
20722
|
continue;
|
|
20389
20723
|
}
|
|
20390
|
-
for (const day of
|
|
20724
|
+
for (const day of import_fs41.default.readdirSync(monthPath)) {
|
|
20391
20725
|
const dayPath = import_path42.default.join(monthPath, day);
|
|
20392
20726
|
try {
|
|
20393
|
-
if (!
|
|
20727
|
+
if (!import_fs41.default.statSync(dayPath).isDirectory()) continue;
|
|
20394
20728
|
} catch {
|
|
20395
20729
|
continue;
|
|
20396
20730
|
}
|
|
20397
|
-
for (const file of
|
|
20731
|
+
for (const file of import_fs41.default.readdirSync(dayPath)) {
|
|
20398
20732
|
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path42.default.join(dayPath, file));
|
|
20399
20733
|
}
|
|
20400
20734
|
}
|
|
@@ -20407,7 +20741,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
20407
20741
|
for (const filePath of jsonlFiles) {
|
|
20408
20742
|
let lines;
|
|
20409
20743
|
try {
|
|
20410
|
-
lines =
|
|
20744
|
+
lines = import_fs41.default.readFileSync(filePath, "utf-8").split("\n");
|
|
20411
20745
|
} catch {
|
|
20412
20746
|
continue;
|
|
20413
20747
|
}
|
|
@@ -20488,7 +20822,7 @@ function buildSessions(days, historyPath) {
|
|
|
20488
20822
|
const hPath = historyPath ?? import_path42.default.join(import_os36.default.homedir(), ".claude", "history.jsonl");
|
|
20489
20823
|
let historyRaw;
|
|
20490
20824
|
try {
|
|
20491
|
-
historyRaw =
|
|
20825
|
+
historyRaw = import_fs41.default.readFileSync(hPath, "utf-8");
|
|
20492
20826
|
} catch {
|
|
20493
20827
|
return [];
|
|
20494
20828
|
}
|
|
@@ -20513,7 +20847,7 @@ function buildSessions(days, historyPath) {
|
|
|
20513
20847
|
const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
|
|
20514
20848
|
let sessionLines = [];
|
|
20515
20849
|
try {
|
|
20516
|
-
sessionLines =
|
|
20850
|
+
sessionLines = import_fs41.default.readFileSync(jsonlFile, "utf-8").split("\n");
|
|
20517
20851
|
} catch {
|
|
20518
20852
|
}
|
|
20519
20853
|
const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
|
|
@@ -20780,7 +21114,7 @@ function registerSessionsCommand(program2) {
|
|
|
20780
21114
|
console.log(import_chalk24.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk24.default.dim(" \u2014 what your AI agent did"));
|
|
20781
21115
|
console.log("");
|
|
20782
21116
|
const historyPath = import_path42.default.join(import_os36.default.homedir(), ".claude", "history.jsonl");
|
|
20783
|
-
if (!
|
|
21117
|
+
if (!import_fs41.default.existsSync(historyPath)) {
|
|
20784
21118
|
console.log(import_chalk24.default.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
|
|
20785
21119
|
console.log(import_chalk24.default.gray(" Install Claude Code, run a few sessions, then try again.\n"));
|
|
20786
21120
|
return;
|
|
@@ -20817,12 +21151,12 @@ function registerSessionsCommand(program2) {
|
|
|
20817
21151
|
|
|
20818
21152
|
// src/cli/commands/skill-pin.ts
|
|
20819
21153
|
var import_chalk25 = __toESM(require("chalk"));
|
|
20820
|
-
var
|
|
21154
|
+
var import_fs42 = __toESM(require("fs"));
|
|
20821
21155
|
var import_os37 = __toESM(require("os"));
|
|
20822
21156
|
var import_path43 = __toESM(require("path"));
|
|
20823
21157
|
function wipeSkillSessions() {
|
|
20824
21158
|
try {
|
|
20825
|
-
|
|
21159
|
+
import_fs42.default.rmSync(import_path43.default.join(import_os37.default.homedir(), ".node9", "skill-sessions"), {
|
|
20826
21160
|
recursive: true,
|
|
20827
21161
|
force: true
|
|
20828
21162
|
});
|
|
@@ -20880,7 +21214,7 @@ function registerSkillPinCommand(program2) {
|
|
|
20880
21214
|
process.exit(1);
|
|
20881
21215
|
}
|
|
20882
21216
|
const rootPath = pins.roots[rootKey].rootPath;
|
|
20883
|
-
|
|
21217
|
+
removePin2(rootKey);
|
|
20884
21218
|
wipeSkillSessions();
|
|
20885
21219
|
console.log(import_chalk25.default.green(`
|
|
20886
21220
|
\u{1F513} Pin removed for ${import_chalk25.default.cyan(rootKey)}`));
|
|
@@ -20895,7 +21229,7 @@ function registerSkillPinCommand(program2) {
|
|
|
20895
21229
|
return;
|
|
20896
21230
|
}
|
|
20897
21231
|
const count = result.ok ? Object.keys(result.pins.roots).length : "?";
|
|
20898
|
-
|
|
21232
|
+
clearAllPins2();
|
|
20899
21233
|
wipeSkillSessions();
|
|
20900
21234
|
console.log(import_chalk25.default.green(`
|
|
20901
21235
|
\u{1F513} Cleared ${count} skill pin(s).`));
|
|
@@ -20904,15 +21238,15 @@ function registerSkillPinCommand(program2) {
|
|
|
20904
21238
|
}
|
|
20905
21239
|
|
|
20906
21240
|
// src/cli/commands/decisions.ts
|
|
20907
|
-
var
|
|
21241
|
+
var import_fs43 = __toESM(require("fs"));
|
|
20908
21242
|
var import_os38 = __toESM(require("os"));
|
|
20909
21243
|
var import_path44 = __toESM(require("path"));
|
|
20910
21244
|
var import_chalk26 = __toESM(require("chalk"));
|
|
20911
21245
|
var DECISIONS_FILE2 = import_path44.default.join(import_os38.default.homedir(), ".node9", "decisions.json");
|
|
20912
21246
|
function readDecisions() {
|
|
20913
21247
|
try {
|
|
20914
|
-
if (!
|
|
20915
|
-
const raw =
|
|
21248
|
+
if (!import_fs43.default.existsSync(DECISIONS_FILE2)) return {};
|
|
21249
|
+
const raw = import_fs43.default.readFileSync(DECISIONS_FILE2, "utf-8");
|
|
20916
21250
|
const parsed = JSON.parse(raw);
|
|
20917
21251
|
const out = {};
|
|
20918
21252
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -20925,10 +21259,10 @@ function readDecisions() {
|
|
|
20925
21259
|
}
|
|
20926
21260
|
function writeDecisions(d) {
|
|
20927
21261
|
const dir = import_path44.default.dirname(DECISIONS_FILE2);
|
|
20928
|
-
if (!
|
|
21262
|
+
if (!import_fs43.default.existsSync(dir)) import_fs43.default.mkdirSync(dir, { recursive: true });
|
|
20929
21263
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
20930
|
-
|
|
20931
|
-
|
|
21264
|
+
import_fs43.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
21265
|
+
import_fs43.default.renameSync(tmp, DECISIONS_FILE2);
|
|
20932
21266
|
}
|
|
20933
21267
|
function registerDecisionsCommand(program2) {
|
|
20934
21268
|
const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
|
|
@@ -20985,7 +21319,7 @@ Persistent decisions (${entries.length})
|
|
|
20985
21319
|
|
|
20986
21320
|
// src/cli/commands/dlp.ts
|
|
20987
21321
|
var import_chalk27 = __toESM(require("chalk"));
|
|
20988
|
-
var
|
|
21322
|
+
var import_fs44 = __toESM(require("fs"));
|
|
20989
21323
|
var import_path45 = __toESM(require("path"));
|
|
20990
21324
|
var import_os39 = __toESM(require("os"));
|
|
20991
21325
|
var AUDIT_LOG = import_path45.default.join(import_os39.default.homedir(), ".node9", "audit.log");
|
|
@@ -20996,7 +21330,7 @@ function stripAnsi(s) {
|
|
|
20996
21330
|
}
|
|
20997
21331
|
function loadResolved() {
|
|
20998
21332
|
try {
|
|
20999
|
-
const raw = JSON.parse(
|
|
21333
|
+
const raw = JSON.parse(import_fs44.default.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
21000
21334
|
return new Set(raw);
|
|
21001
21335
|
} catch {
|
|
21002
21336
|
return /* @__PURE__ */ new Set();
|
|
@@ -21004,13 +21338,13 @@ function loadResolved() {
|
|
|
21004
21338
|
}
|
|
21005
21339
|
function saveResolved(resolved) {
|
|
21006
21340
|
try {
|
|
21007
|
-
|
|
21341
|
+
import_fs44.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
21008
21342
|
} catch {
|
|
21009
21343
|
}
|
|
21010
21344
|
}
|
|
21011
21345
|
function loadDlpFindings() {
|
|
21012
|
-
if (!
|
|
21013
|
-
return
|
|
21346
|
+
if (!import_fs44.default.existsSync(AUDIT_LOG)) return [];
|
|
21347
|
+
return import_fs44.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
21014
21348
|
if (!line.trim()) return [];
|
|
21015
21349
|
try {
|
|
21016
21350
|
const e = JSON.parse(line);
|
|
@@ -21108,14 +21442,14 @@ function registerDlpCommand(program2) {
|
|
|
21108
21442
|
|
|
21109
21443
|
// src/cli/commands/mask.ts
|
|
21110
21444
|
var import_chalk28 = __toESM(require("chalk"));
|
|
21111
|
-
var
|
|
21445
|
+
var import_fs45 = __toESM(require("fs"));
|
|
21112
21446
|
var import_path46 = __toESM(require("path"));
|
|
21113
21447
|
var import_os40 = __toESM(require("os"));
|
|
21114
21448
|
init_dlp();
|
|
21115
21449
|
function findJsonlFiles(dir) {
|
|
21116
21450
|
const results = [];
|
|
21117
|
-
if (!
|
|
21118
|
-
for (const entry of
|
|
21451
|
+
if (!import_fs45.default.existsSync(dir)) return results;
|
|
21452
|
+
for (const entry of import_fs45.default.readdirSync(dir, { withFileTypes: true })) {
|
|
21119
21453
|
const full = import_path46.default.join(dir, entry.name);
|
|
21120
21454
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
21121
21455
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
@@ -21159,7 +21493,7 @@ function redactJson(obj) {
|
|
|
21159
21493
|
function processFile(filePath, dryRun) {
|
|
21160
21494
|
let raw;
|
|
21161
21495
|
try {
|
|
21162
|
-
raw =
|
|
21496
|
+
raw = import_fs45.default.readFileSync(filePath, "utf-8");
|
|
21163
21497
|
} catch {
|
|
21164
21498
|
return { redactedLines: 0, patterns: [] };
|
|
21165
21499
|
}
|
|
@@ -21191,14 +21525,14 @@ function processFile(filePath, dryRun) {
|
|
|
21191
21525
|
}
|
|
21192
21526
|
}
|
|
21193
21527
|
if (!dryRun && redactedLines > 0) {
|
|
21194
|
-
|
|
21528
|
+
import_fs45.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
21195
21529
|
}
|
|
21196
21530
|
return { redactedLines, patterns };
|
|
21197
21531
|
}
|
|
21198
21532
|
function processJsonFile(filePath, dryRun) {
|
|
21199
21533
|
let raw;
|
|
21200
21534
|
try {
|
|
21201
|
-
raw =
|
|
21535
|
+
raw = import_fs45.default.readFileSync(filePath, "utf-8");
|
|
21202
21536
|
} catch {
|
|
21203
21537
|
return { redactedLines: 0, patterns: [] };
|
|
21204
21538
|
}
|
|
@@ -21211,14 +21545,14 @@ function processJsonFile(filePath, dryRun) {
|
|
|
21211
21545
|
const { value, modified, found } = redactJson(parsed);
|
|
21212
21546
|
if (!modified) return { redactedLines: 0, patterns: [] };
|
|
21213
21547
|
if (!dryRun) {
|
|
21214
|
-
|
|
21548
|
+
import_fs45.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
|
|
21215
21549
|
}
|
|
21216
21550
|
return { redactedLines: 1, patterns: found };
|
|
21217
21551
|
}
|
|
21218
21552
|
function findJsonFiles(dir) {
|
|
21219
21553
|
const results = [];
|
|
21220
|
-
if (!
|
|
21221
|
-
for (const entry of
|
|
21554
|
+
if (!import_fs45.default.existsSync(dir)) return results;
|
|
21555
|
+
for (const entry of import_fs45.default.readdirSync(dir, { withFileTypes: true })) {
|
|
21222
21556
|
const full = import_path46.default.join(dir, entry.name);
|
|
21223
21557
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
21224
21558
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
@@ -21238,7 +21572,7 @@ function registerMaskCommand(program2) {
|
|
|
21238
21572
|
const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
21239
21573
|
const filtered = cutoff ? allFiles.filter((f) => {
|
|
21240
21574
|
try {
|
|
21241
|
-
return
|
|
21575
|
+
return import_fs45.default.statSync(f.path).mtime >= cutoff;
|
|
21242
21576
|
} catch {
|
|
21243
21577
|
return false;
|
|
21244
21578
|
}
|
|
@@ -21294,20 +21628,20 @@ function registerMaskCommand(program2) {
|
|
|
21294
21628
|
// src/cli.ts
|
|
21295
21629
|
init_blast();
|
|
21296
21630
|
var { version } = JSON.parse(
|
|
21297
|
-
|
|
21631
|
+
import_fs48.default.readFileSync(import_path49.default.join(__dirname, "../package.json"), "utf-8")
|
|
21298
21632
|
);
|
|
21299
21633
|
var program = new import_commander.Command();
|
|
21300
21634
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
21301
21635
|
program.command("login").argument("<apiKey>").option("--local", "Save key for audit/logging only \u2014 local config still controls all decisions").option("--profile <name>", 'Save as a named profile (default: "default")').action((apiKey, options) => {
|
|
21302
21636
|
const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
|
|
21303
21637
|
const credPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "credentials.json");
|
|
21304
|
-
if (!
|
|
21305
|
-
|
|
21638
|
+
if (!import_fs48.default.existsSync(import_path49.default.dirname(credPath)))
|
|
21639
|
+
import_fs48.default.mkdirSync(import_path49.default.dirname(credPath), { recursive: true });
|
|
21306
21640
|
const profileName = options.profile || "default";
|
|
21307
21641
|
let existingCreds = {};
|
|
21308
21642
|
try {
|
|
21309
|
-
if (
|
|
21310
|
-
const raw = JSON.parse(
|
|
21643
|
+
if (import_fs48.default.existsSync(credPath)) {
|
|
21644
|
+
const raw = JSON.parse(import_fs48.default.readFileSync(credPath, "utf-8"));
|
|
21311
21645
|
if (raw.apiKey) {
|
|
21312
21646
|
existingCreds = {
|
|
21313
21647
|
default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
|
|
@@ -21319,13 +21653,13 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
21319
21653
|
} catch {
|
|
21320
21654
|
}
|
|
21321
21655
|
existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
|
|
21322
|
-
|
|
21656
|
+
import_fs48.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
|
|
21323
21657
|
if (profileName === "default") {
|
|
21324
21658
|
const configPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "config.json");
|
|
21325
21659
|
let config = {};
|
|
21326
21660
|
try {
|
|
21327
|
-
if (
|
|
21328
|
-
config = JSON.parse(
|
|
21661
|
+
if (import_fs48.default.existsSync(configPath))
|
|
21662
|
+
config = JSON.parse(import_fs48.default.readFileSync(configPath, "utf-8"));
|
|
21329
21663
|
} catch {
|
|
21330
21664
|
}
|
|
21331
21665
|
if (!config.settings || typeof config.settings !== "object") config.settings = {};
|
|
@@ -21340,9 +21674,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
21340
21674
|
approvers.cloud = false;
|
|
21341
21675
|
}
|
|
21342
21676
|
s.approvers = approvers;
|
|
21343
|
-
if (!
|
|
21344
|
-
|
|
21345
|
-
|
|
21677
|
+
if (!import_fs48.default.existsSync(import_path49.default.dirname(configPath)))
|
|
21678
|
+
import_fs48.default.mkdirSync(import_path49.default.dirname(configPath), { recursive: true });
|
|
21679
|
+
import_fs48.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
21346
21680
|
}
|
|
21347
21681
|
if (options.profile && profileName !== "default") {
|
|
21348
21682
|
console.log(import_chalk30.default.green(`\u2705 Profile "${profileName}" saved`));
|
|
@@ -21480,14 +21814,14 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
21480
21814
|
}
|
|
21481
21815
|
if (options.purge) {
|
|
21482
21816
|
const node9Dir = import_path49.default.join(import_os43.default.homedir(), ".node9");
|
|
21483
|
-
if (
|
|
21817
|
+
if (import_fs48.default.existsSync(node9Dir)) {
|
|
21484
21818
|
const confirmed = await (0, import_prompts2.confirm)({
|
|
21485
21819
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
21486
21820
|
default: false
|
|
21487
21821
|
});
|
|
21488
21822
|
if (confirmed) {
|
|
21489
|
-
|
|
21490
|
-
if (
|
|
21823
|
+
import_fs48.default.rmSync(node9Dir, { recursive: true });
|
|
21824
|
+
if (import_fs48.default.existsSync(node9Dir)) {
|
|
21491
21825
|
console.error(
|
|
21492
21826
|
import_chalk30.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
21493
21827
|
);
|
|
@@ -21642,12 +21976,12 @@ Run "node9 addto claude" to register it as the statusLine.`
|
|
|
21642
21976
|
if (subcommand === "debug") {
|
|
21643
21977
|
const flagFile = import_path49.default.join(import_os43.default.homedir(), ".node9", "hud-debug");
|
|
21644
21978
|
if (state === "on") {
|
|
21645
|
-
|
|
21646
|
-
|
|
21979
|
+
import_fs48.default.mkdirSync(import_path49.default.dirname(flagFile), { recursive: true });
|
|
21980
|
+
import_fs48.default.writeFileSync(flagFile, "");
|
|
21647
21981
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
21648
21982
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
21649
21983
|
} else if (state === "off") {
|
|
21650
|
-
if (
|
|
21984
|
+
if (import_fs48.default.existsSync(flagFile)) import_fs48.default.unlinkSync(flagFile);
|
|
21651
21985
|
console.log("HUD debug logging disabled.");
|
|
21652
21986
|
} else {
|
|
21653
21987
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -21763,7 +22097,7 @@ if (process.argv[2] !== "daemon") {
|
|
|
21763
22097
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
21764
22098
|
const logPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log");
|
|
21765
22099
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
21766
|
-
|
|
22100
|
+
import_fs48.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
21767
22101
|
`);
|
|
21768
22102
|
}
|
|
21769
22103
|
process.exit(0);
|