@node9/proxy 1.22.0 → 1.24.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 +948 -810
- package/dist/cli.mjs +917 -780
- 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,32 +6488,32 @@ 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) {
|
|
@@ -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 ?? {};
|
|
@@ -6631,8 +6790,9 @@ async function setupClaude() {
|
|
|
6631
6790
|
}
|
|
6632
6791
|
}
|
|
6633
6792
|
async function setupGemini() {
|
|
6634
|
-
|
|
6635
|
-
const
|
|
6793
|
+
seedMcpPinsIfMissing();
|
|
6794
|
+
const homeDir2 = import_os12.default.homedir();
|
|
6795
|
+
const settingsPath = import_path15.default.join(homeDir2, ".gemini", "settings.json");
|
|
6636
6796
|
const settings = readJson(settingsPath) ?? {};
|
|
6637
6797
|
const servers = settings.mcpServers ?? {};
|
|
6638
6798
|
let hooksChanged = false;
|
|
@@ -6727,9 +6887,9 @@ async function setupGemini() {
|
|
|
6727
6887
|
printDaemonTip();
|
|
6728
6888
|
}
|
|
6729
6889
|
}
|
|
6730
|
-
function claudeDesktopConfigPath(homeDir2 =
|
|
6890
|
+
function claudeDesktopConfigPath(homeDir2 = import_os12.default.homedir()) {
|
|
6731
6891
|
if (process.platform === "darwin") {
|
|
6732
|
-
return
|
|
6892
|
+
return import_path15.default.join(
|
|
6733
6893
|
homeDir2,
|
|
6734
6894
|
"Library",
|
|
6735
6895
|
"Application Support",
|
|
@@ -6738,18 +6898,18 @@ function claudeDesktopConfigPath(homeDir2 = import_os11.default.homedir()) {
|
|
|
6738
6898
|
);
|
|
6739
6899
|
}
|
|
6740
6900
|
if (process.platform === "linux") {
|
|
6741
|
-
return
|
|
6901
|
+
return import_path15.default.join(homeDir2, ".config", "Claude", "claude_desktop_config.json");
|
|
6742
6902
|
}
|
|
6743
6903
|
if (process.platform === "win32") {
|
|
6744
|
-
const appData = process.env.APPDATA ??
|
|
6745
|
-
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");
|
|
6746
6906
|
}
|
|
6747
6907
|
return null;
|
|
6748
6908
|
}
|
|
6749
|
-
function detectAgents(homeDir2 =
|
|
6909
|
+
function detectAgents(homeDir2 = import_os12.default.homedir()) {
|
|
6750
6910
|
const exists = (p) => {
|
|
6751
6911
|
try {
|
|
6752
|
-
return
|
|
6912
|
+
return import_fs13.default.existsSync(p);
|
|
6753
6913
|
} catch (err2) {
|
|
6754
6914
|
const code = err2.code;
|
|
6755
6915
|
if (code !== "ENOENT") {
|
|
@@ -6761,18 +6921,19 @@ function detectAgents(homeDir2 = import_os11.default.homedir()) {
|
|
|
6761
6921
|
};
|
|
6762
6922
|
const desktopPath = claudeDesktopConfigPath(homeDir2);
|
|
6763
6923
|
return {
|
|
6764
|
-
claude: exists(
|
|
6765
|
-
gemini: exists(
|
|
6766
|
-
cursor: exists(
|
|
6767
|
-
codex: exists(
|
|
6768
|
-
windsurf: exists(
|
|
6769
|
-
vscode: exists(
|
|
6770
|
-
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))
|
|
6771
6931
|
};
|
|
6772
6932
|
}
|
|
6773
6933
|
async function setupCursor() {
|
|
6774
|
-
|
|
6775
|
-
const
|
|
6934
|
+
seedMcpPinsIfMissing();
|
|
6935
|
+
const homeDir2 = import_os12.default.homedir();
|
|
6936
|
+
const mcpPath = import_path15.default.join(homeDir2, ".cursor", "mcp.json");
|
|
6776
6937
|
const mcpConfig = readJson(mcpPath) ?? {};
|
|
6777
6938
|
const servers = mcpConfig.mcpServers ?? {};
|
|
6778
6939
|
let anythingChanged = false;
|
|
@@ -6838,22 +6999,23 @@ async function setupCursor() {
|
|
|
6838
6999
|
}
|
|
6839
7000
|
function readToml(filePath) {
|
|
6840
7001
|
try {
|
|
6841
|
-
if (
|
|
6842
|
-
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"));
|
|
6843
7004
|
}
|
|
6844
7005
|
} catch {
|
|
6845
7006
|
}
|
|
6846
7007
|
return null;
|
|
6847
7008
|
}
|
|
6848
7009
|
function writeToml(filePath, data) {
|
|
6849
|
-
const dir =
|
|
6850
|
-
if (!
|
|
6851
|
-
|
|
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));
|
|
6852
7013
|
}
|
|
6853
7014
|
async function setupCodex() {
|
|
6854
|
-
|
|
6855
|
-
const
|
|
6856
|
-
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");
|
|
6857
7019
|
const config = readToml(configPath) ?? {};
|
|
6858
7020
|
const servers = config.mcp_servers ?? {};
|
|
6859
7021
|
let anythingChanged = false;
|
|
@@ -7003,9 +7165,9 @@ async function setupCodex() {
|
|
|
7003
7165
|
}
|
|
7004
7166
|
}
|
|
7005
7167
|
function teardownCodex() {
|
|
7006
|
-
const homeDir2 =
|
|
7007
|
-
const configPath =
|
|
7008
|
-
const hooksPath =
|
|
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");
|
|
7009
7171
|
const hooksFile = readJson(hooksPath);
|
|
7010
7172
|
if (hooksFile?.hooks) {
|
|
7011
7173
|
let hooksChanged = false;
|
|
@@ -7052,8 +7214,8 @@ function teardownCodex() {
|
|
|
7052
7214
|
}
|
|
7053
7215
|
}
|
|
7054
7216
|
function setupHud() {
|
|
7055
|
-
const homeDir2 =
|
|
7056
|
-
const hooksPath =
|
|
7217
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7218
|
+
const hooksPath = import_path15.default.join(homeDir2, ".claude", "settings.json");
|
|
7057
7219
|
const settings = readJson(hooksPath) ?? {};
|
|
7058
7220
|
const hudCommand = fullPathCommand("hud");
|
|
7059
7221
|
const statusLineObj = { type: "command", command: hudCommand };
|
|
@@ -7079,8 +7241,8 @@ function setupHud() {
|
|
|
7079
7241
|
console.log(import_chalk.default.gray(" Restart Claude Code to activate."));
|
|
7080
7242
|
}
|
|
7081
7243
|
function teardownHud() {
|
|
7082
|
-
const homeDir2 =
|
|
7083
|
-
const hooksPath =
|
|
7244
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7245
|
+
const hooksPath = import_path15.default.join(homeDir2, ".claude", "settings.json");
|
|
7084
7246
|
const settings = readJson(hooksPath);
|
|
7085
7247
|
if (!settings) {
|
|
7086
7248
|
console.log(import_chalk.default.blue(" \u2139\uFE0F ~/.claude/settings.json not found \u2014 nothing to remove"));
|
|
@@ -7098,8 +7260,9 @@ function teardownHud() {
|
|
|
7098
7260
|
console.log(import_chalk.default.gray(" Restart Claude Code for changes to take effect."));
|
|
7099
7261
|
}
|
|
7100
7262
|
async function setupWindsurf() {
|
|
7101
|
-
|
|
7102
|
-
const
|
|
7263
|
+
seedMcpPinsIfMissing();
|
|
7264
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7265
|
+
const mcpPath = import_path15.default.join(homeDir2, ".codeium", "windsurf", "mcp_config.json");
|
|
7103
7266
|
const mcpConfig = readJson(mcpPath) ?? {};
|
|
7104
7267
|
const servers = mcpConfig.mcpServers ?? {};
|
|
7105
7268
|
let anythingChanged = false;
|
|
@@ -7159,8 +7322,8 @@ async function setupWindsurf() {
|
|
|
7159
7322
|
}
|
|
7160
7323
|
}
|
|
7161
7324
|
function teardownWindsurf() {
|
|
7162
|
-
const homeDir2 =
|
|
7163
|
-
const mcpPath =
|
|
7325
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7326
|
+
const mcpPath = import_path15.default.join(homeDir2, ".codeium", "windsurf", "mcp_config.json");
|
|
7164
7327
|
const mcpConfig = readJson(mcpPath);
|
|
7165
7328
|
if (!mcpConfig?.mcpServers) {
|
|
7166
7329
|
console.log(
|
|
@@ -7201,8 +7364,9 @@ function hasNode9McpServerVSCode(servers) {
|
|
|
7201
7364
|
return !!entry && entry.command === "node9" && Array.isArray(entry.args) && entry.args[0] === "mcp-server";
|
|
7202
7365
|
}
|
|
7203
7366
|
async function setupVSCode() {
|
|
7204
|
-
|
|
7205
|
-
const
|
|
7367
|
+
seedMcpPinsIfMissing();
|
|
7368
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7369
|
+
const mcpPath = import_path15.default.join(homeDir2, ".vscode", "mcp.json");
|
|
7206
7370
|
const mcpConfig = readJson(mcpPath) ?? {};
|
|
7207
7371
|
const servers = mcpConfig.servers ?? {};
|
|
7208
7372
|
let anythingChanged = false;
|
|
@@ -7263,8 +7427,8 @@ async function setupVSCode() {
|
|
|
7263
7427
|
}
|
|
7264
7428
|
}
|
|
7265
7429
|
function teardownVSCode() {
|
|
7266
|
-
const homeDir2 =
|
|
7267
|
-
const mcpPath =
|
|
7430
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7431
|
+
const mcpPath = import_path15.default.join(homeDir2, ".vscode", "mcp.json");
|
|
7268
7432
|
const mcpConfig = readJson(mcpPath);
|
|
7269
7433
|
if (!mcpConfig?.servers) {
|
|
7270
7434
|
console.log(import_chalk.default.blue(" \u2139\uFE0F ~/.vscode/mcp.json not found \u2014 nothing to remove"));
|
|
@@ -7297,6 +7461,7 @@ function teardownVSCode() {
|
|
|
7297
7461
|
}
|
|
7298
7462
|
}
|
|
7299
7463
|
async function setupClaudeDesktop() {
|
|
7464
|
+
seedMcpPinsIfMissing();
|
|
7300
7465
|
const configPath = claudeDesktopConfigPath();
|
|
7301
7466
|
if (!configPath) {
|
|
7302
7467
|
console.log(import_chalk.default.yellow(" \u26A0\uFE0F Claude Desktop is not supported on this platform."));
|
|
@@ -7395,32 +7560,32 @@ function teardownClaudeDesktop() {
|
|
|
7395
7560
|
console.log(import_chalk.default.blue(" \u2139\uFE0F No Node9-wrapped MCP servers found in Claude Desktop config"));
|
|
7396
7561
|
}
|
|
7397
7562
|
}
|
|
7398
|
-
function getAgentsStatus(homeDir2 =
|
|
7563
|
+
function getAgentsStatus(homeDir2 = import_os12.default.homedir()) {
|
|
7399
7564
|
const detected = detectAgents(homeDir2);
|
|
7400
7565
|
const claudeWired = (() => {
|
|
7401
|
-
const settings = readJson(
|
|
7566
|
+
const settings = readJson(import_path15.default.join(homeDir2, ".claude", "settings.json"));
|
|
7402
7567
|
return !!settings?.hooks?.PreToolUse?.some((m) => m.hooks.some((h) => isNode9Hook(h.command)));
|
|
7403
7568
|
})();
|
|
7404
7569
|
const geminiWired = (() => {
|
|
7405
|
-
const settings = readJson(
|
|
7570
|
+
const settings = readJson(import_path15.default.join(homeDir2, ".gemini", "settings.json"));
|
|
7406
7571
|
return !!settings?.hooks?.BeforeTool?.some((m) => m.hooks.some((h) => isNode9Hook(h.command)));
|
|
7407
7572
|
})();
|
|
7408
7573
|
const cursorWired = (() => {
|
|
7409
|
-
const cfg = readJson(
|
|
7574
|
+
const cfg = readJson(import_path15.default.join(homeDir2, ".cursor", "mcp.json"));
|
|
7410
7575
|
return !!(cfg?.mcpServers && hasNode9McpServer(cfg.mcpServers));
|
|
7411
7576
|
})();
|
|
7412
7577
|
const codexWired = (() => {
|
|
7413
|
-
const cfg = readToml(
|
|
7578
|
+
const cfg = readToml(import_path15.default.join(homeDir2, ".codex", "config.toml"));
|
|
7414
7579
|
return !!(cfg?.mcp_servers && hasNode9McpServer(cfg.mcp_servers));
|
|
7415
7580
|
})();
|
|
7416
7581
|
const windsurfWired = (() => {
|
|
7417
7582
|
const cfg = readJson(
|
|
7418
|
-
|
|
7583
|
+
import_path15.default.join(homeDir2, ".codeium", "windsurf", "mcp_config.json")
|
|
7419
7584
|
);
|
|
7420
7585
|
return !!(cfg?.mcpServers && hasNode9McpServer(cfg.mcpServers));
|
|
7421
7586
|
})();
|
|
7422
7587
|
const vscodeWired = (() => {
|
|
7423
|
-
const cfg = readJson(
|
|
7588
|
+
const cfg = readJson(import_path15.default.join(homeDir2, ".vscode", "mcp.json"));
|
|
7424
7589
|
return !!(cfg?.servers && hasNode9McpServerVSCode(cfg.servers));
|
|
7425
7590
|
})();
|
|
7426
7591
|
return [
|
|
@@ -7480,16 +7645,17 @@ function getAgentsStatus(homeDir2 = import_os11.default.homedir()) {
|
|
|
7480
7645
|
}
|
|
7481
7646
|
];
|
|
7482
7647
|
}
|
|
7483
|
-
var
|
|
7648
|
+
var import_fs13, import_path15, import_os12, import_chalk, import_prompts, import_smol_toml, NODE9_MCP_SERVER_ENTRY, CODEX_PRE_TOOL_MATCHERS;
|
|
7484
7649
|
var init_setup = __esm({
|
|
7485
7650
|
"src/setup.ts"() {
|
|
7486
7651
|
"use strict";
|
|
7487
|
-
|
|
7488
|
-
|
|
7489
|
-
|
|
7652
|
+
import_fs13 = __toESM(require("fs"));
|
|
7653
|
+
import_path15 = __toESM(require("path"));
|
|
7654
|
+
import_os12 = __toESM(require("os"));
|
|
7490
7655
|
import_chalk = __toESM(require("chalk"));
|
|
7491
7656
|
import_prompts = require("@inquirer/prompts");
|
|
7492
7657
|
import_smol_toml = require("smol-toml");
|
|
7658
|
+
init_mcp_pin();
|
|
7493
7659
|
NODE9_MCP_SERVER_ENTRY = { command: "node9", args: ["mcp-server"] };
|
|
7494
7660
|
CODEX_PRE_TOOL_MATCHERS = ["^Bash$", "^apply_patch$", "^mcp__.*"];
|
|
7495
7661
|
}
|
|
@@ -7685,79 +7851,79 @@ var init_scan_summary = __esm({
|
|
|
7685
7851
|
function buildSensitivePaths(home, cwd) {
|
|
7686
7852
|
return [
|
|
7687
7853
|
{
|
|
7688
|
-
full:
|
|
7854
|
+
full: import_path16.default.join(home, ".ssh", "id_rsa"),
|
|
7689
7855
|
label: "~/.ssh/id_rsa",
|
|
7690
7856
|
description: "RSA private key \u2014 grants SSH access to your servers",
|
|
7691
7857
|
score: 20
|
|
7692
7858
|
},
|
|
7693
7859
|
{
|
|
7694
|
-
full:
|
|
7860
|
+
full: import_path16.default.join(home, ".ssh", "id_ed25519"),
|
|
7695
7861
|
label: "~/.ssh/id_ed25519",
|
|
7696
7862
|
description: "Ed25519 private key \u2014 grants SSH access to your servers",
|
|
7697
7863
|
score: 20
|
|
7698
7864
|
},
|
|
7699
7865
|
{
|
|
7700
|
-
full:
|
|
7866
|
+
full: import_path16.default.join(home, ".ssh", "id_ecdsa"),
|
|
7701
7867
|
label: "~/.ssh/id_ecdsa",
|
|
7702
7868
|
description: "ECDSA private key \u2014 grants SSH access to your servers",
|
|
7703
7869
|
score: 20
|
|
7704
7870
|
},
|
|
7705
7871
|
{
|
|
7706
|
-
full:
|
|
7872
|
+
full: import_path16.default.join(home, ".aws", "credentials"),
|
|
7707
7873
|
label: "~/.aws/credentials",
|
|
7708
7874
|
description: "AWS access keys \u2014 full cloud account access",
|
|
7709
7875
|
score: 20
|
|
7710
7876
|
},
|
|
7711
7877
|
{
|
|
7712
|
-
full:
|
|
7878
|
+
full: import_path16.default.join(home, ".aws", "config"),
|
|
7713
7879
|
label: "~/.aws/config",
|
|
7714
7880
|
description: "AWS configuration \u2014 account and region settings",
|
|
7715
7881
|
score: 5
|
|
7716
7882
|
},
|
|
7717
7883
|
{
|
|
7718
|
-
full:
|
|
7884
|
+
full: import_path16.default.join(home, ".config", "gcloud", "credentials.db"),
|
|
7719
7885
|
label: "~/.config/gcloud/credentials.db",
|
|
7720
7886
|
description: "Google Cloud credentials",
|
|
7721
7887
|
score: 15
|
|
7722
7888
|
},
|
|
7723
7889
|
{
|
|
7724
|
-
full:
|
|
7890
|
+
full: import_path16.default.join(home, ".docker", "config.json"),
|
|
7725
7891
|
label: "~/.docker/config.json",
|
|
7726
7892
|
description: "Docker registry auth tokens",
|
|
7727
7893
|
score: 10
|
|
7728
7894
|
},
|
|
7729
7895
|
{
|
|
7730
|
-
full:
|
|
7896
|
+
full: import_path16.default.join(home, ".netrc"),
|
|
7731
7897
|
label: "~/.netrc",
|
|
7732
7898
|
description: "FTP/HTTP credentials in plain text",
|
|
7733
7899
|
score: 15
|
|
7734
7900
|
},
|
|
7735
7901
|
{
|
|
7736
|
-
full:
|
|
7902
|
+
full: import_path16.default.join(home, ".npmrc"),
|
|
7737
7903
|
label: "~/.npmrc",
|
|
7738
7904
|
description: "npm auth token \u2014 can publish packages as you",
|
|
7739
7905
|
score: 10
|
|
7740
7906
|
},
|
|
7741
7907
|
{
|
|
7742
|
-
full:
|
|
7908
|
+
full: import_path16.default.join(home, ".node9", "credentials.json"),
|
|
7743
7909
|
label: "~/.node9/credentials.json",
|
|
7744
7910
|
description: "Node9 cloud API key",
|
|
7745
7911
|
score: 10
|
|
7746
7912
|
},
|
|
7747
7913
|
{
|
|
7748
|
-
full:
|
|
7914
|
+
full: import_path16.default.join(cwd, ".env"),
|
|
7749
7915
|
label: ".env (current folder)",
|
|
7750
7916
|
description: "App secrets \u2014 database passwords, API keys",
|
|
7751
7917
|
score: 20
|
|
7752
7918
|
},
|
|
7753
7919
|
{
|
|
7754
|
-
full:
|
|
7920
|
+
full: import_path16.default.join(cwd, ".env.local"),
|
|
7755
7921
|
label: ".env.local (current folder)",
|
|
7756
7922
|
description: "Local overrides \u2014 often contains real credentials",
|
|
7757
7923
|
score: 15
|
|
7758
7924
|
},
|
|
7759
7925
|
{
|
|
7760
|
-
full:
|
|
7926
|
+
full: import_path16.default.join(cwd, ".env.production"),
|
|
7761
7927
|
label: ".env.production (current folder)",
|
|
7762
7928
|
description: "Production secrets",
|
|
7763
7929
|
score: 20
|
|
@@ -7766,7 +7932,7 @@ function buildSensitivePaths(home, cwd) {
|
|
|
7766
7932
|
}
|
|
7767
7933
|
function isReadable(filePath) {
|
|
7768
7934
|
try {
|
|
7769
|
-
|
|
7935
|
+
import_fs14.default.accessSync(filePath, import_fs14.default.constants.R_OK);
|
|
7770
7936
|
return true;
|
|
7771
7937
|
} catch {
|
|
7772
7938
|
return false;
|
|
@@ -7779,13 +7945,13 @@ function scoreLabel(score) {
|
|
|
7779
7945
|
return import_chalk2.default.red.bold(`${score}/100 Critical`);
|
|
7780
7946
|
}
|
|
7781
7947
|
function runBlast() {
|
|
7782
|
-
const home =
|
|
7948
|
+
const home = import_os13.default.homedir();
|
|
7783
7949
|
const cwd = process.cwd();
|
|
7784
7950
|
const paths = buildSensitivePaths(home, cwd);
|
|
7785
7951
|
let scoreDeduction = 0;
|
|
7786
7952
|
const reachable = [];
|
|
7787
7953
|
for (const p of paths) {
|
|
7788
|
-
if (
|
|
7954
|
+
if (import_fs14.default.existsSync(p.full) && isReadable(p.full)) {
|
|
7789
7955
|
reachable.push(p);
|
|
7790
7956
|
scoreDeduction += p.score;
|
|
7791
7957
|
}
|
|
@@ -7803,7 +7969,7 @@ function runBlast() {
|
|
|
7803
7969
|
}
|
|
7804
7970
|
function registerBlastCommand(program2) {
|
|
7805
7971
|
program2.command("blast").description("Map what an AI agent can currently reach on this machine").action(() => {
|
|
7806
|
-
const home =
|
|
7972
|
+
const home = import_os13.default.homedir();
|
|
7807
7973
|
const cwd = process.cwd();
|
|
7808
7974
|
const { reachable, envFindings, score } = runBlast();
|
|
7809
7975
|
console.log("");
|
|
@@ -7850,14 +8016,14 @@ function registerBlastCommand(program2) {
|
|
|
7850
8016
|
console.log("");
|
|
7851
8017
|
});
|
|
7852
8018
|
}
|
|
7853
|
-
var import_chalk2,
|
|
8019
|
+
var import_chalk2, import_fs14, import_path16, import_os13;
|
|
7854
8020
|
var init_blast = __esm({
|
|
7855
8021
|
"src/cli/commands/blast.ts"() {
|
|
7856
8022
|
"use strict";
|
|
7857
8023
|
import_chalk2 = __toESM(require("chalk"));
|
|
7858
|
-
|
|
7859
|
-
|
|
7860
|
-
|
|
8024
|
+
import_fs14 = __toESM(require("fs"));
|
|
8025
|
+
import_path16 = __toESM(require("path"));
|
|
8026
|
+
import_os13 = __toESM(require("os"));
|
|
7861
8027
|
init_dlp();
|
|
7862
8028
|
}
|
|
7863
8029
|
});
|
|
@@ -7985,13 +8151,13 @@ var init_scan_json = __esm({
|
|
|
7985
8151
|
|
|
7986
8152
|
// src/cli/render/scan-history.ts
|
|
7987
8153
|
function defaultHistoryPath() {
|
|
7988
|
-
return
|
|
8154
|
+
return import_path17.default.join(import_os14.default.homedir(), ".node9", "scan-history.json");
|
|
7989
8155
|
}
|
|
7990
8156
|
function readPreviousScan(opts = {}) {
|
|
7991
8157
|
const filePath = opts.path ?? defaultHistoryPath();
|
|
7992
8158
|
try {
|
|
7993
|
-
if (!
|
|
7994
|
-
const raw =
|
|
8159
|
+
if (!import_fs15.default.existsSync(filePath)) return null;
|
|
8160
|
+
const raw = import_fs15.default.readFileSync(filePath, "utf8");
|
|
7995
8161
|
const parsed = JSON.parse(raw);
|
|
7996
8162
|
if (!Array.isArray(parsed) || parsed.length === 0) return null;
|
|
7997
8163
|
const last = parsed[parsed.length - 1];
|
|
@@ -8005,11 +8171,11 @@ function appendScanHistory(record, opts = {}) {
|
|
|
8005
8171
|
const filePath = opts.path ?? defaultHistoryPath();
|
|
8006
8172
|
const cap = opts.cap ?? SCAN_HISTORY_CAP;
|
|
8007
8173
|
try {
|
|
8008
|
-
|
|
8174
|
+
import_fs15.default.mkdirSync(import_path17.default.dirname(filePath), { recursive: true });
|
|
8009
8175
|
let history = [];
|
|
8010
|
-
if (
|
|
8176
|
+
if (import_fs15.default.existsSync(filePath)) {
|
|
8011
8177
|
try {
|
|
8012
|
-
const parsed = JSON.parse(
|
|
8178
|
+
const parsed = JSON.parse(import_fs15.default.readFileSync(filePath, "utf8"));
|
|
8013
8179
|
if (Array.isArray(parsed)) {
|
|
8014
8180
|
history = parsed.filter(isValidRecord);
|
|
8015
8181
|
}
|
|
@@ -8020,7 +8186,7 @@ function appendScanHistory(record, opts = {}) {
|
|
|
8020
8186
|
if (history.length > cap) {
|
|
8021
8187
|
history = history.slice(history.length - cap);
|
|
8022
8188
|
}
|
|
8023
|
-
|
|
8189
|
+
import_fs15.default.writeFileSync(filePath, JSON.stringify(history, null, 2));
|
|
8024
8190
|
} catch (err2) {
|
|
8025
8191
|
process.stderr.write(
|
|
8026
8192
|
`[node9] Warning: could not write scan-history.json: ${err2.message}
|
|
@@ -8042,13 +8208,13 @@ function isValidRecord(x) {
|
|
|
8042
8208
|
const r = x;
|
|
8043
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";
|
|
8044
8210
|
}
|
|
8045
|
-
var
|
|
8211
|
+
var import_fs15, import_path17, import_os14, SCAN_HISTORY_CAP;
|
|
8046
8212
|
var init_scan_history = __esm({
|
|
8047
8213
|
"src/cli/render/scan-history.ts"() {
|
|
8048
8214
|
"use strict";
|
|
8049
|
-
|
|
8050
|
-
|
|
8051
|
-
|
|
8215
|
+
import_fs15 = __toESM(require("fs"));
|
|
8216
|
+
import_path17 = __toESM(require("path"));
|
|
8217
|
+
import_os14 = __toESM(require("os"));
|
|
8052
8218
|
SCAN_HISTORY_CAP = 30;
|
|
8053
8219
|
}
|
|
8054
8220
|
});
|
|
@@ -8059,7 +8225,7 @@ function normalizeModel(raw) {
|
|
|
8059
8225
|
}
|
|
8060
8226
|
function readCache() {
|
|
8061
8227
|
try {
|
|
8062
|
-
const raw = JSON.parse(
|
|
8228
|
+
const raw = JSON.parse(import_fs16.default.readFileSync(CACHE_FILE(), "utf-8"));
|
|
8063
8229
|
if (typeof raw.fetchedAt !== "string" || typeof raw.prices !== "object" || raw.prices === null) {
|
|
8064
8230
|
return null;
|
|
8065
8231
|
}
|
|
@@ -8073,18 +8239,18 @@ function readCache() {
|
|
|
8073
8239
|
function writeCache(prices) {
|
|
8074
8240
|
try {
|
|
8075
8241
|
const target = CACHE_FILE();
|
|
8076
|
-
const dir =
|
|
8077
|
-
if (!
|
|
8242
|
+
const dir = import_path18.default.dirname(target);
|
|
8243
|
+
if (!import_fs16.default.existsSync(dir)) import_fs16.default.mkdirSync(dir, { recursive: true });
|
|
8078
8244
|
const tmp = target + ".tmp";
|
|
8079
8245
|
const body = {
|
|
8080
8246
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8081
8247
|
prices
|
|
8082
8248
|
};
|
|
8083
|
-
|
|
8084
|
-
|
|
8249
|
+
import_fs16.default.writeFileSync(tmp, JSON.stringify(body) + "\n", "utf-8");
|
|
8250
|
+
import_fs16.default.renameSync(tmp, target);
|
|
8085
8251
|
} catch (err2) {
|
|
8086
8252
|
try {
|
|
8087
|
-
|
|
8253
|
+
import_fs16.default.appendFileSync(
|
|
8088
8254
|
HOOK_DEBUG_LOG,
|
|
8089
8255
|
`[pricing] cache write failed: ${err2.message}
|
|
8090
8256
|
`
|
|
@@ -8177,13 +8343,13 @@ function pricingFor(model) {
|
|
|
8177
8343
|
lookupCache.set(norm, resolved);
|
|
8178
8344
|
return resolved;
|
|
8179
8345
|
}
|
|
8180
|
-
var
|
|
8346
|
+
var import_fs16, import_path18, import_os15, LITELLM_URL, BUNDLED_PRICING, CACHE_FILE, TTL_MS, memCache, memCacheAt, lookupCache;
|
|
8181
8347
|
var init_litellm = __esm({
|
|
8182
8348
|
"src/pricing/litellm.ts"() {
|
|
8183
8349
|
"use strict";
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8350
|
+
import_fs16 = __toESM(require("fs"));
|
|
8351
|
+
import_path18 = __toESM(require("path"));
|
|
8352
|
+
import_os15 = __toESM(require("os"));
|
|
8187
8353
|
init_audit();
|
|
8188
8354
|
LITELLM_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json";
|
|
8189
8355
|
BUNDLED_PRICING = {
|
|
@@ -8210,7 +8376,7 @@ var init_litellm = __esm({
|
|
|
8210
8376
|
"gemini-2.0-flash": [75e-9, 3e-7, 0, 0],
|
|
8211
8377
|
"gemini-1.5-pro": [125e-8, 5e-6, 0, 0]
|
|
8212
8378
|
};
|
|
8213
|
-
CACHE_FILE = () =>
|
|
8379
|
+
CACHE_FILE = () => import_path18.default.join(import_os15.default.homedir(), ".node9", "model-pricing.json");
|
|
8214
8380
|
TTL_MS = 24 * 60 * 60 * 1e3;
|
|
8215
8381
|
memCache = null;
|
|
8216
8382
|
memCacheAt = 0;
|
|
@@ -8223,10 +8389,10 @@ function decodeProjectDirName(dirName) {
|
|
|
8223
8389
|
return dirName.replace(/-/g, "/");
|
|
8224
8390
|
}
|
|
8225
8391
|
function parseJSONLFile(filePath, fallbackWorkingDir) {
|
|
8226
|
-
const runId =
|
|
8392
|
+
const runId = import_path19.default.basename(filePath, ".jsonl");
|
|
8227
8393
|
let content;
|
|
8228
8394
|
try {
|
|
8229
|
-
content =
|
|
8395
|
+
content = import_fs17.default.readFileSync(filePath, "utf8");
|
|
8230
8396
|
} catch {
|
|
8231
8397
|
return /* @__PURE__ */ new Map();
|
|
8232
8398
|
}
|
|
@@ -8282,34 +8448,34 @@ function parseJSONLFile(filePath, fallbackWorkingDir) {
|
|
|
8282
8448
|
return daily;
|
|
8283
8449
|
}
|
|
8284
8450
|
function collectEntries(sinceMs) {
|
|
8285
|
-
const projectsDir =
|
|
8286
|
-
if (!
|
|
8451
|
+
const projectsDir = import_path19.default.join(import_os16.default.homedir(), ".claude", "projects");
|
|
8452
|
+
if (!import_fs17.default.existsSync(projectsDir)) return [];
|
|
8287
8453
|
const combined = /* @__PURE__ */ new Map();
|
|
8288
8454
|
let dirs;
|
|
8289
8455
|
try {
|
|
8290
|
-
dirs =
|
|
8456
|
+
dirs = import_fs17.default.readdirSync(projectsDir);
|
|
8291
8457
|
} catch {
|
|
8292
8458
|
return [];
|
|
8293
8459
|
}
|
|
8294
8460
|
for (const dir of dirs) {
|
|
8295
|
-
const dirPath =
|
|
8461
|
+
const dirPath = import_path19.default.join(projectsDir, dir);
|
|
8296
8462
|
try {
|
|
8297
|
-
if (!
|
|
8463
|
+
if (!import_fs17.default.statSync(dirPath).isDirectory()) continue;
|
|
8298
8464
|
} catch {
|
|
8299
8465
|
continue;
|
|
8300
8466
|
}
|
|
8301
8467
|
let files;
|
|
8302
8468
|
try {
|
|
8303
|
-
files =
|
|
8469
|
+
files = import_fs17.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
8304
8470
|
} catch {
|
|
8305
8471
|
continue;
|
|
8306
8472
|
}
|
|
8307
8473
|
const fallbackWorkingDir = decodeProjectDirName(dir);
|
|
8308
8474
|
for (const file of files) {
|
|
8309
|
-
const filePath =
|
|
8475
|
+
const filePath = import_path19.default.join(dirPath, file);
|
|
8310
8476
|
if (sinceMs !== void 0) {
|
|
8311
8477
|
try {
|
|
8312
|
-
if (
|
|
8478
|
+
if (import_fs17.default.statSync(filePath).mtimeMs < sinceMs) continue;
|
|
8313
8479
|
} catch {
|
|
8314
8480
|
continue;
|
|
8315
8481
|
}
|
|
@@ -8339,10 +8505,10 @@ async function syncCost() {
|
|
|
8339
8505
|
if (entries.length === 0) return;
|
|
8340
8506
|
let username = "unknown";
|
|
8341
8507
|
try {
|
|
8342
|
-
username =
|
|
8508
|
+
username = import_os16.default.userInfo().username;
|
|
8343
8509
|
} catch {
|
|
8344
8510
|
}
|
|
8345
|
-
const machineId = `${
|
|
8511
|
+
const machineId = `${import_os16.default.hostname()}:${username}`;
|
|
8346
8512
|
try {
|
|
8347
8513
|
const res = await fetch(`${creds.apiUrl}/cost-sync`, {
|
|
8348
8514
|
method: "POST",
|
|
@@ -8351,11 +8517,11 @@ async function syncCost() {
|
|
|
8351
8517
|
signal: AbortSignal.timeout(15e3)
|
|
8352
8518
|
});
|
|
8353
8519
|
if (!res.ok) {
|
|
8354
|
-
|
|
8520
|
+
import_fs17.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
|
|
8355
8521
|
`);
|
|
8356
8522
|
}
|
|
8357
8523
|
} catch (err2) {
|
|
8358
|
-
|
|
8524
|
+
import_fs17.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
|
|
8359
8525
|
`);
|
|
8360
8526
|
}
|
|
8361
8527
|
}
|
|
@@ -8368,13 +8534,13 @@ function startCostSync() {
|
|
|
8368
8534
|
}, SYNC_INTERVAL_MS);
|
|
8369
8535
|
timer.unref();
|
|
8370
8536
|
}
|
|
8371
|
-
var
|
|
8537
|
+
var import_fs17, import_path19, import_os16, SYNC_INTERVAL_MS;
|
|
8372
8538
|
var init_costSync = __esm({
|
|
8373
8539
|
"src/costSync.ts"() {
|
|
8374
8540
|
"use strict";
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8541
|
+
import_fs17 = __toESM(require("fs"));
|
|
8542
|
+
import_path19 = __toESM(require("path"));
|
|
8543
|
+
import_os16 = __toESM(require("os"));
|
|
8378
8544
|
init_config();
|
|
8379
8545
|
init_audit();
|
|
8380
8546
|
init_litellm();
|
|
@@ -8405,7 +8571,7 @@ function freshWatermark() {
|
|
|
8405
8571
|
function loadWatermark() {
|
|
8406
8572
|
let raw;
|
|
8407
8573
|
try {
|
|
8408
|
-
raw =
|
|
8574
|
+
raw = import_fs18.default.readFileSync(WATERMARK_FILE(), "utf-8");
|
|
8409
8575
|
} catch {
|
|
8410
8576
|
return { status: "fresh", wm: freshWatermark() };
|
|
8411
8577
|
}
|
|
@@ -8457,28 +8623,28 @@ function loadWatermark() {
|
|
|
8457
8623
|
function saveWatermark(wm) {
|
|
8458
8624
|
if (wm.schemaVersion > WATERMARK_SCHEMA_VERSION) return;
|
|
8459
8625
|
const target = WATERMARK_FILE();
|
|
8460
|
-
const dir =
|
|
8461
|
-
if (!
|
|
8626
|
+
const dir = import_path20.default.dirname(target);
|
|
8627
|
+
if (!import_fs18.default.existsSync(dir)) import_fs18.default.mkdirSync(dir, { recursive: true });
|
|
8462
8628
|
const tmp = target + ".tmp";
|
|
8463
|
-
|
|
8464
|
-
|
|
8629
|
+
import_fs18.default.writeFileSync(tmp, JSON.stringify(wm, null, 2) + "\n", "utf-8");
|
|
8630
|
+
import_fs18.default.renameSync(tmp, target);
|
|
8465
8631
|
}
|
|
8466
8632
|
function listJsonlFiles() {
|
|
8467
8633
|
const root = PROJECTS_DIR();
|
|
8468
|
-
if (!
|
|
8634
|
+
if (!import_fs18.default.existsSync(root)) return [];
|
|
8469
8635
|
const out = [];
|
|
8470
|
-
for (const entry of
|
|
8636
|
+
for (const entry of import_fs18.default.readdirSync(root, { withFileTypes: true })) {
|
|
8471
8637
|
if (!entry.isDirectory()) continue;
|
|
8472
|
-
const projectDir =
|
|
8638
|
+
const projectDir = import_path20.default.join(root, entry.name);
|
|
8473
8639
|
let inner;
|
|
8474
8640
|
try {
|
|
8475
|
-
inner =
|
|
8641
|
+
inner = import_fs18.default.readdirSync(projectDir, { withFileTypes: true });
|
|
8476
8642
|
} catch {
|
|
8477
8643
|
continue;
|
|
8478
8644
|
}
|
|
8479
8645
|
for (const file of inner) {
|
|
8480
8646
|
if (file.isFile() && file.name.endsWith(".jsonl")) {
|
|
8481
|
-
out.push(
|
|
8647
|
+
out.push(import_path20.default.join(projectDir, file.name));
|
|
8482
8648
|
}
|
|
8483
8649
|
}
|
|
8484
8650
|
}
|
|
@@ -8486,7 +8652,7 @@ function listJsonlFiles() {
|
|
|
8486
8652
|
}
|
|
8487
8653
|
function fileSize(p) {
|
|
8488
8654
|
try {
|
|
8489
|
-
return
|
|
8655
|
+
return import_fs18.default.statSync(p).size;
|
|
8490
8656
|
} catch {
|
|
8491
8657
|
return 0;
|
|
8492
8658
|
}
|
|
@@ -8494,7 +8660,7 @@ function fileSize(p) {
|
|
|
8494
8660
|
async function scanDelta(filePath, fromByte, onLine) {
|
|
8495
8661
|
const size = fileSize(filePath);
|
|
8496
8662
|
if (size <= fromByte) return fromByte;
|
|
8497
|
-
const stream =
|
|
8663
|
+
const stream = import_fs18.default.createReadStream(filePath, {
|
|
8498
8664
|
start: fromByte,
|
|
8499
8665
|
end: size - 1,
|
|
8500
8666
|
highWaterMark: 64 * 1024
|
|
@@ -8606,7 +8772,7 @@ async function tickForensicBroadcast(offsets) {
|
|
|
8606
8772
|
continue;
|
|
8607
8773
|
}
|
|
8608
8774
|
if (size <= offset) continue;
|
|
8609
|
-
const sessionId =
|
|
8775
|
+
const sessionId = import_path20.default.basename(file, ".jsonl");
|
|
8610
8776
|
const newOffset = await scanDelta(file, offset, (obj, lineIndex) => {
|
|
8611
8777
|
out.push(...extractFindingsFromLine(obj, sessionId, lineIndex));
|
|
8612
8778
|
});
|
|
@@ -8665,7 +8831,7 @@ function emptyTick(uploadAs) {
|
|
|
8665
8831
|
function readRawWatermarkPreservingOffsets() {
|
|
8666
8832
|
let raw;
|
|
8667
8833
|
try {
|
|
8668
|
-
raw =
|
|
8834
|
+
raw = import_fs18.default.readFileSync(WATERMARK_FILE(), "utf-8");
|
|
8669
8835
|
} catch {
|
|
8670
8836
|
return null;
|
|
8671
8837
|
}
|
|
@@ -8699,13 +8865,13 @@ async function runActualTick(wm) {
|
|
|
8699
8865
|
if (!known) {
|
|
8700
8866
|
let mtimeMs = 0;
|
|
8701
8867
|
try {
|
|
8702
|
-
mtimeMs =
|
|
8868
|
+
mtimeMs = import_fs18.default.statSync(filePath).mtime.getTime();
|
|
8703
8869
|
} catch {
|
|
8704
8870
|
continue;
|
|
8705
8871
|
}
|
|
8706
8872
|
if (mtimeMs >= watermarkCreatedAt) {
|
|
8707
8873
|
filesNew++;
|
|
8708
|
-
const sessionId2 =
|
|
8874
|
+
const sessionId2 = import_path20.default.basename(filePath, ".jsonl");
|
|
8709
8875
|
const newScannedTo2 = await scanDelta(filePath, 0, (obj, lineIndex) => {
|
|
8710
8876
|
totalToolCalls++;
|
|
8711
8877
|
toolCallsBySession[sessionId2] = (toolCallsBySession[sessionId2] ?? 0) + 1;
|
|
@@ -8723,7 +8889,7 @@ async function runActualTick(wm) {
|
|
|
8723
8889
|
filesSkipped++;
|
|
8724
8890
|
continue;
|
|
8725
8891
|
}
|
|
8726
|
-
const sessionId =
|
|
8892
|
+
const sessionId = import_path20.default.basename(filePath, ".jsonl");
|
|
8727
8893
|
const newScannedTo = await scanDelta(filePath, known.scannedTo, (obj, lineIndex) => {
|
|
8728
8894
|
totalToolCalls++;
|
|
8729
8895
|
toolCallsBySession[sessionId] = (toolCallsBySession[sessionId] ?? 0) + 1;
|
|
@@ -8745,18 +8911,18 @@ async function runActualTick(wm) {
|
|
|
8745
8911
|
schemaFuture: false
|
|
8746
8912
|
};
|
|
8747
8913
|
}
|
|
8748
|
-
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;
|
|
8749
8915
|
var init_scan_watermark = __esm({
|
|
8750
8916
|
"src/daemon/scan-watermark.ts"() {
|
|
8751
8917
|
"use strict";
|
|
8752
|
-
|
|
8753
|
-
|
|
8754
|
-
|
|
8918
|
+
import_fs18 = __toESM(require("fs"));
|
|
8919
|
+
import_os17 = __toESM(require("os"));
|
|
8920
|
+
import_path20 = __toESM(require("path"));
|
|
8755
8921
|
import_readline = __toESM(require("readline"));
|
|
8756
8922
|
init_dlp();
|
|
8757
8923
|
init_dist();
|
|
8758
|
-
PROJECTS_DIR = () =>
|
|
8759
|
-
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");
|
|
8760
8926
|
MAX_LINE_BYTES = 2 * 1024 * 1024;
|
|
8761
8927
|
WATERMARK_SCHEMA_VERSION = 2;
|
|
8762
8928
|
LONG_OUTPUT_THRESHOLD_BYTES2 = LONG_OUTPUT_THRESHOLD_BYTES;
|
|
@@ -8804,40 +8970,40 @@ function parseSinceCutoff(raw, now = /* @__PURE__ */ new Date()) {
|
|
|
8804
8970
|
return now.getTime() - 90 * 864e5;
|
|
8805
8971
|
}
|
|
8806
8972
|
function* iterateJsonlFiles(cutoffMs) {
|
|
8807
|
-
const projectsDir =
|
|
8973
|
+
const projectsDir = import_path21.default.join(import_os18.default.homedir(), ".claude", "projects");
|
|
8808
8974
|
let dirs;
|
|
8809
8975
|
try {
|
|
8810
|
-
dirs =
|
|
8976
|
+
dirs = import_fs19.default.readdirSync(projectsDir);
|
|
8811
8977
|
} catch {
|
|
8812
8978
|
return;
|
|
8813
8979
|
}
|
|
8814
8980
|
for (const dir of dirs) {
|
|
8815
|
-
const dirPath =
|
|
8981
|
+
const dirPath = import_path21.default.join(projectsDir, dir);
|
|
8816
8982
|
let stats;
|
|
8817
8983
|
try {
|
|
8818
|
-
stats =
|
|
8984
|
+
stats = import_fs19.default.statSync(dirPath);
|
|
8819
8985
|
} catch {
|
|
8820
8986
|
continue;
|
|
8821
8987
|
}
|
|
8822
8988
|
if (!stats.isDirectory()) continue;
|
|
8823
8989
|
let files;
|
|
8824
8990
|
try {
|
|
8825
|
-
files =
|
|
8991
|
+
files = import_fs19.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
8826
8992
|
} catch {
|
|
8827
8993
|
continue;
|
|
8828
8994
|
}
|
|
8829
8995
|
for (const file of files) {
|
|
8830
|
-
const filePath =
|
|
8996
|
+
const filePath = import_path21.default.join(dirPath, file);
|
|
8831
8997
|
let mtime = 0;
|
|
8832
8998
|
try {
|
|
8833
|
-
mtime =
|
|
8999
|
+
mtime = import_fs19.default.statSync(filePath).mtimeMs;
|
|
8834
9000
|
} catch {
|
|
8835
9001
|
continue;
|
|
8836
9002
|
}
|
|
8837
9003
|
if (mtime < cutoffMs) continue;
|
|
8838
9004
|
yield {
|
|
8839
9005
|
filePath,
|
|
8840
|
-
sessionId:
|
|
9006
|
+
sessionId: import_path21.default.basename(file, ".jsonl"),
|
|
8841
9007
|
projectDir: dir
|
|
8842
9008
|
};
|
|
8843
9009
|
}
|
|
@@ -8890,7 +9056,7 @@ async function runUploadHistory(opts) {
|
|
|
8890
9056
|
filesScanned++;
|
|
8891
9057
|
let content;
|
|
8892
9058
|
try {
|
|
8893
|
-
content =
|
|
9059
|
+
content = import_fs19.default.readFileSync(filePath, "utf8");
|
|
8894
9060
|
} catch {
|
|
8895
9061
|
continue;
|
|
8896
9062
|
}
|
|
@@ -8976,10 +9142,10 @@ async function runUploadHistory(opts) {
|
|
|
8976
9142
|
const costUrl = creds.apiUrl.endsWith("/policies/sync") ? creds.apiUrl.replace(/\/policies\/sync$/, "/cost-sync") : `${creds.apiUrl.replace(/\/$/, "")}/cost-sync`;
|
|
8977
9143
|
let username = "unknown";
|
|
8978
9144
|
try {
|
|
8979
|
-
username =
|
|
9145
|
+
username = import_os18.default.userInfo().username;
|
|
8980
9146
|
} catch {
|
|
8981
9147
|
}
|
|
8982
|
-
const machineId = `${
|
|
9148
|
+
const machineId = `${import_os18.default.hostname()}:${username}`;
|
|
8983
9149
|
await postJson(costUrl, creds.apiKey, {
|
|
8984
9150
|
machineId,
|
|
8985
9151
|
entries: dailyEntries
|
|
@@ -9029,14 +9195,14 @@ async function postJson(url, apiKey, body) {
|
|
|
9029
9195
|
req.end();
|
|
9030
9196
|
});
|
|
9031
9197
|
}
|
|
9032
|
-
var
|
|
9198
|
+
var import_fs19, import_https, import_os18, import_path21, import_chalk4, FINDING_TO_SIGNAL2;
|
|
9033
9199
|
var init_scan_upload_history = __esm({
|
|
9034
9200
|
"src/scan-upload-history.ts"() {
|
|
9035
9201
|
"use strict";
|
|
9036
|
-
|
|
9202
|
+
import_fs19 = __toESM(require("fs"));
|
|
9037
9203
|
import_https = __toESM(require("https"));
|
|
9038
|
-
|
|
9039
|
-
|
|
9204
|
+
import_os18 = __toESM(require("os"));
|
|
9205
|
+
import_path21 = __toESM(require("path"));
|
|
9040
9206
|
import_chalk4 = __toESM(require("chalk"));
|
|
9041
9207
|
init_dist();
|
|
9042
9208
|
init_config();
|
|
@@ -9282,14 +9448,14 @@ function buildRuleSources() {
|
|
|
9282
9448
|
}
|
|
9283
9449
|
function countScanFiles() {
|
|
9284
9450
|
let total = 0;
|
|
9285
|
-
const claudeDir =
|
|
9286
|
-
if (
|
|
9451
|
+
const claudeDir = import_path22.default.join(import_os19.default.homedir(), ".claude", "projects");
|
|
9452
|
+
if (import_fs20.default.existsSync(claudeDir)) {
|
|
9287
9453
|
try {
|
|
9288
|
-
for (const proj of
|
|
9289
|
-
const p =
|
|
9454
|
+
for (const proj of import_fs20.default.readdirSync(claudeDir)) {
|
|
9455
|
+
const p = import_path22.default.join(claudeDir, proj);
|
|
9290
9456
|
try {
|
|
9291
|
-
if (!
|
|
9292
|
-
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;
|
|
9293
9459
|
} catch {
|
|
9294
9460
|
continue;
|
|
9295
9461
|
}
|
|
@@ -9297,17 +9463,17 @@ function countScanFiles() {
|
|
|
9297
9463
|
} catch {
|
|
9298
9464
|
}
|
|
9299
9465
|
}
|
|
9300
|
-
const geminiDir =
|
|
9301
|
-
if (
|
|
9466
|
+
const geminiDir = import_path22.default.join(import_os19.default.homedir(), ".gemini", "tmp");
|
|
9467
|
+
if (import_fs20.default.existsSync(geminiDir)) {
|
|
9302
9468
|
try {
|
|
9303
|
-
for (const slug of
|
|
9304
|
-
const p =
|
|
9469
|
+
for (const slug of import_fs20.default.readdirSync(geminiDir)) {
|
|
9470
|
+
const p = import_path22.default.join(geminiDir, slug);
|
|
9305
9471
|
try {
|
|
9306
|
-
if (!
|
|
9307
|
-
const chatsDir =
|
|
9308
|
-
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)) {
|
|
9309
9475
|
try {
|
|
9310
|
-
total +=
|
|
9476
|
+
total += import_fs20.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
|
|
9311
9477
|
} catch {
|
|
9312
9478
|
}
|
|
9313
9479
|
}
|
|
@@ -9318,22 +9484,22 @@ function countScanFiles() {
|
|
|
9318
9484
|
} catch {
|
|
9319
9485
|
}
|
|
9320
9486
|
}
|
|
9321
|
-
const codexDir =
|
|
9322
|
-
if (
|
|
9487
|
+
const codexDir = import_path22.default.join(import_os19.default.homedir(), ".codex", "sessions");
|
|
9488
|
+
if (import_fs20.default.existsSync(codexDir)) {
|
|
9323
9489
|
try {
|
|
9324
|
-
for (const year of
|
|
9325
|
-
const yp =
|
|
9490
|
+
for (const year of import_fs20.default.readdirSync(codexDir)) {
|
|
9491
|
+
const yp = import_path22.default.join(codexDir, year);
|
|
9326
9492
|
try {
|
|
9327
|
-
if (!
|
|
9328
|
-
for (const month of
|
|
9329
|
-
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);
|
|
9330
9496
|
try {
|
|
9331
|
-
if (!
|
|
9332
|
-
for (const day of
|
|
9333
|
-
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);
|
|
9334
9500
|
try {
|
|
9335
|
-
if (!
|
|
9336
|
-
total +=
|
|
9501
|
+
if (!import_fs20.default.statSync(dp).isDirectory()) continue;
|
|
9502
|
+
total += import_fs20.default.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
|
|
9337
9503
|
} catch {
|
|
9338
9504
|
continue;
|
|
9339
9505
|
}
|
|
@@ -9369,7 +9535,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
9369
9535
|
const sessionId = file.replace(/\.jsonl$/, "");
|
|
9370
9536
|
let raw;
|
|
9371
9537
|
try {
|
|
9372
|
-
raw =
|
|
9538
|
+
raw = import_fs20.default.readFileSync(import_path22.default.join(projPath, file), "utf-8");
|
|
9373
9539
|
} catch {
|
|
9374
9540
|
return;
|
|
9375
9541
|
}
|
|
@@ -9421,7 +9587,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
9421
9587
|
if (block.type !== "tool_result") continue;
|
|
9422
9588
|
const filePath = block.tool_use_id ? toolUseFilePaths.get(block.tool_use_id) : void 0;
|
|
9423
9589
|
if (filePath) {
|
|
9424
|
-
const ext =
|
|
9590
|
+
const ext = import_path22.default.extname(filePath).toLowerCase();
|
|
9425
9591
|
if (CODE_EXTENSIONS.has(ext)) continue;
|
|
9426
9592
|
}
|
|
9427
9593
|
const resultText = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => c.text ?? "").join("\n") : null;
|
|
@@ -9478,7 +9644,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
9478
9644
|
const rawCmd = String(input.command ?? "").trimStart();
|
|
9479
9645
|
if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd)) continue;
|
|
9480
9646
|
const inputFilePath = typeof input.file_path === "string" ? input.file_path : "";
|
|
9481
|
-
const inputFileExt = inputFilePath ?
|
|
9647
|
+
const inputFileExt = inputFilePath ? import_path22.default.extname(inputFilePath).toLowerCase() : "";
|
|
9482
9648
|
if (CODE_EXTENSIONS.has(inputFileExt)) continue;
|
|
9483
9649
|
const dlpMatch = scanArgs(input);
|
|
9484
9650
|
if (dlpMatch) {
|
|
@@ -9575,19 +9741,19 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
9575
9741
|
}
|
|
9576
9742
|
}
|
|
9577
9743
|
function processClaudeProject(proj, projectsDir, ruleSources, startDate, result, dedup, onProgress, onLine) {
|
|
9578
|
-
const projPath =
|
|
9744
|
+
const projPath = import_path22.default.join(projectsDir, proj);
|
|
9579
9745
|
try {
|
|
9580
|
-
if (!
|
|
9746
|
+
if (!import_fs20.default.statSync(projPath).isDirectory()) return;
|
|
9581
9747
|
} catch {
|
|
9582
9748
|
return;
|
|
9583
9749
|
}
|
|
9584
|
-
const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(
|
|
9750
|
+
const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(import_os19.default.homedir(), "~")).slice(
|
|
9585
9751
|
0,
|
|
9586
9752
|
40
|
|
9587
9753
|
);
|
|
9588
9754
|
let files;
|
|
9589
9755
|
try {
|
|
9590
|
-
files =
|
|
9756
|
+
files = import_fs20.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
9591
9757
|
} catch {
|
|
9592
9758
|
return;
|
|
9593
9759
|
}
|
|
@@ -9621,12 +9787,12 @@ function emptyClaudeScan() {
|
|
|
9621
9787
|
};
|
|
9622
9788
|
}
|
|
9623
9789
|
function scanClaudeHistory(startDate, onProgress, onLine) {
|
|
9624
|
-
const projectsDir =
|
|
9790
|
+
const projectsDir = import_path22.default.join(import_os19.default.homedir(), ".claude", "projects");
|
|
9625
9791
|
const result = emptyClaudeScan();
|
|
9626
|
-
if (!
|
|
9792
|
+
if (!import_fs20.default.existsSync(projectsDir)) return result;
|
|
9627
9793
|
let projDirs;
|
|
9628
9794
|
try {
|
|
9629
|
-
projDirs =
|
|
9795
|
+
projDirs = import_fs20.default.readdirSync(projectsDir);
|
|
9630
9796
|
} catch {
|
|
9631
9797
|
return result;
|
|
9632
9798
|
}
|
|
@@ -9647,7 +9813,7 @@ function scanClaudeHistory(startDate, onProgress, onLine) {
|
|
|
9647
9813
|
return result;
|
|
9648
9814
|
}
|
|
9649
9815
|
function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
9650
|
-
const tmpDir =
|
|
9816
|
+
const tmpDir = import_path22.default.join(import_os19.default.homedir(), ".gemini", "tmp");
|
|
9651
9817
|
const result = {
|
|
9652
9818
|
filesScanned: 0,
|
|
9653
9819
|
sessions: 0,
|
|
@@ -9662,33 +9828,33 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
9662
9828
|
sessionsWithEarlySecrets: 0
|
|
9663
9829
|
};
|
|
9664
9830
|
const dedup = emptyScanDedup();
|
|
9665
|
-
if (!
|
|
9831
|
+
if (!import_fs20.default.existsSync(tmpDir)) return result;
|
|
9666
9832
|
let slugDirs;
|
|
9667
9833
|
try {
|
|
9668
|
-
slugDirs =
|
|
9834
|
+
slugDirs = import_fs20.default.readdirSync(tmpDir);
|
|
9669
9835
|
} catch {
|
|
9670
9836
|
return result;
|
|
9671
9837
|
}
|
|
9672
9838
|
const ruleSources = buildRuleSources();
|
|
9673
9839
|
for (const slug of slugDirs) {
|
|
9674
|
-
const slugPath =
|
|
9840
|
+
const slugPath = import_path22.default.join(tmpDir, slug);
|
|
9675
9841
|
try {
|
|
9676
|
-
if (!
|
|
9842
|
+
if (!import_fs20.default.statSync(slugPath).isDirectory()) continue;
|
|
9677
9843
|
} catch {
|
|
9678
9844
|
continue;
|
|
9679
9845
|
}
|
|
9680
9846
|
let projLabel = stripTerminalEscapes(slug).slice(0, 40);
|
|
9681
9847
|
try {
|
|
9682
9848
|
projLabel = stripTerminalEscapes(
|
|
9683
|
-
|
|
9684
|
-
).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);
|
|
9685
9851
|
} catch {
|
|
9686
9852
|
}
|
|
9687
|
-
const chatsDir =
|
|
9688
|
-
if (!
|
|
9853
|
+
const chatsDir = import_path22.default.join(slugPath, "chats");
|
|
9854
|
+
if (!import_fs20.default.existsSync(chatsDir)) continue;
|
|
9689
9855
|
let chatFiles;
|
|
9690
9856
|
try {
|
|
9691
|
-
chatFiles =
|
|
9857
|
+
chatFiles = import_fs20.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
9692
9858
|
} catch {
|
|
9693
9859
|
continue;
|
|
9694
9860
|
}
|
|
@@ -9698,7 +9864,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
9698
9864
|
const sessionId = chatFile.replace(/\.json$/, "");
|
|
9699
9865
|
let raw;
|
|
9700
9866
|
try {
|
|
9701
|
-
raw =
|
|
9867
|
+
raw = import_fs20.default.readFileSync(import_path22.default.join(chatsDir, chatFile), "utf-8");
|
|
9702
9868
|
} catch {
|
|
9703
9869
|
continue;
|
|
9704
9870
|
}
|
|
@@ -9860,7 +10026,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
9860
10026
|
return result;
|
|
9861
10027
|
}
|
|
9862
10028
|
function scanCodexHistory(startDate, onProgress, onLine) {
|
|
9863
|
-
const sessionsBase =
|
|
10029
|
+
const sessionsBase = import_path22.default.join(import_os19.default.homedir(), ".codex", "sessions");
|
|
9864
10030
|
const result = {
|
|
9865
10031
|
filesScanned: 0,
|
|
9866
10032
|
sessions: 0,
|
|
@@ -9875,32 +10041,32 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
9875
10041
|
sessionsWithEarlySecrets: 0
|
|
9876
10042
|
};
|
|
9877
10043
|
const dedup = emptyScanDedup();
|
|
9878
|
-
if (!
|
|
10044
|
+
if (!import_fs20.default.existsSync(sessionsBase)) return result;
|
|
9879
10045
|
const jsonlFiles = [];
|
|
9880
10046
|
try {
|
|
9881
|
-
for (const year of
|
|
9882
|
-
const yearPath =
|
|
10047
|
+
for (const year of import_fs20.default.readdirSync(sessionsBase)) {
|
|
10048
|
+
const yearPath = import_path22.default.join(sessionsBase, year);
|
|
9883
10049
|
try {
|
|
9884
|
-
if (!
|
|
10050
|
+
if (!import_fs20.default.statSync(yearPath).isDirectory()) continue;
|
|
9885
10051
|
} catch {
|
|
9886
10052
|
continue;
|
|
9887
10053
|
}
|
|
9888
|
-
for (const month of
|
|
9889
|
-
const monthPath =
|
|
10054
|
+
for (const month of import_fs20.default.readdirSync(yearPath)) {
|
|
10055
|
+
const monthPath = import_path22.default.join(yearPath, month);
|
|
9890
10056
|
try {
|
|
9891
|
-
if (!
|
|
10057
|
+
if (!import_fs20.default.statSync(monthPath).isDirectory()) continue;
|
|
9892
10058
|
} catch {
|
|
9893
10059
|
continue;
|
|
9894
10060
|
}
|
|
9895
|
-
for (const day of
|
|
9896
|
-
const dayPath =
|
|
10061
|
+
for (const day of import_fs20.default.readdirSync(monthPath)) {
|
|
10062
|
+
const dayPath = import_path22.default.join(monthPath, day);
|
|
9897
10063
|
try {
|
|
9898
|
-
if (!
|
|
10064
|
+
if (!import_fs20.default.statSync(dayPath).isDirectory()) continue;
|
|
9899
10065
|
} catch {
|
|
9900
10066
|
continue;
|
|
9901
10067
|
}
|
|
9902
|
-
for (const file of
|
|
9903
|
-
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));
|
|
9904
10070
|
}
|
|
9905
10071
|
}
|
|
9906
10072
|
}
|
|
@@ -9914,7 +10080,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
9914
10080
|
onProgress?.(result.filesScanned);
|
|
9915
10081
|
let lines;
|
|
9916
10082
|
try {
|
|
9917
|
-
lines =
|
|
10083
|
+
lines = import_fs20.default.readFileSync(filePath, "utf-8").split("\n");
|
|
9918
10084
|
} catch {
|
|
9919
10085
|
continue;
|
|
9920
10086
|
}
|
|
@@ -9940,7 +10106,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
9940
10106
|
sessionId = String(payload["id"] ?? filePath);
|
|
9941
10107
|
startTime = String(payload["timestamp"] ?? "");
|
|
9942
10108
|
const cwd = String(payload["cwd"] ?? "");
|
|
9943
|
-
projLabel = stripTerminalEscapes(cwd.replace(
|
|
10109
|
+
projLabel = stripTerminalEscapes(cwd.replace(import_os19.default.homedir(), "~")).slice(0, 40);
|
|
9944
10110
|
continue;
|
|
9945
10111
|
}
|
|
9946
10112
|
if (entry.type === "event_msg" && payload["type"] === "token_count") {
|
|
@@ -10093,17 +10259,17 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
10093
10259
|
return result;
|
|
10094
10260
|
}
|
|
10095
10261
|
function scanShellConfig() {
|
|
10096
|
-
const home =
|
|
10262
|
+
const home = import_os19.default.homedir();
|
|
10097
10263
|
const configFiles = [".zshrc", ".bashrc", ".bash_profile", ".profile"].map(
|
|
10098
|
-
(f) =>
|
|
10264
|
+
(f) => import_path22.default.join(home, f)
|
|
10099
10265
|
);
|
|
10100
10266
|
const findings = [];
|
|
10101
10267
|
const seen = /* @__PURE__ */ new Set();
|
|
10102
10268
|
for (const filePath of configFiles) {
|
|
10103
|
-
if (!
|
|
10269
|
+
if (!import_fs20.default.existsSync(filePath)) continue;
|
|
10104
10270
|
let lines;
|
|
10105
10271
|
try {
|
|
10106
|
-
lines =
|
|
10272
|
+
lines = import_fs20.default.readFileSync(filePath, "utf-8").split("\n");
|
|
10107
10273
|
} catch {
|
|
10108
10274
|
continue;
|
|
10109
10275
|
}
|
|
@@ -10817,7 +10983,8 @@ function registerScanCommand(program2) {
|
|
|
10817
10983
|
" node9 is still worth running \u2014 it monitors every tool call in real time.\n"
|
|
10818
10984
|
)
|
|
10819
10985
|
);
|
|
10820
|
-
}
|
|
10986
|
+
}
|
|
10987
|
+
{
|
|
10821
10988
|
const totalRisky = totalFindings + scan.dlpFindings.length;
|
|
10822
10989
|
const score = classifyScore(blast.score);
|
|
10823
10990
|
const severityDisplay = score.band === "critical" ? import_chalk5.default.red.bold(score.label) : score.color(score.label);
|
|
@@ -10883,7 +11050,7 @@ function registerScanCommand(program2) {
|
|
|
10883
11050
|
if (!drillDown) {
|
|
10884
11051
|
const useInk2 = !options.classic;
|
|
10885
11052
|
if (useInk2) {
|
|
10886
|
-
const scanInkPath =
|
|
11053
|
+
const scanInkPath = import_path22.default.join(__dirname, "scan-ink.mjs");
|
|
10887
11054
|
const dynamicImport = new Function("id", "return import(id)");
|
|
10888
11055
|
const mod = await dynamicImport(`file://${scanInkPath}`);
|
|
10889
11056
|
const rangeLabel2 = options.all ? "all time" : `last ${options.days ?? 90} days`;
|
|
@@ -11108,14 +11275,14 @@ function registerScanCommand(program2) {
|
|
|
11108
11275
|
}
|
|
11109
11276
|
);
|
|
11110
11277
|
}
|
|
11111
|
-
var import_chalk5,
|
|
11278
|
+
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;
|
|
11112
11279
|
var init_scan = __esm({
|
|
11113
11280
|
"src/cli/commands/scan.ts"() {
|
|
11114
11281
|
"use strict";
|
|
11115
11282
|
import_chalk5 = __toESM(require("chalk"));
|
|
11116
|
-
|
|
11117
|
-
|
|
11118
|
-
|
|
11283
|
+
import_fs20 = __toESM(require("fs"));
|
|
11284
|
+
import_path22 = __toESM(require("path"));
|
|
11285
|
+
import_os19 = __toESM(require("os"));
|
|
11119
11286
|
init_shields();
|
|
11120
11287
|
init_config();
|
|
11121
11288
|
init_policy();
|
|
@@ -11242,11 +11409,11 @@ function commonPathPrefix(paths) {
|
|
|
11242
11409
|
const prefix = common.join("/").replace(/\/?$/, "/");
|
|
11243
11410
|
return prefix.length > 1 ? prefix : null;
|
|
11244
11411
|
}
|
|
11245
|
-
var
|
|
11412
|
+
var import_crypto6, SuggestionTracker;
|
|
11246
11413
|
var init_suggestion_tracker = __esm({
|
|
11247
11414
|
"src/daemon/suggestion-tracker.ts"() {
|
|
11248
11415
|
"use strict";
|
|
11249
|
-
|
|
11416
|
+
import_crypto6 = require("crypto");
|
|
11250
11417
|
SuggestionTracker = class {
|
|
11251
11418
|
events = /* @__PURE__ */ new Map();
|
|
11252
11419
|
threshold;
|
|
@@ -11292,7 +11459,7 @@ var init_suggestion_tracker = __esm({
|
|
|
11292
11459
|
}
|
|
11293
11460
|
} : { type: "ignoredTool", toolName };
|
|
11294
11461
|
return {
|
|
11295
|
-
id: (0,
|
|
11462
|
+
id: (0, import_crypto6.randomUUID)(),
|
|
11296
11463
|
toolName,
|
|
11297
11464
|
allowCount: events.length,
|
|
11298
11465
|
suggestedRule,
|
|
@@ -11306,12 +11473,12 @@ var init_suggestion_tracker = __esm({
|
|
|
11306
11473
|
});
|
|
11307
11474
|
|
|
11308
11475
|
// src/daemon/taint-store.ts
|
|
11309
|
-
var
|
|
11476
|
+
var import_fs21, import_path23, DEFAULT_TTL_MS, TaintStore;
|
|
11310
11477
|
var init_taint_store = __esm({
|
|
11311
11478
|
"src/daemon/taint-store.ts"() {
|
|
11312
11479
|
"use strict";
|
|
11313
|
-
|
|
11314
|
-
|
|
11480
|
+
import_fs21 = __toESM(require("fs"));
|
|
11481
|
+
import_path23 = __toESM(require("path"));
|
|
11315
11482
|
DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
11316
11483
|
TaintStore = class {
|
|
11317
11484
|
records = /* @__PURE__ */ new Map();
|
|
@@ -11376,9 +11543,9 @@ var init_taint_store = __esm({
|
|
|
11376
11543
|
/** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
|
|
11377
11544
|
_resolve(filePath) {
|
|
11378
11545
|
try {
|
|
11379
|
-
return
|
|
11546
|
+
return import_fs21.default.realpathSync.native(import_path23.default.resolve(filePath));
|
|
11380
11547
|
} catch {
|
|
11381
|
-
return
|
|
11548
|
+
return import_path23.default.resolve(filePath);
|
|
11382
11549
|
}
|
|
11383
11550
|
}
|
|
11384
11551
|
};
|
|
@@ -11496,8 +11663,8 @@ var init_session_history = __esm({
|
|
|
11496
11663
|
// src/daemon/state.ts
|
|
11497
11664
|
function loadInsightCounts() {
|
|
11498
11665
|
try {
|
|
11499
|
-
if (!
|
|
11500
|
-
const data = JSON.parse(
|
|
11666
|
+
if (!import_fs22.default.existsSync(INSIGHT_COUNTS_FILE)) return;
|
|
11667
|
+
const data = JSON.parse(import_fs22.default.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
|
|
11501
11668
|
for (const [tool, count] of Object.entries(data)) {
|
|
11502
11669
|
if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
|
|
11503
11670
|
}
|
|
@@ -11536,23 +11703,23 @@ function markRejectionHandlerRegistered() {
|
|
|
11536
11703
|
daemonRejectionHandlerRegistered = true;
|
|
11537
11704
|
}
|
|
11538
11705
|
function atomicWriteSync2(filePath, data, options) {
|
|
11539
|
-
const dir =
|
|
11540
|
-
if (!
|
|
11541
|
-
const tmpPath = `${filePath}.${(0,
|
|
11706
|
+
const dir = import_path24.default.dirname(filePath);
|
|
11707
|
+
if (!import_fs22.default.existsSync(dir)) import_fs22.default.mkdirSync(dir, { recursive: true });
|
|
11708
|
+
const tmpPath = `${filePath}.${(0, import_crypto7.randomUUID)()}.tmp`;
|
|
11542
11709
|
try {
|
|
11543
|
-
|
|
11710
|
+
import_fs22.default.writeFileSync(tmpPath, data, options);
|
|
11544
11711
|
} catch (err2) {
|
|
11545
11712
|
try {
|
|
11546
|
-
|
|
11713
|
+
import_fs22.default.unlinkSync(tmpPath);
|
|
11547
11714
|
} catch {
|
|
11548
11715
|
}
|
|
11549
11716
|
throw err2;
|
|
11550
11717
|
}
|
|
11551
11718
|
try {
|
|
11552
|
-
|
|
11719
|
+
import_fs22.default.renameSync(tmpPath, filePath);
|
|
11553
11720
|
} catch (err2) {
|
|
11554
11721
|
try {
|
|
11555
|
-
|
|
11722
|
+
import_fs22.default.unlinkSync(tmpPath);
|
|
11556
11723
|
} catch {
|
|
11557
11724
|
}
|
|
11558
11725
|
throw err2;
|
|
@@ -11576,16 +11743,16 @@ function appendAuditLog(data) {
|
|
|
11576
11743
|
decision: data.decision,
|
|
11577
11744
|
source: "daemon"
|
|
11578
11745
|
};
|
|
11579
|
-
const dir =
|
|
11580
|
-
if (!
|
|
11581
|
-
|
|
11746
|
+
const dir = import_path24.default.dirname(AUDIT_LOG_FILE);
|
|
11747
|
+
if (!import_fs22.default.existsSync(dir)) import_fs22.default.mkdirSync(dir, { recursive: true });
|
|
11748
|
+
import_fs22.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
11582
11749
|
} catch {
|
|
11583
11750
|
}
|
|
11584
11751
|
}
|
|
11585
11752
|
function getAuditHistory(limit = 20) {
|
|
11586
11753
|
try {
|
|
11587
|
-
if (!
|
|
11588
|
-
const lines =
|
|
11754
|
+
if (!import_fs22.default.existsSync(AUDIT_LOG_FILE)) return [];
|
|
11755
|
+
const lines = import_fs22.default.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
|
|
11589
11756
|
if (lines.length === 1 && lines[0] === "") return [];
|
|
11590
11757
|
return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
|
|
11591
11758
|
} catch {
|
|
@@ -11594,7 +11761,7 @@ function getAuditHistory(limit = 20) {
|
|
|
11594
11761
|
}
|
|
11595
11762
|
function getOrgName() {
|
|
11596
11763
|
try {
|
|
11597
|
-
if (
|
|
11764
|
+
if (import_fs22.default.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
|
|
11598
11765
|
} catch {
|
|
11599
11766
|
}
|
|
11600
11767
|
return null;
|
|
@@ -11602,8 +11769,8 @@ function getOrgName() {
|
|
|
11602
11769
|
function writeGlobalSetting(key, value) {
|
|
11603
11770
|
let config = {};
|
|
11604
11771
|
try {
|
|
11605
|
-
if (
|
|
11606
|
-
config = JSON.parse(
|
|
11772
|
+
if (import_fs22.default.existsSync(GLOBAL_CONFIG_FILE)) {
|
|
11773
|
+
config = JSON.parse(import_fs22.default.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
|
|
11607
11774
|
}
|
|
11608
11775
|
} catch {
|
|
11609
11776
|
}
|
|
@@ -11615,8 +11782,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
11615
11782
|
try {
|
|
11616
11783
|
let trust = { entries: [] };
|
|
11617
11784
|
try {
|
|
11618
|
-
if (
|
|
11619
|
-
trust = JSON.parse(
|
|
11785
|
+
if (import_fs22.default.existsSync(TRUST_FILE2))
|
|
11786
|
+
trust = JSON.parse(import_fs22.default.readFileSync(TRUST_FILE2, "utf-8"));
|
|
11620
11787
|
} catch {
|
|
11621
11788
|
}
|
|
11622
11789
|
trust.entries = trust.entries.filter(
|
|
@@ -11633,8 +11800,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
11633
11800
|
}
|
|
11634
11801
|
function readPersistentDecisions() {
|
|
11635
11802
|
try {
|
|
11636
|
-
if (
|
|
11637
|
-
return JSON.parse(
|
|
11803
|
+
if (import_fs22.default.existsSync(DECISIONS_FILE)) {
|
|
11804
|
+
return JSON.parse(import_fs22.default.readFileSync(DECISIONS_FILE, "utf-8"));
|
|
11638
11805
|
}
|
|
11639
11806
|
} catch {
|
|
11640
11807
|
}
|
|
@@ -11662,7 +11829,7 @@ function estimateToolCost(tool, args) {
|
|
|
11662
11829
|
const filePath = a.file_path ?? a.path;
|
|
11663
11830
|
if (filePath) {
|
|
11664
11831
|
try {
|
|
11665
|
-
const bytes =
|
|
11832
|
+
const bytes = import_fs22.default.statSync(filePath).size;
|
|
11666
11833
|
return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
|
|
11667
11834
|
} catch {
|
|
11668
11835
|
}
|
|
@@ -11713,7 +11880,7 @@ function broadcastForensic(finding) {
|
|
|
11713
11880
|
const severity = CRITICAL_FORENSIC_CATEGORIES.has(finding.type) ? "critical" : "warning";
|
|
11714
11881
|
const event = {
|
|
11715
11882
|
type: "forensic",
|
|
11716
|
-
id: `fnd_${(0,
|
|
11883
|
+
id: `fnd_${(0, import_crypto7.randomUUID)()}`,
|
|
11717
11884
|
ts: Date.now(),
|
|
11718
11885
|
sessionId: finding.sessionId,
|
|
11719
11886
|
category: finding.type,
|
|
@@ -11733,7 +11900,7 @@ function abandonPending() {
|
|
|
11733
11900
|
});
|
|
11734
11901
|
if (autoStarted) {
|
|
11735
11902
|
try {
|
|
11736
|
-
|
|
11903
|
+
import_fs22.default.unlinkSync(DAEMON_PID_FILE);
|
|
11737
11904
|
} catch {
|
|
11738
11905
|
}
|
|
11739
11906
|
setTimeout(() => {
|
|
@@ -11744,8 +11911,8 @@ function abandonPending() {
|
|
|
11744
11911
|
}
|
|
11745
11912
|
function logActivitySocket(msg) {
|
|
11746
11913
|
try {
|
|
11747
|
-
|
|
11748
|
-
|
|
11914
|
+
import_fs22.default.appendFileSync(
|
|
11915
|
+
import_path24.default.join(homeDir, ".node9", "hook-debug.log"),
|
|
11749
11916
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] [activity-socket] ${msg}
|
|
11750
11917
|
`
|
|
11751
11918
|
);
|
|
@@ -11767,13 +11934,13 @@ function shouldRebind(now = Date.now()) {
|
|
|
11767
11934
|
function startActivitySocket() {
|
|
11768
11935
|
bindActivitySocket();
|
|
11769
11936
|
activityHealthInterval = setInterval(() => {
|
|
11770
|
-
if (!
|
|
11937
|
+
if (!import_fs22.default.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
|
|
11771
11938
|
}, ACTIVITY_HEALTH_PROBE_MS);
|
|
11772
11939
|
activityHealthInterval.unref();
|
|
11773
11940
|
process.on("exit", () => {
|
|
11774
11941
|
if (activityHealthInterval) clearInterval(activityHealthInterval);
|
|
11775
11942
|
try {
|
|
11776
|
-
|
|
11943
|
+
import_fs22.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
11777
11944
|
} catch {
|
|
11778
11945
|
}
|
|
11779
11946
|
});
|
|
@@ -11801,7 +11968,7 @@ function attemptRebind(reason) {
|
|
|
11801
11968
|
}
|
|
11802
11969
|
function bindActivitySocket() {
|
|
11803
11970
|
try {
|
|
11804
|
-
|
|
11971
|
+
import_fs22.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
11805
11972
|
} catch {
|
|
11806
11973
|
}
|
|
11807
11974
|
const ACTIVITY_MAX_BYTES = 1024 * 1024;
|
|
@@ -11905,28 +12072,28 @@ function bindActivitySocket() {
|
|
|
11905
12072
|
});
|
|
11906
12073
|
activitySocketServer = unixServer;
|
|
11907
12074
|
}
|
|
11908
|
-
var import_net2,
|
|
12075
|
+
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;
|
|
11909
12076
|
var init_state2 = __esm({
|
|
11910
12077
|
"src/daemon/state.ts"() {
|
|
11911
12078
|
"use strict";
|
|
11912
12079
|
import_net2 = __toESM(require("net"));
|
|
11913
|
-
|
|
11914
|
-
|
|
11915
|
-
|
|
11916
|
-
|
|
12080
|
+
import_fs22 = __toESM(require("fs"));
|
|
12081
|
+
import_path24 = __toESM(require("path"));
|
|
12082
|
+
import_os20 = __toESM(require("os"));
|
|
12083
|
+
import_crypto7 = require("crypto");
|
|
11917
12084
|
init_daemon();
|
|
11918
12085
|
init_suggestion_tracker();
|
|
11919
12086
|
init_taint_store();
|
|
11920
12087
|
init_session_counters();
|
|
11921
12088
|
init_session_history();
|
|
11922
|
-
homeDir =
|
|
11923
|
-
DAEMON_PID_FILE =
|
|
11924
|
-
DECISIONS_FILE =
|
|
11925
|
-
AUDIT_LOG_FILE =
|
|
11926
|
-
TRUST_FILE2 =
|
|
11927
|
-
GLOBAL_CONFIG_FILE =
|
|
11928
|
-
CREDENTIALS_FILE =
|
|
11929
|
-
INSIGHT_COUNTS_FILE =
|
|
12089
|
+
homeDir = import_os20.default.homedir();
|
|
12090
|
+
DAEMON_PID_FILE = import_path24.default.join(homeDir, ".node9", "daemon.pid");
|
|
12091
|
+
DECISIONS_FILE = import_path24.default.join(homeDir, ".node9", "decisions.json");
|
|
12092
|
+
AUDIT_LOG_FILE = import_path24.default.join(homeDir, ".node9", "audit.log");
|
|
12093
|
+
TRUST_FILE2 = import_path24.default.join(homeDir, ".node9", "trust.json");
|
|
12094
|
+
GLOBAL_CONFIG_FILE = import_path24.default.join(homeDir, ".node9", "config.json");
|
|
12095
|
+
CREDENTIALS_FILE = import_path24.default.join(homeDir, ".node9", "credentials.json");
|
|
12096
|
+
INSIGHT_COUNTS_FILE = import_path24.default.join(homeDir, ".node9", "insight-counts.json");
|
|
11930
12097
|
pending = /* @__PURE__ */ new Map();
|
|
11931
12098
|
sseClients = /* @__PURE__ */ new Set();
|
|
11932
12099
|
suggestionTracker = new SuggestionTracker(3);
|
|
@@ -11943,7 +12110,7 @@ var init_state2 = __esm({
|
|
|
11943
12110
|
"2h": 2 * 60 * 6e4
|
|
11944
12111
|
};
|
|
11945
12112
|
autoStarted = process.env.NODE9_AUTO_STARTED === "1";
|
|
11946
|
-
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
12113
|
+
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path24.default.join(import_os20.default.tmpdir(), "node9-activity.sock");
|
|
11947
12114
|
ACTIVITY_RING_SIZE = 100;
|
|
11948
12115
|
activityRing = [];
|
|
11949
12116
|
LARGE_RESPONSE_RING_SIZE = 20;
|
|
@@ -12021,8 +12188,8 @@ function readCredentials() {
|
|
|
12021
12188
|
};
|
|
12022
12189
|
}
|
|
12023
12190
|
try {
|
|
12024
|
-
const credPath =
|
|
12025
|
-
const creds = JSON.parse(
|
|
12191
|
+
const credPath = import_path25.default.join(import_os21.default.homedir(), ".node9", "credentials.json");
|
|
12192
|
+
const creds = JSON.parse(import_fs23.default.readFileSync(credPath, "utf-8"));
|
|
12026
12193
|
const profileName = process.env.NODE9_PROFILE ?? "default";
|
|
12027
12194
|
const profile = creds[profileName];
|
|
12028
12195
|
if (typeof profile?.apiKey === "string" && profile.apiKey.length > 0) {
|
|
@@ -12048,7 +12215,7 @@ function readCredentials() {
|
|
|
12048
12215
|
}
|
|
12049
12216
|
function readCachedEtag() {
|
|
12050
12217
|
try {
|
|
12051
|
-
const raw = JSON.parse(
|
|
12218
|
+
const raw = JSON.parse(import_fs23.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
12052
12219
|
return typeof raw.etag === "string" ? raw.etag : void 0;
|
|
12053
12220
|
} catch {
|
|
12054
12221
|
return void 0;
|
|
@@ -12109,9 +12276,9 @@ function extractRules(body) {
|
|
|
12109
12276
|
return [];
|
|
12110
12277
|
}
|
|
12111
12278
|
function writeCache2(cache) {
|
|
12112
|
-
const dir =
|
|
12113
|
-
if (!
|
|
12114
|
-
|
|
12279
|
+
const dir = import_path25.default.dirname(rulesCacheFile());
|
|
12280
|
+
if (!import_fs23.default.existsSync(dir)) import_fs23.default.mkdirSync(dir, { recursive: true });
|
|
12281
|
+
import_fs23.default.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
|
|
12115
12282
|
}
|
|
12116
12283
|
async function syncOnce() {
|
|
12117
12284
|
const creds = readCredentials();
|
|
@@ -12268,7 +12435,7 @@ async function runCloudSync() {
|
|
|
12268
12435
|
}
|
|
12269
12436
|
function getCloudSyncStatus() {
|
|
12270
12437
|
try {
|
|
12271
|
-
const raw = JSON.parse(
|
|
12438
|
+
const raw = JSON.parse(import_fs23.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
12272
12439
|
if (!Array.isArray(raw.rules) || typeof raw.fetchedAt !== "string") return { cached: false };
|
|
12273
12440
|
return {
|
|
12274
12441
|
cached: true,
|
|
@@ -12285,7 +12452,7 @@ function getCloudSyncStatus() {
|
|
|
12285
12452
|
}
|
|
12286
12453
|
function getCloudRules() {
|
|
12287
12454
|
try {
|
|
12288
|
-
const raw = JSON.parse(
|
|
12455
|
+
const raw = JSON.parse(import_fs23.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
12289
12456
|
return Array.isArray(raw.rules) ? raw.rules : null;
|
|
12290
12457
|
} catch {
|
|
12291
12458
|
return null;
|
|
@@ -12319,14 +12486,14 @@ function startForensicBroadcast() {
|
|
|
12319
12486
|
const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
|
|
12320
12487
|
recurring.unref();
|
|
12321
12488
|
}
|
|
12322
|
-
var
|
|
12489
|
+
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;
|
|
12323
12490
|
var init_sync = __esm({
|
|
12324
12491
|
"src/daemon/sync.ts"() {
|
|
12325
12492
|
"use strict";
|
|
12326
|
-
|
|
12493
|
+
import_fs23 = __toESM(require("fs"));
|
|
12327
12494
|
import_https2 = __toESM(require("https"));
|
|
12328
|
-
|
|
12329
|
-
|
|
12495
|
+
import_os21 = __toESM(require("os"));
|
|
12496
|
+
import_path25 = __toESM(require("path"));
|
|
12330
12497
|
init_config();
|
|
12331
12498
|
init_blast();
|
|
12332
12499
|
init_dist();
|
|
@@ -12345,7 +12512,7 @@ var init_sync = __esm({
|
|
|
12345
12512
|
loop: "loops",
|
|
12346
12513
|
"long-output-redacted": "longOutputRedactions"
|
|
12347
12514
|
};
|
|
12348
|
-
rulesCacheFile = () =>
|
|
12515
|
+
rulesCacheFile = () => import_path25.default.join(import_os21.default.homedir(), ".node9", "rules-cache.json");
|
|
12349
12516
|
DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept/policies/sync";
|
|
12350
12517
|
DEFAULT_INTERVAL_HOURS = 5;
|
|
12351
12518
|
MIN_INTERVAL_HOURS = 1;
|
|
@@ -12358,68 +12525,68 @@ var init_sync = __esm({
|
|
|
12358
12525
|
// src/daemon/dlp-scanner.ts
|
|
12359
12526
|
function loadIndex() {
|
|
12360
12527
|
try {
|
|
12361
|
-
return JSON.parse(
|
|
12528
|
+
return JSON.parse(import_fs24.default.readFileSync(INDEX_FILE, "utf-8"));
|
|
12362
12529
|
} catch {
|
|
12363
12530
|
return {};
|
|
12364
12531
|
}
|
|
12365
12532
|
}
|
|
12366
12533
|
function saveIndex(index) {
|
|
12367
12534
|
try {
|
|
12368
|
-
|
|
12535
|
+
import_fs24.default.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
|
|
12369
12536
|
} catch {
|
|
12370
12537
|
}
|
|
12371
12538
|
}
|
|
12372
12539
|
function appendAuditEntry(entry) {
|
|
12373
12540
|
try {
|
|
12374
|
-
|
|
12541
|
+
import_fs24.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
12375
12542
|
} catch {
|
|
12376
12543
|
}
|
|
12377
12544
|
}
|
|
12378
12545
|
function runDlpScan() {
|
|
12379
|
-
if (!
|
|
12546
|
+
if (!import_fs24.default.existsSync(PROJECTS_DIR2)) return;
|
|
12380
12547
|
const index = loadIndex();
|
|
12381
12548
|
let updated = false;
|
|
12382
12549
|
let projDirs;
|
|
12383
12550
|
try {
|
|
12384
|
-
projDirs =
|
|
12551
|
+
projDirs = import_fs24.default.readdirSync(PROJECTS_DIR2);
|
|
12385
12552
|
} catch {
|
|
12386
12553
|
return;
|
|
12387
12554
|
}
|
|
12388
12555
|
for (const proj of projDirs) {
|
|
12389
|
-
const projPath =
|
|
12556
|
+
const projPath = import_path26.default.join(PROJECTS_DIR2, proj);
|
|
12390
12557
|
try {
|
|
12391
|
-
if (!
|
|
12392
|
-
const real =
|
|
12393
|
-
if (!real.startsWith(PROJECTS_DIR2 +
|
|
12558
|
+
if (!import_fs24.default.lstatSync(projPath).isDirectory()) continue;
|
|
12559
|
+
const real = import_fs24.default.realpathSync(projPath);
|
|
12560
|
+
if (!real.startsWith(PROJECTS_DIR2 + import_path26.default.sep) && real !== PROJECTS_DIR2) continue;
|
|
12394
12561
|
} catch {
|
|
12395
12562
|
continue;
|
|
12396
12563
|
}
|
|
12397
12564
|
let files;
|
|
12398
12565
|
try {
|
|
12399
|
-
files =
|
|
12566
|
+
files = import_fs24.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
12400
12567
|
} catch {
|
|
12401
12568
|
continue;
|
|
12402
12569
|
}
|
|
12403
12570
|
for (const file of files) {
|
|
12404
|
-
const filePath =
|
|
12571
|
+
const filePath = import_path26.default.join(projPath, file);
|
|
12405
12572
|
const lastOffset = index[filePath] ?? 0;
|
|
12406
12573
|
let size;
|
|
12407
12574
|
try {
|
|
12408
|
-
size =
|
|
12575
|
+
size = import_fs24.default.statSync(filePath).size;
|
|
12409
12576
|
} catch {
|
|
12410
12577
|
continue;
|
|
12411
12578
|
}
|
|
12412
12579
|
if (size <= lastOffset) continue;
|
|
12413
12580
|
let fd;
|
|
12414
12581
|
try {
|
|
12415
|
-
fd =
|
|
12582
|
+
fd = import_fs24.default.openSync(filePath, "r");
|
|
12416
12583
|
} catch {
|
|
12417
12584
|
continue;
|
|
12418
12585
|
}
|
|
12419
12586
|
try {
|
|
12420
12587
|
const chunkSize = size - lastOffset;
|
|
12421
12588
|
const buf = Buffer.alloc(chunkSize);
|
|
12422
|
-
|
|
12589
|
+
import_fs24.default.readSync(fd, buf, 0, chunkSize, lastOffset);
|
|
12423
12590
|
const chunk = buf.toString("utf-8");
|
|
12424
12591
|
for (const line of chunk.split("\n")) {
|
|
12425
12592
|
if (!line.trim()) continue;
|
|
@@ -12439,7 +12606,7 @@ function runDlpScan() {
|
|
|
12439
12606
|
if (typeof text !== "string") continue;
|
|
12440
12607
|
const match = scanText(text);
|
|
12441
12608
|
if (!match) continue;
|
|
12442
|
-
const projLabel = decodeURIComponent(proj).replace(
|
|
12609
|
+
const projLabel = decodeURIComponent(proj).replace(import_os22.default.homedir(), "~").slice(0, 40);
|
|
12443
12610
|
const ts = entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
12444
12611
|
appendAuditEntry({
|
|
12445
12612
|
ts,
|
|
@@ -12464,7 +12631,7 @@ Run: node9 report --period 30d`
|
|
|
12464
12631
|
updated = true;
|
|
12465
12632
|
} finally {
|
|
12466
12633
|
try {
|
|
12467
|
-
|
|
12634
|
+
import_fs24.default.closeSync(fd);
|
|
12468
12635
|
} catch {
|
|
12469
12636
|
}
|
|
12470
12637
|
}
|
|
@@ -12490,30 +12657,30 @@ function startDlpScanner() {
|
|
|
12490
12657
|
);
|
|
12491
12658
|
timer.unref();
|
|
12492
12659
|
}
|
|
12493
|
-
var
|
|
12660
|
+
var import_fs24, import_path26, import_os22, INDEX_FILE, PROJECTS_DIR2;
|
|
12494
12661
|
var init_dlp_scanner = __esm({
|
|
12495
12662
|
"src/daemon/dlp-scanner.ts"() {
|
|
12496
12663
|
"use strict";
|
|
12497
|
-
|
|
12498
|
-
|
|
12499
|
-
|
|
12664
|
+
import_fs24 = __toESM(require("fs"));
|
|
12665
|
+
import_path26 = __toESM(require("path"));
|
|
12666
|
+
import_os22 = __toESM(require("os"));
|
|
12500
12667
|
init_dlp();
|
|
12501
12668
|
init_native();
|
|
12502
12669
|
init_state2();
|
|
12503
|
-
INDEX_FILE =
|
|
12504
|
-
PROJECTS_DIR2 =
|
|
12670
|
+
INDEX_FILE = import_path26.default.join(import_os22.default.homedir(), ".node9", "dlp-index.json");
|
|
12671
|
+
PROJECTS_DIR2 = import_path26.default.join(import_os22.default.homedir(), ".claude", "projects");
|
|
12505
12672
|
}
|
|
12506
12673
|
});
|
|
12507
12674
|
|
|
12508
12675
|
// src/daemon/mcp-tools.ts
|
|
12509
12676
|
function getMcpToolsFile() {
|
|
12510
|
-
return
|
|
12677
|
+
return import_path27.default.join(import_os23.default.homedir(), ".node9", "mcp-tools.json");
|
|
12511
12678
|
}
|
|
12512
12679
|
function readMcpToolsConfig() {
|
|
12513
12680
|
try {
|
|
12514
12681
|
const file = getMcpToolsFile();
|
|
12515
|
-
if (!
|
|
12516
|
-
const raw =
|
|
12682
|
+
if (!import_fs25.default.existsSync(file)) return {};
|
|
12683
|
+
const raw = import_fs25.default.readFileSync(file, "utf-8");
|
|
12517
12684
|
return JSON.parse(raw);
|
|
12518
12685
|
} catch {
|
|
12519
12686
|
return {};
|
|
@@ -12522,11 +12689,11 @@ function readMcpToolsConfig() {
|
|
|
12522
12689
|
function writeMcpToolsConfig(config) {
|
|
12523
12690
|
try {
|
|
12524
12691
|
const file = getMcpToolsFile();
|
|
12525
|
-
const dir =
|
|
12526
|
-
if (!
|
|
12527
|
-
const tmpPath = `${file}.${
|
|
12528
|
-
|
|
12529
|
-
|
|
12692
|
+
const dir = import_path27.default.dirname(file);
|
|
12693
|
+
if (!import_fs25.default.existsSync(dir)) import_fs25.default.mkdirSync(dir, { recursive: true });
|
|
12694
|
+
const tmpPath = `${file}.${import_os23.default.hostname()}.${process.pid}.tmp`;
|
|
12695
|
+
import_fs25.default.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
|
|
12696
|
+
import_fs25.default.renameSync(tmpPath, file);
|
|
12530
12697
|
} catch (e) {
|
|
12531
12698
|
console.error("Failed to write mcp-tools.json", e);
|
|
12532
12699
|
}
|
|
@@ -12565,13 +12732,13 @@ function approveServer(serverKey, disabledTools) {
|
|
|
12565
12732
|
writeMcpToolsConfig(config);
|
|
12566
12733
|
}
|
|
12567
12734
|
}
|
|
12568
|
-
var
|
|
12735
|
+
var import_fs25, import_path27, import_os23;
|
|
12569
12736
|
var init_mcp_tools = __esm({
|
|
12570
12737
|
"src/daemon/mcp-tools.ts"() {
|
|
12571
12738
|
"use strict";
|
|
12572
|
-
|
|
12573
|
-
|
|
12574
|
-
|
|
12739
|
+
import_fs25 = __toESM(require("fs"));
|
|
12740
|
+
import_path27 = __toESM(require("path"));
|
|
12741
|
+
import_os23 = __toESM(require("os"));
|
|
12575
12742
|
}
|
|
12576
12743
|
});
|
|
12577
12744
|
|
|
@@ -12582,7 +12749,7 @@ function startDaemon() {
|
|
|
12582
12749
|
startForensicBroadcast();
|
|
12583
12750
|
startDlpScanner();
|
|
12584
12751
|
loadInsightCounts();
|
|
12585
|
-
const internalToken = (0,
|
|
12752
|
+
const internalToken = (0, import_crypto8.randomUUID)();
|
|
12586
12753
|
const validToken = (req) => req.headers["x-node9-internal"] === internalToken || req.headers["x-node9-token"] === internalToken;
|
|
12587
12754
|
const IDLE_TIMEOUT_MS = 12 * 60 * 60 * 1e3;
|
|
12588
12755
|
const watchMode = process.env.NODE9_WATCH_MODE === "1";
|
|
@@ -12593,7 +12760,7 @@ function startDaemon() {
|
|
|
12593
12760
|
idleTimer = setTimeout(() => {
|
|
12594
12761
|
if (autoStarted) {
|
|
12595
12762
|
try {
|
|
12596
|
-
|
|
12763
|
+
import_fs26.default.unlinkSync(DAEMON_PID_FILE);
|
|
12597
12764
|
} catch {
|
|
12598
12765
|
}
|
|
12599
12766
|
}
|
|
@@ -12694,7 +12861,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
12694
12861
|
cwd,
|
|
12695
12862
|
localSmartRuleMatched = false
|
|
12696
12863
|
} = JSON.parse(body);
|
|
12697
|
-
const id = fromCLI && typeof activityId === "string" && activityId || (0,
|
|
12864
|
+
const id = fromCLI && typeof activityId === "string" && activityId || (0, import_crypto8.randomUUID)();
|
|
12698
12865
|
const entry = {
|
|
12699
12866
|
id,
|
|
12700
12867
|
toolName,
|
|
@@ -12738,7 +12905,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
12738
12905
|
mcpServer: entry.mcpServer
|
|
12739
12906
|
});
|
|
12740
12907
|
}
|
|
12741
|
-
const projectCwd = typeof cwd === "string" &&
|
|
12908
|
+
const projectCwd = typeof cwd === "string" && import_path28.default.isAbsolute(cwd) ? cwd : void 0;
|
|
12742
12909
|
const projectConfig = getConfig(projectCwd);
|
|
12743
12910
|
const browserEnabled = projectConfig.settings.approvers?.browser !== false;
|
|
12744
12911
|
const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
|
|
@@ -13030,8 +13197,8 @@ data: ${JSON.stringify(item.data)}
|
|
|
13030
13197
|
if (!validToken(req)) return res.writeHead(403).end();
|
|
13031
13198
|
const periodParam = reqUrl.searchParams.get("period") || "7d";
|
|
13032
13199
|
const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
|
|
13033
|
-
const logPath =
|
|
13034
|
-
if (!
|
|
13200
|
+
const logPath = import_path28.default.join(import_os24.default.homedir(), ".node9", "audit.log");
|
|
13201
|
+
if (!import_fs26.default.existsSync(logPath)) {
|
|
13035
13202
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
13036
13203
|
return res.end(
|
|
13037
13204
|
JSON.stringify({
|
|
@@ -13044,7 +13211,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
13044
13211
|
);
|
|
13045
13212
|
}
|
|
13046
13213
|
try {
|
|
13047
|
-
const raw =
|
|
13214
|
+
const raw = import_fs26.default.readFileSync(logPath, "utf-8");
|
|
13048
13215
|
const allEntries = raw.split("\n").flatMap((line) => {
|
|
13049
13216
|
if (!line.trim()) return [];
|
|
13050
13217
|
try {
|
|
@@ -13279,7 +13446,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
13279
13446
|
args: { toolCount: tools.length, status },
|
|
13280
13447
|
decision: "mcp-discovered"
|
|
13281
13448
|
});
|
|
13282
|
-
const id = (0,
|
|
13449
|
+
const id = (0, import_crypto8.randomUUID)();
|
|
13283
13450
|
const entry = {
|
|
13284
13451
|
id,
|
|
13285
13452
|
type: "mcp-discovery",
|
|
@@ -13367,14 +13534,14 @@ data: ${JSON.stringify(item.data)}
|
|
|
13367
13534
|
server.on("error", (e) => {
|
|
13368
13535
|
if (e.code === "EADDRINUSE") {
|
|
13369
13536
|
try {
|
|
13370
|
-
if (
|
|
13371
|
-
const { pid } = JSON.parse(
|
|
13537
|
+
if (import_fs26.default.existsSync(DAEMON_PID_FILE)) {
|
|
13538
|
+
const { pid } = JSON.parse(import_fs26.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
13372
13539
|
process.kill(pid, 0);
|
|
13373
13540
|
return process.exit(0);
|
|
13374
13541
|
}
|
|
13375
13542
|
} catch {
|
|
13376
13543
|
try {
|
|
13377
|
-
|
|
13544
|
+
import_fs26.default.unlinkSync(DAEMON_PID_FILE);
|
|
13378
13545
|
} catch {
|
|
13379
13546
|
}
|
|
13380
13547
|
server.listen(DAEMON_PORT, DAEMON_HOST);
|
|
@@ -13446,15 +13613,15 @@ data: ${JSON.stringify(item.data)}
|
|
|
13446
13613
|
}
|
|
13447
13614
|
startActivitySocket();
|
|
13448
13615
|
}
|
|
13449
|
-
var import_http,
|
|
13616
|
+
var import_http, import_fs26, import_path28, import_os24, import_crypto8, import_child_process2, import_chalk6;
|
|
13450
13617
|
var init_server = __esm({
|
|
13451
13618
|
"src/daemon/server.ts"() {
|
|
13452
13619
|
"use strict";
|
|
13453
13620
|
import_http = __toESM(require("http"));
|
|
13454
|
-
|
|
13455
|
-
|
|
13456
|
-
|
|
13457
|
-
|
|
13621
|
+
import_fs26 = __toESM(require("fs"));
|
|
13622
|
+
import_path28 = __toESM(require("path"));
|
|
13623
|
+
import_os24 = __toESM(require("os"));
|
|
13624
|
+
import_crypto8 = require("crypto");
|
|
13458
13625
|
import_child_process2 = require("child_process");
|
|
13459
13626
|
import_chalk6 = __toESM(require("chalk"));
|
|
13460
13627
|
init_core();
|
|
@@ -13473,8 +13640,8 @@ var init_server = __esm({
|
|
|
13473
13640
|
function resolveNode9Binary() {
|
|
13474
13641
|
try {
|
|
13475
13642
|
const script = process.argv[1];
|
|
13476
|
-
if (typeof script === "string" &&
|
|
13477
|
-
return
|
|
13643
|
+
if (typeof script === "string" && import_path29.default.isAbsolute(script) && import_fs27.default.existsSync(script)) {
|
|
13644
|
+
return import_fs27.default.realpathSync(script);
|
|
13478
13645
|
}
|
|
13479
13646
|
} catch {
|
|
13480
13647
|
}
|
|
@@ -13492,11 +13659,11 @@ function xmlEscape(s) {
|
|
|
13492
13659
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
13493
13660
|
}
|
|
13494
13661
|
function launchdPlist(binaryPath) {
|
|
13495
|
-
const logDir =
|
|
13662
|
+
const logDir = import_path29.default.join(import_os25.default.homedir(), ".node9");
|
|
13496
13663
|
const nodePath = xmlEscape(process.execPath);
|
|
13497
13664
|
const scriptPath = xmlEscape(binaryPath);
|
|
13498
|
-
const outLog = xmlEscape(
|
|
13499
|
-
const errLog = xmlEscape(
|
|
13665
|
+
const outLog = xmlEscape(import_path29.default.join(logDir, "daemon.log"));
|
|
13666
|
+
const errLog = xmlEscape(import_path29.default.join(logDir, "daemon-error.log"));
|
|
13500
13667
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
13501
13668
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
13502
13669
|
<plist version="1.0">
|
|
@@ -13529,9 +13696,9 @@ function launchdPlist(binaryPath) {
|
|
|
13529
13696
|
`;
|
|
13530
13697
|
}
|
|
13531
13698
|
function installLaunchd(binaryPath) {
|
|
13532
|
-
const dir =
|
|
13533
|
-
if (!
|
|
13534
|
-
|
|
13699
|
+
const dir = import_path29.default.dirname(LAUNCHD_PLIST);
|
|
13700
|
+
if (!import_fs27.default.existsSync(dir)) import_fs27.default.mkdirSync(dir, { recursive: true });
|
|
13701
|
+
import_fs27.default.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
|
|
13535
13702
|
(0, import_child_process3.spawnSync)("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
|
|
13536
13703
|
const r = (0, import_child_process3.spawnSync)("launchctl", ["load", "-w", LAUNCHD_PLIST], {
|
|
13537
13704
|
encoding: "utf8",
|
|
@@ -13542,13 +13709,13 @@ function installLaunchd(binaryPath) {
|
|
|
13542
13709
|
}
|
|
13543
13710
|
}
|
|
13544
13711
|
function uninstallLaunchd() {
|
|
13545
|
-
if (
|
|
13712
|
+
if (import_fs27.default.existsSync(LAUNCHD_PLIST)) {
|
|
13546
13713
|
(0, import_child_process3.spawnSync)("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
|
|
13547
|
-
|
|
13714
|
+
import_fs27.default.unlinkSync(LAUNCHD_PLIST);
|
|
13548
13715
|
}
|
|
13549
13716
|
}
|
|
13550
13717
|
function isLaunchdInstalled() {
|
|
13551
|
-
return
|
|
13718
|
+
return import_fs27.default.existsSync(LAUNCHD_PLIST);
|
|
13552
13719
|
}
|
|
13553
13720
|
function systemdUnit(binaryPath) {
|
|
13554
13721
|
return `[Unit]
|
|
@@ -13567,12 +13734,12 @@ WantedBy=default.target
|
|
|
13567
13734
|
`;
|
|
13568
13735
|
}
|
|
13569
13736
|
function installSystemd(binaryPath) {
|
|
13570
|
-
if (!
|
|
13571
|
-
|
|
13737
|
+
if (!import_fs27.default.existsSync(SYSTEMD_UNIT_DIR)) {
|
|
13738
|
+
import_fs27.default.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
|
|
13572
13739
|
}
|
|
13573
|
-
|
|
13740
|
+
import_fs27.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
|
|
13574
13741
|
try {
|
|
13575
|
-
(0, import_child_process3.execFileSync)("loginctl", ["enable-linger",
|
|
13742
|
+
(0, import_child_process3.execFileSync)("loginctl", ["enable-linger", import_os25.default.userInfo().username], { timeout: 3e3 });
|
|
13576
13743
|
} catch {
|
|
13577
13744
|
}
|
|
13578
13745
|
const reload = (0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], {
|
|
@@ -13592,23 +13759,23 @@ function installSystemd(binaryPath) {
|
|
|
13592
13759
|
}
|
|
13593
13760
|
}
|
|
13594
13761
|
function uninstallSystemd() {
|
|
13595
|
-
if (
|
|
13762
|
+
if (import_fs27.default.existsSync(SYSTEMD_UNIT)) {
|
|
13596
13763
|
(0, import_child_process3.spawnSync)("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
|
|
13597
13764
|
encoding: "utf8",
|
|
13598
13765
|
timeout: 5e3
|
|
13599
13766
|
});
|
|
13600
13767
|
(0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
|
|
13601
|
-
|
|
13768
|
+
import_fs27.default.unlinkSync(SYSTEMD_UNIT);
|
|
13602
13769
|
}
|
|
13603
13770
|
}
|
|
13604
13771
|
function isSystemdInstalled() {
|
|
13605
|
-
return
|
|
13772
|
+
return import_fs27.default.existsSync(SYSTEMD_UNIT);
|
|
13606
13773
|
}
|
|
13607
13774
|
function stopRunningDaemon() {
|
|
13608
|
-
const pidFile =
|
|
13609
|
-
if (!
|
|
13775
|
+
const pidFile = import_path29.default.join(import_os25.default.homedir(), ".node9", "daemon.pid");
|
|
13776
|
+
if (!import_fs27.default.existsSync(pidFile)) return;
|
|
13610
13777
|
try {
|
|
13611
|
-
const data = JSON.parse(
|
|
13778
|
+
const data = JSON.parse(import_fs27.default.readFileSync(pidFile, "utf-8"));
|
|
13612
13779
|
const pid = data.pid;
|
|
13613
13780
|
const MAX_PID2 = 4194304;
|
|
13614
13781
|
if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
|
|
@@ -13628,7 +13795,7 @@ function stopRunningDaemon() {
|
|
|
13628
13795
|
}
|
|
13629
13796
|
}
|
|
13630
13797
|
try {
|
|
13631
|
-
|
|
13798
|
+
import_fs27.default.unlinkSync(pidFile);
|
|
13632
13799
|
} catch {
|
|
13633
13800
|
}
|
|
13634
13801
|
} catch {
|
|
@@ -13698,26 +13865,26 @@ function isDaemonServiceInstalled() {
|
|
|
13698
13865
|
if (process.platform === "linux") return isSystemdInstalled();
|
|
13699
13866
|
return false;
|
|
13700
13867
|
}
|
|
13701
|
-
var
|
|
13868
|
+
var import_fs27, import_path29, import_os25, import_child_process3, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
|
|
13702
13869
|
var init_service = __esm({
|
|
13703
13870
|
"src/daemon/service.ts"() {
|
|
13704
13871
|
"use strict";
|
|
13705
|
-
|
|
13706
|
-
|
|
13707
|
-
|
|
13872
|
+
import_fs27 = __toESM(require("fs"));
|
|
13873
|
+
import_path29 = __toESM(require("path"));
|
|
13874
|
+
import_os25 = __toESM(require("os"));
|
|
13708
13875
|
import_child_process3 = require("child_process");
|
|
13709
13876
|
LAUNCHD_LABEL = "ai.node9.daemon";
|
|
13710
|
-
LAUNCHD_PLIST =
|
|
13711
|
-
SYSTEMD_UNIT_DIR =
|
|
13712
|
-
SYSTEMD_UNIT =
|
|
13877
|
+
LAUNCHD_PLIST = import_path29.default.join(import_os25.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
13878
|
+
SYSTEMD_UNIT_DIR = import_path29.default.join(import_os25.default.homedir(), ".config", "systemd", "user");
|
|
13879
|
+
SYSTEMD_UNIT = import_path29.default.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
|
|
13713
13880
|
}
|
|
13714
13881
|
});
|
|
13715
13882
|
|
|
13716
13883
|
// src/daemon/index.ts
|
|
13717
13884
|
function stopDaemon() {
|
|
13718
|
-
if (!
|
|
13885
|
+
if (!import_fs28.default.existsSync(DAEMON_PID_FILE)) return console.log(import_chalk7.default.yellow("Not running."));
|
|
13719
13886
|
try {
|
|
13720
|
-
const data = JSON.parse(
|
|
13887
|
+
const data = JSON.parse(import_fs28.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
13721
13888
|
const pid = data.pid;
|
|
13722
13889
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
13723
13890
|
console.log(import_chalk7.default.gray("Cleaned up invalid PID file."));
|
|
@@ -13729,7 +13896,7 @@ function stopDaemon() {
|
|
|
13729
13896
|
console.log(import_chalk7.default.gray("Cleaned up stale PID file."));
|
|
13730
13897
|
} finally {
|
|
13731
13898
|
try {
|
|
13732
|
-
|
|
13899
|
+
import_fs28.default.unlinkSync(DAEMON_PID_FILE);
|
|
13733
13900
|
} catch {
|
|
13734
13901
|
}
|
|
13735
13902
|
}
|
|
@@ -13738,9 +13905,9 @@ function daemonStatus() {
|
|
|
13738
13905
|
const serviceInstalled = isDaemonServiceInstalled();
|
|
13739
13906
|
const serviceLabel = serviceInstalled ? import_chalk7.default.green("installed (starts on login)") : import_chalk7.default.yellow("not installed \u2014 run: node9 daemon install");
|
|
13740
13907
|
let processStatus;
|
|
13741
|
-
if (
|
|
13908
|
+
if (import_fs28.default.existsSync(DAEMON_PID_FILE)) {
|
|
13742
13909
|
try {
|
|
13743
|
-
const data = JSON.parse(
|
|
13910
|
+
const data = JSON.parse(import_fs28.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
13744
13911
|
const pid = data.pid;
|
|
13745
13912
|
const port = data.port;
|
|
13746
13913
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
@@ -13762,11 +13929,11 @@ function daemonStatus() {
|
|
|
13762
13929
|
console.log(` Service : ${serviceLabel}
|
|
13763
13930
|
`);
|
|
13764
13931
|
}
|
|
13765
|
-
var
|
|
13932
|
+
var import_fs28, import_chalk7, MAX_PID;
|
|
13766
13933
|
var init_daemon2 = __esm({
|
|
13767
13934
|
"src/daemon/index.ts"() {
|
|
13768
13935
|
"use strict";
|
|
13769
|
-
|
|
13936
|
+
import_fs28 = __toESM(require("fs"));
|
|
13770
13937
|
import_chalk7 = __toESM(require("chalk"));
|
|
13771
13938
|
init_server();
|
|
13772
13939
|
init_state2();
|
|
@@ -13807,19 +13974,19 @@ function getModelContextLimit(model) {
|
|
|
13807
13974
|
}
|
|
13808
13975
|
function readSessionUsage() {
|
|
13809
13976
|
const projectsDir = import_path47.default.join(import_os41.default.homedir(), ".claude", "projects");
|
|
13810
|
-
if (!
|
|
13977
|
+
if (!import_fs46.default.existsSync(projectsDir)) return null;
|
|
13811
13978
|
let latestFile = null;
|
|
13812
13979
|
let latestMtime = 0;
|
|
13813
13980
|
try {
|
|
13814
|
-
for (const dir of
|
|
13981
|
+
for (const dir of import_fs46.default.readdirSync(projectsDir)) {
|
|
13815
13982
|
const dirPath = import_path47.default.join(projectsDir, dir);
|
|
13816
13983
|
try {
|
|
13817
|
-
if (!
|
|
13818
|
-
for (const file of
|
|
13984
|
+
if (!import_fs46.default.statSync(dirPath).isDirectory()) continue;
|
|
13985
|
+
for (const file of import_fs46.default.readdirSync(dirPath)) {
|
|
13819
13986
|
if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
|
|
13820
13987
|
const filePath = import_path47.default.join(dirPath, file);
|
|
13821
13988
|
try {
|
|
13822
|
-
const mtime =
|
|
13989
|
+
const mtime = import_fs46.default.statSync(filePath).mtimeMs;
|
|
13823
13990
|
if (mtime > latestMtime) {
|
|
13824
13991
|
latestMtime = mtime;
|
|
13825
13992
|
latestFile = filePath;
|
|
@@ -13834,7 +14001,7 @@ function readSessionUsage() {
|
|
|
13834
14001
|
}
|
|
13835
14002
|
if (!latestFile) return null;
|
|
13836
14003
|
try {
|
|
13837
|
-
const lines =
|
|
14004
|
+
const lines = import_fs46.default.readFileSync(latestFile, "utf-8").split("\n");
|
|
13838
14005
|
let lastModel = "";
|
|
13839
14006
|
let lastInput = 0;
|
|
13840
14007
|
let lastOutput = 0;
|
|
@@ -13934,9 +14101,9 @@ function renderPending(activity) {
|
|
|
13934
14101
|
}
|
|
13935
14102
|
async function ensureDaemon() {
|
|
13936
14103
|
let pidPort = null;
|
|
13937
|
-
if (
|
|
14104
|
+
if (import_fs46.default.existsSync(PID_FILE)) {
|
|
13938
14105
|
try {
|
|
13939
|
-
const { port } = JSON.parse(
|
|
14106
|
+
const { port } = JSON.parse(import_fs46.default.readFileSync(PID_FILE, "utf-8"));
|
|
13940
14107
|
pidPort = port;
|
|
13941
14108
|
} catch {
|
|
13942
14109
|
console.error(import_chalk29.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
@@ -14094,7 +14261,7 @@ function buildRecoveryCardLines(req) {
|
|
|
14094
14261
|
function readApproversFromDisk() {
|
|
14095
14262
|
const configPath = import_path47.default.join(import_os41.default.homedir(), ".node9", "config.json");
|
|
14096
14263
|
try {
|
|
14097
|
-
const raw = JSON.parse(
|
|
14264
|
+
const raw = JSON.parse(import_fs46.default.readFileSync(configPath, "utf-8"));
|
|
14098
14265
|
const settings = raw.settings ?? {};
|
|
14099
14266
|
return settings.approvers ?? {};
|
|
14100
14267
|
} catch {
|
|
@@ -14112,13 +14279,13 @@ function approverStatusLine() {
|
|
|
14112
14279
|
function toggleApprover(channel) {
|
|
14113
14280
|
const configPath = import_path47.default.join(import_os41.default.homedir(), ".node9", "config.json");
|
|
14114
14281
|
try {
|
|
14115
|
-
const raw = JSON.parse(
|
|
14282
|
+
const raw = JSON.parse(import_fs46.default.readFileSync(configPath, "utf-8"));
|
|
14116
14283
|
const settings = raw.settings ?? {};
|
|
14117
14284
|
const approvers = settings.approvers ?? {};
|
|
14118
14285
|
approvers[channel] = approvers[channel] === false;
|
|
14119
14286
|
settings.approvers = approvers;
|
|
14120
14287
|
raw.settings = settings;
|
|
14121
|
-
|
|
14288
|
+
import_fs46.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
|
|
14122
14289
|
} catch (err2) {
|
|
14123
14290
|
process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
|
|
14124
14291
|
`);
|
|
@@ -14290,7 +14457,7 @@ async function startTail(options = {}) {
|
|
|
14290
14457
|
}
|
|
14291
14458
|
postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
|
|
14292
14459
|
try {
|
|
14293
|
-
|
|
14460
|
+
import_fs46.default.appendFileSync(
|
|
14294
14461
|
import_path47.default.join(import_os41.default.homedir(), ".node9", "hook-debug.log"),
|
|
14295
14462
|
`[tail] POST /decision failed: ${String(err2)}
|
|
14296
14463
|
`
|
|
@@ -14357,7 +14524,7 @@ async function startTail(options = {}) {
|
|
|
14357
14524
|
}
|
|
14358
14525
|
const auditLog = import_path47.default.join(import_os41.default.homedir(), ".node9", "audit.log");
|
|
14359
14526
|
try {
|
|
14360
|
-
const unackedDlp =
|
|
14527
|
+
const unackedDlp = import_fs46.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
14361
14528
|
if (unackedDlp > 0) {
|
|
14362
14529
|
console.log("");
|
|
14363
14530
|
console.log(
|
|
@@ -14397,7 +14564,7 @@ async function startTail(options = {}) {
|
|
|
14397
14564
|
if (stallWarned) return;
|
|
14398
14565
|
if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
|
|
14399
14566
|
try {
|
|
14400
|
-
const auditMtime =
|
|
14567
|
+
const auditMtime = import_fs46.default.statSync(auditLog).mtimeMs;
|
|
14401
14568
|
if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
|
|
14402
14569
|
console.log("");
|
|
14403
14570
|
console.log(
|
|
@@ -14582,13 +14749,13 @@ async function startTail(options = {}) {
|
|
|
14582
14749
|
process.exit(1);
|
|
14583
14750
|
});
|
|
14584
14751
|
}
|
|
14585
|
-
var import_http2, import_chalk29,
|
|
14752
|
+
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;
|
|
14586
14753
|
var init_tail = __esm({
|
|
14587
14754
|
"src/tui/tail.ts"() {
|
|
14588
14755
|
"use strict";
|
|
14589
14756
|
import_http2 = __toESM(require("http"));
|
|
14590
14757
|
import_chalk29 = __toESM(require("chalk"));
|
|
14591
|
-
|
|
14758
|
+
import_fs46 = __toESM(require("fs"));
|
|
14592
14759
|
import_os41 = __toESM(require("os"));
|
|
14593
14760
|
import_path47 = __toESM(require("path"));
|
|
14594
14761
|
import_readline6 = __toESM(require("readline"));
|
|
@@ -14717,9 +14884,9 @@ function formatTimeLeft(resetsAt) {
|
|
|
14717
14884
|
return ` (${m}m left)`;
|
|
14718
14885
|
}
|
|
14719
14886
|
function safeReadJson(filePath) {
|
|
14720
|
-
if (!
|
|
14887
|
+
if (!import_fs47.default.existsSync(filePath)) return null;
|
|
14721
14888
|
try {
|
|
14722
|
-
return JSON.parse(
|
|
14889
|
+
return JSON.parse(import_fs47.default.readFileSync(filePath, "utf-8"));
|
|
14723
14890
|
} catch {
|
|
14724
14891
|
return null;
|
|
14725
14892
|
}
|
|
@@ -14740,10 +14907,10 @@ function countHooksInFile(filePath) {
|
|
|
14740
14907
|
return Object.keys(cfg.hooks).length;
|
|
14741
14908
|
}
|
|
14742
14909
|
function countRulesInDir(rulesDir) {
|
|
14743
|
-
if (!
|
|
14910
|
+
if (!import_fs47.default.existsSync(rulesDir)) return 0;
|
|
14744
14911
|
let count = 0;
|
|
14745
14912
|
try {
|
|
14746
|
-
for (const entry of
|
|
14913
|
+
for (const entry of import_fs47.default.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
14747
14914
|
if (entry.isDirectory()) {
|
|
14748
14915
|
count += countRulesInDir(import_path48.default.join(rulesDir, entry.name));
|
|
14749
14916
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -14769,7 +14936,7 @@ function countConfigs(cwd) {
|
|
|
14769
14936
|
let hooksCount = 0;
|
|
14770
14937
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
14771
14938
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
14772
|
-
if (
|
|
14939
|
+
if (import_fs47.default.existsSync(import_path48.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
14773
14940
|
rulesCount += countRulesInDir(import_path48.default.join(claudeDir, "rules"));
|
|
14774
14941
|
const userSettings = import_path48.default.join(claudeDir, "settings.json");
|
|
14775
14942
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
@@ -14780,18 +14947,18 @@ function countConfigs(cwd) {
|
|
|
14780
14947
|
userMcpServers.delete(name);
|
|
14781
14948
|
}
|
|
14782
14949
|
if (cwd) {
|
|
14783
|
-
if (
|
|
14784
|
-
if (
|
|
14950
|
+
if (import_fs47.default.existsSync(import_path48.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
14951
|
+
if (import_fs47.default.existsSync(import_path48.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
14785
14952
|
const projectClaudeDir = import_path48.default.join(cwd, ".claude");
|
|
14786
14953
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
14787
14954
|
if (!overlapsUserScope) {
|
|
14788
|
-
if (
|
|
14955
|
+
if (import_fs47.default.existsSync(import_path48.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
14789
14956
|
rulesCount += countRulesInDir(import_path48.default.join(projectClaudeDir, "rules"));
|
|
14790
14957
|
const projSettings = import_path48.default.join(projectClaudeDir, "settings.json");
|
|
14791
14958
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
14792
14959
|
hooksCount += countHooksInFile(projSettings);
|
|
14793
14960
|
}
|
|
14794
|
-
if (
|
|
14961
|
+
if (import_fs47.default.existsSync(import_path48.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
14795
14962
|
const localSettings = import_path48.default.join(projectClaudeDir, "settings.local.json");
|
|
14796
14963
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
14797
14964
|
hooksCount += countHooksInFile(localSettings);
|
|
@@ -14829,11 +14996,11 @@ function readActiveShieldsHud() {
|
|
|
14829
14996
|
}
|
|
14830
14997
|
try {
|
|
14831
14998
|
const shieldsPath = import_path48.default.join(import_os42.default.homedir(), ".node9", "shields.json");
|
|
14832
|
-
if (!
|
|
14999
|
+
if (!import_fs47.default.existsSync(shieldsPath)) {
|
|
14833
15000
|
shieldsCache = { value: [], ts: now };
|
|
14834
15001
|
return [];
|
|
14835
15002
|
}
|
|
14836
|
-
const parsed = JSON.parse(
|
|
15003
|
+
const parsed = JSON.parse(import_fs47.default.readFileSync(shieldsPath, "utf-8"));
|
|
14837
15004
|
if (!Array.isArray(parsed.active)) {
|
|
14838
15005
|
shieldsCache = { value: [], ts: now };
|
|
14839
15006
|
return [];
|
|
@@ -14935,17 +15102,17 @@ function renderContextLine(stdin) {
|
|
|
14935
15102
|
async function main() {
|
|
14936
15103
|
try {
|
|
14937
15104
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
14938
|
-
if (
|
|
15105
|
+
if (import_fs47.default.existsSync(import_path48.default.join(import_os42.default.homedir(), ".node9", "hud-debug"))) {
|
|
14939
15106
|
try {
|
|
14940
15107
|
const logPath = import_path48.default.join(import_os42.default.homedir(), ".node9", "hud-debug.log");
|
|
14941
15108
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
14942
15109
|
let size = 0;
|
|
14943
15110
|
try {
|
|
14944
|
-
size =
|
|
15111
|
+
size = import_fs47.default.statSync(logPath).size;
|
|
14945
15112
|
} catch {
|
|
14946
15113
|
}
|
|
14947
15114
|
if (size < MAX_LOG_SIZE) {
|
|
14948
|
-
|
|
15115
|
+
import_fs47.default.appendFileSync(
|
|
14949
15116
|
logPath,
|
|
14950
15117
|
JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
|
|
14951
15118
|
);
|
|
@@ -14969,8 +15136,8 @@ async function main() {
|
|
|
14969
15136
|
import_path48.default.join(cwd, "node9.config.json"),
|
|
14970
15137
|
import_path48.default.join(import_os42.default.homedir(), ".node9", "config.json")
|
|
14971
15138
|
]) {
|
|
14972
|
-
if (!
|
|
14973
|
-
const cfg = JSON.parse(
|
|
15139
|
+
if (!import_fs47.default.existsSync(configPath)) continue;
|
|
15140
|
+
const cfg = JSON.parse(import_fs47.default.readFileSync(configPath, "utf-8"));
|
|
14974
15141
|
const hud = cfg.settings?.hud;
|
|
14975
15142
|
if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
|
|
14976
15143
|
}
|
|
@@ -14988,11 +15155,11 @@ async function main() {
|
|
|
14988
15155
|
renderOffline();
|
|
14989
15156
|
}
|
|
14990
15157
|
}
|
|
14991
|
-
var
|
|
15158
|
+
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;
|
|
14992
15159
|
var init_hud = __esm({
|
|
14993
15160
|
"src/cli/hud.ts"() {
|
|
14994
15161
|
"use strict";
|
|
14995
|
-
|
|
15162
|
+
import_fs47 = __toESM(require("fs"));
|
|
14996
15163
|
import_path48 = __toESM(require("path"));
|
|
14997
15164
|
import_os42 = __toESM(require("os"));
|
|
14998
15165
|
import_http3 = __toESM(require("http"));
|
|
@@ -15021,7 +15188,7 @@ init_core();
|
|
|
15021
15188
|
init_setup();
|
|
15022
15189
|
init_daemon2();
|
|
15023
15190
|
var import_chalk30 = __toESM(require("chalk"));
|
|
15024
|
-
var
|
|
15191
|
+
var import_fs48 = __toESM(require("fs"));
|
|
15025
15192
|
var import_path49 = __toESM(require("path"));
|
|
15026
15193
|
var import_os43 = __toESM(require("os"));
|
|
15027
15194
|
var import_prompts2 = require("@inquirer/prompts");
|
|
@@ -15205,18 +15372,18 @@ async function runProxy(targetCommand) {
|
|
|
15205
15372
|
|
|
15206
15373
|
// src/cli/daemon-starter.ts
|
|
15207
15374
|
var import_child_process5 = require("child_process");
|
|
15208
|
-
var
|
|
15209
|
-
var
|
|
15375
|
+
var import_path30 = __toESM(require("path"));
|
|
15376
|
+
var import_fs29 = __toESM(require("fs"));
|
|
15210
15377
|
init_daemon();
|
|
15211
15378
|
function isTestingMode() {
|
|
15212
15379
|
return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
|
|
15213
15380
|
}
|
|
15214
15381
|
async function autoStartDaemonAndWait() {
|
|
15215
15382
|
if (isTestingMode()) return false;
|
|
15216
|
-
if (!
|
|
15383
|
+
if (!import_path30.default.isAbsolute(process.argv[1])) return false;
|
|
15217
15384
|
let resolvedArgv1;
|
|
15218
15385
|
try {
|
|
15219
|
-
resolvedArgv1 =
|
|
15386
|
+
resolvedArgv1 = import_fs29.default.realpathSync(process.argv[1]);
|
|
15220
15387
|
} catch {
|
|
15221
15388
|
return false;
|
|
15222
15389
|
}
|
|
@@ -15243,10 +15410,10 @@ async function autoStartDaemonAndWait() {
|
|
|
15243
15410
|
|
|
15244
15411
|
// src/cli/commands/check.ts
|
|
15245
15412
|
var import_chalk9 = __toESM(require("chalk"));
|
|
15246
|
-
var
|
|
15413
|
+
var import_fs32 = __toESM(require("fs"));
|
|
15247
15414
|
var import_child_process7 = require("child_process");
|
|
15248
|
-
var
|
|
15249
|
-
var
|
|
15415
|
+
var import_path33 = __toESM(require("path"));
|
|
15416
|
+
var import_os28 = __toESM(require("os"));
|
|
15250
15417
|
init_orchestrator();
|
|
15251
15418
|
init_daemon();
|
|
15252
15419
|
init_config();
|
|
@@ -15254,12 +15421,12 @@ init_policy();
|
|
|
15254
15421
|
|
|
15255
15422
|
// src/undo.ts
|
|
15256
15423
|
var import_child_process6 = require("child_process");
|
|
15257
|
-
var
|
|
15258
|
-
var
|
|
15424
|
+
var import_crypto9 = __toESM(require("crypto"));
|
|
15425
|
+
var import_fs30 = __toESM(require("fs"));
|
|
15259
15426
|
var import_net3 = __toESM(require("net"));
|
|
15260
|
-
var
|
|
15261
|
-
var
|
|
15262
|
-
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
15427
|
+
var import_path31 = __toESM(require("path"));
|
|
15428
|
+
var import_os26 = __toESM(require("os"));
|
|
15429
|
+
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path31.default.join(import_os26.default.tmpdir(), "node9-activity.sock");
|
|
15263
15430
|
function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
15264
15431
|
try {
|
|
15265
15432
|
const payload = JSON.stringify({
|
|
@@ -15279,22 +15446,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
|
15279
15446
|
} catch {
|
|
15280
15447
|
}
|
|
15281
15448
|
}
|
|
15282
|
-
var SNAPSHOT_STACK_PATH =
|
|
15283
|
-
var UNDO_LATEST_PATH =
|
|
15449
|
+
var SNAPSHOT_STACK_PATH = import_path31.default.join(import_os26.default.homedir(), ".node9", "snapshots.json");
|
|
15450
|
+
var UNDO_LATEST_PATH = import_path31.default.join(import_os26.default.homedir(), ".node9", "undo_latest.txt");
|
|
15284
15451
|
var MAX_SNAPSHOTS = 10;
|
|
15285
15452
|
var GIT_TIMEOUT = 15e3;
|
|
15286
15453
|
function readStack() {
|
|
15287
15454
|
try {
|
|
15288
|
-
if (
|
|
15289
|
-
return JSON.parse(
|
|
15455
|
+
if (import_fs30.default.existsSync(SNAPSHOT_STACK_PATH))
|
|
15456
|
+
return JSON.parse(import_fs30.default.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
|
|
15290
15457
|
} catch {
|
|
15291
15458
|
}
|
|
15292
15459
|
return [];
|
|
15293
15460
|
}
|
|
15294
15461
|
function writeStack(stack) {
|
|
15295
|
-
const dir =
|
|
15296
|
-
if (!
|
|
15297
|
-
|
|
15462
|
+
const dir = import_path31.default.dirname(SNAPSHOT_STACK_PATH);
|
|
15463
|
+
if (!import_fs30.default.existsSync(dir)) import_fs30.default.mkdirSync(dir, { recursive: true });
|
|
15464
|
+
import_fs30.default.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
|
|
15298
15465
|
}
|
|
15299
15466
|
function extractFilePath(args) {
|
|
15300
15467
|
if (!args || typeof args !== "object") return null;
|
|
@@ -15314,12 +15481,12 @@ function buildArgsSummary(tool, args) {
|
|
|
15314
15481
|
return "";
|
|
15315
15482
|
}
|
|
15316
15483
|
function findProjectRoot(filePath) {
|
|
15317
|
-
let dir =
|
|
15484
|
+
let dir = import_path31.default.dirname(filePath);
|
|
15318
15485
|
while (true) {
|
|
15319
|
-
if (
|
|
15486
|
+
if (import_fs30.default.existsSync(import_path31.default.join(dir, ".git")) || import_fs30.default.existsSync(import_path31.default.join(dir, "package.json"))) {
|
|
15320
15487
|
return dir;
|
|
15321
15488
|
}
|
|
15322
|
-
const parent =
|
|
15489
|
+
const parent = import_path31.default.dirname(dir);
|
|
15323
15490
|
if (parent === dir) return process.cwd();
|
|
15324
15491
|
dir = parent;
|
|
15325
15492
|
}
|
|
@@ -15327,7 +15494,7 @@ function findProjectRoot(filePath) {
|
|
|
15327
15494
|
function normalizeCwdForHash(cwd) {
|
|
15328
15495
|
let normalized;
|
|
15329
15496
|
try {
|
|
15330
|
-
normalized =
|
|
15497
|
+
normalized = import_fs30.default.realpathSync(cwd);
|
|
15331
15498
|
} catch {
|
|
15332
15499
|
normalized = cwd;
|
|
15333
15500
|
}
|
|
@@ -15336,17 +15503,17 @@ function normalizeCwdForHash(cwd) {
|
|
|
15336
15503
|
return normalized;
|
|
15337
15504
|
}
|
|
15338
15505
|
function getShadowRepoDir(cwd) {
|
|
15339
|
-
const hash =
|
|
15340
|
-
return
|
|
15506
|
+
const hash = import_crypto9.default.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
|
|
15507
|
+
return import_path31.default.join(import_os26.default.homedir(), ".node9", "snapshots", hash);
|
|
15341
15508
|
}
|
|
15342
15509
|
function cleanOrphanedIndexFiles(shadowDir) {
|
|
15343
15510
|
try {
|
|
15344
15511
|
const cutoff = Date.now() - 6e4;
|
|
15345
|
-
for (const f of
|
|
15512
|
+
for (const f of import_fs30.default.readdirSync(shadowDir)) {
|
|
15346
15513
|
if (f.startsWith("index_")) {
|
|
15347
|
-
const fp =
|
|
15514
|
+
const fp = import_path31.default.join(shadowDir, f);
|
|
15348
15515
|
try {
|
|
15349
|
-
if (
|
|
15516
|
+
if (import_fs30.default.statSync(fp).mtimeMs < cutoff) import_fs30.default.unlinkSync(fp);
|
|
15350
15517
|
} catch {
|
|
15351
15518
|
}
|
|
15352
15519
|
}
|
|
@@ -15358,7 +15525,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
|
|
|
15358
15525
|
const hardcoded = [".git", ".node9"];
|
|
15359
15526
|
const lines = [...hardcoded, ...ignorePaths].join("\n");
|
|
15360
15527
|
try {
|
|
15361
|
-
|
|
15528
|
+
import_fs30.default.writeFileSync(import_path31.default.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
|
|
15362
15529
|
} catch {
|
|
15363
15530
|
}
|
|
15364
15531
|
}
|
|
@@ -15371,25 +15538,25 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
15371
15538
|
timeout: 3e3
|
|
15372
15539
|
});
|
|
15373
15540
|
if (check.status === 0) {
|
|
15374
|
-
const ptPath =
|
|
15541
|
+
const ptPath = import_path31.default.join(shadowDir, "project-path.txt");
|
|
15375
15542
|
try {
|
|
15376
|
-
const stored =
|
|
15543
|
+
const stored = import_fs30.default.readFileSync(ptPath, "utf8").trim();
|
|
15377
15544
|
if (stored === normalizedCwd) return true;
|
|
15378
15545
|
if (process.env.NODE9_DEBUG === "1")
|
|
15379
15546
|
console.error(
|
|
15380
15547
|
`[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
|
|
15381
15548
|
);
|
|
15382
|
-
|
|
15549
|
+
import_fs30.default.rmSync(shadowDir, { recursive: true, force: true });
|
|
15383
15550
|
} catch {
|
|
15384
15551
|
try {
|
|
15385
|
-
|
|
15552
|
+
import_fs30.default.writeFileSync(ptPath, normalizedCwd, "utf8");
|
|
15386
15553
|
} catch {
|
|
15387
15554
|
}
|
|
15388
15555
|
return true;
|
|
15389
15556
|
}
|
|
15390
15557
|
}
|
|
15391
15558
|
try {
|
|
15392
|
-
|
|
15559
|
+
import_fs30.default.mkdirSync(shadowDir, { recursive: true });
|
|
15393
15560
|
} catch {
|
|
15394
15561
|
}
|
|
15395
15562
|
const init = (0, import_child_process6.spawnSync)("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
|
|
@@ -15398,7 +15565,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
15398
15565
|
if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
|
|
15399
15566
|
return false;
|
|
15400
15567
|
}
|
|
15401
|
-
const configFile =
|
|
15568
|
+
const configFile = import_path31.default.join(shadowDir, "config");
|
|
15402
15569
|
(0, import_child_process6.spawnSync)("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
|
|
15403
15570
|
timeout: 3e3
|
|
15404
15571
|
});
|
|
@@ -15406,7 +15573,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
15406
15573
|
timeout: 3e3
|
|
15407
15574
|
});
|
|
15408
15575
|
try {
|
|
15409
|
-
|
|
15576
|
+
import_fs30.default.writeFileSync(import_path31.default.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
|
|
15410
15577
|
} catch {
|
|
15411
15578
|
}
|
|
15412
15579
|
return true;
|
|
@@ -15429,12 +15596,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
15429
15596
|
let indexFile = null;
|
|
15430
15597
|
try {
|
|
15431
15598
|
const rawFilePath = extractFilePath(args);
|
|
15432
|
-
const absFilePath = rawFilePath &&
|
|
15599
|
+
const absFilePath = rawFilePath && import_path31.default.isAbsolute(rawFilePath) ? rawFilePath : null;
|
|
15433
15600
|
const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
|
|
15434
15601
|
const shadowDir = getShadowRepoDir(cwd);
|
|
15435
15602
|
if (!ensureShadowRepo(shadowDir, cwd)) return null;
|
|
15436
15603
|
writeShadowExcludes(shadowDir, ignorePaths);
|
|
15437
|
-
indexFile =
|
|
15604
|
+
indexFile = import_path31.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
|
|
15438
15605
|
const shadowEnv = {
|
|
15439
15606
|
...process.env,
|
|
15440
15607
|
GIT_DIR: shadowDir,
|
|
@@ -15506,7 +15673,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
15506
15673
|
writeStack(stack);
|
|
15507
15674
|
const entry = stack[stack.length - 1];
|
|
15508
15675
|
notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
|
|
15509
|
-
|
|
15676
|
+
import_fs30.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
|
|
15510
15677
|
if (shouldGc) {
|
|
15511
15678
|
(0, import_child_process6.spawn)("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
|
|
15512
15679
|
}
|
|
@@ -15517,7 +15684,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
15517
15684
|
} finally {
|
|
15518
15685
|
if (indexFile) {
|
|
15519
15686
|
try {
|
|
15520
|
-
|
|
15687
|
+
import_fs30.default.unlinkSync(indexFile);
|
|
15521
15688
|
} catch {
|
|
15522
15689
|
}
|
|
15523
15690
|
}
|
|
@@ -15593,9 +15760,9 @@ function applyUndo(hash, cwd) {
|
|
|
15593
15760
|
timeout: GIT_TIMEOUT
|
|
15594
15761
|
}).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
|
|
15595
15762
|
for (const file of [...tracked, ...untracked]) {
|
|
15596
|
-
const fullPath =
|
|
15597
|
-
if (!snapshotFiles.has(file) &&
|
|
15598
|
-
|
|
15763
|
+
const fullPath = import_path31.default.join(dir, file);
|
|
15764
|
+
if (!snapshotFiles.has(file) && import_fs30.default.existsSync(fullPath)) {
|
|
15765
|
+
import_fs30.default.unlinkSync(fullPath);
|
|
15599
15766
|
}
|
|
15600
15767
|
}
|
|
15601
15768
|
return true;
|
|
@@ -15605,17 +15772,17 @@ function applyUndo(hash, cwd) {
|
|
|
15605
15772
|
}
|
|
15606
15773
|
|
|
15607
15774
|
// src/skill-pin.ts
|
|
15608
|
-
var
|
|
15609
|
-
var
|
|
15610
|
-
var
|
|
15611
|
-
var
|
|
15612
|
-
function
|
|
15613
|
-
return
|
|
15775
|
+
var import_fs31 = __toESM(require("fs"));
|
|
15776
|
+
var import_path32 = __toESM(require("path"));
|
|
15777
|
+
var import_os27 = __toESM(require("os"));
|
|
15778
|
+
var import_crypto10 = __toESM(require("crypto"));
|
|
15779
|
+
function getPinsFilePath2() {
|
|
15780
|
+
return import_path32.default.join(import_os27.default.homedir(), ".node9", "skill-pins.json");
|
|
15614
15781
|
}
|
|
15615
15782
|
var MAX_FILES = 5e3;
|
|
15616
15783
|
var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
|
|
15617
15784
|
function sha256Bytes(buf) {
|
|
15618
|
-
return
|
|
15785
|
+
return import_crypto10.default.createHash("sha256").update(buf).digest("hex");
|
|
15619
15786
|
}
|
|
15620
15787
|
function walkDir(root) {
|
|
15621
15788
|
const out = [];
|
|
@@ -15624,18 +15791,18 @@ function walkDir(root) {
|
|
|
15624
15791
|
if (out.length >= MAX_FILES) return;
|
|
15625
15792
|
let entries;
|
|
15626
15793
|
try {
|
|
15627
|
-
entries =
|
|
15794
|
+
entries = import_fs31.default.readdirSync(dir, { withFileTypes: true });
|
|
15628
15795
|
} catch {
|
|
15629
15796
|
return;
|
|
15630
15797
|
}
|
|
15631
15798
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
15632
15799
|
for (const entry of entries) {
|
|
15633
15800
|
if (out.length >= MAX_FILES) return;
|
|
15634
|
-
const full =
|
|
15635
|
-
const rel = relDir ?
|
|
15801
|
+
const full = import_path32.default.join(dir, entry.name);
|
|
15802
|
+
const rel = relDir ? import_path32.default.posix.join(relDir, entry.name) : entry.name;
|
|
15636
15803
|
let lst;
|
|
15637
15804
|
try {
|
|
15638
|
-
lst =
|
|
15805
|
+
lst = import_fs31.default.lstatSync(full);
|
|
15639
15806
|
} catch {
|
|
15640
15807
|
continue;
|
|
15641
15808
|
}
|
|
@@ -15647,7 +15814,7 @@ function walkDir(root) {
|
|
|
15647
15814
|
if (!lst.isFile()) continue;
|
|
15648
15815
|
if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
|
|
15649
15816
|
try {
|
|
15650
|
-
const buf =
|
|
15817
|
+
const buf = import_fs31.default.readFileSync(full);
|
|
15651
15818
|
totalBytes += buf.length;
|
|
15652
15819
|
out.push({ rel, hash: sha256Bytes(buf) });
|
|
15653
15820
|
} catch {
|
|
@@ -15661,32 +15828,32 @@ function walkDir(root) {
|
|
|
15661
15828
|
function hashSkillRoot(absPath) {
|
|
15662
15829
|
let lst;
|
|
15663
15830
|
try {
|
|
15664
|
-
lst =
|
|
15831
|
+
lst = import_fs31.default.lstatSync(absPath);
|
|
15665
15832
|
} catch {
|
|
15666
15833
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
15667
15834
|
}
|
|
15668
15835
|
if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
|
|
15669
15836
|
if (lst.isFile()) {
|
|
15670
15837
|
try {
|
|
15671
|
-
return { exists: true, contentHash: sha256Bytes(
|
|
15838
|
+
return { exists: true, contentHash: sha256Bytes(import_fs31.default.readFileSync(absPath)), fileCount: 1 };
|
|
15672
15839
|
} catch {
|
|
15673
15840
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
15674
15841
|
}
|
|
15675
15842
|
}
|
|
15676
15843
|
if (lst.isDirectory()) {
|
|
15677
15844
|
const entries = walkDir(absPath);
|
|
15678
|
-
const contentHash =
|
|
15845
|
+
const contentHash = import_crypto10.default.createHash("sha256").update(entries.join("\n")).digest("hex");
|
|
15679
15846
|
return { exists: true, contentHash, fileCount: entries.length };
|
|
15680
15847
|
}
|
|
15681
15848
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
15682
15849
|
}
|
|
15683
15850
|
function getRootKey(absPath) {
|
|
15684
|
-
return
|
|
15851
|
+
return import_crypto10.default.createHash("sha256").update(absPath).digest("hex").slice(0, 16);
|
|
15685
15852
|
}
|
|
15686
15853
|
function readSkillPinsSafe() {
|
|
15687
|
-
const filePath =
|
|
15854
|
+
const filePath = getPinsFilePath2();
|
|
15688
15855
|
try {
|
|
15689
|
-
const raw =
|
|
15856
|
+
const raw = import_fs31.default.readFileSync(filePath, "utf-8");
|
|
15690
15857
|
if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
15691
15858
|
const parsed = JSON.parse(raw);
|
|
15692
15859
|
if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
|
|
@@ -15705,18 +15872,18 @@ function readSkillPins() {
|
|
|
15705
15872
|
throw new Error(`[node9] skill pin file is corrupt: ${result.detail}`);
|
|
15706
15873
|
}
|
|
15707
15874
|
function writeSkillPins(data) {
|
|
15708
|
-
const filePath =
|
|
15709
|
-
|
|
15710
|
-
const tmp = `${filePath}.${
|
|
15711
|
-
|
|
15712
|
-
|
|
15875
|
+
const filePath = getPinsFilePath2();
|
|
15876
|
+
import_fs31.default.mkdirSync(import_path32.default.dirname(filePath), { recursive: true });
|
|
15877
|
+
const tmp = `${filePath}.${import_crypto10.default.randomBytes(6).toString("hex")}.tmp`;
|
|
15878
|
+
import_fs31.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
15879
|
+
import_fs31.default.renameSync(tmp, filePath);
|
|
15713
15880
|
}
|
|
15714
|
-
function
|
|
15881
|
+
function removePin2(rootKey) {
|
|
15715
15882
|
const pins = readSkillPins();
|
|
15716
15883
|
delete pins.roots[rootKey];
|
|
15717
15884
|
writeSkillPins(pins);
|
|
15718
15885
|
}
|
|
15719
|
-
function
|
|
15886
|
+
function clearAllPins2() {
|
|
15720
15887
|
writeSkillPins({ roots: {} });
|
|
15721
15888
|
}
|
|
15722
15889
|
function verifyAndPinRoots(roots) {
|
|
@@ -15753,36 +15920,36 @@ function verifyAndPinRoots(roots) {
|
|
|
15753
15920
|
return { kind: "verified" };
|
|
15754
15921
|
}
|
|
15755
15922
|
function defaultSkillRoots(_cwd) {
|
|
15756
|
-
const marketplaces =
|
|
15923
|
+
const marketplaces = import_path32.default.join(import_os27.default.homedir(), ".claude", "plugins", "marketplaces");
|
|
15757
15924
|
const roots = [];
|
|
15758
15925
|
let registries;
|
|
15759
15926
|
try {
|
|
15760
|
-
registries =
|
|
15927
|
+
registries = import_fs31.default.readdirSync(marketplaces, { withFileTypes: true });
|
|
15761
15928
|
} catch {
|
|
15762
15929
|
return [];
|
|
15763
15930
|
}
|
|
15764
15931
|
for (const registry of registries) {
|
|
15765
15932
|
if (!registry.isDirectory()) continue;
|
|
15766
|
-
const pluginsDir =
|
|
15933
|
+
const pluginsDir = import_path32.default.join(marketplaces, registry.name, "plugins");
|
|
15767
15934
|
let plugins;
|
|
15768
15935
|
try {
|
|
15769
|
-
plugins =
|
|
15936
|
+
plugins = import_fs31.default.readdirSync(pluginsDir, { withFileTypes: true });
|
|
15770
15937
|
} catch {
|
|
15771
15938
|
continue;
|
|
15772
15939
|
}
|
|
15773
15940
|
for (const plugin of plugins) {
|
|
15774
15941
|
if (!plugin.isDirectory()) continue;
|
|
15775
|
-
roots.push(
|
|
15942
|
+
roots.push(import_path32.default.join(pluginsDir, plugin.name));
|
|
15776
15943
|
}
|
|
15777
15944
|
}
|
|
15778
15945
|
return roots;
|
|
15779
15946
|
}
|
|
15780
15947
|
function resolveUserSkillRoot(entry, cwd) {
|
|
15781
15948
|
if (!entry) return null;
|
|
15782
|
-
if (entry.startsWith("~/") || entry === "~") return
|
|
15783
|
-
if (
|
|
15784
|
-
if (!cwd || !
|
|
15785
|
-
return
|
|
15949
|
+
if (entry.startsWith("~/") || entry === "~") return import_path32.default.join(import_os27.default.homedir(), entry.slice(1));
|
|
15950
|
+
if (import_path32.default.isAbsolute(entry)) return entry;
|
|
15951
|
+
if (!cwd || !import_path32.default.isAbsolute(cwd)) return null;
|
|
15952
|
+
return import_path32.default.join(cwd, entry);
|
|
15786
15953
|
}
|
|
15787
15954
|
|
|
15788
15955
|
// src/cli/commands/check.ts
|
|
@@ -15829,9 +15996,9 @@ function registerCheckCommand(program2) {
|
|
|
15829
15996
|
} catch (err2) {
|
|
15830
15997
|
const tempConfig = getConfig();
|
|
15831
15998
|
if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
|
|
15832
|
-
const logPath =
|
|
15999
|
+
const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
15833
16000
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
15834
|
-
|
|
16001
|
+
import_fs32.default.appendFileSync(
|
|
15835
16002
|
logPath,
|
|
15836
16003
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
|
|
15837
16004
|
RAW: ${raw}
|
|
@@ -15844,14 +16011,14 @@ RAW: ${raw}
|
|
|
15844
16011
|
const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
|
|
15845
16012
|
if (process.env.NODE9_DEBUG === "1") {
|
|
15846
16013
|
try {
|
|
15847
|
-
const logPath =
|
|
15848
|
-
if (!
|
|
15849
|
-
|
|
16014
|
+
const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
16015
|
+
if (!import_fs32.default.existsSync(import_path33.default.dirname(logPath)))
|
|
16016
|
+
import_fs32.default.mkdirSync(import_path33.default.dirname(logPath), { recursive: true });
|
|
15850
16017
|
const sanitized = JSON.stringify({
|
|
15851
16018
|
...payload,
|
|
15852
16019
|
prompt: `<redacted, ${prompt.length} bytes>`
|
|
15853
16020
|
});
|
|
15854
|
-
|
|
16021
|
+
import_fs32.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
|
|
15855
16022
|
`);
|
|
15856
16023
|
} catch {
|
|
15857
16024
|
}
|
|
@@ -15871,8 +16038,8 @@ RAW: ${raw}
|
|
|
15871
16038
|
);
|
|
15872
16039
|
const reason = `\u{1F6A8} Node9 DLP: ${dlpMatch.patternName} detected in prompt (${dlpMatch.redactedSample}). Prompt was not submitted \u2014 remove the credential and try again.`;
|
|
15873
16040
|
try {
|
|
15874
|
-
const ttyFd =
|
|
15875
|
-
|
|
16041
|
+
const ttyFd = import_fs32.default.openSync("/dev/tty", "w");
|
|
16042
|
+
import_fs32.default.writeSync(
|
|
15876
16043
|
ttyFd,
|
|
15877
16044
|
import_chalk9.default.bgRed.white.bold(`
|
|
15878
16045
|
\u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
|
|
@@ -15882,7 +16049,7 @@ RAW: ${raw}
|
|
|
15882
16049
|
|
|
15883
16050
|
`)
|
|
15884
16051
|
);
|
|
15885
|
-
|
|
16052
|
+
import_fs32.default.closeSync(ttyFd);
|
|
15886
16053
|
} catch {
|
|
15887
16054
|
}
|
|
15888
16055
|
const isCodex = agent2 === "Codex";
|
|
@@ -15900,16 +16067,16 @@ RAW: ${raw}
|
|
|
15900
16067
|
);
|
|
15901
16068
|
process.exit(2);
|
|
15902
16069
|
}
|
|
15903
|
-
const safeCwdForConfig = typeof payload.cwd === "string" &&
|
|
16070
|
+
const safeCwdForConfig = typeof payload.cwd === "string" && import_path33.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
|
|
15904
16071
|
const config = getConfig(safeCwdForConfig);
|
|
15905
16072
|
if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
|
|
15906
16073
|
try {
|
|
15907
16074
|
const scriptPath = process.argv[1];
|
|
15908
|
-
if (typeof scriptPath !== "string" || !
|
|
16075
|
+
if (typeof scriptPath !== "string" || !import_path33.default.isAbsolute(scriptPath))
|
|
15909
16076
|
throw new Error("node9: argv[1] is not an absolute path");
|
|
15910
|
-
const resolvedScript =
|
|
15911
|
-
const packageDist =
|
|
15912
|
-
if (!resolvedScript.startsWith(packageDist +
|
|
16077
|
+
const resolvedScript = import_fs32.default.realpathSync(scriptPath);
|
|
16078
|
+
const packageDist = import_fs32.default.realpathSync(import_path33.default.resolve(__dirname, "../.."));
|
|
16079
|
+
if (!resolvedScript.startsWith(packageDist + import_path33.default.sep) && resolvedScript !== packageDist)
|
|
15913
16080
|
throw new Error(
|
|
15914
16081
|
`node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
|
|
15915
16082
|
);
|
|
@@ -15931,10 +16098,10 @@ RAW: ${raw}
|
|
|
15931
16098
|
});
|
|
15932
16099
|
d.unref();
|
|
15933
16100
|
} catch (spawnErr) {
|
|
15934
|
-
const logPath =
|
|
16101
|
+
const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
15935
16102
|
const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
|
|
15936
16103
|
try {
|
|
15937
|
-
|
|
16104
|
+
import_fs32.default.appendFileSync(
|
|
15938
16105
|
logPath,
|
|
15939
16106
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
|
|
15940
16107
|
`
|
|
@@ -15944,10 +16111,10 @@ RAW: ${raw}
|
|
|
15944
16111
|
}
|
|
15945
16112
|
}
|
|
15946
16113
|
if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
|
|
15947
|
-
const logPath =
|
|
15948
|
-
if (!
|
|
15949
|
-
|
|
15950
|
-
|
|
16114
|
+
const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
16115
|
+
if (!import_fs32.default.existsSync(import_path33.default.dirname(logPath)))
|
|
16116
|
+
import_fs32.default.mkdirSync(import_path33.default.dirname(logPath), { recursive: true });
|
|
16117
|
+
import_fs32.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
|
|
15951
16118
|
`);
|
|
15952
16119
|
}
|
|
15953
16120
|
const toolName = sanitize2(payload.tool_name ?? payload.name ?? "");
|
|
@@ -15960,8 +16127,8 @@ RAW: ${raw}
|
|
|
15960
16127
|
const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
|
|
15961
16128
|
let ttyFd = null;
|
|
15962
16129
|
try {
|
|
15963
|
-
ttyFd =
|
|
15964
|
-
const writeTty = (line) =>
|
|
16130
|
+
ttyFd = import_fs32.default.openSync("/dev/tty", "w");
|
|
16131
|
+
const writeTty = (line) => import_fs32.default.writeSync(ttyFd, line + "\n");
|
|
15965
16132
|
if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
|
|
15966
16133
|
writeTty(import_chalk9.default.bgRed.white.bold(`
|
|
15967
16134
|
\u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
|
|
@@ -15980,7 +16147,7 @@ RAW: ${raw}
|
|
|
15980
16147
|
} finally {
|
|
15981
16148
|
if (ttyFd !== null)
|
|
15982
16149
|
try {
|
|
15983
|
-
|
|
16150
|
+
import_fs32.default.closeSync(ttyFd);
|
|
15984
16151
|
} catch {
|
|
15985
16152
|
}
|
|
15986
16153
|
}
|
|
@@ -16016,17 +16183,17 @@ RAW: ${raw}
|
|
|
16016
16183
|
const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
|
|
16017
16184
|
if (skillPinCfg.enabled && safeSessionId) {
|
|
16018
16185
|
try {
|
|
16019
|
-
const sessionsDir =
|
|
16020
|
-
const flagPath =
|
|
16186
|
+
const sessionsDir = import_path33.default.join(import_os28.default.homedir(), ".node9", "skill-sessions");
|
|
16187
|
+
const flagPath = import_path33.default.join(sessionsDir, `${safeSessionId}.json`);
|
|
16021
16188
|
let flag = null;
|
|
16022
16189
|
try {
|
|
16023
|
-
flag = JSON.parse(
|
|
16190
|
+
flag = JSON.parse(import_fs32.default.readFileSync(flagPath, "utf-8"));
|
|
16024
16191
|
} catch {
|
|
16025
16192
|
}
|
|
16026
16193
|
const writeFlag = (data2) => {
|
|
16027
16194
|
try {
|
|
16028
|
-
|
|
16029
|
-
|
|
16195
|
+
import_fs32.default.mkdirSync(sessionsDir, { recursive: true });
|
|
16196
|
+
import_fs32.default.writeFileSync(
|
|
16030
16197
|
flagPath,
|
|
16031
16198
|
JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
|
|
16032
16199
|
{ mode: 384 }
|
|
@@ -16037,8 +16204,8 @@ RAW: ${raw}
|
|
|
16037
16204
|
const sendSkillWarn = (detail, recoveryCmd) => {
|
|
16038
16205
|
let ttyFd = null;
|
|
16039
16206
|
try {
|
|
16040
|
-
ttyFd =
|
|
16041
|
-
const w = (line) =>
|
|
16207
|
+
ttyFd = import_fs32.default.openSync("/dev/tty", "w");
|
|
16208
|
+
const w = (line) => import_fs32.default.writeSync(ttyFd, line + "\n");
|
|
16042
16209
|
w(import_chalk9.default.yellow(`
|
|
16043
16210
|
\u26A0\uFE0F Node9: installed skill drift detected`));
|
|
16044
16211
|
w(import_chalk9.default.gray(` ${detail}`));
|
|
@@ -16053,7 +16220,7 @@ RAW: ${raw}
|
|
|
16053
16220
|
} finally {
|
|
16054
16221
|
if (ttyFd !== null)
|
|
16055
16222
|
try {
|
|
16056
|
-
|
|
16223
|
+
import_fs32.default.closeSync(ttyFd);
|
|
16057
16224
|
} catch {
|
|
16058
16225
|
}
|
|
16059
16226
|
}
|
|
@@ -16069,7 +16236,7 @@ RAW: ${raw}
|
|
|
16069
16236
|
return;
|
|
16070
16237
|
}
|
|
16071
16238
|
if (!flag || flag.state !== "verified" && flag.state !== "warned") {
|
|
16072
|
-
const absoluteCwd = typeof payload.cwd === "string" &&
|
|
16239
|
+
const absoluteCwd = typeof payload.cwd === "string" && import_path33.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
|
|
16073
16240
|
const extraRoots = skillPinCfg.roots;
|
|
16074
16241
|
const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
|
|
16075
16242
|
const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
|
|
@@ -16110,10 +16277,10 @@ RAW: ${raw}
|
|
|
16110
16277
|
}
|
|
16111
16278
|
try {
|
|
16112
16279
|
const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
16113
|
-
for (const name of
|
|
16114
|
-
const p =
|
|
16280
|
+
for (const name of import_fs32.default.readdirSync(sessionsDir)) {
|
|
16281
|
+
const p = import_path33.default.join(sessionsDir, name);
|
|
16115
16282
|
try {
|
|
16116
|
-
if (
|
|
16283
|
+
if (import_fs32.default.statSync(p).mtimeMs < cutoff) import_fs32.default.unlinkSync(p);
|
|
16117
16284
|
} catch {
|
|
16118
16285
|
}
|
|
16119
16286
|
}
|
|
@@ -16123,9 +16290,9 @@ RAW: ${raw}
|
|
|
16123
16290
|
} catch (err2) {
|
|
16124
16291
|
if (process.env.NODE9_DEBUG === "1") {
|
|
16125
16292
|
try {
|
|
16126
|
-
const dbg =
|
|
16293
|
+
const dbg = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
16127
16294
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
16128
|
-
|
|
16295
|
+
import_fs32.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
|
|
16129
16296
|
`);
|
|
16130
16297
|
} catch {
|
|
16131
16298
|
}
|
|
@@ -16135,7 +16302,7 @@ RAW: ${raw}
|
|
|
16135
16302
|
if (shouldSnapshot(toolName, toolInput, config)) {
|
|
16136
16303
|
await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
|
|
16137
16304
|
}
|
|
16138
|
-
const safeCwdForAuth = typeof payload.cwd === "string" &&
|
|
16305
|
+
const safeCwdForAuth = typeof payload.cwd === "string" && import_path33.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
|
|
16139
16306
|
const result = await authorizeHeadless(toolName, toolInput, meta, {
|
|
16140
16307
|
cwd: safeCwdForAuth
|
|
16141
16308
|
});
|
|
@@ -16147,12 +16314,12 @@ RAW: ${raw}
|
|
|
16147
16314
|
}
|
|
16148
16315
|
if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
|
|
16149
16316
|
try {
|
|
16150
|
-
const tty =
|
|
16151
|
-
|
|
16317
|
+
const tty = import_fs32.default.openSync("/dev/tty", "w");
|
|
16318
|
+
import_fs32.default.writeSync(
|
|
16152
16319
|
tty,
|
|
16153
16320
|
import_chalk9.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
|
|
16154
16321
|
);
|
|
16155
|
-
|
|
16322
|
+
import_fs32.default.closeSync(tty);
|
|
16156
16323
|
} catch {
|
|
16157
16324
|
}
|
|
16158
16325
|
const daemonReady = await autoStartDaemonAndWait();
|
|
@@ -16179,9 +16346,9 @@ RAW: ${raw}
|
|
|
16179
16346
|
});
|
|
16180
16347
|
} catch (err2) {
|
|
16181
16348
|
if (process.env.NODE9_DEBUG === "1") {
|
|
16182
|
-
const logPath =
|
|
16349
|
+
const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
16183
16350
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
16184
|
-
|
|
16351
|
+
import_fs32.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
|
|
16185
16352
|
`);
|
|
16186
16353
|
}
|
|
16187
16354
|
process.exit(0);
|
|
@@ -16215,9 +16382,9 @@ RAW: ${raw}
|
|
|
16215
16382
|
}
|
|
16216
16383
|
|
|
16217
16384
|
// src/cli/commands/log.ts
|
|
16218
|
-
var
|
|
16219
|
-
var
|
|
16220
|
-
var
|
|
16385
|
+
var import_fs33 = __toESM(require("fs"));
|
|
16386
|
+
var import_path34 = __toESM(require("path"));
|
|
16387
|
+
var import_os29 = __toESM(require("os"));
|
|
16221
16388
|
init_audit();
|
|
16222
16389
|
init_config();
|
|
16223
16390
|
init_daemon();
|
|
@@ -16295,10 +16462,10 @@ function registerLogCommand(program2) {
|
|
|
16295
16462
|
};
|
|
16296
16463
|
if (agent) entry.agent = agent;
|
|
16297
16464
|
if (payload.session_id) entry.sessionId = payload.session_id;
|
|
16298
|
-
const logPath =
|
|
16299
|
-
if (!
|
|
16300
|
-
|
|
16301
|
-
|
|
16465
|
+
const logPath = import_path34.default.join(import_os29.default.homedir(), ".node9", "audit.log");
|
|
16466
|
+
if (!import_fs33.default.existsSync(import_path34.default.dirname(logPath)))
|
|
16467
|
+
import_fs33.default.mkdirSync(import_path34.default.dirname(logPath), { recursive: true });
|
|
16468
|
+
import_fs33.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
|
|
16302
16469
|
if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
|
|
16303
16470
|
const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
16304
16471
|
if (command) {
|
|
@@ -16331,7 +16498,7 @@ function registerLogCommand(program2) {
|
|
|
16331
16498
|
}
|
|
16332
16499
|
}
|
|
16333
16500
|
}
|
|
16334
|
-
const safeCwd = typeof payload.cwd === "string" &&
|
|
16501
|
+
const safeCwd = typeof payload.cwd === "string" && import_path34.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
|
|
16335
16502
|
const config = getConfig(safeCwd);
|
|
16336
16503
|
if ((tool === "Bash" || tool === "bash") && config.settings.enableUndo !== false) {
|
|
16337
16504
|
const bashCommand = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
@@ -16352,9 +16519,9 @@ function registerLogCommand(program2) {
|
|
|
16352
16519
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
16353
16520
|
process.stderr.write(`[Node9] audit log error: ${msg}
|
|
16354
16521
|
`);
|
|
16355
|
-
const debugPath =
|
|
16522
|
+
const debugPath = import_path34.default.join(import_os29.default.homedir(), ".node9", "hook-debug.log");
|
|
16356
16523
|
try {
|
|
16357
|
-
|
|
16524
|
+
import_fs33.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
|
|
16358
16525
|
`);
|
|
16359
16526
|
} catch {
|
|
16360
16527
|
}
|
|
@@ -16754,14 +16921,14 @@ function registerConfigShowCommand(program2) {
|
|
|
16754
16921
|
|
|
16755
16922
|
// src/cli/commands/doctor.ts
|
|
16756
16923
|
var import_chalk11 = __toESM(require("chalk"));
|
|
16757
|
-
var
|
|
16758
|
-
var
|
|
16759
|
-
var
|
|
16924
|
+
var import_fs34 = __toESM(require("fs"));
|
|
16925
|
+
var import_path35 = __toESM(require("path"));
|
|
16926
|
+
var import_os30 = __toESM(require("os"));
|
|
16760
16927
|
var import_child_process8 = require("child_process");
|
|
16761
16928
|
init_daemon();
|
|
16762
16929
|
function registerDoctorCommand(program2, version2) {
|
|
16763
16930
|
program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(() => {
|
|
16764
|
-
const homeDir2 =
|
|
16931
|
+
const homeDir2 = import_os30.default.homedir();
|
|
16765
16932
|
let failures = 0;
|
|
16766
16933
|
function pass(msg) {
|
|
16767
16934
|
console.log(import_chalk11.default.green(" \u2705 ") + msg);
|
|
@@ -16810,10 +16977,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16810
16977
|
);
|
|
16811
16978
|
}
|
|
16812
16979
|
section("Configuration");
|
|
16813
|
-
const globalConfigPath =
|
|
16814
|
-
if (
|
|
16980
|
+
const globalConfigPath = import_path35.default.join(homeDir2, ".node9", "config.json");
|
|
16981
|
+
if (import_fs34.default.existsSync(globalConfigPath)) {
|
|
16815
16982
|
try {
|
|
16816
|
-
JSON.parse(
|
|
16983
|
+
JSON.parse(import_fs34.default.readFileSync(globalConfigPath, "utf-8"));
|
|
16817
16984
|
pass("~/.node9/config.json found and valid");
|
|
16818
16985
|
} catch {
|
|
16819
16986
|
fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
|
|
@@ -16821,10 +16988,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16821
16988
|
} else {
|
|
16822
16989
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
16823
16990
|
}
|
|
16824
|
-
const projectConfigPath =
|
|
16825
|
-
if (
|
|
16991
|
+
const projectConfigPath = import_path35.default.join(process.cwd(), "node9.config.json");
|
|
16992
|
+
if (import_fs34.default.existsSync(projectConfigPath)) {
|
|
16826
16993
|
try {
|
|
16827
|
-
JSON.parse(
|
|
16994
|
+
JSON.parse(import_fs34.default.readFileSync(projectConfigPath, "utf-8"));
|
|
16828
16995
|
pass("node9.config.json found and valid (project)");
|
|
16829
16996
|
} catch {
|
|
16830
16997
|
fail(
|
|
@@ -16833,8 +17000,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16833
17000
|
);
|
|
16834
17001
|
}
|
|
16835
17002
|
}
|
|
16836
|
-
const credsPath =
|
|
16837
|
-
if (
|
|
17003
|
+
const credsPath = import_path35.default.join(homeDir2, ".node9", "credentials.json");
|
|
17004
|
+
if (import_fs34.default.existsSync(credsPath)) {
|
|
16838
17005
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
16839
17006
|
} else {
|
|
16840
17007
|
warn(
|
|
@@ -16843,10 +17010,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16843
17010
|
);
|
|
16844
17011
|
}
|
|
16845
17012
|
section("Agent Hooks");
|
|
16846
|
-
const claudeSettingsPath =
|
|
16847
|
-
if (
|
|
17013
|
+
const claudeSettingsPath = import_path35.default.join(homeDir2, ".claude", "settings.json");
|
|
17014
|
+
if (import_fs34.default.existsSync(claudeSettingsPath)) {
|
|
16848
17015
|
try {
|
|
16849
|
-
const cs = JSON.parse(
|
|
17016
|
+
const cs = JSON.parse(import_fs34.default.readFileSync(claudeSettingsPath, "utf-8"));
|
|
16850
17017
|
const hasHook = cs.hooks?.PreToolUse?.some(
|
|
16851
17018
|
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
16852
17019
|
);
|
|
@@ -16862,10 +17029,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16862
17029
|
} else {
|
|
16863
17030
|
warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
|
|
16864
17031
|
}
|
|
16865
|
-
const geminiSettingsPath =
|
|
16866
|
-
if (
|
|
17032
|
+
const geminiSettingsPath = import_path35.default.join(homeDir2, ".gemini", "settings.json");
|
|
17033
|
+
if (import_fs34.default.existsSync(geminiSettingsPath)) {
|
|
16867
17034
|
try {
|
|
16868
|
-
const gs = JSON.parse(
|
|
17035
|
+
const gs = JSON.parse(import_fs34.default.readFileSync(geminiSettingsPath, "utf-8"));
|
|
16869
17036
|
const hasHook = gs.hooks?.BeforeTool?.some(
|
|
16870
17037
|
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
16871
17038
|
);
|
|
@@ -16881,10 +17048,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16881
17048
|
} else {
|
|
16882
17049
|
warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
|
|
16883
17050
|
}
|
|
16884
|
-
const cursorHooksPath =
|
|
16885
|
-
if (
|
|
17051
|
+
const cursorHooksPath = import_path35.default.join(homeDir2, ".cursor", "hooks.json");
|
|
17052
|
+
if (import_fs34.default.existsSync(cursorHooksPath)) {
|
|
16886
17053
|
try {
|
|
16887
|
-
const cur = JSON.parse(
|
|
17054
|
+
const cur = JSON.parse(import_fs34.default.readFileSync(cursorHooksPath, "utf-8"));
|
|
16888
17055
|
const hasHook = cur.hooks?.preToolUse?.some(
|
|
16889
17056
|
(h) => h.command?.includes("node9") || h.command?.includes("cli.js")
|
|
16890
17057
|
);
|
|
@@ -16924,9 +17091,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16924
17091
|
|
|
16925
17092
|
// src/cli/commands/audit.ts
|
|
16926
17093
|
var import_chalk12 = __toESM(require("chalk"));
|
|
16927
|
-
var
|
|
16928
|
-
var
|
|
16929
|
-
var
|
|
17094
|
+
var import_fs35 = __toESM(require("fs"));
|
|
17095
|
+
var import_path36 = __toESM(require("path"));
|
|
17096
|
+
var import_os31 = __toESM(require("os"));
|
|
16930
17097
|
function formatRelativeTime(timestamp) {
|
|
16931
17098
|
const diff = Date.now() - new Date(timestamp).getTime();
|
|
16932
17099
|
const sec = Math.floor(diff / 1e3);
|
|
@@ -16939,14 +17106,14 @@ function formatRelativeTime(timestamp) {
|
|
|
16939
17106
|
}
|
|
16940
17107
|
function registerAuditCommand(program2) {
|
|
16941
17108
|
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) => {
|
|
16942
|
-
const logPath =
|
|
16943
|
-
if (!
|
|
17109
|
+
const logPath = import_path36.default.join(import_os31.default.homedir(), ".node9", "audit.log");
|
|
17110
|
+
if (!import_fs35.default.existsSync(logPath)) {
|
|
16944
17111
|
console.log(
|
|
16945
17112
|
import_chalk12.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
16946
17113
|
);
|
|
16947
17114
|
return;
|
|
16948
17115
|
}
|
|
16949
|
-
const raw =
|
|
17116
|
+
const raw = import_fs35.default.readFileSync(logPath, "utf-8");
|
|
16950
17117
|
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
16951
17118
|
let entries = lines.flatMap((line) => {
|
|
16952
17119
|
try {
|
|
@@ -17002,9 +17169,9 @@ function registerAuditCommand(program2) {
|
|
|
17002
17169
|
var import_chalk13 = __toESM(require("chalk"));
|
|
17003
17170
|
|
|
17004
17171
|
// src/cli/aggregate/report-audit.ts
|
|
17005
|
-
var
|
|
17006
|
-
var
|
|
17007
|
-
var
|
|
17172
|
+
var import_fs36 = __toESM(require("fs"));
|
|
17173
|
+
var import_os32 = __toESM(require("os"));
|
|
17174
|
+
var import_path37 = __toESM(require("path"));
|
|
17008
17175
|
init_costSync();
|
|
17009
17176
|
init_litellm();
|
|
17010
17177
|
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;
|
|
@@ -17086,8 +17253,8 @@ function getDateRange(period, now) {
|
|
|
17086
17253
|
}
|
|
17087
17254
|
}
|
|
17088
17255
|
function parseAuditLog(logPath) {
|
|
17089
|
-
if (!
|
|
17090
|
-
const raw =
|
|
17256
|
+
if (!import_fs36.default.existsSync(logPath)) return [];
|
|
17257
|
+
const raw = import_fs36.default.readFileSync(logPath, "utf-8");
|
|
17091
17258
|
return raw.split("\n").flatMap((line) => {
|
|
17092
17259
|
if (!line.trim()) return [];
|
|
17093
17260
|
try {
|
|
@@ -17147,25 +17314,25 @@ function freezeClaudeCost(acc) {
|
|
|
17147
17314
|
};
|
|
17148
17315
|
}
|
|
17149
17316
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
17150
|
-
const projPath =
|
|
17317
|
+
const projPath = import_path37.default.join(projectsDir, proj);
|
|
17151
17318
|
let files;
|
|
17152
17319
|
try {
|
|
17153
|
-
const stat =
|
|
17320
|
+
const stat = import_fs36.default.statSync(projPath);
|
|
17154
17321
|
if (!stat.isDirectory()) return;
|
|
17155
|
-
files =
|
|
17322
|
+
files = import_fs36.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
17156
17323
|
} catch {
|
|
17157
17324
|
return;
|
|
17158
17325
|
}
|
|
17159
17326
|
const startMs = start.getTime();
|
|
17160
17327
|
for (const file of files) {
|
|
17161
|
-
const filePath =
|
|
17328
|
+
const filePath = import_path37.default.join(projPath, file);
|
|
17162
17329
|
try {
|
|
17163
|
-
if (
|
|
17330
|
+
if (import_fs36.default.statSync(filePath).mtimeMs < startMs) continue;
|
|
17164
17331
|
} catch {
|
|
17165
17332
|
continue;
|
|
17166
17333
|
}
|
|
17167
17334
|
try {
|
|
17168
|
-
const raw =
|
|
17335
|
+
const raw = import_fs36.default.readFileSync(filePath, "utf-8");
|
|
17169
17336
|
for (const line of raw.split("\n")) {
|
|
17170
17337
|
if (!line.trim()) continue;
|
|
17171
17338
|
let entry;
|
|
@@ -17215,10 +17382,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
17215
17382
|
}
|
|
17216
17383
|
function loadClaudeCost(start, end, projectsDir) {
|
|
17217
17384
|
const acc = emptyClaudeCostAccumulator();
|
|
17218
|
-
if (!
|
|
17385
|
+
if (!import_fs36.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
|
|
17219
17386
|
let dirs;
|
|
17220
17387
|
try {
|
|
17221
|
-
dirs =
|
|
17388
|
+
dirs = import_fs36.default.readdirSync(projectsDir);
|
|
17222
17389
|
} catch {
|
|
17223
17390
|
return freezeClaudeCost(acc);
|
|
17224
17391
|
}
|
|
@@ -17230,7 +17397,7 @@ function loadClaudeCost(start, end, projectsDir) {
|
|
|
17230
17397
|
function processCodexCostFile(filePath, start, end, acc) {
|
|
17231
17398
|
let lines;
|
|
17232
17399
|
try {
|
|
17233
|
-
lines =
|
|
17400
|
+
lines = import_fs36.default.readFileSync(filePath, "utf-8").split("\n");
|
|
17234
17401
|
} catch {
|
|
17235
17402
|
return;
|
|
17236
17403
|
}
|
|
@@ -17275,31 +17442,31 @@ function processCodexCostFile(filePath, start, end, acc) {
|
|
|
17275
17442
|
}
|
|
17276
17443
|
function listCodexSessionFiles(sessionsBase) {
|
|
17277
17444
|
const jsonlFiles = [];
|
|
17278
|
-
if (!
|
|
17445
|
+
if (!import_fs36.default.existsSync(sessionsBase)) return jsonlFiles;
|
|
17279
17446
|
try {
|
|
17280
|
-
for (const year of
|
|
17281
|
-
const yearPath =
|
|
17447
|
+
for (const year of import_fs36.default.readdirSync(sessionsBase)) {
|
|
17448
|
+
const yearPath = import_path37.default.join(sessionsBase, year);
|
|
17282
17449
|
try {
|
|
17283
|
-
if (!
|
|
17450
|
+
if (!import_fs36.default.statSync(yearPath).isDirectory()) continue;
|
|
17284
17451
|
} catch {
|
|
17285
17452
|
continue;
|
|
17286
17453
|
}
|
|
17287
|
-
for (const month of
|
|
17288
|
-
const monthPath =
|
|
17454
|
+
for (const month of import_fs36.default.readdirSync(yearPath)) {
|
|
17455
|
+
const monthPath = import_path37.default.join(yearPath, month);
|
|
17289
17456
|
try {
|
|
17290
|
-
if (!
|
|
17457
|
+
if (!import_fs36.default.statSync(monthPath).isDirectory()) continue;
|
|
17291
17458
|
} catch {
|
|
17292
17459
|
continue;
|
|
17293
17460
|
}
|
|
17294
|
-
for (const day of
|
|
17295
|
-
const dayPath =
|
|
17461
|
+
for (const day of import_fs36.default.readdirSync(monthPath)) {
|
|
17462
|
+
const dayPath = import_path37.default.join(monthPath, day);
|
|
17296
17463
|
try {
|
|
17297
|
-
if (!
|
|
17464
|
+
if (!import_fs36.default.statSync(dayPath).isDirectory()) continue;
|
|
17298
17465
|
} catch {
|
|
17299
17466
|
continue;
|
|
17300
17467
|
}
|
|
17301
|
-
for (const file of
|
|
17302
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
17468
|
+
for (const file of import_fs36.default.readdirSync(dayPath)) {
|
|
17469
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path37.default.join(dayPath, file));
|
|
17303
17470
|
}
|
|
17304
17471
|
}
|
|
17305
17472
|
}
|
|
@@ -17352,13 +17519,13 @@ function freezeGeminiCost(acc) {
|
|
|
17352
17519
|
function processGeminiCostFile(filePath, projectKey, start, end, acc) {
|
|
17353
17520
|
const startMs = start.getTime();
|
|
17354
17521
|
try {
|
|
17355
|
-
if (
|
|
17522
|
+
if (import_fs36.default.statSync(filePath).mtimeMs < startMs) return;
|
|
17356
17523
|
} catch {
|
|
17357
17524
|
return;
|
|
17358
17525
|
}
|
|
17359
17526
|
let raw;
|
|
17360
17527
|
try {
|
|
17361
|
-
raw =
|
|
17528
|
+
raw = import_fs36.default.readFileSync(filePath, "utf-8");
|
|
17362
17529
|
} catch {
|
|
17363
17530
|
return;
|
|
17364
17531
|
}
|
|
@@ -17407,30 +17574,30 @@ function listGeminiSessionFiles(geminiTmpDir) {
|
|
|
17407
17574
|
const out = [];
|
|
17408
17575
|
let dirs;
|
|
17409
17576
|
try {
|
|
17410
|
-
if (!
|
|
17411
|
-
dirs =
|
|
17577
|
+
if (!import_fs36.default.statSync(geminiTmpDir).isDirectory()) return out;
|
|
17578
|
+
dirs = import_fs36.default.readdirSync(geminiTmpDir);
|
|
17412
17579
|
} catch {
|
|
17413
17580
|
return out;
|
|
17414
17581
|
}
|
|
17415
17582
|
for (const proj of dirs) {
|
|
17416
|
-
const chatsDir =
|
|
17583
|
+
const chatsDir = import_path37.default.join(geminiTmpDir, proj, "chats");
|
|
17417
17584
|
let files;
|
|
17418
17585
|
try {
|
|
17419
|
-
if (!
|
|
17420
|
-
files =
|
|
17586
|
+
if (!import_fs36.default.statSync(chatsDir).isDirectory()) continue;
|
|
17587
|
+
files = import_fs36.default.readdirSync(chatsDir);
|
|
17421
17588
|
} catch {
|
|
17422
17589
|
continue;
|
|
17423
17590
|
}
|
|
17424
17591
|
for (const f of files) {
|
|
17425
17592
|
if (!f.endsWith(".jsonl")) continue;
|
|
17426
|
-
out.push({ projectKey: proj, file:
|
|
17593
|
+
out.push({ projectKey: proj, file: import_path37.default.join(chatsDir, f) });
|
|
17427
17594
|
}
|
|
17428
17595
|
}
|
|
17429
17596
|
return out;
|
|
17430
17597
|
}
|
|
17431
17598
|
function loadGeminiCost(start, end, geminiTmpDir) {
|
|
17432
17599
|
const acc = emptyGeminiAccumulator();
|
|
17433
|
-
if (!
|
|
17600
|
+
if (!import_fs36.default.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
|
|
17434
17601
|
for (const { projectKey, file } of listGeminiSessionFiles(geminiTmpDir)) {
|
|
17435
17602
|
processGeminiCostFile(file, projectKey, start, end, acc);
|
|
17436
17603
|
}
|
|
@@ -17438,11 +17605,11 @@ function loadGeminiCost(start, end, geminiTmpDir) {
|
|
|
17438
17605
|
}
|
|
17439
17606
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
17440
17607
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
17441
|
-
const auditLogPath = opts.auditLogPath ??
|
|
17442
|
-
const claudeProjectsDir = opts.claudeProjectsDir ??
|
|
17443
|
-
const codexSessionsDir = opts.codexSessionsDir ??
|
|
17444
|
-
const geminiTmpDir = opts.geminiTmpDir ??
|
|
17445
|
-
const hasAuditFile =
|
|
17608
|
+
const auditLogPath = opts.auditLogPath ?? import_path37.default.join(import_os32.default.homedir(), ".node9", "audit.log");
|
|
17609
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? import_path37.default.join(import_os32.default.homedir(), ".claude", "projects");
|
|
17610
|
+
const codexSessionsDir = opts.codexSessionsDir ?? import_path37.default.join(import_os32.default.homedir(), ".codex", "sessions");
|
|
17611
|
+
const geminiTmpDir = opts.geminiTmpDir ?? import_path37.default.join(import_os32.default.homedir(), ".gemini", "tmp");
|
|
17612
|
+
const hasAuditFile = import_fs36.default.existsSync(auditLogPath);
|
|
17446
17613
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
|
|
17447
17614
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
17448
17615
|
const { start, end } = getDateRange(period, now);
|
|
@@ -18138,14 +18305,14 @@ function registerDaemonCommand(program2) {
|
|
|
18138
18305
|
|
|
18139
18306
|
// src/cli/commands/status.ts
|
|
18140
18307
|
var import_chalk15 = __toESM(require("chalk"));
|
|
18141
|
-
var
|
|
18142
|
-
var
|
|
18143
|
-
var
|
|
18308
|
+
var import_fs37 = __toESM(require("fs"));
|
|
18309
|
+
var import_path38 = __toESM(require("path"));
|
|
18310
|
+
var import_os33 = __toESM(require("os"));
|
|
18144
18311
|
init_core();
|
|
18145
18312
|
init_daemon();
|
|
18146
18313
|
function readJson2(filePath) {
|
|
18147
18314
|
try {
|
|
18148
|
-
if (
|
|
18315
|
+
if (import_fs37.default.existsSync(filePath)) return JSON.parse(import_fs37.default.readFileSync(filePath, "utf-8"));
|
|
18149
18316
|
} catch {
|
|
18150
18317
|
}
|
|
18151
18318
|
return null;
|
|
@@ -18210,28 +18377,28 @@ function registerStatusCommand(program2) {
|
|
|
18210
18377
|
console.log("");
|
|
18211
18378
|
const modeLabel = settings.mode === "audit" ? import_chalk15.default.blue("audit") : settings.mode === "strict" ? import_chalk15.default.red("strict") : import_chalk15.default.white("standard");
|
|
18212
18379
|
console.log(` Mode: ${modeLabel}`);
|
|
18213
|
-
const projectConfig =
|
|
18214
|
-
const globalConfig =
|
|
18380
|
+
const projectConfig = import_path38.default.join(process.cwd(), "node9.config.json");
|
|
18381
|
+
const globalConfig = import_path38.default.join(import_os33.default.homedir(), ".node9", "config.json");
|
|
18215
18382
|
console.log(
|
|
18216
|
-
` Local: ${
|
|
18383
|
+
` Local: ${import_fs37.default.existsSync(projectConfig) ? import_chalk15.default.green("Active (node9.config.json)") : import_chalk15.default.gray("Not present")}`
|
|
18217
18384
|
);
|
|
18218
18385
|
console.log(
|
|
18219
|
-
` Global: ${
|
|
18386
|
+
` Global: ${import_fs37.default.existsSync(globalConfig) ? import_chalk15.default.green("Active (~/.node9/config.json)") : import_chalk15.default.gray("Not present")}`
|
|
18220
18387
|
);
|
|
18221
18388
|
if (mergedConfig.policy.sandboxPaths.length > 0) {
|
|
18222
18389
|
console.log(
|
|
18223
18390
|
` Sandbox: ${import_chalk15.default.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
|
|
18224
18391
|
);
|
|
18225
18392
|
}
|
|
18226
|
-
const homeDir2 =
|
|
18393
|
+
const homeDir2 = import_os33.default.homedir();
|
|
18227
18394
|
const claudeSettings = readJson2(
|
|
18228
|
-
|
|
18395
|
+
import_path38.default.join(homeDir2, ".claude", "settings.json")
|
|
18229
18396
|
);
|
|
18230
|
-
const claudeConfig = readJson2(
|
|
18397
|
+
const claudeConfig = readJson2(import_path38.default.join(homeDir2, ".claude.json"));
|
|
18231
18398
|
const geminiSettings = readJson2(
|
|
18232
|
-
|
|
18399
|
+
import_path38.default.join(homeDir2, ".gemini", "settings.json")
|
|
18233
18400
|
);
|
|
18234
|
-
const cursorConfig = readJson2(
|
|
18401
|
+
const cursorConfig = readJson2(import_path38.default.join(homeDir2, ".cursor", "mcp.json"));
|
|
18235
18402
|
const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig;
|
|
18236
18403
|
if (agentFound) {
|
|
18237
18404
|
console.log("");
|
|
@@ -18290,9 +18457,9 @@ function registerStatusCommand(program2) {
|
|
|
18290
18457
|
|
|
18291
18458
|
// src/cli/commands/init.ts
|
|
18292
18459
|
var import_chalk16 = __toESM(require("chalk"));
|
|
18293
|
-
var
|
|
18294
|
-
var
|
|
18295
|
-
var
|
|
18460
|
+
var import_fs38 = __toESM(require("fs"));
|
|
18461
|
+
var import_path39 = __toESM(require("path"));
|
|
18462
|
+
var import_os34 = __toESM(require("os"));
|
|
18296
18463
|
var import_https4 = __toESM(require("https"));
|
|
18297
18464
|
init_core();
|
|
18298
18465
|
init_setup();
|
|
@@ -18372,15 +18539,15 @@ function registerInitCommand(program2) {
|
|
|
18372
18539
|
}
|
|
18373
18540
|
console.log("");
|
|
18374
18541
|
}
|
|
18375
|
-
const configPath =
|
|
18376
|
-
if (
|
|
18542
|
+
const configPath = import_path39.default.join(import_os34.default.homedir(), ".node9", "config.json");
|
|
18543
|
+
if (import_fs38.default.existsSync(configPath) && !options.force) {
|
|
18377
18544
|
try {
|
|
18378
|
-
const existing = JSON.parse(
|
|
18545
|
+
const existing = JSON.parse(import_fs38.default.readFileSync(configPath, "utf-8"));
|
|
18379
18546
|
const settings = existing.settings ?? {};
|
|
18380
18547
|
if (settings.mode !== chosenMode) {
|
|
18381
18548
|
settings.mode = chosenMode;
|
|
18382
18549
|
existing.settings = settings;
|
|
18383
|
-
|
|
18550
|
+
import_fs38.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
|
|
18384
18551
|
console.log(import_chalk16.default.green(`\u2705 Mode updated: ${chosenMode}`));
|
|
18385
18552
|
} else {
|
|
18386
18553
|
console.log(import_chalk16.default.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
|
|
@@ -18393,9 +18560,9 @@ function registerInitCommand(program2) {
|
|
|
18393
18560
|
...DEFAULT_CONFIG,
|
|
18394
18561
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
18395
18562
|
};
|
|
18396
|
-
const dir =
|
|
18397
|
-
if (!
|
|
18398
|
-
|
|
18563
|
+
const dir = import_path39.default.dirname(configPath);
|
|
18564
|
+
if (!import_fs38.default.existsSync(dir)) import_fs38.default.mkdirSync(dir, { recursive: true });
|
|
18565
|
+
import_fs38.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
|
|
18399
18566
|
console.log(import_chalk16.default.green(`\u2705 Config created: ${configPath}`));
|
|
18400
18567
|
console.log(import_chalk16.default.gray(` Mode: ${chosenMode}`));
|
|
18401
18568
|
}
|
|
@@ -18493,7 +18660,7 @@ function registerInitCommand(program2) {
|
|
|
18493
18660
|
}
|
|
18494
18661
|
|
|
18495
18662
|
// src/cli/commands/undo.ts
|
|
18496
|
-
var
|
|
18663
|
+
var import_path40 = __toESM(require("path"));
|
|
18497
18664
|
var import_chalk18 = __toESM(require("chalk"));
|
|
18498
18665
|
|
|
18499
18666
|
// src/tui/undo-navigator.ts
|
|
@@ -18652,7 +18819,7 @@ function findMatchingCwd(startDir, history) {
|
|
|
18652
18819
|
let dir = startDir;
|
|
18653
18820
|
while (true) {
|
|
18654
18821
|
if (cwds.has(dir)) return dir;
|
|
18655
|
-
const parent =
|
|
18822
|
+
const parent = import_path40.default.dirname(dir);
|
|
18656
18823
|
if (parent === dir) return null;
|
|
18657
18824
|
dir = parent;
|
|
18658
18825
|
}
|
|
@@ -18785,90 +18952,7 @@ var import_child_process10 = require("child_process");
|
|
|
18785
18952
|
var import_execa3 = require("execa");
|
|
18786
18953
|
init_orchestrator();
|
|
18787
18954
|
init_provenance();
|
|
18788
|
-
|
|
18789
|
-
// src/mcp-pin.ts
|
|
18790
|
-
var import_fs38 = __toESM(require("fs"));
|
|
18791
|
-
var import_path40 = __toESM(require("path"));
|
|
18792
|
-
var import_os34 = __toESM(require("os"));
|
|
18793
|
-
var import_crypto10 = __toESM(require("crypto"));
|
|
18794
|
-
function getPinsFilePath2() {
|
|
18795
|
-
return import_path40.default.join(import_os34.default.homedir(), ".node9", "mcp-pins.json");
|
|
18796
|
-
}
|
|
18797
|
-
function hashToolDefinitions(tools) {
|
|
18798
|
-
const sorted = [...tools].sort((a, b) => {
|
|
18799
|
-
const nameA = a.name ?? "";
|
|
18800
|
-
const nameB = b.name ?? "";
|
|
18801
|
-
return nameA.localeCompare(nameB);
|
|
18802
|
-
});
|
|
18803
|
-
const canonical = JSON.stringify(sorted);
|
|
18804
|
-
return import_crypto10.default.createHash("sha256").update(canonical).digest("hex");
|
|
18805
|
-
}
|
|
18806
|
-
function getServerKey(upstreamCommand) {
|
|
18807
|
-
return import_crypto10.default.createHash("sha256").update(upstreamCommand).digest("hex").slice(0, 16);
|
|
18808
|
-
}
|
|
18809
|
-
function readMcpPinsSafe() {
|
|
18810
|
-
const filePath = getPinsFilePath2();
|
|
18811
|
-
try {
|
|
18812
|
-
const raw = import_fs38.default.readFileSync(filePath, "utf-8");
|
|
18813
|
-
if (!raw.trim()) {
|
|
18814
|
-
return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
18815
|
-
}
|
|
18816
|
-
const parsed = JSON.parse(raw);
|
|
18817
|
-
if (!parsed.servers || typeof parsed.servers !== "object" || Array.isArray(parsed.servers)) {
|
|
18818
|
-
return { ok: false, reason: "corrupt", detail: "invalid structure: missing servers object" };
|
|
18819
|
-
}
|
|
18820
|
-
return { ok: true, pins: { servers: parsed.servers } };
|
|
18821
|
-
} catch (err2) {
|
|
18822
|
-
if (err2.code === "ENOENT") {
|
|
18823
|
-
return { ok: false, reason: "missing" };
|
|
18824
|
-
}
|
|
18825
|
-
return { ok: false, reason: "corrupt", detail: String(err2) };
|
|
18826
|
-
}
|
|
18827
|
-
}
|
|
18828
|
-
function readMcpPins() {
|
|
18829
|
-
const result = readMcpPinsSafe();
|
|
18830
|
-
if (result.ok) return result.pins;
|
|
18831
|
-
if (result.reason === "missing") return { servers: {} };
|
|
18832
|
-
throw new Error(`[node9] MCP pin file is corrupt: ${result.detail}`);
|
|
18833
|
-
}
|
|
18834
|
-
function writeMcpPins(data) {
|
|
18835
|
-
const filePath = getPinsFilePath2();
|
|
18836
|
-
import_fs38.default.mkdirSync(import_path40.default.dirname(filePath), { recursive: true });
|
|
18837
|
-
const tmp = `${filePath}.${import_crypto10.default.randomBytes(6).toString("hex")}.tmp`;
|
|
18838
|
-
import_fs38.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
18839
|
-
import_fs38.default.renameSync(tmp, filePath);
|
|
18840
|
-
}
|
|
18841
|
-
function checkPin(serverKey, currentHash) {
|
|
18842
|
-
const result = readMcpPinsSafe();
|
|
18843
|
-
if (!result.ok) {
|
|
18844
|
-
if (result.reason === "missing") return "new";
|
|
18845
|
-
return "corrupt";
|
|
18846
|
-
}
|
|
18847
|
-
const entry = result.pins.servers[serverKey];
|
|
18848
|
-
if (!entry) return "new";
|
|
18849
|
-
return entry.toolsHash === currentHash ? "match" : "mismatch";
|
|
18850
|
-
}
|
|
18851
|
-
function updatePin(serverKey, label, toolsHash, toolNames) {
|
|
18852
|
-
const pins = readMcpPins();
|
|
18853
|
-
pins.servers[serverKey] = {
|
|
18854
|
-
label,
|
|
18855
|
-
toolsHash,
|
|
18856
|
-
toolNames,
|
|
18857
|
-
toolCount: toolNames.length,
|
|
18858
|
-
pinnedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
18859
|
-
};
|
|
18860
|
-
writeMcpPins(pins);
|
|
18861
|
-
}
|
|
18862
|
-
function removePin2(serverKey) {
|
|
18863
|
-
const pins = readMcpPins();
|
|
18864
|
-
delete pins.servers[serverKey];
|
|
18865
|
-
writeMcpPins(pins);
|
|
18866
|
-
}
|
|
18867
|
-
function clearAllPins2() {
|
|
18868
|
-
writeMcpPins({ servers: {} });
|
|
18869
|
-
}
|
|
18870
|
-
|
|
18871
|
-
// src/mcp-gateway/index.ts
|
|
18955
|
+
init_mcp_pin();
|
|
18872
18956
|
init_mcp_tools();
|
|
18873
18957
|
init_daemon();
|
|
18874
18958
|
function sanitize4(value) {
|
|
@@ -18930,6 +19014,7 @@ function tokenize4(cmd) {
|
|
|
18930
19014
|
return tokens;
|
|
18931
19015
|
}
|
|
18932
19016
|
async function runMcpGateway(upstreamCommand) {
|
|
19017
|
+
const gatewayCwd = process.cwd();
|
|
18933
19018
|
const commandParts = tokenize4(upstreamCommand);
|
|
18934
19019
|
const cmd = commandParts[0];
|
|
18935
19020
|
const cmdArgs = commandParts.slice(1);
|
|
@@ -19152,7 +19237,7 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
19152
19237
|
if (parsed.result && Array.isArray(parsed.result.tools)) {
|
|
19153
19238
|
const tools = parsed.result.tools || [];
|
|
19154
19239
|
const currentHash = hashToolDefinitions(tools);
|
|
19155
|
-
const pinStatus = checkPin(serverKey, currentHash);
|
|
19240
|
+
const pinStatus = checkPin(serverKey, currentHash, gatewayCwd);
|
|
19156
19241
|
const token = getInternalToken();
|
|
19157
19242
|
if (isDaemonRunning() && process.env.NODE9_TESTING !== "1") {
|
|
19158
19243
|
const toolSummary = tools.map((t) => ({ name: t.name, description: t.description }));
|
|
@@ -20037,26 +20122,45 @@ function registerTrustCommand(program2) {
|
|
|
20037
20122
|
|
|
20038
20123
|
// src/cli/commands/mcp-pin.ts
|
|
20039
20124
|
var import_chalk21 = __toESM(require("chalk"));
|
|
20125
|
+
init_mcp_pin();
|
|
20126
|
+
var import_fs40 = __toESM(require("fs"));
|
|
20040
20127
|
function registerMcpPinCommand(program2) {
|
|
20041
20128
|
const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
|
|
20042
20129
|
const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
|
|
20043
20130
|
pinSubCmd.command("list").description("Show all pinned MCP servers and their tool definition hashes").action(() => {
|
|
20044
|
-
const
|
|
20045
|
-
|
|
20046
|
-
|
|
20047
|
-
|
|
20048
|
-
|
|
20049
|
-
|
|
20050
|
-
);
|
|
20051
|
-
|
|
20131
|
+
const found = findPinsFilePath(process.cwd());
|
|
20132
|
+
const homeResult = readMcpPinsSafe();
|
|
20133
|
+
let repoEntries = {};
|
|
20134
|
+
let repoCorrupt = false;
|
|
20135
|
+
if (found.source === "repo") {
|
|
20136
|
+
try {
|
|
20137
|
+
const raw = import_fs40.default.readFileSync(found.path, "utf-8");
|
|
20138
|
+
const parsed = JSON.parse(raw);
|
|
20139
|
+
repoEntries = parsed.servers ?? {};
|
|
20140
|
+
} catch {
|
|
20141
|
+
repoCorrupt = true;
|
|
20052
20142
|
}
|
|
20143
|
+
}
|
|
20144
|
+
if (repoCorrupt) {
|
|
20053
20145
|
console.error(import_chalk21.default.red(`
|
|
20054
|
-
\u274C
|
|
20146
|
+
\u274C Repo pin file at ${found.path} is corrupt or unreadable.`));
|
|
20147
|
+
process.exit(1);
|
|
20148
|
+
}
|
|
20149
|
+
if (!homeResult.ok && homeResult.reason === "corrupt") {
|
|
20150
|
+
console.error(import_chalk21.default.red(`
|
|
20151
|
+
\u274C Home pin file is corrupt: ${homeResult.detail}`));
|
|
20055
20152
|
console.error(import_chalk21.default.yellow(" Run: node9 mcp pin reset\n"));
|
|
20056
20153
|
process.exit(1);
|
|
20057
20154
|
}
|
|
20058
|
-
const
|
|
20059
|
-
|
|
20155
|
+
const homeEntries = homeResult.ok ? homeResult.pins.servers : {};
|
|
20156
|
+
const merged = /* @__PURE__ */ new Map();
|
|
20157
|
+
for (const [key, entry] of Object.entries(homeEntries)) {
|
|
20158
|
+
merged.set(key, { entry, source: "home" });
|
|
20159
|
+
}
|
|
20160
|
+
for (const [key, entry] of Object.entries(repoEntries)) {
|
|
20161
|
+
merged.set(key, { entry, source: "repo" });
|
|
20162
|
+
}
|
|
20163
|
+
if (merged.size === 0) {
|
|
20060
20164
|
console.log(import_chalk21.default.gray("\nNo MCP servers are pinned yet."));
|
|
20061
20165
|
console.log(
|
|
20062
20166
|
import_chalk21.default.gray("Pins are created automatically when the MCP gateway first connects.\n")
|
|
@@ -20064,13 +20168,47 @@ function registerMcpPinCommand(program2) {
|
|
|
20064
20168
|
return;
|
|
20065
20169
|
}
|
|
20066
20170
|
console.log(import_chalk21.default.bold("\n\u{1F512} Pinned MCP Servers\n"));
|
|
20067
|
-
|
|
20068
|
-
|
|
20171
|
+
const showSource = found.source === "repo";
|
|
20172
|
+
for (const [key, { entry, source }] of merged) {
|
|
20173
|
+
const tag = showSource ? ` ${import_chalk21.default.yellow(`[${source}]`)}` : "";
|
|
20174
|
+
console.log(` ${import_chalk21.default.cyan(key)}${tag} ${import_chalk21.default.gray(entry.label)}`);
|
|
20069
20175
|
console.log(` Tools (${entry.toolCount}): ${import_chalk21.default.white(entry.toolNames.join(", "))}`);
|
|
20070
20176
|
console.log(` Hash: ${import_chalk21.default.gray(entry.toolsHash.slice(0, 16))}...`);
|
|
20071
20177
|
console.log(` Pinned: ${import_chalk21.default.gray(entry.pinnedAt)}`);
|
|
20072
20178
|
console.log("");
|
|
20073
20179
|
}
|
|
20180
|
+
if (showSource) {
|
|
20181
|
+
console.log(import_chalk21.default.gray(` [repo] entries come from ${found.path}`));
|
|
20182
|
+
console.log(import_chalk21.default.gray(" [home] entries come from ~/.node9/mcp-pins.json\n"));
|
|
20183
|
+
}
|
|
20184
|
+
});
|
|
20185
|
+
pinSubCmd.command("promote <serverKey>").description(
|
|
20186
|
+
"Copy a pin from ~/.node9/mcp-pins.json into <repo>/.node9/mcp-pins.json so teammates share the same vetted baseline"
|
|
20187
|
+
).action((serverKey) => {
|
|
20188
|
+
try {
|
|
20189
|
+
const { repoPath, created } = promotePin(serverKey, process.cwd());
|
|
20190
|
+
if (created) {
|
|
20191
|
+
console.log(
|
|
20192
|
+
import_chalk21.default.green(
|
|
20193
|
+
`
|
|
20194
|
+
\u2705 Created ${repoPath} with the promoted pin for ${import_chalk21.default.cyan(serverKey)}.`
|
|
20195
|
+
)
|
|
20196
|
+
);
|
|
20197
|
+
} else {
|
|
20198
|
+
console.log(import_chalk21.default.green(`
|
|
20199
|
+
\u2705 Promoted ${import_chalk21.default.cyan(serverKey)} into ${repoPath}.`));
|
|
20200
|
+
}
|
|
20201
|
+
console.log(import_chalk21.default.gray(" Review the change and commit it:"));
|
|
20202
|
+
console.log(import_chalk21.default.cyan(` git add ${repoPath}`));
|
|
20203
|
+
console.log(import_chalk21.default.cyan(` git commit -m "pin ${serverKey} (node9)"`));
|
|
20204
|
+
console.log("");
|
|
20205
|
+
} catch (err2) {
|
|
20206
|
+
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
20207
|
+
console.error(import_chalk21.default.red(`
|
|
20208
|
+
\u274C ${msg}
|
|
20209
|
+
`));
|
|
20210
|
+
process.exit(1);
|
|
20211
|
+
}
|
|
20074
20212
|
});
|
|
20075
20213
|
pinSubCmd.command("update <serverKey>").description(
|
|
20076
20214
|
"Remove a pin so the next gateway connection re-pins with current tool definitions"
|
|
@@ -20092,7 +20230,7 @@ function registerMcpPinCommand(program2) {
|
|
|
20092
20230
|
process.exit(1);
|
|
20093
20231
|
}
|
|
20094
20232
|
const label = pins.servers[serverKey].label;
|
|
20095
|
-
|
|
20233
|
+
removePin(serverKey);
|
|
20096
20234
|
console.log(import_chalk21.default.green(`
|
|
20097
20235
|
\u{1F513} Pin removed for ${import_chalk21.default.cyan(serverKey)}`));
|
|
20098
20236
|
console.log(import_chalk21.default.gray(` Server: ${label}`));
|
|
@@ -20105,7 +20243,7 @@ function registerMcpPinCommand(program2) {
|
|
|
20105
20243
|
return;
|
|
20106
20244
|
}
|
|
20107
20245
|
const count = result.ok ? Object.keys(result.pins.servers).length : "?";
|
|
20108
|
-
|
|
20246
|
+
clearAllPins();
|
|
20109
20247
|
console.log(import_chalk21.default.green(`
|
|
20110
20248
|
\u{1F513} Cleared ${count} MCP pin(s).`));
|
|
20111
20249
|
console.log(import_chalk21.default.gray(" Next connection to each server will re-pin.\n"));
|
|
@@ -20288,7 +20426,7 @@ init_scan();
|
|
|
20288
20426
|
|
|
20289
20427
|
// src/cli/commands/sessions.ts
|
|
20290
20428
|
var import_chalk24 = __toESM(require("chalk"));
|
|
20291
|
-
var
|
|
20429
|
+
var import_fs41 = __toESM(require("fs"));
|
|
20292
20430
|
var import_path42 = __toESM(require("path"));
|
|
20293
20431
|
var import_os36 = __toESM(require("os"));
|
|
20294
20432
|
var CLAUDE_PRICING3 = {
|
|
@@ -20406,7 +20544,7 @@ function loadAuditEntries(auditPath) {
|
|
|
20406
20544
|
const aPath = auditPath ?? import_path42.default.join(import_os36.default.homedir(), ".node9", "audit.log");
|
|
20407
20545
|
let raw;
|
|
20408
20546
|
try {
|
|
20409
|
-
raw =
|
|
20547
|
+
raw = import_fs41.default.readFileSync(aPath, "utf-8");
|
|
20410
20548
|
} catch {
|
|
20411
20549
|
return [];
|
|
20412
20550
|
}
|
|
@@ -20443,7 +20581,7 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
20443
20581
|
}
|
|
20444
20582
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
20445
20583
|
const tmpDir = import_path42.default.join(import_os36.default.homedir(), ".gemini", "tmp");
|
|
20446
|
-
if (!
|
|
20584
|
+
if (!import_fs41.default.existsSync(tmpDir)) return [];
|
|
20447
20585
|
const cutoff = days !== null ? (() => {
|
|
20448
20586
|
const d = /* @__PURE__ */ new Date();
|
|
20449
20587
|
d.setDate(d.getDate() - days);
|
|
@@ -20452,7 +20590,7 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
20452
20590
|
})() : null;
|
|
20453
20591
|
let slugDirs;
|
|
20454
20592
|
try {
|
|
20455
|
-
slugDirs =
|
|
20593
|
+
slugDirs = import_fs41.default.readdirSync(tmpDir);
|
|
20456
20594
|
} catch {
|
|
20457
20595
|
return [];
|
|
20458
20596
|
}
|
|
@@ -20460,27 +20598,27 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
20460
20598
|
for (const slug of slugDirs) {
|
|
20461
20599
|
const slugPath = import_path42.default.join(tmpDir, slug);
|
|
20462
20600
|
try {
|
|
20463
|
-
if (!
|
|
20601
|
+
if (!import_fs41.default.statSync(slugPath).isDirectory()) continue;
|
|
20464
20602
|
} catch {
|
|
20465
20603
|
continue;
|
|
20466
20604
|
}
|
|
20467
20605
|
let projectRoot = import_path42.default.join(import_os36.default.homedir(), slug);
|
|
20468
20606
|
try {
|
|
20469
|
-
projectRoot =
|
|
20607
|
+
projectRoot = import_fs41.default.readFileSync(import_path42.default.join(slugPath, ".project_root"), "utf-8").trim();
|
|
20470
20608
|
} catch {
|
|
20471
20609
|
}
|
|
20472
20610
|
const chatsDir = import_path42.default.join(slugPath, "chats");
|
|
20473
|
-
if (!
|
|
20611
|
+
if (!import_fs41.default.existsSync(chatsDir)) continue;
|
|
20474
20612
|
let chatFiles;
|
|
20475
20613
|
try {
|
|
20476
|
-
chatFiles =
|
|
20614
|
+
chatFiles = import_fs41.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
20477
20615
|
} catch {
|
|
20478
20616
|
continue;
|
|
20479
20617
|
}
|
|
20480
20618
|
for (const chatFile of chatFiles) {
|
|
20481
20619
|
let raw;
|
|
20482
20620
|
try {
|
|
20483
|
-
raw =
|
|
20621
|
+
raw = import_fs41.default.readFileSync(import_path42.default.join(chatsDir, chatFile), "utf-8");
|
|
20484
20622
|
} catch {
|
|
20485
20623
|
continue;
|
|
20486
20624
|
}
|
|
@@ -20561,7 +20699,7 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
20561
20699
|
}
|
|
20562
20700
|
function buildCodexSessions(days, allAuditEntries) {
|
|
20563
20701
|
const sessionsBase = import_path42.default.join(import_os36.default.homedir(), ".codex", "sessions");
|
|
20564
|
-
if (!
|
|
20702
|
+
if (!import_fs41.default.existsSync(sessionsBase)) return [];
|
|
20565
20703
|
const cutoff = days !== null ? (() => {
|
|
20566
20704
|
const d = /* @__PURE__ */ new Date();
|
|
20567
20705
|
d.setDate(d.getDate() - days);
|
|
@@ -20570,28 +20708,28 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
20570
20708
|
})() : null;
|
|
20571
20709
|
const jsonlFiles = [];
|
|
20572
20710
|
try {
|
|
20573
|
-
for (const year of
|
|
20711
|
+
for (const year of import_fs41.default.readdirSync(sessionsBase)) {
|
|
20574
20712
|
const yearPath = import_path42.default.join(sessionsBase, year);
|
|
20575
20713
|
try {
|
|
20576
|
-
if (!
|
|
20714
|
+
if (!import_fs41.default.statSync(yearPath).isDirectory()) continue;
|
|
20577
20715
|
} catch {
|
|
20578
20716
|
continue;
|
|
20579
20717
|
}
|
|
20580
|
-
for (const month of
|
|
20718
|
+
for (const month of import_fs41.default.readdirSync(yearPath)) {
|
|
20581
20719
|
const monthPath = import_path42.default.join(yearPath, month);
|
|
20582
20720
|
try {
|
|
20583
|
-
if (!
|
|
20721
|
+
if (!import_fs41.default.statSync(monthPath).isDirectory()) continue;
|
|
20584
20722
|
} catch {
|
|
20585
20723
|
continue;
|
|
20586
20724
|
}
|
|
20587
|
-
for (const day of
|
|
20725
|
+
for (const day of import_fs41.default.readdirSync(monthPath)) {
|
|
20588
20726
|
const dayPath = import_path42.default.join(monthPath, day);
|
|
20589
20727
|
try {
|
|
20590
|
-
if (!
|
|
20728
|
+
if (!import_fs41.default.statSync(dayPath).isDirectory()) continue;
|
|
20591
20729
|
} catch {
|
|
20592
20730
|
continue;
|
|
20593
20731
|
}
|
|
20594
|
-
for (const file of
|
|
20732
|
+
for (const file of import_fs41.default.readdirSync(dayPath)) {
|
|
20595
20733
|
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path42.default.join(dayPath, file));
|
|
20596
20734
|
}
|
|
20597
20735
|
}
|
|
@@ -20604,7 +20742,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
20604
20742
|
for (const filePath of jsonlFiles) {
|
|
20605
20743
|
let lines;
|
|
20606
20744
|
try {
|
|
20607
|
-
lines =
|
|
20745
|
+
lines = import_fs41.default.readFileSync(filePath, "utf-8").split("\n");
|
|
20608
20746
|
} catch {
|
|
20609
20747
|
continue;
|
|
20610
20748
|
}
|
|
@@ -20685,7 +20823,7 @@ function buildSessions(days, historyPath) {
|
|
|
20685
20823
|
const hPath = historyPath ?? import_path42.default.join(import_os36.default.homedir(), ".claude", "history.jsonl");
|
|
20686
20824
|
let historyRaw;
|
|
20687
20825
|
try {
|
|
20688
|
-
historyRaw =
|
|
20826
|
+
historyRaw = import_fs41.default.readFileSync(hPath, "utf-8");
|
|
20689
20827
|
} catch {
|
|
20690
20828
|
return [];
|
|
20691
20829
|
}
|
|
@@ -20710,7 +20848,7 @@ function buildSessions(days, historyPath) {
|
|
|
20710
20848
|
const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
|
|
20711
20849
|
let sessionLines = [];
|
|
20712
20850
|
try {
|
|
20713
|
-
sessionLines =
|
|
20851
|
+
sessionLines = import_fs41.default.readFileSync(jsonlFile, "utf-8").split("\n");
|
|
20714
20852
|
} catch {
|
|
20715
20853
|
}
|
|
20716
20854
|
const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
|
|
@@ -20977,7 +21115,7 @@ function registerSessionsCommand(program2) {
|
|
|
20977
21115
|
console.log(import_chalk24.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk24.default.dim(" \u2014 what your AI agent did"));
|
|
20978
21116
|
console.log("");
|
|
20979
21117
|
const historyPath = import_path42.default.join(import_os36.default.homedir(), ".claude", "history.jsonl");
|
|
20980
|
-
if (!
|
|
21118
|
+
if (!import_fs41.default.existsSync(historyPath)) {
|
|
20981
21119
|
console.log(import_chalk24.default.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
|
|
20982
21120
|
console.log(import_chalk24.default.gray(" Install Claude Code, run a few sessions, then try again.\n"));
|
|
20983
21121
|
return;
|
|
@@ -21014,12 +21152,12 @@ function registerSessionsCommand(program2) {
|
|
|
21014
21152
|
|
|
21015
21153
|
// src/cli/commands/skill-pin.ts
|
|
21016
21154
|
var import_chalk25 = __toESM(require("chalk"));
|
|
21017
|
-
var
|
|
21155
|
+
var import_fs42 = __toESM(require("fs"));
|
|
21018
21156
|
var import_os37 = __toESM(require("os"));
|
|
21019
21157
|
var import_path43 = __toESM(require("path"));
|
|
21020
21158
|
function wipeSkillSessions() {
|
|
21021
21159
|
try {
|
|
21022
|
-
|
|
21160
|
+
import_fs42.default.rmSync(import_path43.default.join(import_os37.default.homedir(), ".node9", "skill-sessions"), {
|
|
21023
21161
|
recursive: true,
|
|
21024
21162
|
force: true
|
|
21025
21163
|
});
|
|
@@ -21077,7 +21215,7 @@ function registerSkillPinCommand(program2) {
|
|
|
21077
21215
|
process.exit(1);
|
|
21078
21216
|
}
|
|
21079
21217
|
const rootPath = pins.roots[rootKey].rootPath;
|
|
21080
|
-
|
|
21218
|
+
removePin2(rootKey);
|
|
21081
21219
|
wipeSkillSessions();
|
|
21082
21220
|
console.log(import_chalk25.default.green(`
|
|
21083
21221
|
\u{1F513} Pin removed for ${import_chalk25.default.cyan(rootKey)}`));
|
|
@@ -21092,7 +21230,7 @@ function registerSkillPinCommand(program2) {
|
|
|
21092
21230
|
return;
|
|
21093
21231
|
}
|
|
21094
21232
|
const count = result.ok ? Object.keys(result.pins.roots).length : "?";
|
|
21095
|
-
|
|
21233
|
+
clearAllPins2();
|
|
21096
21234
|
wipeSkillSessions();
|
|
21097
21235
|
console.log(import_chalk25.default.green(`
|
|
21098
21236
|
\u{1F513} Cleared ${count} skill pin(s).`));
|
|
@@ -21101,15 +21239,15 @@ function registerSkillPinCommand(program2) {
|
|
|
21101
21239
|
}
|
|
21102
21240
|
|
|
21103
21241
|
// src/cli/commands/decisions.ts
|
|
21104
|
-
var
|
|
21242
|
+
var import_fs43 = __toESM(require("fs"));
|
|
21105
21243
|
var import_os38 = __toESM(require("os"));
|
|
21106
21244
|
var import_path44 = __toESM(require("path"));
|
|
21107
21245
|
var import_chalk26 = __toESM(require("chalk"));
|
|
21108
21246
|
var DECISIONS_FILE2 = import_path44.default.join(import_os38.default.homedir(), ".node9", "decisions.json");
|
|
21109
21247
|
function readDecisions() {
|
|
21110
21248
|
try {
|
|
21111
|
-
if (!
|
|
21112
|
-
const raw =
|
|
21249
|
+
if (!import_fs43.default.existsSync(DECISIONS_FILE2)) return {};
|
|
21250
|
+
const raw = import_fs43.default.readFileSync(DECISIONS_FILE2, "utf-8");
|
|
21113
21251
|
const parsed = JSON.parse(raw);
|
|
21114
21252
|
const out = {};
|
|
21115
21253
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -21122,10 +21260,10 @@ function readDecisions() {
|
|
|
21122
21260
|
}
|
|
21123
21261
|
function writeDecisions(d) {
|
|
21124
21262
|
const dir = import_path44.default.dirname(DECISIONS_FILE2);
|
|
21125
|
-
if (!
|
|
21263
|
+
if (!import_fs43.default.existsSync(dir)) import_fs43.default.mkdirSync(dir, { recursive: true });
|
|
21126
21264
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
21127
|
-
|
|
21128
|
-
|
|
21265
|
+
import_fs43.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
21266
|
+
import_fs43.default.renameSync(tmp, DECISIONS_FILE2);
|
|
21129
21267
|
}
|
|
21130
21268
|
function registerDecisionsCommand(program2) {
|
|
21131
21269
|
const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
|
|
@@ -21182,7 +21320,7 @@ Persistent decisions (${entries.length})
|
|
|
21182
21320
|
|
|
21183
21321
|
// src/cli/commands/dlp.ts
|
|
21184
21322
|
var import_chalk27 = __toESM(require("chalk"));
|
|
21185
|
-
var
|
|
21323
|
+
var import_fs44 = __toESM(require("fs"));
|
|
21186
21324
|
var import_path45 = __toESM(require("path"));
|
|
21187
21325
|
var import_os39 = __toESM(require("os"));
|
|
21188
21326
|
var AUDIT_LOG = import_path45.default.join(import_os39.default.homedir(), ".node9", "audit.log");
|
|
@@ -21193,7 +21331,7 @@ function stripAnsi(s) {
|
|
|
21193
21331
|
}
|
|
21194
21332
|
function loadResolved() {
|
|
21195
21333
|
try {
|
|
21196
|
-
const raw = JSON.parse(
|
|
21334
|
+
const raw = JSON.parse(import_fs44.default.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
21197
21335
|
return new Set(raw);
|
|
21198
21336
|
} catch {
|
|
21199
21337
|
return /* @__PURE__ */ new Set();
|
|
@@ -21201,13 +21339,13 @@ function loadResolved() {
|
|
|
21201
21339
|
}
|
|
21202
21340
|
function saveResolved(resolved) {
|
|
21203
21341
|
try {
|
|
21204
|
-
|
|
21342
|
+
import_fs44.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
21205
21343
|
} catch {
|
|
21206
21344
|
}
|
|
21207
21345
|
}
|
|
21208
21346
|
function loadDlpFindings() {
|
|
21209
|
-
if (!
|
|
21210
|
-
return
|
|
21347
|
+
if (!import_fs44.default.existsSync(AUDIT_LOG)) return [];
|
|
21348
|
+
return import_fs44.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
21211
21349
|
if (!line.trim()) return [];
|
|
21212
21350
|
try {
|
|
21213
21351
|
const e = JSON.parse(line);
|
|
@@ -21305,14 +21443,14 @@ function registerDlpCommand(program2) {
|
|
|
21305
21443
|
|
|
21306
21444
|
// src/cli/commands/mask.ts
|
|
21307
21445
|
var import_chalk28 = __toESM(require("chalk"));
|
|
21308
|
-
var
|
|
21446
|
+
var import_fs45 = __toESM(require("fs"));
|
|
21309
21447
|
var import_path46 = __toESM(require("path"));
|
|
21310
21448
|
var import_os40 = __toESM(require("os"));
|
|
21311
21449
|
init_dlp();
|
|
21312
21450
|
function findJsonlFiles(dir) {
|
|
21313
21451
|
const results = [];
|
|
21314
|
-
if (!
|
|
21315
|
-
for (const entry of
|
|
21452
|
+
if (!import_fs45.default.existsSync(dir)) return results;
|
|
21453
|
+
for (const entry of import_fs45.default.readdirSync(dir, { withFileTypes: true })) {
|
|
21316
21454
|
const full = import_path46.default.join(dir, entry.name);
|
|
21317
21455
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
21318
21456
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
@@ -21356,7 +21494,7 @@ function redactJson(obj) {
|
|
|
21356
21494
|
function processFile(filePath, dryRun) {
|
|
21357
21495
|
let raw;
|
|
21358
21496
|
try {
|
|
21359
|
-
raw =
|
|
21497
|
+
raw = import_fs45.default.readFileSync(filePath, "utf-8");
|
|
21360
21498
|
} catch {
|
|
21361
21499
|
return { redactedLines: 0, patterns: [] };
|
|
21362
21500
|
}
|
|
@@ -21388,14 +21526,14 @@ function processFile(filePath, dryRun) {
|
|
|
21388
21526
|
}
|
|
21389
21527
|
}
|
|
21390
21528
|
if (!dryRun && redactedLines > 0) {
|
|
21391
|
-
|
|
21529
|
+
import_fs45.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
21392
21530
|
}
|
|
21393
21531
|
return { redactedLines, patterns };
|
|
21394
21532
|
}
|
|
21395
21533
|
function processJsonFile(filePath, dryRun) {
|
|
21396
21534
|
let raw;
|
|
21397
21535
|
try {
|
|
21398
|
-
raw =
|
|
21536
|
+
raw = import_fs45.default.readFileSync(filePath, "utf-8");
|
|
21399
21537
|
} catch {
|
|
21400
21538
|
return { redactedLines: 0, patterns: [] };
|
|
21401
21539
|
}
|
|
@@ -21408,14 +21546,14 @@ function processJsonFile(filePath, dryRun) {
|
|
|
21408
21546
|
const { value, modified, found } = redactJson(parsed);
|
|
21409
21547
|
if (!modified) return { redactedLines: 0, patterns: [] };
|
|
21410
21548
|
if (!dryRun) {
|
|
21411
|
-
|
|
21549
|
+
import_fs45.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
|
|
21412
21550
|
}
|
|
21413
21551
|
return { redactedLines: 1, patterns: found };
|
|
21414
21552
|
}
|
|
21415
21553
|
function findJsonFiles(dir) {
|
|
21416
21554
|
const results = [];
|
|
21417
|
-
if (!
|
|
21418
|
-
for (const entry of
|
|
21555
|
+
if (!import_fs45.default.existsSync(dir)) return results;
|
|
21556
|
+
for (const entry of import_fs45.default.readdirSync(dir, { withFileTypes: true })) {
|
|
21419
21557
|
const full = import_path46.default.join(dir, entry.name);
|
|
21420
21558
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
21421
21559
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
@@ -21435,7 +21573,7 @@ function registerMaskCommand(program2) {
|
|
|
21435
21573
|
const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
21436
21574
|
const filtered = cutoff ? allFiles.filter((f) => {
|
|
21437
21575
|
try {
|
|
21438
|
-
return
|
|
21576
|
+
return import_fs45.default.statSync(f.path).mtime >= cutoff;
|
|
21439
21577
|
} catch {
|
|
21440
21578
|
return false;
|
|
21441
21579
|
}
|
|
@@ -21491,20 +21629,20 @@ function registerMaskCommand(program2) {
|
|
|
21491
21629
|
// src/cli.ts
|
|
21492
21630
|
init_blast();
|
|
21493
21631
|
var { version } = JSON.parse(
|
|
21494
|
-
|
|
21632
|
+
import_fs48.default.readFileSync(import_path49.default.join(__dirname, "../package.json"), "utf-8")
|
|
21495
21633
|
);
|
|
21496
21634
|
var program = new import_commander.Command();
|
|
21497
21635
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
21498
21636
|
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) => {
|
|
21499
21637
|
const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
|
|
21500
21638
|
const credPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "credentials.json");
|
|
21501
|
-
if (!
|
|
21502
|
-
|
|
21639
|
+
if (!import_fs48.default.existsSync(import_path49.default.dirname(credPath)))
|
|
21640
|
+
import_fs48.default.mkdirSync(import_path49.default.dirname(credPath), { recursive: true });
|
|
21503
21641
|
const profileName = options.profile || "default";
|
|
21504
21642
|
let existingCreds = {};
|
|
21505
21643
|
try {
|
|
21506
|
-
if (
|
|
21507
|
-
const raw = JSON.parse(
|
|
21644
|
+
if (import_fs48.default.existsSync(credPath)) {
|
|
21645
|
+
const raw = JSON.parse(import_fs48.default.readFileSync(credPath, "utf-8"));
|
|
21508
21646
|
if (raw.apiKey) {
|
|
21509
21647
|
existingCreds = {
|
|
21510
21648
|
default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
|
|
@@ -21516,13 +21654,13 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
21516
21654
|
} catch {
|
|
21517
21655
|
}
|
|
21518
21656
|
existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
|
|
21519
|
-
|
|
21657
|
+
import_fs48.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
|
|
21520
21658
|
if (profileName === "default") {
|
|
21521
21659
|
const configPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "config.json");
|
|
21522
21660
|
let config = {};
|
|
21523
21661
|
try {
|
|
21524
|
-
if (
|
|
21525
|
-
config = JSON.parse(
|
|
21662
|
+
if (import_fs48.default.existsSync(configPath))
|
|
21663
|
+
config = JSON.parse(import_fs48.default.readFileSync(configPath, "utf-8"));
|
|
21526
21664
|
} catch {
|
|
21527
21665
|
}
|
|
21528
21666
|
if (!config.settings || typeof config.settings !== "object") config.settings = {};
|
|
@@ -21537,9 +21675,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
21537
21675
|
approvers.cloud = false;
|
|
21538
21676
|
}
|
|
21539
21677
|
s.approvers = approvers;
|
|
21540
|
-
if (!
|
|
21541
|
-
|
|
21542
|
-
|
|
21678
|
+
if (!import_fs48.default.existsSync(import_path49.default.dirname(configPath)))
|
|
21679
|
+
import_fs48.default.mkdirSync(import_path49.default.dirname(configPath), { recursive: true });
|
|
21680
|
+
import_fs48.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
21543
21681
|
}
|
|
21544
21682
|
if (options.profile && profileName !== "default") {
|
|
21545
21683
|
console.log(import_chalk30.default.green(`\u2705 Profile "${profileName}" saved`));
|
|
@@ -21677,14 +21815,14 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
21677
21815
|
}
|
|
21678
21816
|
if (options.purge) {
|
|
21679
21817
|
const node9Dir = import_path49.default.join(import_os43.default.homedir(), ".node9");
|
|
21680
|
-
if (
|
|
21818
|
+
if (import_fs48.default.existsSync(node9Dir)) {
|
|
21681
21819
|
const confirmed = await (0, import_prompts2.confirm)({
|
|
21682
21820
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
21683
21821
|
default: false
|
|
21684
21822
|
});
|
|
21685
21823
|
if (confirmed) {
|
|
21686
|
-
|
|
21687
|
-
if (
|
|
21824
|
+
import_fs48.default.rmSync(node9Dir, { recursive: true });
|
|
21825
|
+
if (import_fs48.default.existsSync(node9Dir)) {
|
|
21688
21826
|
console.error(
|
|
21689
21827
|
import_chalk30.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
21690
21828
|
);
|
|
@@ -21839,12 +21977,12 @@ Run "node9 addto claude" to register it as the statusLine.`
|
|
|
21839
21977
|
if (subcommand === "debug") {
|
|
21840
21978
|
const flagFile = import_path49.default.join(import_os43.default.homedir(), ".node9", "hud-debug");
|
|
21841
21979
|
if (state === "on") {
|
|
21842
|
-
|
|
21843
|
-
|
|
21980
|
+
import_fs48.default.mkdirSync(import_path49.default.dirname(flagFile), { recursive: true });
|
|
21981
|
+
import_fs48.default.writeFileSync(flagFile, "");
|
|
21844
21982
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
21845
21983
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
21846
21984
|
} else if (state === "off") {
|
|
21847
|
-
if (
|
|
21985
|
+
if (import_fs48.default.existsSync(flagFile)) import_fs48.default.unlinkSync(flagFile);
|
|
21848
21986
|
console.log("HUD debug logging disabled.");
|
|
21849
21987
|
} else {
|
|
21850
21988
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -21960,7 +22098,7 @@ if (process.argv[2] !== "daemon") {
|
|
|
21960
22098
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
21961
22099
|
const logPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log");
|
|
21962
22100
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
21963
|
-
|
|
22101
|
+
import_fs48.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
21964
22102
|
`);
|
|
21965
22103
|
}
|
|
21966
22104
|
process.exit(0);
|