@node9/proxy 1.22.0 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +946 -809
- package/dist/cli.mjs +915 -779
- 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
|
}
|
|
@@ -10883,7 +11049,7 @@ function registerScanCommand(program2) {
|
|
|
10883
11049
|
if (!drillDown) {
|
|
10884
11050
|
const useInk2 = !options.classic;
|
|
10885
11051
|
if (useInk2) {
|
|
10886
|
-
const scanInkPath =
|
|
11052
|
+
const scanInkPath = import_path22.default.join(__dirname, "scan-ink.mjs");
|
|
10887
11053
|
const dynamicImport = new Function("id", "return import(id)");
|
|
10888
11054
|
const mod = await dynamicImport(`file://${scanInkPath}`);
|
|
10889
11055
|
const rangeLabel2 = options.all ? "all time" : `last ${options.days ?? 90} days`;
|
|
@@ -11108,14 +11274,14 @@ function registerScanCommand(program2) {
|
|
|
11108
11274
|
}
|
|
11109
11275
|
);
|
|
11110
11276
|
}
|
|
11111
|
-
var import_chalk5,
|
|
11277
|
+
var import_chalk5, import_fs20, import_path22, import_os19, import_string_width2, CLAUDE_PRICING, GEMINI_PRICING, CODE_EXTENSIONS, SELF_OUTPUT_MARKERS, FIXTURE_TOKEN_PATTERNS, TERMINAL_ESCAPE_RE2, LOOP_TOOLS, LOOP_THRESHOLD, LOOP_TIMESPAN_THRESHOLD_MS, STUCK_TOOLS_MIN_WASTE, STUCK_TOOLS_LIMIT, RECURRING_SESSION_THRESHOLD, STALE_AGE_DAYS, classifyRuleSeverity2, narrativeRuleLabel2;
|
|
11112
11278
|
var init_scan = __esm({
|
|
11113
11279
|
"src/cli/commands/scan.ts"() {
|
|
11114
11280
|
"use strict";
|
|
11115
11281
|
import_chalk5 = __toESM(require("chalk"));
|
|
11116
|
-
|
|
11117
|
-
|
|
11118
|
-
|
|
11282
|
+
import_fs20 = __toESM(require("fs"));
|
|
11283
|
+
import_path22 = __toESM(require("path"));
|
|
11284
|
+
import_os19 = __toESM(require("os"));
|
|
11119
11285
|
init_shields();
|
|
11120
11286
|
init_config();
|
|
11121
11287
|
init_policy();
|
|
@@ -11242,11 +11408,11 @@ function commonPathPrefix(paths) {
|
|
|
11242
11408
|
const prefix = common.join("/").replace(/\/?$/, "/");
|
|
11243
11409
|
return prefix.length > 1 ? prefix : null;
|
|
11244
11410
|
}
|
|
11245
|
-
var
|
|
11411
|
+
var import_crypto6, SuggestionTracker;
|
|
11246
11412
|
var init_suggestion_tracker = __esm({
|
|
11247
11413
|
"src/daemon/suggestion-tracker.ts"() {
|
|
11248
11414
|
"use strict";
|
|
11249
|
-
|
|
11415
|
+
import_crypto6 = require("crypto");
|
|
11250
11416
|
SuggestionTracker = class {
|
|
11251
11417
|
events = /* @__PURE__ */ new Map();
|
|
11252
11418
|
threshold;
|
|
@@ -11292,7 +11458,7 @@ var init_suggestion_tracker = __esm({
|
|
|
11292
11458
|
}
|
|
11293
11459
|
} : { type: "ignoredTool", toolName };
|
|
11294
11460
|
return {
|
|
11295
|
-
id: (0,
|
|
11461
|
+
id: (0, import_crypto6.randomUUID)(),
|
|
11296
11462
|
toolName,
|
|
11297
11463
|
allowCount: events.length,
|
|
11298
11464
|
suggestedRule,
|
|
@@ -11306,12 +11472,12 @@ var init_suggestion_tracker = __esm({
|
|
|
11306
11472
|
});
|
|
11307
11473
|
|
|
11308
11474
|
// src/daemon/taint-store.ts
|
|
11309
|
-
var
|
|
11475
|
+
var import_fs21, import_path23, DEFAULT_TTL_MS, TaintStore;
|
|
11310
11476
|
var init_taint_store = __esm({
|
|
11311
11477
|
"src/daemon/taint-store.ts"() {
|
|
11312
11478
|
"use strict";
|
|
11313
|
-
|
|
11314
|
-
|
|
11479
|
+
import_fs21 = __toESM(require("fs"));
|
|
11480
|
+
import_path23 = __toESM(require("path"));
|
|
11315
11481
|
DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
11316
11482
|
TaintStore = class {
|
|
11317
11483
|
records = /* @__PURE__ */ new Map();
|
|
@@ -11376,9 +11542,9 @@ var init_taint_store = __esm({
|
|
|
11376
11542
|
/** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
|
|
11377
11543
|
_resolve(filePath) {
|
|
11378
11544
|
try {
|
|
11379
|
-
return
|
|
11545
|
+
return import_fs21.default.realpathSync.native(import_path23.default.resolve(filePath));
|
|
11380
11546
|
} catch {
|
|
11381
|
-
return
|
|
11547
|
+
return import_path23.default.resolve(filePath);
|
|
11382
11548
|
}
|
|
11383
11549
|
}
|
|
11384
11550
|
};
|
|
@@ -11496,8 +11662,8 @@ var init_session_history = __esm({
|
|
|
11496
11662
|
// src/daemon/state.ts
|
|
11497
11663
|
function loadInsightCounts() {
|
|
11498
11664
|
try {
|
|
11499
|
-
if (!
|
|
11500
|
-
const data = JSON.parse(
|
|
11665
|
+
if (!import_fs22.default.existsSync(INSIGHT_COUNTS_FILE)) return;
|
|
11666
|
+
const data = JSON.parse(import_fs22.default.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
|
|
11501
11667
|
for (const [tool, count] of Object.entries(data)) {
|
|
11502
11668
|
if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
|
|
11503
11669
|
}
|
|
@@ -11536,23 +11702,23 @@ function markRejectionHandlerRegistered() {
|
|
|
11536
11702
|
daemonRejectionHandlerRegistered = true;
|
|
11537
11703
|
}
|
|
11538
11704
|
function atomicWriteSync2(filePath, data, options) {
|
|
11539
|
-
const dir =
|
|
11540
|
-
if (!
|
|
11541
|
-
const tmpPath = `${filePath}.${(0,
|
|
11705
|
+
const dir = import_path24.default.dirname(filePath);
|
|
11706
|
+
if (!import_fs22.default.existsSync(dir)) import_fs22.default.mkdirSync(dir, { recursive: true });
|
|
11707
|
+
const tmpPath = `${filePath}.${(0, import_crypto7.randomUUID)()}.tmp`;
|
|
11542
11708
|
try {
|
|
11543
|
-
|
|
11709
|
+
import_fs22.default.writeFileSync(tmpPath, data, options);
|
|
11544
11710
|
} catch (err2) {
|
|
11545
11711
|
try {
|
|
11546
|
-
|
|
11712
|
+
import_fs22.default.unlinkSync(tmpPath);
|
|
11547
11713
|
} catch {
|
|
11548
11714
|
}
|
|
11549
11715
|
throw err2;
|
|
11550
11716
|
}
|
|
11551
11717
|
try {
|
|
11552
|
-
|
|
11718
|
+
import_fs22.default.renameSync(tmpPath, filePath);
|
|
11553
11719
|
} catch (err2) {
|
|
11554
11720
|
try {
|
|
11555
|
-
|
|
11721
|
+
import_fs22.default.unlinkSync(tmpPath);
|
|
11556
11722
|
} catch {
|
|
11557
11723
|
}
|
|
11558
11724
|
throw err2;
|
|
@@ -11576,16 +11742,16 @@ function appendAuditLog(data) {
|
|
|
11576
11742
|
decision: data.decision,
|
|
11577
11743
|
source: "daemon"
|
|
11578
11744
|
};
|
|
11579
|
-
const dir =
|
|
11580
|
-
if (!
|
|
11581
|
-
|
|
11745
|
+
const dir = import_path24.default.dirname(AUDIT_LOG_FILE);
|
|
11746
|
+
if (!import_fs22.default.existsSync(dir)) import_fs22.default.mkdirSync(dir, { recursive: true });
|
|
11747
|
+
import_fs22.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
11582
11748
|
} catch {
|
|
11583
11749
|
}
|
|
11584
11750
|
}
|
|
11585
11751
|
function getAuditHistory(limit = 20) {
|
|
11586
11752
|
try {
|
|
11587
|
-
if (!
|
|
11588
|
-
const lines =
|
|
11753
|
+
if (!import_fs22.default.existsSync(AUDIT_LOG_FILE)) return [];
|
|
11754
|
+
const lines = import_fs22.default.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
|
|
11589
11755
|
if (lines.length === 1 && lines[0] === "") return [];
|
|
11590
11756
|
return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
|
|
11591
11757
|
} catch {
|
|
@@ -11594,7 +11760,7 @@ function getAuditHistory(limit = 20) {
|
|
|
11594
11760
|
}
|
|
11595
11761
|
function getOrgName() {
|
|
11596
11762
|
try {
|
|
11597
|
-
if (
|
|
11763
|
+
if (import_fs22.default.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
|
|
11598
11764
|
} catch {
|
|
11599
11765
|
}
|
|
11600
11766
|
return null;
|
|
@@ -11602,8 +11768,8 @@ function getOrgName() {
|
|
|
11602
11768
|
function writeGlobalSetting(key, value) {
|
|
11603
11769
|
let config = {};
|
|
11604
11770
|
try {
|
|
11605
|
-
if (
|
|
11606
|
-
config = JSON.parse(
|
|
11771
|
+
if (import_fs22.default.existsSync(GLOBAL_CONFIG_FILE)) {
|
|
11772
|
+
config = JSON.parse(import_fs22.default.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
|
|
11607
11773
|
}
|
|
11608
11774
|
} catch {
|
|
11609
11775
|
}
|
|
@@ -11615,8 +11781,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
11615
11781
|
try {
|
|
11616
11782
|
let trust = { entries: [] };
|
|
11617
11783
|
try {
|
|
11618
|
-
if (
|
|
11619
|
-
trust = JSON.parse(
|
|
11784
|
+
if (import_fs22.default.existsSync(TRUST_FILE2))
|
|
11785
|
+
trust = JSON.parse(import_fs22.default.readFileSync(TRUST_FILE2, "utf-8"));
|
|
11620
11786
|
} catch {
|
|
11621
11787
|
}
|
|
11622
11788
|
trust.entries = trust.entries.filter(
|
|
@@ -11633,8 +11799,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
11633
11799
|
}
|
|
11634
11800
|
function readPersistentDecisions() {
|
|
11635
11801
|
try {
|
|
11636
|
-
if (
|
|
11637
|
-
return JSON.parse(
|
|
11802
|
+
if (import_fs22.default.existsSync(DECISIONS_FILE)) {
|
|
11803
|
+
return JSON.parse(import_fs22.default.readFileSync(DECISIONS_FILE, "utf-8"));
|
|
11638
11804
|
}
|
|
11639
11805
|
} catch {
|
|
11640
11806
|
}
|
|
@@ -11662,7 +11828,7 @@ function estimateToolCost(tool, args) {
|
|
|
11662
11828
|
const filePath = a.file_path ?? a.path;
|
|
11663
11829
|
if (filePath) {
|
|
11664
11830
|
try {
|
|
11665
|
-
const bytes =
|
|
11831
|
+
const bytes = import_fs22.default.statSync(filePath).size;
|
|
11666
11832
|
return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
|
|
11667
11833
|
} catch {
|
|
11668
11834
|
}
|
|
@@ -11713,7 +11879,7 @@ function broadcastForensic(finding) {
|
|
|
11713
11879
|
const severity = CRITICAL_FORENSIC_CATEGORIES.has(finding.type) ? "critical" : "warning";
|
|
11714
11880
|
const event = {
|
|
11715
11881
|
type: "forensic",
|
|
11716
|
-
id: `fnd_${(0,
|
|
11882
|
+
id: `fnd_${(0, import_crypto7.randomUUID)()}`,
|
|
11717
11883
|
ts: Date.now(),
|
|
11718
11884
|
sessionId: finding.sessionId,
|
|
11719
11885
|
category: finding.type,
|
|
@@ -11733,7 +11899,7 @@ function abandonPending() {
|
|
|
11733
11899
|
});
|
|
11734
11900
|
if (autoStarted) {
|
|
11735
11901
|
try {
|
|
11736
|
-
|
|
11902
|
+
import_fs22.default.unlinkSync(DAEMON_PID_FILE);
|
|
11737
11903
|
} catch {
|
|
11738
11904
|
}
|
|
11739
11905
|
setTimeout(() => {
|
|
@@ -11744,8 +11910,8 @@ function abandonPending() {
|
|
|
11744
11910
|
}
|
|
11745
11911
|
function logActivitySocket(msg) {
|
|
11746
11912
|
try {
|
|
11747
|
-
|
|
11748
|
-
|
|
11913
|
+
import_fs22.default.appendFileSync(
|
|
11914
|
+
import_path24.default.join(homeDir, ".node9", "hook-debug.log"),
|
|
11749
11915
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] [activity-socket] ${msg}
|
|
11750
11916
|
`
|
|
11751
11917
|
);
|
|
@@ -11767,13 +11933,13 @@ function shouldRebind(now = Date.now()) {
|
|
|
11767
11933
|
function startActivitySocket() {
|
|
11768
11934
|
bindActivitySocket();
|
|
11769
11935
|
activityHealthInterval = setInterval(() => {
|
|
11770
|
-
if (!
|
|
11936
|
+
if (!import_fs22.default.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
|
|
11771
11937
|
}, ACTIVITY_HEALTH_PROBE_MS);
|
|
11772
11938
|
activityHealthInterval.unref();
|
|
11773
11939
|
process.on("exit", () => {
|
|
11774
11940
|
if (activityHealthInterval) clearInterval(activityHealthInterval);
|
|
11775
11941
|
try {
|
|
11776
|
-
|
|
11942
|
+
import_fs22.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
11777
11943
|
} catch {
|
|
11778
11944
|
}
|
|
11779
11945
|
});
|
|
@@ -11801,7 +11967,7 @@ function attemptRebind(reason) {
|
|
|
11801
11967
|
}
|
|
11802
11968
|
function bindActivitySocket() {
|
|
11803
11969
|
try {
|
|
11804
|
-
|
|
11970
|
+
import_fs22.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
11805
11971
|
} catch {
|
|
11806
11972
|
}
|
|
11807
11973
|
const ACTIVITY_MAX_BYTES = 1024 * 1024;
|
|
@@ -11905,28 +12071,28 @@ function bindActivitySocket() {
|
|
|
11905
12071
|
});
|
|
11906
12072
|
activitySocketServer = unixServer;
|
|
11907
12073
|
}
|
|
11908
|
-
var import_net2,
|
|
12074
|
+
var import_net2, import_fs22, import_path24, import_os20, import_crypto7, homeDir, DAEMON_PID_FILE, DECISIONS_FILE, AUDIT_LOG_FILE, TRUST_FILE2, GLOBAL_CONFIG_FILE, CREDENTIALS_FILE, INSIGHT_COUNTS_FILE, pending, sseClients, suggestionTracker, taintStore, insightCounts, _abandonTimer, _hadBrowserClient, _daemonServer, daemonRejectionHandlerRegistered, AUTO_DENY_MS, TRUST_DURATIONS, autoStarted, ACTIVITY_SOCKET_PATH2, ACTIVITY_RING_SIZE, activityRing, LARGE_RESPONSE_RING_SIZE, largeResponseRing, cachedScanResult, cachedScanTs, SCAN_CACHE_TTL_MS, SECRET_KEY_RE, INPUT_PRICE_PER_1M, OUTPUT_PRICE_PER_1M, BYTES_PER_TOKEN, CRITICAL_FORENSIC_CATEGORIES, WRITE_TOOL_NAMES, ACTIVITY_REBIND_MAX_ATTEMPTS, ACTIVITY_REBIND_WINDOW_MS, ACTIVITY_HEALTH_PROBE_MS, activitySocketServer, activityHealthInterval, activityRebindAttempts, activityCircuitTripped;
|
|
11909
12075
|
var init_state2 = __esm({
|
|
11910
12076
|
"src/daemon/state.ts"() {
|
|
11911
12077
|
"use strict";
|
|
11912
12078
|
import_net2 = __toESM(require("net"));
|
|
11913
|
-
|
|
11914
|
-
|
|
11915
|
-
|
|
11916
|
-
|
|
12079
|
+
import_fs22 = __toESM(require("fs"));
|
|
12080
|
+
import_path24 = __toESM(require("path"));
|
|
12081
|
+
import_os20 = __toESM(require("os"));
|
|
12082
|
+
import_crypto7 = require("crypto");
|
|
11917
12083
|
init_daemon();
|
|
11918
12084
|
init_suggestion_tracker();
|
|
11919
12085
|
init_taint_store();
|
|
11920
12086
|
init_session_counters();
|
|
11921
12087
|
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 =
|
|
12088
|
+
homeDir = import_os20.default.homedir();
|
|
12089
|
+
DAEMON_PID_FILE = import_path24.default.join(homeDir, ".node9", "daemon.pid");
|
|
12090
|
+
DECISIONS_FILE = import_path24.default.join(homeDir, ".node9", "decisions.json");
|
|
12091
|
+
AUDIT_LOG_FILE = import_path24.default.join(homeDir, ".node9", "audit.log");
|
|
12092
|
+
TRUST_FILE2 = import_path24.default.join(homeDir, ".node9", "trust.json");
|
|
12093
|
+
GLOBAL_CONFIG_FILE = import_path24.default.join(homeDir, ".node9", "config.json");
|
|
12094
|
+
CREDENTIALS_FILE = import_path24.default.join(homeDir, ".node9", "credentials.json");
|
|
12095
|
+
INSIGHT_COUNTS_FILE = import_path24.default.join(homeDir, ".node9", "insight-counts.json");
|
|
11930
12096
|
pending = /* @__PURE__ */ new Map();
|
|
11931
12097
|
sseClients = /* @__PURE__ */ new Set();
|
|
11932
12098
|
suggestionTracker = new SuggestionTracker(3);
|
|
@@ -11943,7 +12109,7 @@ var init_state2 = __esm({
|
|
|
11943
12109
|
"2h": 2 * 60 * 6e4
|
|
11944
12110
|
};
|
|
11945
12111
|
autoStarted = process.env.NODE9_AUTO_STARTED === "1";
|
|
11946
|
-
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
12112
|
+
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path24.default.join(import_os20.default.tmpdir(), "node9-activity.sock");
|
|
11947
12113
|
ACTIVITY_RING_SIZE = 100;
|
|
11948
12114
|
activityRing = [];
|
|
11949
12115
|
LARGE_RESPONSE_RING_SIZE = 20;
|
|
@@ -12021,8 +12187,8 @@ function readCredentials() {
|
|
|
12021
12187
|
};
|
|
12022
12188
|
}
|
|
12023
12189
|
try {
|
|
12024
|
-
const credPath =
|
|
12025
|
-
const creds = JSON.parse(
|
|
12190
|
+
const credPath = import_path25.default.join(import_os21.default.homedir(), ".node9", "credentials.json");
|
|
12191
|
+
const creds = JSON.parse(import_fs23.default.readFileSync(credPath, "utf-8"));
|
|
12026
12192
|
const profileName = process.env.NODE9_PROFILE ?? "default";
|
|
12027
12193
|
const profile = creds[profileName];
|
|
12028
12194
|
if (typeof profile?.apiKey === "string" && profile.apiKey.length > 0) {
|
|
@@ -12048,7 +12214,7 @@ function readCredentials() {
|
|
|
12048
12214
|
}
|
|
12049
12215
|
function readCachedEtag() {
|
|
12050
12216
|
try {
|
|
12051
|
-
const raw = JSON.parse(
|
|
12217
|
+
const raw = JSON.parse(import_fs23.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
12052
12218
|
return typeof raw.etag === "string" ? raw.etag : void 0;
|
|
12053
12219
|
} catch {
|
|
12054
12220
|
return void 0;
|
|
@@ -12109,9 +12275,9 @@ function extractRules(body) {
|
|
|
12109
12275
|
return [];
|
|
12110
12276
|
}
|
|
12111
12277
|
function writeCache2(cache) {
|
|
12112
|
-
const dir =
|
|
12113
|
-
if (!
|
|
12114
|
-
|
|
12278
|
+
const dir = import_path25.default.dirname(rulesCacheFile());
|
|
12279
|
+
if (!import_fs23.default.existsSync(dir)) import_fs23.default.mkdirSync(dir, { recursive: true });
|
|
12280
|
+
import_fs23.default.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
|
|
12115
12281
|
}
|
|
12116
12282
|
async function syncOnce() {
|
|
12117
12283
|
const creds = readCredentials();
|
|
@@ -12268,7 +12434,7 @@ async function runCloudSync() {
|
|
|
12268
12434
|
}
|
|
12269
12435
|
function getCloudSyncStatus() {
|
|
12270
12436
|
try {
|
|
12271
|
-
const raw = JSON.parse(
|
|
12437
|
+
const raw = JSON.parse(import_fs23.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
12272
12438
|
if (!Array.isArray(raw.rules) || typeof raw.fetchedAt !== "string") return { cached: false };
|
|
12273
12439
|
return {
|
|
12274
12440
|
cached: true,
|
|
@@ -12285,7 +12451,7 @@ function getCloudSyncStatus() {
|
|
|
12285
12451
|
}
|
|
12286
12452
|
function getCloudRules() {
|
|
12287
12453
|
try {
|
|
12288
|
-
const raw = JSON.parse(
|
|
12454
|
+
const raw = JSON.parse(import_fs23.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
12289
12455
|
return Array.isArray(raw.rules) ? raw.rules : null;
|
|
12290
12456
|
} catch {
|
|
12291
12457
|
return null;
|
|
@@ -12319,14 +12485,14 @@ function startForensicBroadcast() {
|
|
|
12319
12485
|
const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
|
|
12320
12486
|
recurring.unref();
|
|
12321
12487
|
}
|
|
12322
|
-
var
|
|
12488
|
+
var import_fs23, import_https2, import_os21, import_path25, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_HOURS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
|
|
12323
12489
|
var init_sync = __esm({
|
|
12324
12490
|
"src/daemon/sync.ts"() {
|
|
12325
12491
|
"use strict";
|
|
12326
|
-
|
|
12492
|
+
import_fs23 = __toESM(require("fs"));
|
|
12327
12493
|
import_https2 = __toESM(require("https"));
|
|
12328
|
-
|
|
12329
|
-
|
|
12494
|
+
import_os21 = __toESM(require("os"));
|
|
12495
|
+
import_path25 = __toESM(require("path"));
|
|
12330
12496
|
init_config();
|
|
12331
12497
|
init_blast();
|
|
12332
12498
|
init_dist();
|
|
@@ -12345,7 +12511,7 @@ var init_sync = __esm({
|
|
|
12345
12511
|
loop: "loops",
|
|
12346
12512
|
"long-output-redacted": "longOutputRedactions"
|
|
12347
12513
|
};
|
|
12348
|
-
rulesCacheFile = () =>
|
|
12514
|
+
rulesCacheFile = () => import_path25.default.join(import_os21.default.homedir(), ".node9", "rules-cache.json");
|
|
12349
12515
|
DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept/policies/sync";
|
|
12350
12516
|
DEFAULT_INTERVAL_HOURS = 5;
|
|
12351
12517
|
MIN_INTERVAL_HOURS = 1;
|
|
@@ -12358,68 +12524,68 @@ var init_sync = __esm({
|
|
|
12358
12524
|
// src/daemon/dlp-scanner.ts
|
|
12359
12525
|
function loadIndex() {
|
|
12360
12526
|
try {
|
|
12361
|
-
return JSON.parse(
|
|
12527
|
+
return JSON.parse(import_fs24.default.readFileSync(INDEX_FILE, "utf-8"));
|
|
12362
12528
|
} catch {
|
|
12363
12529
|
return {};
|
|
12364
12530
|
}
|
|
12365
12531
|
}
|
|
12366
12532
|
function saveIndex(index) {
|
|
12367
12533
|
try {
|
|
12368
|
-
|
|
12534
|
+
import_fs24.default.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
|
|
12369
12535
|
} catch {
|
|
12370
12536
|
}
|
|
12371
12537
|
}
|
|
12372
12538
|
function appendAuditEntry(entry) {
|
|
12373
12539
|
try {
|
|
12374
|
-
|
|
12540
|
+
import_fs24.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
12375
12541
|
} catch {
|
|
12376
12542
|
}
|
|
12377
12543
|
}
|
|
12378
12544
|
function runDlpScan() {
|
|
12379
|
-
if (!
|
|
12545
|
+
if (!import_fs24.default.existsSync(PROJECTS_DIR2)) return;
|
|
12380
12546
|
const index = loadIndex();
|
|
12381
12547
|
let updated = false;
|
|
12382
12548
|
let projDirs;
|
|
12383
12549
|
try {
|
|
12384
|
-
projDirs =
|
|
12550
|
+
projDirs = import_fs24.default.readdirSync(PROJECTS_DIR2);
|
|
12385
12551
|
} catch {
|
|
12386
12552
|
return;
|
|
12387
12553
|
}
|
|
12388
12554
|
for (const proj of projDirs) {
|
|
12389
|
-
const projPath =
|
|
12555
|
+
const projPath = import_path26.default.join(PROJECTS_DIR2, proj);
|
|
12390
12556
|
try {
|
|
12391
|
-
if (!
|
|
12392
|
-
const real =
|
|
12393
|
-
if (!real.startsWith(PROJECTS_DIR2 +
|
|
12557
|
+
if (!import_fs24.default.lstatSync(projPath).isDirectory()) continue;
|
|
12558
|
+
const real = import_fs24.default.realpathSync(projPath);
|
|
12559
|
+
if (!real.startsWith(PROJECTS_DIR2 + import_path26.default.sep) && real !== PROJECTS_DIR2) continue;
|
|
12394
12560
|
} catch {
|
|
12395
12561
|
continue;
|
|
12396
12562
|
}
|
|
12397
12563
|
let files;
|
|
12398
12564
|
try {
|
|
12399
|
-
files =
|
|
12565
|
+
files = import_fs24.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
12400
12566
|
} catch {
|
|
12401
12567
|
continue;
|
|
12402
12568
|
}
|
|
12403
12569
|
for (const file of files) {
|
|
12404
|
-
const filePath =
|
|
12570
|
+
const filePath = import_path26.default.join(projPath, file);
|
|
12405
12571
|
const lastOffset = index[filePath] ?? 0;
|
|
12406
12572
|
let size;
|
|
12407
12573
|
try {
|
|
12408
|
-
size =
|
|
12574
|
+
size = import_fs24.default.statSync(filePath).size;
|
|
12409
12575
|
} catch {
|
|
12410
12576
|
continue;
|
|
12411
12577
|
}
|
|
12412
12578
|
if (size <= lastOffset) continue;
|
|
12413
12579
|
let fd;
|
|
12414
12580
|
try {
|
|
12415
|
-
fd =
|
|
12581
|
+
fd = import_fs24.default.openSync(filePath, "r");
|
|
12416
12582
|
} catch {
|
|
12417
12583
|
continue;
|
|
12418
12584
|
}
|
|
12419
12585
|
try {
|
|
12420
12586
|
const chunkSize = size - lastOffset;
|
|
12421
12587
|
const buf = Buffer.alloc(chunkSize);
|
|
12422
|
-
|
|
12588
|
+
import_fs24.default.readSync(fd, buf, 0, chunkSize, lastOffset);
|
|
12423
12589
|
const chunk = buf.toString("utf-8");
|
|
12424
12590
|
for (const line of chunk.split("\n")) {
|
|
12425
12591
|
if (!line.trim()) continue;
|
|
@@ -12439,7 +12605,7 @@ function runDlpScan() {
|
|
|
12439
12605
|
if (typeof text !== "string") continue;
|
|
12440
12606
|
const match = scanText(text);
|
|
12441
12607
|
if (!match) continue;
|
|
12442
|
-
const projLabel = decodeURIComponent(proj).replace(
|
|
12608
|
+
const projLabel = decodeURIComponent(proj).replace(import_os22.default.homedir(), "~").slice(0, 40);
|
|
12443
12609
|
const ts = entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
12444
12610
|
appendAuditEntry({
|
|
12445
12611
|
ts,
|
|
@@ -12464,7 +12630,7 @@ Run: node9 report --period 30d`
|
|
|
12464
12630
|
updated = true;
|
|
12465
12631
|
} finally {
|
|
12466
12632
|
try {
|
|
12467
|
-
|
|
12633
|
+
import_fs24.default.closeSync(fd);
|
|
12468
12634
|
} catch {
|
|
12469
12635
|
}
|
|
12470
12636
|
}
|
|
@@ -12490,30 +12656,30 @@ function startDlpScanner() {
|
|
|
12490
12656
|
);
|
|
12491
12657
|
timer.unref();
|
|
12492
12658
|
}
|
|
12493
|
-
var
|
|
12659
|
+
var import_fs24, import_path26, import_os22, INDEX_FILE, PROJECTS_DIR2;
|
|
12494
12660
|
var init_dlp_scanner = __esm({
|
|
12495
12661
|
"src/daemon/dlp-scanner.ts"() {
|
|
12496
12662
|
"use strict";
|
|
12497
|
-
|
|
12498
|
-
|
|
12499
|
-
|
|
12663
|
+
import_fs24 = __toESM(require("fs"));
|
|
12664
|
+
import_path26 = __toESM(require("path"));
|
|
12665
|
+
import_os22 = __toESM(require("os"));
|
|
12500
12666
|
init_dlp();
|
|
12501
12667
|
init_native();
|
|
12502
12668
|
init_state2();
|
|
12503
|
-
INDEX_FILE =
|
|
12504
|
-
PROJECTS_DIR2 =
|
|
12669
|
+
INDEX_FILE = import_path26.default.join(import_os22.default.homedir(), ".node9", "dlp-index.json");
|
|
12670
|
+
PROJECTS_DIR2 = import_path26.default.join(import_os22.default.homedir(), ".claude", "projects");
|
|
12505
12671
|
}
|
|
12506
12672
|
});
|
|
12507
12673
|
|
|
12508
12674
|
// src/daemon/mcp-tools.ts
|
|
12509
12675
|
function getMcpToolsFile() {
|
|
12510
|
-
return
|
|
12676
|
+
return import_path27.default.join(import_os23.default.homedir(), ".node9", "mcp-tools.json");
|
|
12511
12677
|
}
|
|
12512
12678
|
function readMcpToolsConfig() {
|
|
12513
12679
|
try {
|
|
12514
12680
|
const file = getMcpToolsFile();
|
|
12515
|
-
if (!
|
|
12516
|
-
const raw =
|
|
12681
|
+
if (!import_fs25.default.existsSync(file)) return {};
|
|
12682
|
+
const raw = import_fs25.default.readFileSync(file, "utf-8");
|
|
12517
12683
|
return JSON.parse(raw);
|
|
12518
12684
|
} catch {
|
|
12519
12685
|
return {};
|
|
@@ -12522,11 +12688,11 @@ function readMcpToolsConfig() {
|
|
|
12522
12688
|
function writeMcpToolsConfig(config) {
|
|
12523
12689
|
try {
|
|
12524
12690
|
const file = getMcpToolsFile();
|
|
12525
|
-
const dir =
|
|
12526
|
-
if (!
|
|
12527
|
-
const tmpPath = `${file}.${
|
|
12528
|
-
|
|
12529
|
-
|
|
12691
|
+
const dir = import_path27.default.dirname(file);
|
|
12692
|
+
if (!import_fs25.default.existsSync(dir)) import_fs25.default.mkdirSync(dir, { recursive: true });
|
|
12693
|
+
const tmpPath = `${file}.${import_os23.default.hostname()}.${process.pid}.tmp`;
|
|
12694
|
+
import_fs25.default.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
|
|
12695
|
+
import_fs25.default.renameSync(tmpPath, file);
|
|
12530
12696
|
} catch (e) {
|
|
12531
12697
|
console.error("Failed to write mcp-tools.json", e);
|
|
12532
12698
|
}
|
|
@@ -12565,13 +12731,13 @@ function approveServer(serverKey, disabledTools) {
|
|
|
12565
12731
|
writeMcpToolsConfig(config);
|
|
12566
12732
|
}
|
|
12567
12733
|
}
|
|
12568
|
-
var
|
|
12734
|
+
var import_fs25, import_path27, import_os23;
|
|
12569
12735
|
var init_mcp_tools = __esm({
|
|
12570
12736
|
"src/daemon/mcp-tools.ts"() {
|
|
12571
12737
|
"use strict";
|
|
12572
|
-
|
|
12573
|
-
|
|
12574
|
-
|
|
12738
|
+
import_fs25 = __toESM(require("fs"));
|
|
12739
|
+
import_path27 = __toESM(require("path"));
|
|
12740
|
+
import_os23 = __toESM(require("os"));
|
|
12575
12741
|
}
|
|
12576
12742
|
});
|
|
12577
12743
|
|
|
@@ -12582,7 +12748,7 @@ function startDaemon() {
|
|
|
12582
12748
|
startForensicBroadcast();
|
|
12583
12749
|
startDlpScanner();
|
|
12584
12750
|
loadInsightCounts();
|
|
12585
|
-
const internalToken = (0,
|
|
12751
|
+
const internalToken = (0, import_crypto8.randomUUID)();
|
|
12586
12752
|
const validToken = (req) => req.headers["x-node9-internal"] === internalToken || req.headers["x-node9-token"] === internalToken;
|
|
12587
12753
|
const IDLE_TIMEOUT_MS = 12 * 60 * 60 * 1e3;
|
|
12588
12754
|
const watchMode = process.env.NODE9_WATCH_MODE === "1";
|
|
@@ -12593,7 +12759,7 @@ function startDaemon() {
|
|
|
12593
12759
|
idleTimer = setTimeout(() => {
|
|
12594
12760
|
if (autoStarted) {
|
|
12595
12761
|
try {
|
|
12596
|
-
|
|
12762
|
+
import_fs26.default.unlinkSync(DAEMON_PID_FILE);
|
|
12597
12763
|
} catch {
|
|
12598
12764
|
}
|
|
12599
12765
|
}
|
|
@@ -12694,7 +12860,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
12694
12860
|
cwd,
|
|
12695
12861
|
localSmartRuleMatched = false
|
|
12696
12862
|
} = JSON.parse(body);
|
|
12697
|
-
const id = fromCLI && typeof activityId === "string" && activityId || (0,
|
|
12863
|
+
const id = fromCLI && typeof activityId === "string" && activityId || (0, import_crypto8.randomUUID)();
|
|
12698
12864
|
const entry = {
|
|
12699
12865
|
id,
|
|
12700
12866
|
toolName,
|
|
@@ -12738,7 +12904,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
12738
12904
|
mcpServer: entry.mcpServer
|
|
12739
12905
|
});
|
|
12740
12906
|
}
|
|
12741
|
-
const projectCwd = typeof cwd === "string" &&
|
|
12907
|
+
const projectCwd = typeof cwd === "string" && import_path28.default.isAbsolute(cwd) ? cwd : void 0;
|
|
12742
12908
|
const projectConfig = getConfig(projectCwd);
|
|
12743
12909
|
const browserEnabled = projectConfig.settings.approvers?.browser !== false;
|
|
12744
12910
|
const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
|
|
@@ -13030,8 +13196,8 @@ data: ${JSON.stringify(item.data)}
|
|
|
13030
13196
|
if (!validToken(req)) return res.writeHead(403).end();
|
|
13031
13197
|
const periodParam = reqUrl.searchParams.get("period") || "7d";
|
|
13032
13198
|
const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
|
|
13033
|
-
const logPath =
|
|
13034
|
-
if (!
|
|
13199
|
+
const logPath = import_path28.default.join(import_os24.default.homedir(), ".node9", "audit.log");
|
|
13200
|
+
if (!import_fs26.default.existsSync(logPath)) {
|
|
13035
13201
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
13036
13202
|
return res.end(
|
|
13037
13203
|
JSON.stringify({
|
|
@@ -13044,7 +13210,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
13044
13210
|
);
|
|
13045
13211
|
}
|
|
13046
13212
|
try {
|
|
13047
|
-
const raw =
|
|
13213
|
+
const raw = import_fs26.default.readFileSync(logPath, "utf-8");
|
|
13048
13214
|
const allEntries = raw.split("\n").flatMap((line) => {
|
|
13049
13215
|
if (!line.trim()) return [];
|
|
13050
13216
|
try {
|
|
@@ -13279,7 +13445,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
13279
13445
|
args: { toolCount: tools.length, status },
|
|
13280
13446
|
decision: "mcp-discovered"
|
|
13281
13447
|
});
|
|
13282
|
-
const id = (0,
|
|
13448
|
+
const id = (0, import_crypto8.randomUUID)();
|
|
13283
13449
|
const entry = {
|
|
13284
13450
|
id,
|
|
13285
13451
|
type: "mcp-discovery",
|
|
@@ -13367,14 +13533,14 @@ data: ${JSON.stringify(item.data)}
|
|
|
13367
13533
|
server.on("error", (e) => {
|
|
13368
13534
|
if (e.code === "EADDRINUSE") {
|
|
13369
13535
|
try {
|
|
13370
|
-
if (
|
|
13371
|
-
const { pid } = JSON.parse(
|
|
13536
|
+
if (import_fs26.default.existsSync(DAEMON_PID_FILE)) {
|
|
13537
|
+
const { pid } = JSON.parse(import_fs26.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
13372
13538
|
process.kill(pid, 0);
|
|
13373
13539
|
return process.exit(0);
|
|
13374
13540
|
}
|
|
13375
13541
|
} catch {
|
|
13376
13542
|
try {
|
|
13377
|
-
|
|
13543
|
+
import_fs26.default.unlinkSync(DAEMON_PID_FILE);
|
|
13378
13544
|
} catch {
|
|
13379
13545
|
}
|
|
13380
13546
|
server.listen(DAEMON_PORT, DAEMON_HOST);
|
|
@@ -13446,15 +13612,15 @@ data: ${JSON.stringify(item.data)}
|
|
|
13446
13612
|
}
|
|
13447
13613
|
startActivitySocket();
|
|
13448
13614
|
}
|
|
13449
|
-
var import_http,
|
|
13615
|
+
var import_http, import_fs26, import_path28, import_os24, import_crypto8, import_child_process2, import_chalk6;
|
|
13450
13616
|
var init_server = __esm({
|
|
13451
13617
|
"src/daemon/server.ts"() {
|
|
13452
13618
|
"use strict";
|
|
13453
13619
|
import_http = __toESM(require("http"));
|
|
13454
|
-
|
|
13455
|
-
|
|
13456
|
-
|
|
13457
|
-
|
|
13620
|
+
import_fs26 = __toESM(require("fs"));
|
|
13621
|
+
import_path28 = __toESM(require("path"));
|
|
13622
|
+
import_os24 = __toESM(require("os"));
|
|
13623
|
+
import_crypto8 = require("crypto");
|
|
13458
13624
|
import_child_process2 = require("child_process");
|
|
13459
13625
|
import_chalk6 = __toESM(require("chalk"));
|
|
13460
13626
|
init_core();
|
|
@@ -13473,8 +13639,8 @@ var init_server = __esm({
|
|
|
13473
13639
|
function resolveNode9Binary() {
|
|
13474
13640
|
try {
|
|
13475
13641
|
const script = process.argv[1];
|
|
13476
|
-
if (typeof script === "string" &&
|
|
13477
|
-
return
|
|
13642
|
+
if (typeof script === "string" && import_path29.default.isAbsolute(script) && import_fs27.default.existsSync(script)) {
|
|
13643
|
+
return import_fs27.default.realpathSync(script);
|
|
13478
13644
|
}
|
|
13479
13645
|
} catch {
|
|
13480
13646
|
}
|
|
@@ -13492,11 +13658,11 @@ function xmlEscape(s) {
|
|
|
13492
13658
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
13493
13659
|
}
|
|
13494
13660
|
function launchdPlist(binaryPath) {
|
|
13495
|
-
const logDir =
|
|
13661
|
+
const logDir = import_path29.default.join(import_os25.default.homedir(), ".node9");
|
|
13496
13662
|
const nodePath = xmlEscape(process.execPath);
|
|
13497
13663
|
const scriptPath = xmlEscape(binaryPath);
|
|
13498
|
-
const outLog = xmlEscape(
|
|
13499
|
-
const errLog = xmlEscape(
|
|
13664
|
+
const outLog = xmlEscape(import_path29.default.join(logDir, "daemon.log"));
|
|
13665
|
+
const errLog = xmlEscape(import_path29.default.join(logDir, "daemon-error.log"));
|
|
13500
13666
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
13501
13667
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
13502
13668
|
<plist version="1.0">
|
|
@@ -13529,9 +13695,9 @@ function launchdPlist(binaryPath) {
|
|
|
13529
13695
|
`;
|
|
13530
13696
|
}
|
|
13531
13697
|
function installLaunchd(binaryPath) {
|
|
13532
|
-
const dir =
|
|
13533
|
-
if (!
|
|
13534
|
-
|
|
13698
|
+
const dir = import_path29.default.dirname(LAUNCHD_PLIST);
|
|
13699
|
+
if (!import_fs27.default.existsSync(dir)) import_fs27.default.mkdirSync(dir, { recursive: true });
|
|
13700
|
+
import_fs27.default.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
|
|
13535
13701
|
(0, import_child_process3.spawnSync)("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
|
|
13536
13702
|
const r = (0, import_child_process3.spawnSync)("launchctl", ["load", "-w", LAUNCHD_PLIST], {
|
|
13537
13703
|
encoding: "utf8",
|
|
@@ -13542,13 +13708,13 @@ function installLaunchd(binaryPath) {
|
|
|
13542
13708
|
}
|
|
13543
13709
|
}
|
|
13544
13710
|
function uninstallLaunchd() {
|
|
13545
|
-
if (
|
|
13711
|
+
if (import_fs27.default.existsSync(LAUNCHD_PLIST)) {
|
|
13546
13712
|
(0, import_child_process3.spawnSync)("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
|
|
13547
|
-
|
|
13713
|
+
import_fs27.default.unlinkSync(LAUNCHD_PLIST);
|
|
13548
13714
|
}
|
|
13549
13715
|
}
|
|
13550
13716
|
function isLaunchdInstalled() {
|
|
13551
|
-
return
|
|
13717
|
+
return import_fs27.default.existsSync(LAUNCHD_PLIST);
|
|
13552
13718
|
}
|
|
13553
13719
|
function systemdUnit(binaryPath) {
|
|
13554
13720
|
return `[Unit]
|
|
@@ -13567,12 +13733,12 @@ WantedBy=default.target
|
|
|
13567
13733
|
`;
|
|
13568
13734
|
}
|
|
13569
13735
|
function installSystemd(binaryPath) {
|
|
13570
|
-
if (!
|
|
13571
|
-
|
|
13736
|
+
if (!import_fs27.default.existsSync(SYSTEMD_UNIT_DIR)) {
|
|
13737
|
+
import_fs27.default.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
|
|
13572
13738
|
}
|
|
13573
|
-
|
|
13739
|
+
import_fs27.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
|
|
13574
13740
|
try {
|
|
13575
|
-
(0, import_child_process3.execFileSync)("loginctl", ["enable-linger",
|
|
13741
|
+
(0, import_child_process3.execFileSync)("loginctl", ["enable-linger", import_os25.default.userInfo().username], { timeout: 3e3 });
|
|
13576
13742
|
} catch {
|
|
13577
13743
|
}
|
|
13578
13744
|
const reload = (0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], {
|
|
@@ -13592,23 +13758,23 @@ function installSystemd(binaryPath) {
|
|
|
13592
13758
|
}
|
|
13593
13759
|
}
|
|
13594
13760
|
function uninstallSystemd() {
|
|
13595
|
-
if (
|
|
13761
|
+
if (import_fs27.default.existsSync(SYSTEMD_UNIT)) {
|
|
13596
13762
|
(0, import_child_process3.spawnSync)("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
|
|
13597
13763
|
encoding: "utf8",
|
|
13598
13764
|
timeout: 5e3
|
|
13599
13765
|
});
|
|
13600
13766
|
(0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
|
|
13601
|
-
|
|
13767
|
+
import_fs27.default.unlinkSync(SYSTEMD_UNIT);
|
|
13602
13768
|
}
|
|
13603
13769
|
}
|
|
13604
13770
|
function isSystemdInstalled() {
|
|
13605
|
-
return
|
|
13771
|
+
return import_fs27.default.existsSync(SYSTEMD_UNIT);
|
|
13606
13772
|
}
|
|
13607
13773
|
function stopRunningDaemon() {
|
|
13608
|
-
const pidFile =
|
|
13609
|
-
if (!
|
|
13774
|
+
const pidFile = import_path29.default.join(import_os25.default.homedir(), ".node9", "daemon.pid");
|
|
13775
|
+
if (!import_fs27.default.existsSync(pidFile)) return;
|
|
13610
13776
|
try {
|
|
13611
|
-
const data = JSON.parse(
|
|
13777
|
+
const data = JSON.parse(import_fs27.default.readFileSync(pidFile, "utf-8"));
|
|
13612
13778
|
const pid = data.pid;
|
|
13613
13779
|
const MAX_PID2 = 4194304;
|
|
13614
13780
|
if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
|
|
@@ -13628,7 +13794,7 @@ function stopRunningDaemon() {
|
|
|
13628
13794
|
}
|
|
13629
13795
|
}
|
|
13630
13796
|
try {
|
|
13631
|
-
|
|
13797
|
+
import_fs27.default.unlinkSync(pidFile);
|
|
13632
13798
|
} catch {
|
|
13633
13799
|
}
|
|
13634
13800
|
} catch {
|
|
@@ -13698,26 +13864,26 @@ function isDaemonServiceInstalled() {
|
|
|
13698
13864
|
if (process.platform === "linux") return isSystemdInstalled();
|
|
13699
13865
|
return false;
|
|
13700
13866
|
}
|
|
13701
|
-
var
|
|
13867
|
+
var import_fs27, import_path29, import_os25, import_child_process3, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
|
|
13702
13868
|
var init_service = __esm({
|
|
13703
13869
|
"src/daemon/service.ts"() {
|
|
13704
13870
|
"use strict";
|
|
13705
|
-
|
|
13706
|
-
|
|
13707
|
-
|
|
13871
|
+
import_fs27 = __toESM(require("fs"));
|
|
13872
|
+
import_path29 = __toESM(require("path"));
|
|
13873
|
+
import_os25 = __toESM(require("os"));
|
|
13708
13874
|
import_child_process3 = require("child_process");
|
|
13709
13875
|
LAUNCHD_LABEL = "ai.node9.daemon";
|
|
13710
|
-
LAUNCHD_PLIST =
|
|
13711
|
-
SYSTEMD_UNIT_DIR =
|
|
13712
|
-
SYSTEMD_UNIT =
|
|
13876
|
+
LAUNCHD_PLIST = import_path29.default.join(import_os25.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
13877
|
+
SYSTEMD_UNIT_DIR = import_path29.default.join(import_os25.default.homedir(), ".config", "systemd", "user");
|
|
13878
|
+
SYSTEMD_UNIT = import_path29.default.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
|
|
13713
13879
|
}
|
|
13714
13880
|
});
|
|
13715
13881
|
|
|
13716
13882
|
// src/daemon/index.ts
|
|
13717
13883
|
function stopDaemon() {
|
|
13718
|
-
if (!
|
|
13884
|
+
if (!import_fs28.default.existsSync(DAEMON_PID_FILE)) return console.log(import_chalk7.default.yellow("Not running."));
|
|
13719
13885
|
try {
|
|
13720
|
-
const data = JSON.parse(
|
|
13886
|
+
const data = JSON.parse(import_fs28.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
13721
13887
|
const pid = data.pid;
|
|
13722
13888
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
13723
13889
|
console.log(import_chalk7.default.gray("Cleaned up invalid PID file."));
|
|
@@ -13729,7 +13895,7 @@ function stopDaemon() {
|
|
|
13729
13895
|
console.log(import_chalk7.default.gray("Cleaned up stale PID file."));
|
|
13730
13896
|
} finally {
|
|
13731
13897
|
try {
|
|
13732
|
-
|
|
13898
|
+
import_fs28.default.unlinkSync(DAEMON_PID_FILE);
|
|
13733
13899
|
} catch {
|
|
13734
13900
|
}
|
|
13735
13901
|
}
|
|
@@ -13738,9 +13904,9 @@ function daemonStatus() {
|
|
|
13738
13904
|
const serviceInstalled = isDaemonServiceInstalled();
|
|
13739
13905
|
const serviceLabel = serviceInstalled ? import_chalk7.default.green("installed (starts on login)") : import_chalk7.default.yellow("not installed \u2014 run: node9 daemon install");
|
|
13740
13906
|
let processStatus;
|
|
13741
|
-
if (
|
|
13907
|
+
if (import_fs28.default.existsSync(DAEMON_PID_FILE)) {
|
|
13742
13908
|
try {
|
|
13743
|
-
const data = JSON.parse(
|
|
13909
|
+
const data = JSON.parse(import_fs28.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
13744
13910
|
const pid = data.pid;
|
|
13745
13911
|
const port = data.port;
|
|
13746
13912
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
@@ -13762,11 +13928,11 @@ function daemonStatus() {
|
|
|
13762
13928
|
console.log(` Service : ${serviceLabel}
|
|
13763
13929
|
`);
|
|
13764
13930
|
}
|
|
13765
|
-
var
|
|
13931
|
+
var import_fs28, import_chalk7, MAX_PID;
|
|
13766
13932
|
var init_daemon2 = __esm({
|
|
13767
13933
|
"src/daemon/index.ts"() {
|
|
13768
13934
|
"use strict";
|
|
13769
|
-
|
|
13935
|
+
import_fs28 = __toESM(require("fs"));
|
|
13770
13936
|
import_chalk7 = __toESM(require("chalk"));
|
|
13771
13937
|
init_server();
|
|
13772
13938
|
init_state2();
|
|
@@ -13807,19 +13973,19 @@ function getModelContextLimit(model) {
|
|
|
13807
13973
|
}
|
|
13808
13974
|
function readSessionUsage() {
|
|
13809
13975
|
const projectsDir = import_path47.default.join(import_os41.default.homedir(), ".claude", "projects");
|
|
13810
|
-
if (!
|
|
13976
|
+
if (!import_fs46.default.existsSync(projectsDir)) return null;
|
|
13811
13977
|
let latestFile = null;
|
|
13812
13978
|
let latestMtime = 0;
|
|
13813
13979
|
try {
|
|
13814
|
-
for (const dir of
|
|
13980
|
+
for (const dir of import_fs46.default.readdirSync(projectsDir)) {
|
|
13815
13981
|
const dirPath = import_path47.default.join(projectsDir, dir);
|
|
13816
13982
|
try {
|
|
13817
|
-
if (!
|
|
13818
|
-
for (const file of
|
|
13983
|
+
if (!import_fs46.default.statSync(dirPath).isDirectory()) continue;
|
|
13984
|
+
for (const file of import_fs46.default.readdirSync(dirPath)) {
|
|
13819
13985
|
if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
|
|
13820
13986
|
const filePath = import_path47.default.join(dirPath, file);
|
|
13821
13987
|
try {
|
|
13822
|
-
const mtime =
|
|
13988
|
+
const mtime = import_fs46.default.statSync(filePath).mtimeMs;
|
|
13823
13989
|
if (mtime > latestMtime) {
|
|
13824
13990
|
latestMtime = mtime;
|
|
13825
13991
|
latestFile = filePath;
|
|
@@ -13834,7 +14000,7 @@ function readSessionUsage() {
|
|
|
13834
14000
|
}
|
|
13835
14001
|
if (!latestFile) return null;
|
|
13836
14002
|
try {
|
|
13837
|
-
const lines =
|
|
14003
|
+
const lines = import_fs46.default.readFileSync(latestFile, "utf-8").split("\n");
|
|
13838
14004
|
let lastModel = "";
|
|
13839
14005
|
let lastInput = 0;
|
|
13840
14006
|
let lastOutput = 0;
|
|
@@ -13934,9 +14100,9 @@ function renderPending(activity) {
|
|
|
13934
14100
|
}
|
|
13935
14101
|
async function ensureDaemon() {
|
|
13936
14102
|
let pidPort = null;
|
|
13937
|
-
if (
|
|
14103
|
+
if (import_fs46.default.existsSync(PID_FILE)) {
|
|
13938
14104
|
try {
|
|
13939
|
-
const { port } = JSON.parse(
|
|
14105
|
+
const { port } = JSON.parse(import_fs46.default.readFileSync(PID_FILE, "utf-8"));
|
|
13940
14106
|
pidPort = port;
|
|
13941
14107
|
} catch {
|
|
13942
14108
|
console.error(import_chalk29.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
@@ -14094,7 +14260,7 @@ function buildRecoveryCardLines(req) {
|
|
|
14094
14260
|
function readApproversFromDisk() {
|
|
14095
14261
|
const configPath = import_path47.default.join(import_os41.default.homedir(), ".node9", "config.json");
|
|
14096
14262
|
try {
|
|
14097
|
-
const raw = JSON.parse(
|
|
14263
|
+
const raw = JSON.parse(import_fs46.default.readFileSync(configPath, "utf-8"));
|
|
14098
14264
|
const settings = raw.settings ?? {};
|
|
14099
14265
|
return settings.approvers ?? {};
|
|
14100
14266
|
} catch {
|
|
@@ -14112,13 +14278,13 @@ function approverStatusLine() {
|
|
|
14112
14278
|
function toggleApprover(channel) {
|
|
14113
14279
|
const configPath = import_path47.default.join(import_os41.default.homedir(), ".node9", "config.json");
|
|
14114
14280
|
try {
|
|
14115
|
-
const raw = JSON.parse(
|
|
14281
|
+
const raw = JSON.parse(import_fs46.default.readFileSync(configPath, "utf-8"));
|
|
14116
14282
|
const settings = raw.settings ?? {};
|
|
14117
14283
|
const approvers = settings.approvers ?? {};
|
|
14118
14284
|
approvers[channel] = approvers[channel] === false;
|
|
14119
14285
|
settings.approvers = approvers;
|
|
14120
14286
|
raw.settings = settings;
|
|
14121
|
-
|
|
14287
|
+
import_fs46.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
|
|
14122
14288
|
} catch (err2) {
|
|
14123
14289
|
process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
|
|
14124
14290
|
`);
|
|
@@ -14290,7 +14456,7 @@ async function startTail(options = {}) {
|
|
|
14290
14456
|
}
|
|
14291
14457
|
postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
|
|
14292
14458
|
try {
|
|
14293
|
-
|
|
14459
|
+
import_fs46.default.appendFileSync(
|
|
14294
14460
|
import_path47.default.join(import_os41.default.homedir(), ".node9", "hook-debug.log"),
|
|
14295
14461
|
`[tail] POST /decision failed: ${String(err2)}
|
|
14296
14462
|
`
|
|
@@ -14357,7 +14523,7 @@ async function startTail(options = {}) {
|
|
|
14357
14523
|
}
|
|
14358
14524
|
const auditLog = import_path47.default.join(import_os41.default.homedir(), ".node9", "audit.log");
|
|
14359
14525
|
try {
|
|
14360
|
-
const unackedDlp =
|
|
14526
|
+
const unackedDlp = import_fs46.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
14361
14527
|
if (unackedDlp > 0) {
|
|
14362
14528
|
console.log("");
|
|
14363
14529
|
console.log(
|
|
@@ -14397,7 +14563,7 @@ async function startTail(options = {}) {
|
|
|
14397
14563
|
if (stallWarned) return;
|
|
14398
14564
|
if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
|
|
14399
14565
|
try {
|
|
14400
|
-
const auditMtime =
|
|
14566
|
+
const auditMtime = import_fs46.default.statSync(auditLog).mtimeMs;
|
|
14401
14567
|
if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
|
|
14402
14568
|
console.log("");
|
|
14403
14569
|
console.log(
|
|
@@ -14582,13 +14748,13 @@ async function startTail(options = {}) {
|
|
|
14582
14748
|
process.exit(1);
|
|
14583
14749
|
});
|
|
14584
14750
|
}
|
|
14585
|
-
var import_http2, import_chalk29,
|
|
14751
|
+
var import_http2, import_chalk29, import_fs46, import_os41, import_path47, import_readline6, import_child_process12, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
|
|
14586
14752
|
var init_tail = __esm({
|
|
14587
14753
|
"src/tui/tail.ts"() {
|
|
14588
14754
|
"use strict";
|
|
14589
14755
|
import_http2 = __toESM(require("http"));
|
|
14590
14756
|
import_chalk29 = __toESM(require("chalk"));
|
|
14591
|
-
|
|
14757
|
+
import_fs46 = __toESM(require("fs"));
|
|
14592
14758
|
import_os41 = __toESM(require("os"));
|
|
14593
14759
|
import_path47 = __toESM(require("path"));
|
|
14594
14760
|
import_readline6 = __toESM(require("readline"));
|
|
@@ -14717,9 +14883,9 @@ function formatTimeLeft(resetsAt) {
|
|
|
14717
14883
|
return ` (${m}m left)`;
|
|
14718
14884
|
}
|
|
14719
14885
|
function safeReadJson(filePath) {
|
|
14720
|
-
if (!
|
|
14886
|
+
if (!import_fs47.default.existsSync(filePath)) return null;
|
|
14721
14887
|
try {
|
|
14722
|
-
return JSON.parse(
|
|
14888
|
+
return JSON.parse(import_fs47.default.readFileSync(filePath, "utf-8"));
|
|
14723
14889
|
} catch {
|
|
14724
14890
|
return null;
|
|
14725
14891
|
}
|
|
@@ -14740,10 +14906,10 @@ function countHooksInFile(filePath) {
|
|
|
14740
14906
|
return Object.keys(cfg.hooks).length;
|
|
14741
14907
|
}
|
|
14742
14908
|
function countRulesInDir(rulesDir) {
|
|
14743
|
-
if (!
|
|
14909
|
+
if (!import_fs47.default.existsSync(rulesDir)) return 0;
|
|
14744
14910
|
let count = 0;
|
|
14745
14911
|
try {
|
|
14746
|
-
for (const entry of
|
|
14912
|
+
for (const entry of import_fs47.default.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
14747
14913
|
if (entry.isDirectory()) {
|
|
14748
14914
|
count += countRulesInDir(import_path48.default.join(rulesDir, entry.name));
|
|
14749
14915
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -14769,7 +14935,7 @@ function countConfigs(cwd) {
|
|
|
14769
14935
|
let hooksCount = 0;
|
|
14770
14936
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
14771
14937
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
14772
|
-
if (
|
|
14938
|
+
if (import_fs47.default.existsSync(import_path48.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
14773
14939
|
rulesCount += countRulesInDir(import_path48.default.join(claudeDir, "rules"));
|
|
14774
14940
|
const userSettings = import_path48.default.join(claudeDir, "settings.json");
|
|
14775
14941
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
@@ -14780,18 +14946,18 @@ function countConfigs(cwd) {
|
|
|
14780
14946
|
userMcpServers.delete(name);
|
|
14781
14947
|
}
|
|
14782
14948
|
if (cwd) {
|
|
14783
|
-
if (
|
|
14784
|
-
if (
|
|
14949
|
+
if (import_fs47.default.existsSync(import_path48.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
14950
|
+
if (import_fs47.default.existsSync(import_path48.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
14785
14951
|
const projectClaudeDir = import_path48.default.join(cwd, ".claude");
|
|
14786
14952
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
14787
14953
|
if (!overlapsUserScope) {
|
|
14788
|
-
if (
|
|
14954
|
+
if (import_fs47.default.existsSync(import_path48.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
14789
14955
|
rulesCount += countRulesInDir(import_path48.default.join(projectClaudeDir, "rules"));
|
|
14790
14956
|
const projSettings = import_path48.default.join(projectClaudeDir, "settings.json");
|
|
14791
14957
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
14792
14958
|
hooksCount += countHooksInFile(projSettings);
|
|
14793
14959
|
}
|
|
14794
|
-
if (
|
|
14960
|
+
if (import_fs47.default.existsSync(import_path48.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
14795
14961
|
const localSettings = import_path48.default.join(projectClaudeDir, "settings.local.json");
|
|
14796
14962
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
14797
14963
|
hooksCount += countHooksInFile(localSettings);
|
|
@@ -14829,11 +14995,11 @@ function readActiveShieldsHud() {
|
|
|
14829
14995
|
}
|
|
14830
14996
|
try {
|
|
14831
14997
|
const shieldsPath = import_path48.default.join(import_os42.default.homedir(), ".node9", "shields.json");
|
|
14832
|
-
if (!
|
|
14998
|
+
if (!import_fs47.default.existsSync(shieldsPath)) {
|
|
14833
14999
|
shieldsCache = { value: [], ts: now };
|
|
14834
15000
|
return [];
|
|
14835
15001
|
}
|
|
14836
|
-
const parsed = JSON.parse(
|
|
15002
|
+
const parsed = JSON.parse(import_fs47.default.readFileSync(shieldsPath, "utf-8"));
|
|
14837
15003
|
if (!Array.isArray(parsed.active)) {
|
|
14838
15004
|
shieldsCache = { value: [], ts: now };
|
|
14839
15005
|
return [];
|
|
@@ -14935,17 +15101,17 @@ function renderContextLine(stdin) {
|
|
|
14935
15101
|
async function main() {
|
|
14936
15102
|
try {
|
|
14937
15103
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
14938
|
-
if (
|
|
15104
|
+
if (import_fs47.default.existsSync(import_path48.default.join(import_os42.default.homedir(), ".node9", "hud-debug"))) {
|
|
14939
15105
|
try {
|
|
14940
15106
|
const logPath = import_path48.default.join(import_os42.default.homedir(), ".node9", "hud-debug.log");
|
|
14941
15107
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
14942
15108
|
let size = 0;
|
|
14943
15109
|
try {
|
|
14944
|
-
size =
|
|
15110
|
+
size = import_fs47.default.statSync(logPath).size;
|
|
14945
15111
|
} catch {
|
|
14946
15112
|
}
|
|
14947
15113
|
if (size < MAX_LOG_SIZE) {
|
|
14948
|
-
|
|
15114
|
+
import_fs47.default.appendFileSync(
|
|
14949
15115
|
logPath,
|
|
14950
15116
|
JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
|
|
14951
15117
|
);
|
|
@@ -14969,8 +15135,8 @@ async function main() {
|
|
|
14969
15135
|
import_path48.default.join(cwd, "node9.config.json"),
|
|
14970
15136
|
import_path48.default.join(import_os42.default.homedir(), ".node9", "config.json")
|
|
14971
15137
|
]) {
|
|
14972
|
-
if (!
|
|
14973
|
-
const cfg = JSON.parse(
|
|
15138
|
+
if (!import_fs47.default.existsSync(configPath)) continue;
|
|
15139
|
+
const cfg = JSON.parse(import_fs47.default.readFileSync(configPath, "utf-8"));
|
|
14974
15140
|
const hud = cfg.settings?.hud;
|
|
14975
15141
|
if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
|
|
14976
15142
|
}
|
|
@@ -14988,11 +15154,11 @@ async function main() {
|
|
|
14988
15154
|
renderOffline();
|
|
14989
15155
|
}
|
|
14990
15156
|
}
|
|
14991
|
-
var
|
|
15157
|
+
var import_fs47, import_path48, import_os42, import_http3, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
|
|
14992
15158
|
var init_hud = __esm({
|
|
14993
15159
|
"src/cli/hud.ts"() {
|
|
14994
15160
|
"use strict";
|
|
14995
|
-
|
|
15161
|
+
import_fs47 = __toESM(require("fs"));
|
|
14996
15162
|
import_path48 = __toESM(require("path"));
|
|
14997
15163
|
import_os42 = __toESM(require("os"));
|
|
14998
15164
|
import_http3 = __toESM(require("http"));
|
|
@@ -15021,7 +15187,7 @@ init_core();
|
|
|
15021
15187
|
init_setup();
|
|
15022
15188
|
init_daemon2();
|
|
15023
15189
|
var import_chalk30 = __toESM(require("chalk"));
|
|
15024
|
-
var
|
|
15190
|
+
var import_fs48 = __toESM(require("fs"));
|
|
15025
15191
|
var import_path49 = __toESM(require("path"));
|
|
15026
15192
|
var import_os43 = __toESM(require("os"));
|
|
15027
15193
|
var import_prompts2 = require("@inquirer/prompts");
|
|
@@ -15205,18 +15371,18 @@ async function runProxy(targetCommand) {
|
|
|
15205
15371
|
|
|
15206
15372
|
// src/cli/daemon-starter.ts
|
|
15207
15373
|
var import_child_process5 = require("child_process");
|
|
15208
|
-
var
|
|
15209
|
-
var
|
|
15374
|
+
var import_path30 = __toESM(require("path"));
|
|
15375
|
+
var import_fs29 = __toESM(require("fs"));
|
|
15210
15376
|
init_daemon();
|
|
15211
15377
|
function isTestingMode() {
|
|
15212
15378
|
return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
|
|
15213
15379
|
}
|
|
15214
15380
|
async function autoStartDaemonAndWait() {
|
|
15215
15381
|
if (isTestingMode()) return false;
|
|
15216
|
-
if (!
|
|
15382
|
+
if (!import_path30.default.isAbsolute(process.argv[1])) return false;
|
|
15217
15383
|
let resolvedArgv1;
|
|
15218
15384
|
try {
|
|
15219
|
-
resolvedArgv1 =
|
|
15385
|
+
resolvedArgv1 = import_fs29.default.realpathSync(process.argv[1]);
|
|
15220
15386
|
} catch {
|
|
15221
15387
|
return false;
|
|
15222
15388
|
}
|
|
@@ -15243,10 +15409,10 @@ async function autoStartDaemonAndWait() {
|
|
|
15243
15409
|
|
|
15244
15410
|
// src/cli/commands/check.ts
|
|
15245
15411
|
var import_chalk9 = __toESM(require("chalk"));
|
|
15246
|
-
var
|
|
15412
|
+
var import_fs32 = __toESM(require("fs"));
|
|
15247
15413
|
var import_child_process7 = require("child_process");
|
|
15248
|
-
var
|
|
15249
|
-
var
|
|
15414
|
+
var import_path33 = __toESM(require("path"));
|
|
15415
|
+
var import_os28 = __toESM(require("os"));
|
|
15250
15416
|
init_orchestrator();
|
|
15251
15417
|
init_daemon();
|
|
15252
15418
|
init_config();
|
|
@@ -15254,12 +15420,12 @@ init_policy();
|
|
|
15254
15420
|
|
|
15255
15421
|
// src/undo.ts
|
|
15256
15422
|
var import_child_process6 = require("child_process");
|
|
15257
|
-
var
|
|
15258
|
-
var
|
|
15423
|
+
var import_crypto9 = __toESM(require("crypto"));
|
|
15424
|
+
var import_fs30 = __toESM(require("fs"));
|
|
15259
15425
|
var import_net3 = __toESM(require("net"));
|
|
15260
|
-
var
|
|
15261
|
-
var
|
|
15262
|
-
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
15426
|
+
var import_path31 = __toESM(require("path"));
|
|
15427
|
+
var import_os26 = __toESM(require("os"));
|
|
15428
|
+
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path31.default.join(import_os26.default.tmpdir(), "node9-activity.sock");
|
|
15263
15429
|
function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
15264
15430
|
try {
|
|
15265
15431
|
const payload = JSON.stringify({
|
|
@@ -15279,22 +15445,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
|
15279
15445
|
} catch {
|
|
15280
15446
|
}
|
|
15281
15447
|
}
|
|
15282
|
-
var SNAPSHOT_STACK_PATH =
|
|
15283
|
-
var UNDO_LATEST_PATH =
|
|
15448
|
+
var SNAPSHOT_STACK_PATH = import_path31.default.join(import_os26.default.homedir(), ".node9", "snapshots.json");
|
|
15449
|
+
var UNDO_LATEST_PATH = import_path31.default.join(import_os26.default.homedir(), ".node9", "undo_latest.txt");
|
|
15284
15450
|
var MAX_SNAPSHOTS = 10;
|
|
15285
15451
|
var GIT_TIMEOUT = 15e3;
|
|
15286
15452
|
function readStack() {
|
|
15287
15453
|
try {
|
|
15288
|
-
if (
|
|
15289
|
-
return JSON.parse(
|
|
15454
|
+
if (import_fs30.default.existsSync(SNAPSHOT_STACK_PATH))
|
|
15455
|
+
return JSON.parse(import_fs30.default.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
|
|
15290
15456
|
} catch {
|
|
15291
15457
|
}
|
|
15292
15458
|
return [];
|
|
15293
15459
|
}
|
|
15294
15460
|
function writeStack(stack) {
|
|
15295
|
-
const dir =
|
|
15296
|
-
if (!
|
|
15297
|
-
|
|
15461
|
+
const dir = import_path31.default.dirname(SNAPSHOT_STACK_PATH);
|
|
15462
|
+
if (!import_fs30.default.existsSync(dir)) import_fs30.default.mkdirSync(dir, { recursive: true });
|
|
15463
|
+
import_fs30.default.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
|
|
15298
15464
|
}
|
|
15299
15465
|
function extractFilePath(args) {
|
|
15300
15466
|
if (!args || typeof args !== "object") return null;
|
|
@@ -15314,12 +15480,12 @@ function buildArgsSummary(tool, args) {
|
|
|
15314
15480
|
return "";
|
|
15315
15481
|
}
|
|
15316
15482
|
function findProjectRoot(filePath) {
|
|
15317
|
-
let dir =
|
|
15483
|
+
let dir = import_path31.default.dirname(filePath);
|
|
15318
15484
|
while (true) {
|
|
15319
|
-
if (
|
|
15485
|
+
if (import_fs30.default.existsSync(import_path31.default.join(dir, ".git")) || import_fs30.default.existsSync(import_path31.default.join(dir, "package.json"))) {
|
|
15320
15486
|
return dir;
|
|
15321
15487
|
}
|
|
15322
|
-
const parent =
|
|
15488
|
+
const parent = import_path31.default.dirname(dir);
|
|
15323
15489
|
if (parent === dir) return process.cwd();
|
|
15324
15490
|
dir = parent;
|
|
15325
15491
|
}
|
|
@@ -15327,7 +15493,7 @@ function findProjectRoot(filePath) {
|
|
|
15327
15493
|
function normalizeCwdForHash(cwd) {
|
|
15328
15494
|
let normalized;
|
|
15329
15495
|
try {
|
|
15330
|
-
normalized =
|
|
15496
|
+
normalized = import_fs30.default.realpathSync(cwd);
|
|
15331
15497
|
} catch {
|
|
15332
15498
|
normalized = cwd;
|
|
15333
15499
|
}
|
|
@@ -15336,17 +15502,17 @@ function normalizeCwdForHash(cwd) {
|
|
|
15336
15502
|
return normalized;
|
|
15337
15503
|
}
|
|
15338
15504
|
function getShadowRepoDir(cwd) {
|
|
15339
|
-
const hash =
|
|
15340
|
-
return
|
|
15505
|
+
const hash = import_crypto9.default.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
|
|
15506
|
+
return import_path31.default.join(import_os26.default.homedir(), ".node9", "snapshots", hash);
|
|
15341
15507
|
}
|
|
15342
15508
|
function cleanOrphanedIndexFiles(shadowDir) {
|
|
15343
15509
|
try {
|
|
15344
15510
|
const cutoff = Date.now() - 6e4;
|
|
15345
|
-
for (const f of
|
|
15511
|
+
for (const f of import_fs30.default.readdirSync(shadowDir)) {
|
|
15346
15512
|
if (f.startsWith("index_")) {
|
|
15347
|
-
const fp =
|
|
15513
|
+
const fp = import_path31.default.join(shadowDir, f);
|
|
15348
15514
|
try {
|
|
15349
|
-
if (
|
|
15515
|
+
if (import_fs30.default.statSync(fp).mtimeMs < cutoff) import_fs30.default.unlinkSync(fp);
|
|
15350
15516
|
} catch {
|
|
15351
15517
|
}
|
|
15352
15518
|
}
|
|
@@ -15358,7 +15524,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
|
|
|
15358
15524
|
const hardcoded = [".git", ".node9"];
|
|
15359
15525
|
const lines = [...hardcoded, ...ignorePaths].join("\n");
|
|
15360
15526
|
try {
|
|
15361
|
-
|
|
15527
|
+
import_fs30.default.writeFileSync(import_path31.default.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
|
|
15362
15528
|
} catch {
|
|
15363
15529
|
}
|
|
15364
15530
|
}
|
|
@@ -15371,25 +15537,25 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
15371
15537
|
timeout: 3e3
|
|
15372
15538
|
});
|
|
15373
15539
|
if (check.status === 0) {
|
|
15374
|
-
const ptPath =
|
|
15540
|
+
const ptPath = import_path31.default.join(shadowDir, "project-path.txt");
|
|
15375
15541
|
try {
|
|
15376
|
-
const stored =
|
|
15542
|
+
const stored = import_fs30.default.readFileSync(ptPath, "utf8").trim();
|
|
15377
15543
|
if (stored === normalizedCwd) return true;
|
|
15378
15544
|
if (process.env.NODE9_DEBUG === "1")
|
|
15379
15545
|
console.error(
|
|
15380
15546
|
`[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
|
|
15381
15547
|
);
|
|
15382
|
-
|
|
15548
|
+
import_fs30.default.rmSync(shadowDir, { recursive: true, force: true });
|
|
15383
15549
|
} catch {
|
|
15384
15550
|
try {
|
|
15385
|
-
|
|
15551
|
+
import_fs30.default.writeFileSync(ptPath, normalizedCwd, "utf8");
|
|
15386
15552
|
} catch {
|
|
15387
15553
|
}
|
|
15388
15554
|
return true;
|
|
15389
15555
|
}
|
|
15390
15556
|
}
|
|
15391
15557
|
try {
|
|
15392
|
-
|
|
15558
|
+
import_fs30.default.mkdirSync(shadowDir, { recursive: true });
|
|
15393
15559
|
} catch {
|
|
15394
15560
|
}
|
|
15395
15561
|
const init = (0, import_child_process6.spawnSync)("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
|
|
@@ -15398,7 +15564,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
15398
15564
|
if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
|
|
15399
15565
|
return false;
|
|
15400
15566
|
}
|
|
15401
|
-
const configFile =
|
|
15567
|
+
const configFile = import_path31.default.join(shadowDir, "config");
|
|
15402
15568
|
(0, import_child_process6.spawnSync)("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
|
|
15403
15569
|
timeout: 3e3
|
|
15404
15570
|
});
|
|
@@ -15406,7 +15572,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
15406
15572
|
timeout: 3e3
|
|
15407
15573
|
});
|
|
15408
15574
|
try {
|
|
15409
|
-
|
|
15575
|
+
import_fs30.default.writeFileSync(import_path31.default.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
|
|
15410
15576
|
} catch {
|
|
15411
15577
|
}
|
|
15412
15578
|
return true;
|
|
@@ -15429,12 +15595,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
15429
15595
|
let indexFile = null;
|
|
15430
15596
|
try {
|
|
15431
15597
|
const rawFilePath = extractFilePath(args);
|
|
15432
|
-
const absFilePath = rawFilePath &&
|
|
15598
|
+
const absFilePath = rawFilePath && import_path31.default.isAbsolute(rawFilePath) ? rawFilePath : null;
|
|
15433
15599
|
const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
|
|
15434
15600
|
const shadowDir = getShadowRepoDir(cwd);
|
|
15435
15601
|
if (!ensureShadowRepo(shadowDir, cwd)) return null;
|
|
15436
15602
|
writeShadowExcludes(shadowDir, ignorePaths);
|
|
15437
|
-
indexFile =
|
|
15603
|
+
indexFile = import_path31.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
|
|
15438
15604
|
const shadowEnv = {
|
|
15439
15605
|
...process.env,
|
|
15440
15606
|
GIT_DIR: shadowDir,
|
|
@@ -15506,7 +15672,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
15506
15672
|
writeStack(stack);
|
|
15507
15673
|
const entry = stack[stack.length - 1];
|
|
15508
15674
|
notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
|
|
15509
|
-
|
|
15675
|
+
import_fs30.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
|
|
15510
15676
|
if (shouldGc) {
|
|
15511
15677
|
(0, import_child_process6.spawn)("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
|
|
15512
15678
|
}
|
|
@@ -15517,7 +15683,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
15517
15683
|
} finally {
|
|
15518
15684
|
if (indexFile) {
|
|
15519
15685
|
try {
|
|
15520
|
-
|
|
15686
|
+
import_fs30.default.unlinkSync(indexFile);
|
|
15521
15687
|
} catch {
|
|
15522
15688
|
}
|
|
15523
15689
|
}
|
|
@@ -15593,9 +15759,9 @@ function applyUndo(hash, cwd) {
|
|
|
15593
15759
|
timeout: GIT_TIMEOUT
|
|
15594
15760
|
}).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
|
|
15595
15761
|
for (const file of [...tracked, ...untracked]) {
|
|
15596
|
-
const fullPath =
|
|
15597
|
-
if (!snapshotFiles.has(file) &&
|
|
15598
|
-
|
|
15762
|
+
const fullPath = import_path31.default.join(dir, file);
|
|
15763
|
+
if (!snapshotFiles.has(file) && import_fs30.default.existsSync(fullPath)) {
|
|
15764
|
+
import_fs30.default.unlinkSync(fullPath);
|
|
15599
15765
|
}
|
|
15600
15766
|
}
|
|
15601
15767
|
return true;
|
|
@@ -15605,17 +15771,17 @@ function applyUndo(hash, cwd) {
|
|
|
15605
15771
|
}
|
|
15606
15772
|
|
|
15607
15773
|
// src/skill-pin.ts
|
|
15608
|
-
var
|
|
15609
|
-
var
|
|
15610
|
-
var
|
|
15611
|
-
var
|
|
15612
|
-
function
|
|
15613
|
-
return
|
|
15774
|
+
var import_fs31 = __toESM(require("fs"));
|
|
15775
|
+
var import_path32 = __toESM(require("path"));
|
|
15776
|
+
var import_os27 = __toESM(require("os"));
|
|
15777
|
+
var import_crypto10 = __toESM(require("crypto"));
|
|
15778
|
+
function getPinsFilePath2() {
|
|
15779
|
+
return import_path32.default.join(import_os27.default.homedir(), ".node9", "skill-pins.json");
|
|
15614
15780
|
}
|
|
15615
15781
|
var MAX_FILES = 5e3;
|
|
15616
15782
|
var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
|
|
15617
15783
|
function sha256Bytes(buf) {
|
|
15618
|
-
return
|
|
15784
|
+
return import_crypto10.default.createHash("sha256").update(buf).digest("hex");
|
|
15619
15785
|
}
|
|
15620
15786
|
function walkDir(root) {
|
|
15621
15787
|
const out = [];
|
|
@@ -15624,18 +15790,18 @@ function walkDir(root) {
|
|
|
15624
15790
|
if (out.length >= MAX_FILES) return;
|
|
15625
15791
|
let entries;
|
|
15626
15792
|
try {
|
|
15627
|
-
entries =
|
|
15793
|
+
entries = import_fs31.default.readdirSync(dir, { withFileTypes: true });
|
|
15628
15794
|
} catch {
|
|
15629
15795
|
return;
|
|
15630
15796
|
}
|
|
15631
15797
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
15632
15798
|
for (const entry of entries) {
|
|
15633
15799
|
if (out.length >= MAX_FILES) return;
|
|
15634
|
-
const full =
|
|
15635
|
-
const rel = relDir ?
|
|
15800
|
+
const full = import_path32.default.join(dir, entry.name);
|
|
15801
|
+
const rel = relDir ? import_path32.default.posix.join(relDir, entry.name) : entry.name;
|
|
15636
15802
|
let lst;
|
|
15637
15803
|
try {
|
|
15638
|
-
lst =
|
|
15804
|
+
lst = import_fs31.default.lstatSync(full);
|
|
15639
15805
|
} catch {
|
|
15640
15806
|
continue;
|
|
15641
15807
|
}
|
|
@@ -15647,7 +15813,7 @@ function walkDir(root) {
|
|
|
15647
15813
|
if (!lst.isFile()) continue;
|
|
15648
15814
|
if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
|
|
15649
15815
|
try {
|
|
15650
|
-
const buf =
|
|
15816
|
+
const buf = import_fs31.default.readFileSync(full);
|
|
15651
15817
|
totalBytes += buf.length;
|
|
15652
15818
|
out.push({ rel, hash: sha256Bytes(buf) });
|
|
15653
15819
|
} catch {
|
|
@@ -15661,32 +15827,32 @@ function walkDir(root) {
|
|
|
15661
15827
|
function hashSkillRoot(absPath) {
|
|
15662
15828
|
let lst;
|
|
15663
15829
|
try {
|
|
15664
|
-
lst =
|
|
15830
|
+
lst = import_fs31.default.lstatSync(absPath);
|
|
15665
15831
|
} catch {
|
|
15666
15832
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
15667
15833
|
}
|
|
15668
15834
|
if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
|
|
15669
15835
|
if (lst.isFile()) {
|
|
15670
15836
|
try {
|
|
15671
|
-
return { exists: true, contentHash: sha256Bytes(
|
|
15837
|
+
return { exists: true, contentHash: sha256Bytes(import_fs31.default.readFileSync(absPath)), fileCount: 1 };
|
|
15672
15838
|
} catch {
|
|
15673
15839
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
15674
15840
|
}
|
|
15675
15841
|
}
|
|
15676
15842
|
if (lst.isDirectory()) {
|
|
15677
15843
|
const entries = walkDir(absPath);
|
|
15678
|
-
const contentHash =
|
|
15844
|
+
const contentHash = import_crypto10.default.createHash("sha256").update(entries.join("\n")).digest("hex");
|
|
15679
15845
|
return { exists: true, contentHash, fileCount: entries.length };
|
|
15680
15846
|
}
|
|
15681
15847
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
15682
15848
|
}
|
|
15683
15849
|
function getRootKey(absPath) {
|
|
15684
|
-
return
|
|
15850
|
+
return import_crypto10.default.createHash("sha256").update(absPath).digest("hex").slice(0, 16);
|
|
15685
15851
|
}
|
|
15686
15852
|
function readSkillPinsSafe() {
|
|
15687
|
-
const filePath =
|
|
15853
|
+
const filePath = getPinsFilePath2();
|
|
15688
15854
|
try {
|
|
15689
|
-
const raw =
|
|
15855
|
+
const raw = import_fs31.default.readFileSync(filePath, "utf-8");
|
|
15690
15856
|
if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
15691
15857
|
const parsed = JSON.parse(raw);
|
|
15692
15858
|
if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
|
|
@@ -15705,18 +15871,18 @@ function readSkillPins() {
|
|
|
15705
15871
|
throw new Error(`[node9] skill pin file is corrupt: ${result.detail}`);
|
|
15706
15872
|
}
|
|
15707
15873
|
function writeSkillPins(data) {
|
|
15708
|
-
const filePath =
|
|
15709
|
-
|
|
15710
|
-
const tmp = `${filePath}.${
|
|
15711
|
-
|
|
15712
|
-
|
|
15874
|
+
const filePath = getPinsFilePath2();
|
|
15875
|
+
import_fs31.default.mkdirSync(import_path32.default.dirname(filePath), { recursive: true });
|
|
15876
|
+
const tmp = `${filePath}.${import_crypto10.default.randomBytes(6).toString("hex")}.tmp`;
|
|
15877
|
+
import_fs31.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
15878
|
+
import_fs31.default.renameSync(tmp, filePath);
|
|
15713
15879
|
}
|
|
15714
|
-
function
|
|
15880
|
+
function removePin2(rootKey) {
|
|
15715
15881
|
const pins = readSkillPins();
|
|
15716
15882
|
delete pins.roots[rootKey];
|
|
15717
15883
|
writeSkillPins(pins);
|
|
15718
15884
|
}
|
|
15719
|
-
function
|
|
15885
|
+
function clearAllPins2() {
|
|
15720
15886
|
writeSkillPins({ roots: {} });
|
|
15721
15887
|
}
|
|
15722
15888
|
function verifyAndPinRoots(roots) {
|
|
@@ -15753,36 +15919,36 @@ function verifyAndPinRoots(roots) {
|
|
|
15753
15919
|
return { kind: "verified" };
|
|
15754
15920
|
}
|
|
15755
15921
|
function defaultSkillRoots(_cwd) {
|
|
15756
|
-
const marketplaces =
|
|
15922
|
+
const marketplaces = import_path32.default.join(import_os27.default.homedir(), ".claude", "plugins", "marketplaces");
|
|
15757
15923
|
const roots = [];
|
|
15758
15924
|
let registries;
|
|
15759
15925
|
try {
|
|
15760
|
-
registries =
|
|
15926
|
+
registries = import_fs31.default.readdirSync(marketplaces, { withFileTypes: true });
|
|
15761
15927
|
} catch {
|
|
15762
15928
|
return [];
|
|
15763
15929
|
}
|
|
15764
15930
|
for (const registry of registries) {
|
|
15765
15931
|
if (!registry.isDirectory()) continue;
|
|
15766
|
-
const pluginsDir =
|
|
15932
|
+
const pluginsDir = import_path32.default.join(marketplaces, registry.name, "plugins");
|
|
15767
15933
|
let plugins;
|
|
15768
15934
|
try {
|
|
15769
|
-
plugins =
|
|
15935
|
+
plugins = import_fs31.default.readdirSync(pluginsDir, { withFileTypes: true });
|
|
15770
15936
|
} catch {
|
|
15771
15937
|
continue;
|
|
15772
15938
|
}
|
|
15773
15939
|
for (const plugin of plugins) {
|
|
15774
15940
|
if (!plugin.isDirectory()) continue;
|
|
15775
|
-
roots.push(
|
|
15941
|
+
roots.push(import_path32.default.join(pluginsDir, plugin.name));
|
|
15776
15942
|
}
|
|
15777
15943
|
}
|
|
15778
15944
|
return roots;
|
|
15779
15945
|
}
|
|
15780
15946
|
function resolveUserSkillRoot(entry, cwd) {
|
|
15781
15947
|
if (!entry) return null;
|
|
15782
|
-
if (entry.startsWith("~/") || entry === "~") return
|
|
15783
|
-
if (
|
|
15784
|
-
if (!cwd || !
|
|
15785
|
-
return
|
|
15948
|
+
if (entry.startsWith("~/") || entry === "~") return import_path32.default.join(import_os27.default.homedir(), entry.slice(1));
|
|
15949
|
+
if (import_path32.default.isAbsolute(entry)) return entry;
|
|
15950
|
+
if (!cwd || !import_path32.default.isAbsolute(cwd)) return null;
|
|
15951
|
+
return import_path32.default.join(cwd, entry);
|
|
15786
15952
|
}
|
|
15787
15953
|
|
|
15788
15954
|
// src/cli/commands/check.ts
|
|
@@ -15829,9 +15995,9 @@ function registerCheckCommand(program2) {
|
|
|
15829
15995
|
} catch (err2) {
|
|
15830
15996
|
const tempConfig = getConfig();
|
|
15831
15997
|
if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
|
|
15832
|
-
const logPath =
|
|
15998
|
+
const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
15833
15999
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
15834
|
-
|
|
16000
|
+
import_fs32.default.appendFileSync(
|
|
15835
16001
|
logPath,
|
|
15836
16002
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
|
|
15837
16003
|
RAW: ${raw}
|
|
@@ -15844,14 +16010,14 @@ RAW: ${raw}
|
|
|
15844
16010
|
const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
|
|
15845
16011
|
if (process.env.NODE9_DEBUG === "1") {
|
|
15846
16012
|
try {
|
|
15847
|
-
const logPath =
|
|
15848
|
-
if (!
|
|
15849
|
-
|
|
16013
|
+
const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
16014
|
+
if (!import_fs32.default.existsSync(import_path33.default.dirname(logPath)))
|
|
16015
|
+
import_fs32.default.mkdirSync(import_path33.default.dirname(logPath), { recursive: true });
|
|
15850
16016
|
const sanitized = JSON.stringify({
|
|
15851
16017
|
...payload,
|
|
15852
16018
|
prompt: `<redacted, ${prompt.length} bytes>`
|
|
15853
16019
|
});
|
|
15854
|
-
|
|
16020
|
+
import_fs32.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
|
|
15855
16021
|
`);
|
|
15856
16022
|
} catch {
|
|
15857
16023
|
}
|
|
@@ -15871,8 +16037,8 @@ RAW: ${raw}
|
|
|
15871
16037
|
);
|
|
15872
16038
|
const reason = `\u{1F6A8} Node9 DLP: ${dlpMatch.patternName} detected in prompt (${dlpMatch.redactedSample}). Prompt was not submitted \u2014 remove the credential and try again.`;
|
|
15873
16039
|
try {
|
|
15874
|
-
const ttyFd =
|
|
15875
|
-
|
|
16040
|
+
const ttyFd = import_fs32.default.openSync("/dev/tty", "w");
|
|
16041
|
+
import_fs32.default.writeSync(
|
|
15876
16042
|
ttyFd,
|
|
15877
16043
|
import_chalk9.default.bgRed.white.bold(`
|
|
15878
16044
|
\u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
|
|
@@ -15882,7 +16048,7 @@ RAW: ${raw}
|
|
|
15882
16048
|
|
|
15883
16049
|
`)
|
|
15884
16050
|
);
|
|
15885
|
-
|
|
16051
|
+
import_fs32.default.closeSync(ttyFd);
|
|
15886
16052
|
} catch {
|
|
15887
16053
|
}
|
|
15888
16054
|
const isCodex = agent2 === "Codex";
|
|
@@ -15900,16 +16066,16 @@ RAW: ${raw}
|
|
|
15900
16066
|
);
|
|
15901
16067
|
process.exit(2);
|
|
15902
16068
|
}
|
|
15903
|
-
const safeCwdForConfig = typeof payload.cwd === "string" &&
|
|
16069
|
+
const safeCwdForConfig = typeof payload.cwd === "string" && import_path33.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
|
|
15904
16070
|
const config = getConfig(safeCwdForConfig);
|
|
15905
16071
|
if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
|
|
15906
16072
|
try {
|
|
15907
16073
|
const scriptPath = process.argv[1];
|
|
15908
|
-
if (typeof scriptPath !== "string" || !
|
|
16074
|
+
if (typeof scriptPath !== "string" || !import_path33.default.isAbsolute(scriptPath))
|
|
15909
16075
|
throw new Error("node9: argv[1] is not an absolute path");
|
|
15910
|
-
const resolvedScript =
|
|
15911
|
-
const packageDist =
|
|
15912
|
-
if (!resolvedScript.startsWith(packageDist +
|
|
16076
|
+
const resolvedScript = import_fs32.default.realpathSync(scriptPath);
|
|
16077
|
+
const packageDist = import_fs32.default.realpathSync(import_path33.default.resolve(__dirname, "../.."));
|
|
16078
|
+
if (!resolvedScript.startsWith(packageDist + import_path33.default.sep) && resolvedScript !== packageDist)
|
|
15913
16079
|
throw new Error(
|
|
15914
16080
|
`node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
|
|
15915
16081
|
);
|
|
@@ -15931,10 +16097,10 @@ RAW: ${raw}
|
|
|
15931
16097
|
});
|
|
15932
16098
|
d.unref();
|
|
15933
16099
|
} catch (spawnErr) {
|
|
15934
|
-
const logPath =
|
|
16100
|
+
const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
15935
16101
|
const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
|
|
15936
16102
|
try {
|
|
15937
|
-
|
|
16103
|
+
import_fs32.default.appendFileSync(
|
|
15938
16104
|
logPath,
|
|
15939
16105
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
|
|
15940
16106
|
`
|
|
@@ -15944,10 +16110,10 @@ RAW: ${raw}
|
|
|
15944
16110
|
}
|
|
15945
16111
|
}
|
|
15946
16112
|
if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
|
|
15947
|
-
const logPath =
|
|
15948
|
-
if (!
|
|
15949
|
-
|
|
15950
|
-
|
|
16113
|
+
const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
16114
|
+
if (!import_fs32.default.existsSync(import_path33.default.dirname(logPath)))
|
|
16115
|
+
import_fs32.default.mkdirSync(import_path33.default.dirname(logPath), { recursive: true });
|
|
16116
|
+
import_fs32.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
|
|
15951
16117
|
`);
|
|
15952
16118
|
}
|
|
15953
16119
|
const toolName = sanitize2(payload.tool_name ?? payload.name ?? "");
|
|
@@ -15960,8 +16126,8 @@ RAW: ${raw}
|
|
|
15960
16126
|
const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
|
|
15961
16127
|
let ttyFd = null;
|
|
15962
16128
|
try {
|
|
15963
|
-
ttyFd =
|
|
15964
|
-
const writeTty = (line) =>
|
|
16129
|
+
ttyFd = import_fs32.default.openSync("/dev/tty", "w");
|
|
16130
|
+
const writeTty = (line) => import_fs32.default.writeSync(ttyFd, line + "\n");
|
|
15965
16131
|
if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
|
|
15966
16132
|
writeTty(import_chalk9.default.bgRed.white.bold(`
|
|
15967
16133
|
\u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
|
|
@@ -15980,7 +16146,7 @@ RAW: ${raw}
|
|
|
15980
16146
|
} finally {
|
|
15981
16147
|
if (ttyFd !== null)
|
|
15982
16148
|
try {
|
|
15983
|
-
|
|
16149
|
+
import_fs32.default.closeSync(ttyFd);
|
|
15984
16150
|
} catch {
|
|
15985
16151
|
}
|
|
15986
16152
|
}
|
|
@@ -16016,17 +16182,17 @@ RAW: ${raw}
|
|
|
16016
16182
|
const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
|
|
16017
16183
|
if (skillPinCfg.enabled && safeSessionId) {
|
|
16018
16184
|
try {
|
|
16019
|
-
const sessionsDir =
|
|
16020
|
-
const flagPath =
|
|
16185
|
+
const sessionsDir = import_path33.default.join(import_os28.default.homedir(), ".node9", "skill-sessions");
|
|
16186
|
+
const flagPath = import_path33.default.join(sessionsDir, `${safeSessionId}.json`);
|
|
16021
16187
|
let flag = null;
|
|
16022
16188
|
try {
|
|
16023
|
-
flag = JSON.parse(
|
|
16189
|
+
flag = JSON.parse(import_fs32.default.readFileSync(flagPath, "utf-8"));
|
|
16024
16190
|
} catch {
|
|
16025
16191
|
}
|
|
16026
16192
|
const writeFlag = (data2) => {
|
|
16027
16193
|
try {
|
|
16028
|
-
|
|
16029
|
-
|
|
16194
|
+
import_fs32.default.mkdirSync(sessionsDir, { recursive: true });
|
|
16195
|
+
import_fs32.default.writeFileSync(
|
|
16030
16196
|
flagPath,
|
|
16031
16197
|
JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
|
|
16032
16198
|
{ mode: 384 }
|
|
@@ -16037,8 +16203,8 @@ RAW: ${raw}
|
|
|
16037
16203
|
const sendSkillWarn = (detail, recoveryCmd) => {
|
|
16038
16204
|
let ttyFd = null;
|
|
16039
16205
|
try {
|
|
16040
|
-
ttyFd =
|
|
16041
|
-
const w = (line) =>
|
|
16206
|
+
ttyFd = import_fs32.default.openSync("/dev/tty", "w");
|
|
16207
|
+
const w = (line) => import_fs32.default.writeSync(ttyFd, line + "\n");
|
|
16042
16208
|
w(import_chalk9.default.yellow(`
|
|
16043
16209
|
\u26A0\uFE0F Node9: installed skill drift detected`));
|
|
16044
16210
|
w(import_chalk9.default.gray(` ${detail}`));
|
|
@@ -16053,7 +16219,7 @@ RAW: ${raw}
|
|
|
16053
16219
|
} finally {
|
|
16054
16220
|
if (ttyFd !== null)
|
|
16055
16221
|
try {
|
|
16056
|
-
|
|
16222
|
+
import_fs32.default.closeSync(ttyFd);
|
|
16057
16223
|
} catch {
|
|
16058
16224
|
}
|
|
16059
16225
|
}
|
|
@@ -16069,7 +16235,7 @@ RAW: ${raw}
|
|
|
16069
16235
|
return;
|
|
16070
16236
|
}
|
|
16071
16237
|
if (!flag || flag.state !== "verified" && flag.state !== "warned") {
|
|
16072
|
-
const absoluteCwd = typeof payload.cwd === "string" &&
|
|
16238
|
+
const absoluteCwd = typeof payload.cwd === "string" && import_path33.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
|
|
16073
16239
|
const extraRoots = skillPinCfg.roots;
|
|
16074
16240
|
const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
|
|
16075
16241
|
const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
|
|
@@ -16110,10 +16276,10 @@ RAW: ${raw}
|
|
|
16110
16276
|
}
|
|
16111
16277
|
try {
|
|
16112
16278
|
const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
16113
|
-
for (const name of
|
|
16114
|
-
const p =
|
|
16279
|
+
for (const name of import_fs32.default.readdirSync(sessionsDir)) {
|
|
16280
|
+
const p = import_path33.default.join(sessionsDir, name);
|
|
16115
16281
|
try {
|
|
16116
|
-
if (
|
|
16282
|
+
if (import_fs32.default.statSync(p).mtimeMs < cutoff) import_fs32.default.unlinkSync(p);
|
|
16117
16283
|
} catch {
|
|
16118
16284
|
}
|
|
16119
16285
|
}
|
|
@@ -16123,9 +16289,9 @@ RAW: ${raw}
|
|
|
16123
16289
|
} catch (err2) {
|
|
16124
16290
|
if (process.env.NODE9_DEBUG === "1") {
|
|
16125
16291
|
try {
|
|
16126
|
-
const dbg =
|
|
16292
|
+
const dbg = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
16127
16293
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
16128
|
-
|
|
16294
|
+
import_fs32.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
|
|
16129
16295
|
`);
|
|
16130
16296
|
} catch {
|
|
16131
16297
|
}
|
|
@@ -16135,7 +16301,7 @@ RAW: ${raw}
|
|
|
16135
16301
|
if (shouldSnapshot(toolName, toolInput, config)) {
|
|
16136
16302
|
await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
|
|
16137
16303
|
}
|
|
16138
|
-
const safeCwdForAuth = typeof payload.cwd === "string" &&
|
|
16304
|
+
const safeCwdForAuth = typeof payload.cwd === "string" && import_path33.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
|
|
16139
16305
|
const result = await authorizeHeadless(toolName, toolInput, meta, {
|
|
16140
16306
|
cwd: safeCwdForAuth
|
|
16141
16307
|
});
|
|
@@ -16147,12 +16313,12 @@ RAW: ${raw}
|
|
|
16147
16313
|
}
|
|
16148
16314
|
if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
|
|
16149
16315
|
try {
|
|
16150
|
-
const tty =
|
|
16151
|
-
|
|
16316
|
+
const tty = import_fs32.default.openSync("/dev/tty", "w");
|
|
16317
|
+
import_fs32.default.writeSync(
|
|
16152
16318
|
tty,
|
|
16153
16319
|
import_chalk9.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
|
|
16154
16320
|
);
|
|
16155
|
-
|
|
16321
|
+
import_fs32.default.closeSync(tty);
|
|
16156
16322
|
} catch {
|
|
16157
16323
|
}
|
|
16158
16324
|
const daemonReady = await autoStartDaemonAndWait();
|
|
@@ -16179,9 +16345,9 @@ RAW: ${raw}
|
|
|
16179
16345
|
});
|
|
16180
16346
|
} catch (err2) {
|
|
16181
16347
|
if (process.env.NODE9_DEBUG === "1") {
|
|
16182
|
-
const logPath =
|
|
16348
|
+
const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
|
|
16183
16349
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
16184
|
-
|
|
16350
|
+
import_fs32.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
|
|
16185
16351
|
`);
|
|
16186
16352
|
}
|
|
16187
16353
|
process.exit(0);
|
|
@@ -16215,9 +16381,9 @@ RAW: ${raw}
|
|
|
16215
16381
|
}
|
|
16216
16382
|
|
|
16217
16383
|
// src/cli/commands/log.ts
|
|
16218
|
-
var
|
|
16219
|
-
var
|
|
16220
|
-
var
|
|
16384
|
+
var import_fs33 = __toESM(require("fs"));
|
|
16385
|
+
var import_path34 = __toESM(require("path"));
|
|
16386
|
+
var import_os29 = __toESM(require("os"));
|
|
16221
16387
|
init_audit();
|
|
16222
16388
|
init_config();
|
|
16223
16389
|
init_daemon();
|
|
@@ -16295,10 +16461,10 @@ function registerLogCommand(program2) {
|
|
|
16295
16461
|
};
|
|
16296
16462
|
if (agent) entry.agent = agent;
|
|
16297
16463
|
if (payload.session_id) entry.sessionId = payload.session_id;
|
|
16298
|
-
const logPath =
|
|
16299
|
-
if (!
|
|
16300
|
-
|
|
16301
|
-
|
|
16464
|
+
const logPath = import_path34.default.join(import_os29.default.homedir(), ".node9", "audit.log");
|
|
16465
|
+
if (!import_fs33.default.existsSync(import_path34.default.dirname(logPath)))
|
|
16466
|
+
import_fs33.default.mkdirSync(import_path34.default.dirname(logPath), { recursive: true });
|
|
16467
|
+
import_fs33.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
|
|
16302
16468
|
if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
|
|
16303
16469
|
const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
16304
16470
|
if (command) {
|
|
@@ -16331,7 +16497,7 @@ function registerLogCommand(program2) {
|
|
|
16331
16497
|
}
|
|
16332
16498
|
}
|
|
16333
16499
|
}
|
|
16334
|
-
const safeCwd = typeof payload.cwd === "string" &&
|
|
16500
|
+
const safeCwd = typeof payload.cwd === "string" && import_path34.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
|
|
16335
16501
|
const config = getConfig(safeCwd);
|
|
16336
16502
|
if ((tool === "Bash" || tool === "bash") && config.settings.enableUndo !== false) {
|
|
16337
16503
|
const bashCommand = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
@@ -16352,9 +16518,9 @@ function registerLogCommand(program2) {
|
|
|
16352
16518
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
16353
16519
|
process.stderr.write(`[Node9] audit log error: ${msg}
|
|
16354
16520
|
`);
|
|
16355
|
-
const debugPath =
|
|
16521
|
+
const debugPath = import_path34.default.join(import_os29.default.homedir(), ".node9", "hook-debug.log");
|
|
16356
16522
|
try {
|
|
16357
|
-
|
|
16523
|
+
import_fs33.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
|
|
16358
16524
|
`);
|
|
16359
16525
|
} catch {
|
|
16360
16526
|
}
|
|
@@ -16754,14 +16920,14 @@ function registerConfigShowCommand(program2) {
|
|
|
16754
16920
|
|
|
16755
16921
|
// src/cli/commands/doctor.ts
|
|
16756
16922
|
var import_chalk11 = __toESM(require("chalk"));
|
|
16757
|
-
var
|
|
16758
|
-
var
|
|
16759
|
-
var
|
|
16923
|
+
var import_fs34 = __toESM(require("fs"));
|
|
16924
|
+
var import_path35 = __toESM(require("path"));
|
|
16925
|
+
var import_os30 = __toESM(require("os"));
|
|
16760
16926
|
var import_child_process8 = require("child_process");
|
|
16761
16927
|
init_daemon();
|
|
16762
16928
|
function registerDoctorCommand(program2, version2) {
|
|
16763
16929
|
program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(() => {
|
|
16764
|
-
const homeDir2 =
|
|
16930
|
+
const homeDir2 = import_os30.default.homedir();
|
|
16765
16931
|
let failures = 0;
|
|
16766
16932
|
function pass(msg) {
|
|
16767
16933
|
console.log(import_chalk11.default.green(" \u2705 ") + msg);
|
|
@@ -16810,10 +16976,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16810
16976
|
);
|
|
16811
16977
|
}
|
|
16812
16978
|
section("Configuration");
|
|
16813
|
-
const globalConfigPath =
|
|
16814
|
-
if (
|
|
16979
|
+
const globalConfigPath = import_path35.default.join(homeDir2, ".node9", "config.json");
|
|
16980
|
+
if (import_fs34.default.existsSync(globalConfigPath)) {
|
|
16815
16981
|
try {
|
|
16816
|
-
JSON.parse(
|
|
16982
|
+
JSON.parse(import_fs34.default.readFileSync(globalConfigPath, "utf-8"));
|
|
16817
16983
|
pass("~/.node9/config.json found and valid");
|
|
16818
16984
|
} catch {
|
|
16819
16985
|
fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
|
|
@@ -16821,10 +16987,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16821
16987
|
} else {
|
|
16822
16988
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
16823
16989
|
}
|
|
16824
|
-
const projectConfigPath =
|
|
16825
|
-
if (
|
|
16990
|
+
const projectConfigPath = import_path35.default.join(process.cwd(), "node9.config.json");
|
|
16991
|
+
if (import_fs34.default.existsSync(projectConfigPath)) {
|
|
16826
16992
|
try {
|
|
16827
|
-
JSON.parse(
|
|
16993
|
+
JSON.parse(import_fs34.default.readFileSync(projectConfigPath, "utf-8"));
|
|
16828
16994
|
pass("node9.config.json found and valid (project)");
|
|
16829
16995
|
} catch {
|
|
16830
16996
|
fail(
|
|
@@ -16833,8 +16999,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16833
16999
|
);
|
|
16834
17000
|
}
|
|
16835
17001
|
}
|
|
16836
|
-
const credsPath =
|
|
16837
|
-
if (
|
|
17002
|
+
const credsPath = import_path35.default.join(homeDir2, ".node9", "credentials.json");
|
|
17003
|
+
if (import_fs34.default.existsSync(credsPath)) {
|
|
16838
17004
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
16839
17005
|
} else {
|
|
16840
17006
|
warn(
|
|
@@ -16843,10 +17009,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16843
17009
|
);
|
|
16844
17010
|
}
|
|
16845
17011
|
section("Agent Hooks");
|
|
16846
|
-
const claudeSettingsPath =
|
|
16847
|
-
if (
|
|
17012
|
+
const claudeSettingsPath = import_path35.default.join(homeDir2, ".claude", "settings.json");
|
|
17013
|
+
if (import_fs34.default.existsSync(claudeSettingsPath)) {
|
|
16848
17014
|
try {
|
|
16849
|
-
const cs = JSON.parse(
|
|
17015
|
+
const cs = JSON.parse(import_fs34.default.readFileSync(claudeSettingsPath, "utf-8"));
|
|
16850
17016
|
const hasHook = cs.hooks?.PreToolUse?.some(
|
|
16851
17017
|
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
16852
17018
|
);
|
|
@@ -16862,10 +17028,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16862
17028
|
} else {
|
|
16863
17029
|
warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
|
|
16864
17030
|
}
|
|
16865
|
-
const geminiSettingsPath =
|
|
16866
|
-
if (
|
|
17031
|
+
const geminiSettingsPath = import_path35.default.join(homeDir2, ".gemini", "settings.json");
|
|
17032
|
+
if (import_fs34.default.existsSync(geminiSettingsPath)) {
|
|
16867
17033
|
try {
|
|
16868
|
-
const gs = JSON.parse(
|
|
17034
|
+
const gs = JSON.parse(import_fs34.default.readFileSync(geminiSettingsPath, "utf-8"));
|
|
16869
17035
|
const hasHook = gs.hooks?.BeforeTool?.some(
|
|
16870
17036
|
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
16871
17037
|
);
|
|
@@ -16881,10 +17047,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16881
17047
|
} else {
|
|
16882
17048
|
warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
|
|
16883
17049
|
}
|
|
16884
|
-
const cursorHooksPath =
|
|
16885
|
-
if (
|
|
17050
|
+
const cursorHooksPath = import_path35.default.join(homeDir2, ".cursor", "hooks.json");
|
|
17051
|
+
if (import_fs34.default.existsSync(cursorHooksPath)) {
|
|
16886
17052
|
try {
|
|
16887
|
-
const cur = JSON.parse(
|
|
17053
|
+
const cur = JSON.parse(import_fs34.default.readFileSync(cursorHooksPath, "utf-8"));
|
|
16888
17054
|
const hasHook = cur.hooks?.preToolUse?.some(
|
|
16889
17055
|
(h) => h.command?.includes("node9") || h.command?.includes("cli.js")
|
|
16890
17056
|
);
|
|
@@ -16924,9 +17090,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16924
17090
|
|
|
16925
17091
|
// src/cli/commands/audit.ts
|
|
16926
17092
|
var import_chalk12 = __toESM(require("chalk"));
|
|
16927
|
-
var
|
|
16928
|
-
var
|
|
16929
|
-
var
|
|
17093
|
+
var import_fs35 = __toESM(require("fs"));
|
|
17094
|
+
var import_path36 = __toESM(require("path"));
|
|
17095
|
+
var import_os31 = __toESM(require("os"));
|
|
16930
17096
|
function formatRelativeTime(timestamp) {
|
|
16931
17097
|
const diff = Date.now() - new Date(timestamp).getTime();
|
|
16932
17098
|
const sec = Math.floor(diff / 1e3);
|
|
@@ -16939,14 +17105,14 @@ function formatRelativeTime(timestamp) {
|
|
|
16939
17105
|
}
|
|
16940
17106
|
function registerAuditCommand(program2) {
|
|
16941
17107
|
program2.command("audit").description("View local execution audit log").option("--tail <n>", "Number of entries to show", "20").option("--tool <pattern>", "Filter by tool name (substring match)").option("--deny", "Show only denied actions").option("--json", "Output raw JSON").action((options) => {
|
|
16942
|
-
const logPath =
|
|
16943
|
-
if (!
|
|
17108
|
+
const logPath = import_path36.default.join(import_os31.default.homedir(), ".node9", "audit.log");
|
|
17109
|
+
if (!import_fs35.default.existsSync(logPath)) {
|
|
16944
17110
|
console.log(
|
|
16945
17111
|
import_chalk12.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
16946
17112
|
);
|
|
16947
17113
|
return;
|
|
16948
17114
|
}
|
|
16949
|
-
const raw =
|
|
17115
|
+
const raw = import_fs35.default.readFileSync(logPath, "utf-8");
|
|
16950
17116
|
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
16951
17117
|
let entries = lines.flatMap((line) => {
|
|
16952
17118
|
try {
|
|
@@ -17002,9 +17168,9 @@ function registerAuditCommand(program2) {
|
|
|
17002
17168
|
var import_chalk13 = __toESM(require("chalk"));
|
|
17003
17169
|
|
|
17004
17170
|
// src/cli/aggregate/report-audit.ts
|
|
17005
|
-
var
|
|
17006
|
-
var
|
|
17007
|
-
var
|
|
17171
|
+
var import_fs36 = __toESM(require("fs"));
|
|
17172
|
+
var import_os32 = __toESM(require("os"));
|
|
17173
|
+
var import_path37 = __toESM(require("path"));
|
|
17008
17174
|
init_costSync();
|
|
17009
17175
|
init_litellm();
|
|
17010
17176
|
var TEST_COMMAND_RE3 = /(?:^|\s)(npm\s+(?:run\s+)?test|npx\s+(?:vitest|jest|mocha)|yarn\s+(?:run\s+)?test|pnpm\s+(?:run\s+)?test|vitest|jest|mocha|pytest|py\.test|cargo\s+test|go\s+test|bundle\s+exec\s+rspec|rspec|phpunit|dotnet\s+test)\b/i;
|
|
@@ -17086,8 +17252,8 @@ function getDateRange(period, now) {
|
|
|
17086
17252
|
}
|
|
17087
17253
|
}
|
|
17088
17254
|
function parseAuditLog(logPath) {
|
|
17089
|
-
if (!
|
|
17090
|
-
const raw =
|
|
17255
|
+
if (!import_fs36.default.existsSync(logPath)) return [];
|
|
17256
|
+
const raw = import_fs36.default.readFileSync(logPath, "utf-8");
|
|
17091
17257
|
return raw.split("\n").flatMap((line) => {
|
|
17092
17258
|
if (!line.trim()) return [];
|
|
17093
17259
|
try {
|
|
@@ -17147,25 +17313,25 @@ function freezeClaudeCost(acc) {
|
|
|
17147
17313
|
};
|
|
17148
17314
|
}
|
|
17149
17315
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
17150
|
-
const projPath =
|
|
17316
|
+
const projPath = import_path37.default.join(projectsDir, proj);
|
|
17151
17317
|
let files;
|
|
17152
17318
|
try {
|
|
17153
|
-
const stat =
|
|
17319
|
+
const stat = import_fs36.default.statSync(projPath);
|
|
17154
17320
|
if (!stat.isDirectory()) return;
|
|
17155
|
-
files =
|
|
17321
|
+
files = import_fs36.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
17156
17322
|
} catch {
|
|
17157
17323
|
return;
|
|
17158
17324
|
}
|
|
17159
17325
|
const startMs = start.getTime();
|
|
17160
17326
|
for (const file of files) {
|
|
17161
|
-
const filePath =
|
|
17327
|
+
const filePath = import_path37.default.join(projPath, file);
|
|
17162
17328
|
try {
|
|
17163
|
-
if (
|
|
17329
|
+
if (import_fs36.default.statSync(filePath).mtimeMs < startMs) continue;
|
|
17164
17330
|
} catch {
|
|
17165
17331
|
continue;
|
|
17166
17332
|
}
|
|
17167
17333
|
try {
|
|
17168
|
-
const raw =
|
|
17334
|
+
const raw = import_fs36.default.readFileSync(filePath, "utf-8");
|
|
17169
17335
|
for (const line of raw.split("\n")) {
|
|
17170
17336
|
if (!line.trim()) continue;
|
|
17171
17337
|
let entry;
|
|
@@ -17215,10 +17381,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
17215
17381
|
}
|
|
17216
17382
|
function loadClaudeCost(start, end, projectsDir) {
|
|
17217
17383
|
const acc = emptyClaudeCostAccumulator();
|
|
17218
|
-
if (!
|
|
17384
|
+
if (!import_fs36.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
|
|
17219
17385
|
let dirs;
|
|
17220
17386
|
try {
|
|
17221
|
-
dirs =
|
|
17387
|
+
dirs = import_fs36.default.readdirSync(projectsDir);
|
|
17222
17388
|
} catch {
|
|
17223
17389
|
return freezeClaudeCost(acc);
|
|
17224
17390
|
}
|
|
@@ -17230,7 +17396,7 @@ function loadClaudeCost(start, end, projectsDir) {
|
|
|
17230
17396
|
function processCodexCostFile(filePath, start, end, acc) {
|
|
17231
17397
|
let lines;
|
|
17232
17398
|
try {
|
|
17233
|
-
lines =
|
|
17399
|
+
lines = import_fs36.default.readFileSync(filePath, "utf-8").split("\n");
|
|
17234
17400
|
} catch {
|
|
17235
17401
|
return;
|
|
17236
17402
|
}
|
|
@@ -17275,31 +17441,31 @@ function processCodexCostFile(filePath, start, end, acc) {
|
|
|
17275
17441
|
}
|
|
17276
17442
|
function listCodexSessionFiles(sessionsBase) {
|
|
17277
17443
|
const jsonlFiles = [];
|
|
17278
|
-
if (!
|
|
17444
|
+
if (!import_fs36.default.existsSync(sessionsBase)) return jsonlFiles;
|
|
17279
17445
|
try {
|
|
17280
|
-
for (const year of
|
|
17281
|
-
const yearPath =
|
|
17446
|
+
for (const year of import_fs36.default.readdirSync(sessionsBase)) {
|
|
17447
|
+
const yearPath = import_path37.default.join(sessionsBase, year);
|
|
17282
17448
|
try {
|
|
17283
|
-
if (!
|
|
17449
|
+
if (!import_fs36.default.statSync(yearPath).isDirectory()) continue;
|
|
17284
17450
|
} catch {
|
|
17285
17451
|
continue;
|
|
17286
17452
|
}
|
|
17287
|
-
for (const month of
|
|
17288
|
-
const monthPath =
|
|
17453
|
+
for (const month of import_fs36.default.readdirSync(yearPath)) {
|
|
17454
|
+
const monthPath = import_path37.default.join(yearPath, month);
|
|
17289
17455
|
try {
|
|
17290
|
-
if (!
|
|
17456
|
+
if (!import_fs36.default.statSync(monthPath).isDirectory()) continue;
|
|
17291
17457
|
} catch {
|
|
17292
17458
|
continue;
|
|
17293
17459
|
}
|
|
17294
|
-
for (const day of
|
|
17295
|
-
const dayPath =
|
|
17460
|
+
for (const day of import_fs36.default.readdirSync(monthPath)) {
|
|
17461
|
+
const dayPath = import_path37.default.join(monthPath, day);
|
|
17296
17462
|
try {
|
|
17297
|
-
if (!
|
|
17463
|
+
if (!import_fs36.default.statSync(dayPath).isDirectory()) continue;
|
|
17298
17464
|
} catch {
|
|
17299
17465
|
continue;
|
|
17300
17466
|
}
|
|
17301
|
-
for (const file of
|
|
17302
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
17467
|
+
for (const file of import_fs36.default.readdirSync(dayPath)) {
|
|
17468
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path37.default.join(dayPath, file));
|
|
17303
17469
|
}
|
|
17304
17470
|
}
|
|
17305
17471
|
}
|
|
@@ -17352,13 +17518,13 @@ function freezeGeminiCost(acc) {
|
|
|
17352
17518
|
function processGeminiCostFile(filePath, projectKey, start, end, acc) {
|
|
17353
17519
|
const startMs = start.getTime();
|
|
17354
17520
|
try {
|
|
17355
|
-
if (
|
|
17521
|
+
if (import_fs36.default.statSync(filePath).mtimeMs < startMs) return;
|
|
17356
17522
|
} catch {
|
|
17357
17523
|
return;
|
|
17358
17524
|
}
|
|
17359
17525
|
let raw;
|
|
17360
17526
|
try {
|
|
17361
|
-
raw =
|
|
17527
|
+
raw = import_fs36.default.readFileSync(filePath, "utf-8");
|
|
17362
17528
|
} catch {
|
|
17363
17529
|
return;
|
|
17364
17530
|
}
|
|
@@ -17407,30 +17573,30 @@ function listGeminiSessionFiles(geminiTmpDir) {
|
|
|
17407
17573
|
const out = [];
|
|
17408
17574
|
let dirs;
|
|
17409
17575
|
try {
|
|
17410
|
-
if (!
|
|
17411
|
-
dirs =
|
|
17576
|
+
if (!import_fs36.default.statSync(geminiTmpDir).isDirectory()) return out;
|
|
17577
|
+
dirs = import_fs36.default.readdirSync(geminiTmpDir);
|
|
17412
17578
|
} catch {
|
|
17413
17579
|
return out;
|
|
17414
17580
|
}
|
|
17415
17581
|
for (const proj of dirs) {
|
|
17416
|
-
const chatsDir =
|
|
17582
|
+
const chatsDir = import_path37.default.join(geminiTmpDir, proj, "chats");
|
|
17417
17583
|
let files;
|
|
17418
17584
|
try {
|
|
17419
|
-
if (!
|
|
17420
|
-
files =
|
|
17585
|
+
if (!import_fs36.default.statSync(chatsDir).isDirectory()) continue;
|
|
17586
|
+
files = import_fs36.default.readdirSync(chatsDir);
|
|
17421
17587
|
} catch {
|
|
17422
17588
|
continue;
|
|
17423
17589
|
}
|
|
17424
17590
|
for (const f of files) {
|
|
17425
17591
|
if (!f.endsWith(".jsonl")) continue;
|
|
17426
|
-
out.push({ projectKey: proj, file:
|
|
17592
|
+
out.push({ projectKey: proj, file: import_path37.default.join(chatsDir, f) });
|
|
17427
17593
|
}
|
|
17428
17594
|
}
|
|
17429
17595
|
return out;
|
|
17430
17596
|
}
|
|
17431
17597
|
function loadGeminiCost(start, end, geminiTmpDir) {
|
|
17432
17598
|
const acc = emptyGeminiAccumulator();
|
|
17433
|
-
if (!
|
|
17599
|
+
if (!import_fs36.default.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
|
|
17434
17600
|
for (const { projectKey, file } of listGeminiSessionFiles(geminiTmpDir)) {
|
|
17435
17601
|
processGeminiCostFile(file, projectKey, start, end, acc);
|
|
17436
17602
|
}
|
|
@@ -17438,11 +17604,11 @@ function loadGeminiCost(start, end, geminiTmpDir) {
|
|
|
17438
17604
|
}
|
|
17439
17605
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
17440
17606
|
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 =
|
|
17607
|
+
const auditLogPath = opts.auditLogPath ?? import_path37.default.join(import_os32.default.homedir(), ".node9", "audit.log");
|
|
17608
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? import_path37.default.join(import_os32.default.homedir(), ".claude", "projects");
|
|
17609
|
+
const codexSessionsDir = opts.codexSessionsDir ?? import_path37.default.join(import_os32.default.homedir(), ".codex", "sessions");
|
|
17610
|
+
const geminiTmpDir = opts.geminiTmpDir ?? import_path37.default.join(import_os32.default.homedir(), ".gemini", "tmp");
|
|
17611
|
+
const hasAuditFile = import_fs36.default.existsSync(auditLogPath);
|
|
17446
17612
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
|
|
17447
17613
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
17448
17614
|
const { start, end } = getDateRange(period, now);
|
|
@@ -18138,14 +18304,14 @@ function registerDaemonCommand(program2) {
|
|
|
18138
18304
|
|
|
18139
18305
|
// src/cli/commands/status.ts
|
|
18140
18306
|
var import_chalk15 = __toESM(require("chalk"));
|
|
18141
|
-
var
|
|
18142
|
-
var
|
|
18143
|
-
var
|
|
18307
|
+
var import_fs37 = __toESM(require("fs"));
|
|
18308
|
+
var import_path38 = __toESM(require("path"));
|
|
18309
|
+
var import_os33 = __toESM(require("os"));
|
|
18144
18310
|
init_core();
|
|
18145
18311
|
init_daemon();
|
|
18146
18312
|
function readJson2(filePath) {
|
|
18147
18313
|
try {
|
|
18148
|
-
if (
|
|
18314
|
+
if (import_fs37.default.existsSync(filePath)) return JSON.parse(import_fs37.default.readFileSync(filePath, "utf-8"));
|
|
18149
18315
|
} catch {
|
|
18150
18316
|
}
|
|
18151
18317
|
return null;
|
|
@@ -18210,28 +18376,28 @@ function registerStatusCommand(program2) {
|
|
|
18210
18376
|
console.log("");
|
|
18211
18377
|
const modeLabel = settings.mode === "audit" ? import_chalk15.default.blue("audit") : settings.mode === "strict" ? import_chalk15.default.red("strict") : import_chalk15.default.white("standard");
|
|
18212
18378
|
console.log(` Mode: ${modeLabel}`);
|
|
18213
|
-
const projectConfig =
|
|
18214
|
-
const globalConfig =
|
|
18379
|
+
const projectConfig = import_path38.default.join(process.cwd(), "node9.config.json");
|
|
18380
|
+
const globalConfig = import_path38.default.join(import_os33.default.homedir(), ".node9", "config.json");
|
|
18215
18381
|
console.log(
|
|
18216
|
-
` Local: ${
|
|
18382
|
+
` Local: ${import_fs37.default.existsSync(projectConfig) ? import_chalk15.default.green("Active (node9.config.json)") : import_chalk15.default.gray("Not present")}`
|
|
18217
18383
|
);
|
|
18218
18384
|
console.log(
|
|
18219
|
-
` Global: ${
|
|
18385
|
+
` Global: ${import_fs37.default.existsSync(globalConfig) ? import_chalk15.default.green("Active (~/.node9/config.json)") : import_chalk15.default.gray("Not present")}`
|
|
18220
18386
|
);
|
|
18221
18387
|
if (mergedConfig.policy.sandboxPaths.length > 0) {
|
|
18222
18388
|
console.log(
|
|
18223
18389
|
` Sandbox: ${import_chalk15.default.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
|
|
18224
18390
|
);
|
|
18225
18391
|
}
|
|
18226
|
-
const homeDir2 =
|
|
18392
|
+
const homeDir2 = import_os33.default.homedir();
|
|
18227
18393
|
const claudeSettings = readJson2(
|
|
18228
|
-
|
|
18394
|
+
import_path38.default.join(homeDir2, ".claude", "settings.json")
|
|
18229
18395
|
);
|
|
18230
|
-
const claudeConfig = readJson2(
|
|
18396
|
+
const claudeConfig = readJson2(import_path38.default.join(homeDir2, ".claude.json"));
|
|
18231
18397
|
const geminiSettings = readJson2(
|
|
18232
|
-
|
|
18398
|
+
import_path38.default.join(homeDir2, ".gemini", "settings.json")
|
|
18233
18399
|
);
|
|
18234
|
-
const cursorConfig = readJson2(
|
|
18400
|
+
const cursorConfig = readJson2(import_path38.default.join(homeDir2, ".cursor", "mcp.json"));
|
|
18235
18401
|
const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig;
|
|
18236
18402
|
if (agentFound) {
|
|
18237
18403
|
console.log("");
|
|
@@ -18290,9 +18456,9 @@ function registerStatusCommand(program2) {
|
|
|
18290
18456
|
|
|
18291
18457
|
// src/cli/commands/init.ts
|
|
18292
18458
|
var import_chalk16 = __toESM(require("chalk"));
|
|
18293
|
-
var
|
|
18294
|
-
var
|
|
18295
|
-
var
|
|
18459
|
+
var import_fs38 = __toESM(require("fs"));
|
|
18460
|
+
var import_path39 = __toESM(require("path"));
|
|
18461
|
+
var import_os34 = __toESM(require("os"));
|
|
18296
18462
|
var import_https4 = __toESM(require("https"));
|
|
18297
18463
|
init_core();
|
|
18298
18464
|
init_setup();
|
|
@@ -18372,15 +18538,15 @@ function registerInitCommand(program2) {
|
|
|
18372
18538
|
}
|
|
18373
18539
|
console.log("");
|
|
18374
18540
|
}
|
|
18375
|
-
const configPath =
|
|
18376
|
-
if (
|
|
18541
|
+
const configPath = import_path39.default.join(import_os34.default.homedir(), ".node9", "config.json");
|
|
18542
|
+
if (import_fs38.default.existsSync(configPath) && !options.force) {
|
|
18377
18543
|
try {
|
|
18378
|
-
const existing = JSON.parse(
|
|
18544
|
+
const existing = JSON.parse(import_fs38.default.readFileSync(configPath, "utf-8"));
|
|
18379
18545
|
const settings = existing.settings ?? {};
|
|
18380
18546
|
if (settings.mode !== chosenMode) {
|
|
18381
18547
|
settings.mode = chosenMode;
|
|
18382
18548
|
existing.settings = settings;
|
|
18383
|
-
|
|
18549
|
+
import_fs38.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
|
|
18384
18550
|
console.log(import_chalk16.default.green(`\u2705 Mode updated: ${chosenMode}`));
|
|
18385
18551
|
} else {
|
|
18386
18552
|
console.log(import_chalk16.default.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
|
|
@@ -18393,9 +18559,9 @@ function registerInitCommand(program2) {
|
|
|
18393
18559
|
...DEFAULT_CONFIG,
|
|
18394
18560
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
18395
18561
|
};
|
|
18396
|
-
const dir =
|
|
18397
|
-
if (!
|
|
18398
|
-
|
|
18562
|
+
const dir = import_path39.default.dirname(configPath);
|
|
18563
|
+
if (!import_fs38.default.existsSync(dir)) import_fs38.default.mkdirSync(dir, { recursive: true });
|
|
18564
|
+
import_fs38.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
|
|
18399
18565
|
console.log(import_chalk16.default.green(`\u2705 Config created: ${configPath}`));
|
|
18400
18566
|
console.log(import_chalk16.default.gray(` Mode: ${chosenMode}`));
|
|
18401
18567
|
}
|
|
@@ -18493,7 +18659,7 @@ function registerInitCommand(program2) {
|
|
|
18493
18659
|
}
|
|
18494
18660
|
|
|
18495
18661
|
// src/cli/commands/undo.ts
|
|
18496
|
-
var
|
|
18662
|
+
var import_path40 = __toESM(require("path"));
|
|
18497
18663
|
var import_chalk18 = __toESM(require("chalk"));
|
|
18498
18664
|
|
|
18499
18665
|
// src/tui/undo-navigator.ts
|
|
@@ -18652,7 +18818,7 @@ function findMatchingCwd(startDir, history) {
|
|
|
18652
18818
|
let dir = startDir;
|
|
18653
18819
|
while (true) {
|
|
18654
18820
|
if (cwds.has(dir)) return dir;
|
|
18655
|
-
const parent =
|
|
18821
|
+
const parent = import_path40.default.dirname(dir);
|
|
18656
18822
|
if (parent === dir) return null;
|
|
18657
18823
|
dir = parent;
|
|
18658
18824
|
}
|
|
@@ -18785,90 +18951,7 @@ var import_child_process10 = require("child_process");
|
|
|
18785
18951
|
var import_execa3 = require("execa");
|
|
18786
18952
|
init_orchestrator();
|
|
18787
18953
|
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
|
|
18954
|
+
init_mcp_pin();
|
|
18872
18955
|
init_mcp_tools();
|
|
18873
18956
|
init_daemon();
|
|
18874
18957
|
function sanitize4(value) {
|
|
@@ -18930,6 +19013,7 @@ function tokenize4(cmd) {
|
|
|
18930
19013
|
return tokens;
|
|
18931
19014
|
}
|
|
18932
19015
|
async function runMcpGateway(upstreamCommand) {
|
|
19016
|
+
const gatewayCwd = process.cwd();
|
|
18933
19017
|
const commandParts = tokenize4(upstreamCommand);
|
|
18934
19018
|
const cmd = commandParts[0];
|
|
18935
19019
|
const cmdArgs = commandParts.slice(1);
|
|
@@ -19152,7 +19236,7 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
19152
19236
|
if (parsed.result && Array.isArray(parsed.result.tools)) {
|
|
19153
19237
|
const tools = parsed.result.tools || [];
|
|
19154
19238
|
const currentHash = hashToolDefinitions(tools);
|
|
19155
|
-
const pinStatus = checkPin(serverKey, currentHash);
|
|
19239
|
+
const pinStatus = checkPin(serverKey, currentHash, gatewayCwd);
|
|
19156
19240
|
const token = getInternalToken();
|
|
19157
19241
|
if (isDaemonRunning() && process.env.NODE9_TESTING !== "1") {
|
|
19158
19242
|
const toolSummary = tools.map((t) => ({ name: t.name, description: t.description }));
|
|
@@ -20037,26 +20121,45 @@ function registerTrustCommand(program2) {
|
|
|
20037
20121
|
|
|
20038
20122
|
// src/cli/commands/mcp-pin.ts
|
|
20039
20123
|
var import_chalk21 = __toESM(require("chalk"));
|
|
20124
|
+
init_mcp_pin();
|
|
20125
|
+
var import_fs40 = __toESM(require("fs"));
|
|
20040
20126
|
function registerMcpPinCommand(program2) {
|
|
20041
20127
|
const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
|
|
20042
20128
|
const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
|
|
20043
20129
|
pinSubCmd.command("list").description("Show all pinned MCP servers and their tool definition hashes").action(() => {
|
|
20044
|
-
const
|
|
20045
|
-
|
|
20046
|
-
|
|
20047
|
-
|
|
20048
|
-
|
|
20049
|
-
|
|
20050
|
-
);
|
|
20051
|
-
|
|
20130
|
+
const found = findPinsFilePath(process.cwd());
|
|
20131
|
+
const homeResult = readMcpPinsSafe();
|
|
20132
|
+
let repoEntries = {};
|
|
20133
|
+
let repoCorrupt = false;
|
|
20134
|
+
if (found.source === "repo") {
|
|
20135
|
+
try {
|
|
20136
|
+
const raw = import_fs40.default.readFileSync(found.path, "utf-8");
|
|
20137
|
+
const parsed = JSON.parse(raw);
|
|
20138
|
+
repoEntries = parsed.servers ?? {};
|
|
20139
|
+
} catch {
|
|
20140
|
+
repoCorrupt = true;
|
|
20052
20141
|
}
|
|
20142
|
+
}
|
|
20143
|
+
if (repoCorrupt) {
|
|
20053
20144
|
console.error(import_chalk21.default.red(`
|
|
20054
|
-
\u274C
|
|
20145
|
+
\u274C Repo pin file at ${found.path} is corrupt or unreadable.`));
|
|
20146
|
+
process.exit(1);
|
|
20147
|
+
}
|
|
20148
|
+
if (!homeResult.ok && homeResult.reason === "corrupt") {
|
|
20149
|
+
console.error(import_chalk21.default.red(`
|
|
20150
|
+
\u274C Home pin file is corrupt: ${homeResult.detail}`));
|
|
20055
20151
|
console.error(import_chalk21.default.yellow(" Run: node9 mcp pin reset\n"));
|
|
20056
20152
|
process.exit(1);
|
|
20057
20153
|
}
|
|
20058
|
-
const
|
|
20059
|
-
|
|
20154
|
+
const homeEntries = homeResult.ok ? homeResult.pins.servers : {};
|
|
20155
|
+
const merged = /* @__PURE__ */ new Map();
|
|
20156
|
+
for (const [key, entry] of Object.entries(homeEntries)) {
|
|
20157
|
+
merged.set(key, { entry, source: "home" });
|
|
20158
|
+
}
|
|
20159
|
+
for (const [key, entry] of Object.entries(repoEntries)) {
|
|
20160
|
+
merged.set(key, { entry, source: "repo" });
|
|
20161
|
+
}
|
|
20162
|
+
if (merged.size === 0) {
|
|
20060
20163
|
console.log(import_chalk21.default.gray("\nNo MCP servers are pinned yet."));
|
|
20061
20164
|
console.log(
|
|
20062
20165
|
import_chalk21.default.gray("Pins are created automatically when the MCP gateway first connects.\n")
|
|
@@ -20064,13 +20167,47 @@ function registerMcpPinCommand(program2) {
|
|
|
20064
20167
|
return;
|
|
20065
20168
|
}
|
|
20066
20169
|
console.log(import_chalk21.default.bold("\n\u{1F512} Pinned MCP Servers\n"));
|
|
20067
|
-
|
|
20068
|
-
|
|
20170
|
+
const showSource = found.source === "repo";
|
|
20171
|
+
for (const [key, { entry, source }] of merged) {
|
|
20172
|
+
const tag = showSource ? ` ${import_chalk21.default.yellow(`[${source}]`)}` : "";
|
|
20173
|
+
console.log(` ${import_chalk21.default.cyan(key)}${tag} ${import_chalk21.default.gray(entry.label)}`);
|
|
20069
20174
|
console.log(` Tools (${entry.toolCount}): ${import_chalk21.default.white(entry.toolNames.join(", "))}`);
|
|
20070
20175
|
console.log(` Hash: ${import_chalk21.default.gray(entry.toolsHash.slice(0, 16))}...`);
|
|
20071
20176
|
console.log(` Pinned: ${import_chalk21.default.gray(entry.pinnedAt)}`);
|
|
20072
20177
|
console.log("");
|
|
20073
20178
|
}
|
|
20179
|
+
if (showSource) {
|
|
20180
|
+
console.log(import_chalk21.default.gray(` [repo] entries come from ${found.path}`));
|
|
20181
|
+
console.log(import_chalk21.default.gray(" [home] entries come from ~/.node9/mcp-pins.json\n"));
|
|
20182
|
+
}
|
|
20183
|
+
});
|
|
20184
|
+
pinSubCmd.command("promote <serverKey>").description(
|
|
20185
|
+
"Copy a pin from ~/.node9/mcp-pins.json into <repo>/.node9/mcp-pins.json so teammates share the same vetted baseline"
|
|
20186
|
+
).action((serverKey) => {
|
|
20187
|
+
try {
|
|
20188
|
+
const { repoPath, created } = promotePin(serverKey, process.cwd());
|
|
20189
|
+
if (created) {
|
|
20190
|
+
console.log(
|
|
20191
|
+
import_chalk21.default.green(
|
|
20192
|
+
`
|
|
20193
|
+
\u2705 Created ${repoPath} with the promoted pin for ${import_chalk21.default.cyan(serverKey)}.`
|
|
20194
|
+
)
|
|
20195
|
+
);
|
|
20196
|
+
} else {
|
|
20197
|
+
console.log(import_chalk21.default.green(`
|
|
20198
|
+
\u2705 Promoted ${import_chalk21.default.cyan(serverKey)} into ${repoPath}.`));
|
|
20199
|
+
}
|
|
20200
|
+
console.log(import_chalk21.default.gray(" Review the change and commit it:"));
|
|
20201
|
+
console.log(import_chalk21.default.cyan(` git add ${repoPath}`));
|
|
20202
|
+
console.log(import_chalk21.default.cyan(` git commit -m "pin ${serverKey} (node9)"`));
|
|
20203
|
+
console.log("");
|
|
20204
|
+
} catch (err2) {
|
|
20205
|
+
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
20206
|
+
console.error(import_chalk21.default.red(`
|
|
20207
|
+
\u274C ${msg}
|
|
20208
|
+
`));
|
|
20209
|
+
process.exit(1);
|
|
20210
|
+
}
|
|
20074
20211
|
});
|
|
20075
20212
|
pinSubCmd.command("update <serverKey>").description(
|
|
20076
20213
|
"Remove a pin so the next gateway connection re-pins with current tool definitions"
|
|
@@ -20092,7 +20229,7 @@ function registerMcpPinCommand(program2) {
|
|
|
20092
20229
|
process.exit(1);
|
|
20093
20230
|
}
|
|
20094
20231
|
const label = pins.servers[serverKey].label;
|
|
20095
|
-
|
|
20232
|
+
removePin(serverKey);
|
|
20096
20233
|
console.log(import_chalk21.default.green(`
|
|
20097
20234
|
\u{1F513} Pin removed for ${import_chalk21.default.cyan(serverKey)}`));
|
|
20098
20235
|
console.log(import_chalk21.default.gray(` Server: ${label}`));
|
|
@@ -20105,7 +20242,7 @@ function registerMcpPinCommand(program2) {
|
|
|
20105
20242
|
return;
|
|
20106
20243
|
}
|
|
20107
20244
|
const count = result.ok ? Object.keys(result.pins.servers).length : "?";
|
|
20108
|
-
|
|
20245
|
+
clearAllPins();
|
|
20109
20246
|
console.log(import_chalk21.default.green(`
|
|
20110
20247
|
\u{1F513} Cleared ${count} MCP pin(s).`));
|
|
20111
20248
|
console.log(import_chalk21.default.gray(" Next connection to each server will re-pin.\n"));
|
|
@@ -20288,7 +20425,7 @@ init_scan();
|
|
|
20288
20425
|
|
|
20289
20426
|
// src/cli/commands/sessions.ts
|
|
20290
20427
|
var import_chalk24 = __toESM(require("chalk"));
|
|
20291
|
-
var
|
|
20428
|
+
var import_fs41 = __toESM(require("fs"));
|
|
20292
20429
|
var import_path42 = __toESM(require("path"));
|
|
20293
20430
|
var import_os36 = __toESM(require("os"));
|
|
20294
20431
|
var CLAUDE_PRICING3 = {
|
|
@@ -20406,7 +20543,7 @@ function loadAuditEntries(auditPath) {
|
|
|
20406
20543
|
const aPath = auditPath ?? import_path42.default.join(import_os36.default.homedir(), ".node9", "audit.log");
|
|
20407
20544
|
let raw;
|
|
20408
20545
|
try {
|
|
20409
|
-
raw =
|
|
20546
|
+
raw = import_fs41.default.readFileSync(aPath, "utf-8");
|
|
20410
20547
|
} catch {
|
|
20411
20548
|
return [];
|
|
20412
20549
|
}
|
|
@@ -20443,7 +20580,7 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
20443
20580
|
}
|
|
20444
20581
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
20445
20582
|
const tmpDir = import_path42.default.join(import_os36.default.homedir(), ".gemini", "tmp");
|
|
20446
|
-
if (!
|
|
20583
|
+
if (!import_fs41.default.existsSync(tmpDir)) return [];
|
|
20447
20584
|
const cutoff = days !== null ? (() => {
|
|
20448
20585
|
const d = /* @__PURE__ */ new Date();
|
|
20449
20586
|
d.setDate(d.getDate() - days);
|
|
@@ -20452,7 +20589,7 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
20452
20589
|
})() : null;
|
|
20453
20590
|
let slugDirs;
|
|
20454
20591
|
try {
|
|
20455
|
-
slugDirs =
|
|
20592
|
+
slugDirs = import_fs41.default.readdirSync(tmpDir);
|
|
20456
20593
|
} catch {
|
|
20457
20594
|
return [];
|
|
20458
20595
|
}
|
|
@@ -20460,27 +20597,27 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
20460
20597
|
for (const slug of slugDirs) {
|
|
20461
20598
|
const slugPath = import_path42.default.join(tmpDir, slug);
|
|
20462
20599
|
try {
|
|
20463
|
-
if (!
|
|
20600
|
+
if (!import_fs41.default.statSync(slugPath).isDirectory()) continue;
|
|
20464
20601
|
} catch {
|
|
20465
20602
|
continue;
|
|
20466
20603
|
}
|
|
20467
20604
|
let projectRoot = import_path42.default.join(import_os36.default.homedir(), slug);
|
|
20468
20605
|
try {
|
|
20469
|
-
projectRoot =
|
|
20606
|
+
projectRoot = import_fs41.default.readFileSync(import_path42.default.join(slugPath, ".project_root"), "utf-8").trim();
|
|
20470
20607
|
} catch {
|
|
20471
20608
|
}
|
|
20472
20609
|
const chatsDir = import_path42.default.join(slugPath, "chats");
|
|
20473
|
-
if (!
|
|
20610
|
+
if (!import_fs41.default.existsSync(chatsDir)) continue;
|
|
20474
20611
|
let chatFiles;
|
|
20475
20612
|
try {
|
|
20476
|
-
chatFiles =
|
|
20613
|
+
chatFiles = import_fs41.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
20477
20614
|
} catch {
|
|
20478
20615
|
continue;
|
|
20479
20616
|
}
|
|
20480
20617
|
for (const chatFile of chatFiles) {
|
|
20481
20618
|
let raw;
|
|
20482
20619
|
try {
|
|
20483
|
-
raw =
|
|
20620
|
+
raw = import_fs41.default.readFileSync(import_path42.default.join(chatsDir, chatFile), "utf-8");
|
|
20484
20621
|
} catch {
|
|
20485
20622
|
continue;
|
|
20486
20623
|
}
|
|
@@ -20561,7 +20698,7 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
20561
20698
|
}
|
|
20562
20699
|
function buildCodexSessions(days, allAuditEntries) {
|
|
20563
20700
|
const sessionsBase = import_path42.default.join(import_os36.default.homedir(), ".codex", "sessions");
|
|
20564
|
-
if (!
|
|
20701
|
+
if (!import_fs41.default.existsSync(sessionsBase)) return [];
|
|
20565
20702
|
const cutoff = days !== null ? (() => {
|
|
20566
20703
|
const d = /* @__PURE__ */ new Date();
|
|
20567
20704
|
d.setDate(d.getDate() - days);
|
|
@@ -20570,28 +20707,28 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
20570
20707
|
})() : null;
|
|
20571
20708
|
const jsonlFiles = [];
|
|
20572
20709
|
try {
|
|
20573
|
-
for (const year of
|
|
20710
|
+
for (const year of import_fs41.default.readdirSync(sessionsBase)) {
|
|
20574
20711
|
const yearPath = import_path42.default.join(sessionsBase, year);
|
|
20575
20712
|
try {
|
|
20576
|
-
if (!
|
|
20713
|
+
if (!import_fs41.default.statSync(yearPath).isDirectory()) continue;
|
|
20577
20714
|
} catch {
|
|
20578
20715
|
continue;
|
|
20579
20716
|
}
|
|
20580
|
-
for (const month of
|
|
20717
|
+
for (const month of import_fs41.default.readdirSync(yearPath)) {
|
|
20581
20718
|
const monthPath = import_path42.default.join(yearPath, month);
|
|
20582
20719
|
try {
|
|
20583
|
-
if (!
|
|
20720
|
+
if (!import_fs41.default.statSync(monthPath).isDirectory()) continue;
|
|
20584
20721
|
} catch {
|
|
20585
20722
|
continue;
|
|
20586
20723
|
}
|
|
20587
|
-
for (const day of
|
|
20724
|
+
for (const day of import_fs41.default.readdirSync(monthPath)) {
|
|
20588
20725
|
const dayPath = import_path42.default.join(monthPath, day);
|
|
20589
20726
|
try {
|
|
20590
|
-
if (!
|
|
20727
|
+
if (!import_fs41.default.statSync(dayPath).isDirectory()) continue;
|
|
20591
20728
|
} catch {
|
|
20592
20729
|
continue;
|
|
20593
20730
|
}
|
|
20594
|
-
for (const file of
|
|
20731
|
+
for (const file of import_fs41.default.readdirSync(dayPath)) {
|
|
20595
20732
|
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path42.default.join(dayPath, file));
|
|
20596
20733
|
}
|
|
20597
20734
|
}
|
|
@@ -20604,7 +20741,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
20604
20741
|
for (const filePath of jsonlFiles) {
|
|
20605
20742
|
let lines;
|
|
20606
20743
|
try {
|
|
20607
|
-
lines =
|
|
20744
|
+
lines = import_fs41.default.readFileSync(filePath, "utf-8").split("\n");
|
|
20608
20745
|
} catch {
|
|
20609
20746
|
continue;
|
|
20610
20747
|
}
|
|
@@ -20685,7 +20822,7 @@ function buildSessions(days, historyPath) {
|
|
|
20685
20822
|
const hPath = historyPath ?? import_path42.default.join(import_os36.default.homedir(), ".claude", "history.jsonl");
|
|
20686
20823
|
let historyRaw;
|
|
20687
20824
|
try {
|
|
20688
|
-
historyRaw =
|
|
20825
|
+
historyRaw = import_fs41.default.readFileSync(hPath, "utf-8");
|
|
20689
20826
|
} catch {
|
|
20690
20827
|
return [];
|
|
20691
20828
|
}
|
|
@@ -20710,7 +20847,7 @@ function buildSessions(days, historyPath) {
|
|
|
20710
20847
|
const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
|
|
20711
20848
|
let sessionLines = [];
|
|
20712
20849
|
try {
|
|
20713
|
-
sessionLines =
|
|
20850
|
+
sessionLines = import_fs41.default.readFileSync(jsonlFile, "utf-8").split("\n");
|
|
20714
20851
|
} catch {
|
|
20715
20852
|
}
|
|
20716
20853
|
const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
|
|
@@ -20977,7 +21114,7 @@ function registerSessionsCommand(program2) {
|
|
|
20977
21114
|
console.log(import_chalk24.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk24.default.dim(" \u2014 what your AI agent did"));
|
|
20978
21115
|
console.log("");
|
|
20979
21116
|
const historyPath = import_path42.default.join(import_os36.default.homedir(), ".claude", "history.jsonl");
|
|
20980
|
-
if (!
|
|
21117
|
+
if (!import_fs41.default.existsSync(historyPath)) {
|
|
20981
21118
|
console.log(import_chalk24.default.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
|
|
20982
21119
|
console.log(import_chalk24.default.gray(" Install Claude Code, run a few sessions, then try again.\n"));
|
|
20983
21120
|
return;
|
|
@@ -21014,12 +21151,12 @@ function registerSessionsCommand(program2) {
|
|
|
21014
21151
|
|
|
21015
21152
|
// src/cli/commands/skill-pin.ts
|
|
21016
21153
|
var import_chalk25 = __toESM(require("chalk"));
|
|
21017
|
-
var
|
|
21154
|
+
var import_fs42 = __toESM(require("fs"));
|
|
21018
21155
|
var import_os37 = __toESM(require("os"));
|
|
21019
21156
|
var import_path43 = __toESM(require("path"));
|
|
21020
21157
|
function wipeSkillSessions() {
|
|
21021
21158
|
try {
|
|
21022
|
-
|
|
21159
|
+
import_fs42.default.rmSync(import_path43.default.join(import_os37.default.homedir(), ".node9", "skill-sessions"), {
|
|
21023
21160
|
recursive: true,
|
|
21024
21161
|
force: true
|
|
21025
21162
|
});
|
|
@@ -21077,7 +21214,7 @@ function registerSkillPinCommand(program2) {
|
|
|
21077
21214
|
process.exit(1);
|
|
21078
21215
|
}
|
|
21079
21216
|
const rootPath = pins.roots[rootKey].rootPath;
|
|
21080
|
-
|
|
21217
|
+
removePin2(rootKey);
|
|
21081
21218
|
wipeSkillSessions();
|
|
21082
21219
|
console.log(import_chalk25.default.green(`
|
|
21083
21220
|
\u{1F513} Pin removed for ${import_chalk25.default.cyan(rootKey)}`));
|
|
@@ -21092,7 +21229,7 @@ function registerSkillPinCommand(program2) {
|
|
|
21092
21229
|
return;
|
|
21093
21230
|
}
|
|
21094
21231
|
const count = result.ok ? Object.keys(result.pins.roots).length : "?";
|
|
21095
|
-
|
|
21232
|
+
clearAllPins2();
|
|
21096
21233
|
wipeSkillSessions();
|
|
21097
21234
|
console.log(import_chalk25.default.green(`
|
|
21098
21235
|
\u{1F513} Cleared ${count} skill pin(s).`));
|
|
@@ -21101,15 +21238,15 @@ function registerSkillPinCommand(program2) {
|
|
|
21101
21238
|
}
|
|
21102
21239
|
|
|
21103
21240
|
// src/cli/commands/decisions.ts
|
|
21104
|
-
var
|
|
21241
|
+
var import_fs43 = __toESM(require("fs"));
|
|
21105
21242
|
var import_os38 = __toESM(require("os"));
|
|
21106
21243
|
var import_path44 = __toESM(require("path"));
|
|
21107
21244
|
var import_chalk26 = __toESM(require("chalk"));
|
|
21108
21245
|
var DECISIONS_FILE2 = import_path44.default.join(import_os38.default.homedir(), ".node9", "decisions.json");
|
|
21109
21246
|
function readDecisions() {
|
|
21110
21247
|
try {
|
|
21111
|
-
if (!
|
|
21112
|
-
const raw =
|
|
21248
|
+
if (!import_fs43.default.existsSync(DECISIONS_FILE2)) return {};
|
|
21249
|
+
const raw = import_fs43.default.readFileSync(DECISIONS_FILE2, "utf-8");
|
|
21113
21250
|
const parsed = JSON.parse(raw);
|
|
21114
21251
|
const out = {};
|
|
21115
21252
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -21122,10 +21259,10 @@ function readDecisions() {
|
|
|
21122
21259
|
}
|
|
21123
21260
|
function writeDecisions(d) {
|
|
21124
21261
|
const dir = import_path44.default.dirname(DECISIONS_FILE2);
|
|
21125
|
-
if (!
|
|
21262
|
+
if (!import_fs43.default.existsSync(dir)) import_fs43.default.mkdirSync(dir, { recursive: true });
|
|
21126
21263
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
21127
|
-
|
|
21128
|
-
|
|
21264
|
+
import_fs43.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
21265
|
+
import_fs43.default.renameSync(tmp, DECISIONS_FILE2);
|
|
21129
21266
|
}
|
|
21130
21267
|
function registerDecisionsCommand(program2) {
|
|
21131
21268
|
const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
|
|
@@ -21182,7 +21319,7 @@ Persistent decisions (${entries.length})
|
|
|
21182
21319
|
|
|
21183
21320
|
// src/cli/commands/dlp.ts
|
|
21184
21321
|
var import_chalk27 = __toESM(require("chalk"));
|
|
21185
|
-
var
|
|
21322
|
+
var import_fs44 = __toESM(require("fs"));
|
|
21186
21323
|
var import_path45 = __toESM(require("path"));
|
|
21187
21324
|
var import_os39 = __toESM(require("os"));
|
|
21188
21325
|
var AUDIT_LOG = import_path45.default.join(import_os39.default.homedir(), ".node9", "audit.log");
|
|
@@ -21193,7 +21330,7 @@ function stripAnsi(s) {
|
|
|
21193
21330
|
}
|
|
21194
21331
|
function loadResolved() {
|
|
21195
21332
|
try {
|
|
21196
|
-
const raw = JSON.parse(
|
|
21333
|
+
const raw = JSON.parse(import_fs44.default.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
21197
21334
|
return new Set(raw);
|
|
21198
21335
|
} catch {
|
|
21199
21336
|
return /* @__PURE__ */ new Set();
|
|
@@ -21201,13 +21338,13 @@ function loadResolved() {
|
|
|
21201
21338
|
}
|
|
21202
21339
|
function saveResolved(resolved) {
|
|
21203
21340
|
try {
|
|
21204
|
-
|
|
21341
|
+
import_fs44.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
21205
21342
|
} catch {
|
|
21206
21343
|
}
|
|
21207
21344
|
}
|
|
21208
21345
|
function loadDlpFindings() {
|
|
21209
|
-
if (!
|
|
21210
|
-
return
|
|
21346
|
+
if (!import_fs44.default.existsSync(AUDIT_LOG)) return [];
|
|
21347
|
+
return import_fs44.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
21211
21348
|
if (!line.trim()) return [];
|
|
21212
21349
|
try {
|
|
21213
21350
|
const e = JSON.parse(line);
|
|
@@ -21305,14 +21442,14 @@ function registerDlpCommand(program2) {
|
|
|
21305
21442
|
|
|
21306
21443
|
// src/cli/commands/mask.ts
|
|
21307
21444
|
var import_chalk28 = __toESM(require("chalk"));
|
|
21308
|
-
var
|
|
21445
|
+
var import_fs45 = __toESM(require("fs"));
|
|
21309
21446
|
var import_path46 = __toESM(require("path"));
|
|
21310
21447
|
var import_os40 = __toESM(require("os"));
|
|
21311
21448
|
init_dlp();
|
|
21312
21449
|
function findJsonlFiles(dir) {
|
|
21313
21450
|
const results = [];
|
|
21314
|
-
if (!
|
|
21315
|
-
for (const entry of
|
|
21451
|
+
if (!import_fs45.default.existsSync(dir)) return results;
|
|
21452
|
+
for (const entry of import_fs45.default.readdirSync(dir, { withFileTypes: true })) {
|
|
21316
21453
|
const full = import_path46.default.join(dir, entry.name);
|
|
21317
21454
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
21318
21455
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
@@ -21356,7 +21493,7 @@ function redactJson(obj) {
|
|
|
21356
21493
|
function processFile(filePath, dryRun) {
|
|
21357
21494
|
let raw;
|
|
21358
21495
|
try {
|
|
21359
|
-
raw =
|
|
21496
|
+
raw = import_fs45.default.readFileSync(filePath, "utf-8");
|
|
21360
21497
|
} catch {
|
|
21361
21498
|
return { redactedLines: 0, patterns: [] };
|
|
21362
21499
|
}
|
|
@@ -21388,14 +21525,14 @@ function processFile(filePath, dryRun) {
|
|
|
21388
21525
|
}
|
|
21389
21526
|
}
|
|
21390
21527
|
if (!dryRun && redactedLines > 0) {
|
|
21391
|
-
|
|
21528
|
+
import_fs45.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
21392
21529
|
}
|
|
21393
21530
|
return { redactedLines, patterns };
|
|
21394
21531
|
}
|
|
21395
21532
|
function processJsonFile(filePath, dryRun) {
|
|
21396
21533
|
let raw;
|
|
21397
21534
|
try {
|
|
21398
|
-
raw =
|
|
21535
|
+
raw = import_fs45.default.readFileSync(filePath, "utf-8");
|
|
21399
21536
|
} catch {
|
|
21400
21537
|
return { redactedLines: 0, patterns: [] };
|
|
21401
21538
|
}
|
|
@@ -21408,14 +21545,14 @@ function processJsonFile(filePath, dryRun) {
|
|
|
21408
21545
|
const { value, modified, found } = redactJson(parsed);
|
|
21409
21546
|
if (!modified) return { redactedLines: 0, patterns: [] };
|
|
21410
21547
|
if (!dryRun) {
|
|
21411
|
-
|
|
21548
|
+
import_fs45.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
|
|
21412
21549
|
}
|
|
21413
21550
|
return { redactedLines: 1, patterns: found };
|
|
21414
21551
|
}
|
|
21415
21552
|
function findJsonFiles(dir) {
|
|
21416
21553
|
const results = [];
|
|
21417
|
-
if (!
|
|
21418
|
-
for (const entry of
|
|
21554
|
+
if (!import_fs45.default.existsSync(dir)) return results;
|
|
21555
|
+
for (const entry of import_fs45.default.readdirSync(dir, { withFileTypes: true })) {
|
|
21419
21556
|
const full = import_path46.default.join(dir, entry.name);
|
|
21420
21557
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
21421
21558
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
@@ -21435,7 +21572,7 @@ function registerMaskCommand(program2) {
|
|
|
21435
21572
|
const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
21436
21573
|
const filtered = cutoff ? allFiles.filter((f) => {
|
|
21437
21574
|
try {
|
|
21438
|
-
return
|
|
21575
|
+
return import_fs45.default.statSync(f.path).mtime >= cutoff;
|
|
21439
21576
|
} catch {
|
|
21440
21577
|
return false;
|
|
21441
21578
|
}
|
|
@@ -21491,20 +21628,20 @@ function registerMaskCommand(program2) {
|
|
|
21491
21628
|
// src/cli.ts
|
|
21492
21629
|
init_blast();
|
|
21493
21630
|
var { version } = JSON.parse(
|
|
21494
|
-
|
|
21631
|
+
import_fs48.default.readFileSync(import_path49.default.join(__dirname, "../package.json"), "utf-8")
|
|
21495
21632
|
);
|
|
21496
21633
|
var program = new import_commander.Command();
|
|
21497
21634
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
21498
21635
|
program.command("login").argument("<apiKey>").option("--local", "Save key for audit/logging only \u2014 local config still controls all decisions").option("--profile <name>", 'Save as a named profile (default: "default")').action((apiKey, options) => {
|
|
21499
21636
|
const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
|
|
21500
21637
|
const credPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "credentials.json");
|
|
21501
|
-
if (!
|
|
21502
|
-
|
|
21638
|
+
if (!import_fs48.default.existsSync(import_path49.default.dirname(credPath)))
|
|
21639
|
+
import_fs48.default.mkdirSync(import_path49.default.dirname(credPath), { recursive: true });
|
|
21503
21640
|
const profileName = options.profile || "default";
|
|
21504
21641
|
let existingCreds = {};
|
|
21505
21642
|
try {
|
|
21506
|
-
if (
|
|
21507
|
-
const raw = JSON.parse(
|
|
21643
|
+
if (import_fs48.default.existsSync(credPath)) {
|
|
21644
|
+
const raw = JSON.parse(import_fs48.default.readFileSync(credPath, "utf-8"));
|
|
21508
21645
|
if (raw.apiKey) {
|
|
21509
21646
|
existingCreds = {
|
|
21510
21647
|
default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
|
|
@@ -21516,13 +21653,13 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
21516
21653
|
} catch {
|
|
21517
21654
|
}
|
|
21518
21655
|
existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
|
|
21519
|
-
|
|
21656
|
+
import_fs48.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
|
|
21520
21657
|
if (profileName === "default") {
|
|
21521
21658
|
const configPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "config.json");
|
|
21522
21659
|
let config = {};
|
|
21523
21660
|
try {
|
|
21524
|
-
if (
|
|
21525
|
-
config = JSON.parse(
|
|
21661
|
+
if (import_fs48.default.existsSync(configPath))
|
|
21662
|
+
config = JSON.parse(import_fs48.default.readFileSync(configPath, "utf-8"));
|
|
21526
21663
|
} catch {
|
|
21527
21664
|
}
|
|
21528
21665
|
if (!config.settings || typeof config.settings !== "object") config.settings = {};
|
|
@@ -21537,9 +21674,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
21537
21674
|
approvers.cloud = false;
|
|
21538
21675
|
}
|
|
21539
21676
|
s.approvers = approvers;
|
|
21540
|
-
if (!
|
|
21541
|
-
|
|
21542
|
-
|
|
21677
|
+
if (!import_fs48.default.existsSync(import_path49.default.dirname(configPath)))
|
|
21678
|
+
import_fs48.default.mkdirSync(import_path49.default.dirname(configPath), { recursive: true });
|
|
21679
|
+
import_fs48.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
21543
21680
|
}
|
|
21544
21681
|
if (options.profile && profileName !== "default") {
|
|
21545
21682
|
console.log(import_chalk30.default.green(`\u2705 Profile "${profileName}" saved`));
|
|
@@ -21677,14 +21814,14 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
21677
21814
|
}
|
|
21678
21815
|
if (options.purge) {
|
|
21679
21816
|
const node9Dir = import_path49.default.join(import_os43.default.homedir(), ".node9");
|
|
21680
|
-
if (
|
|
21817
|
+
if (import_fs48.default.existsSync(node9Dir)) {
|
|
21681
21818
|
const confirmed = await (0, import_prompts2.confirm)({
|
|
21682
21819
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
21683
21820
|
default: false
|
|
21684
21821
|
});
|
|
21685
21822
|
if (confirmed) {
|
|
21686
|
-
|
|
21687
|
-
if (
|
|
21823
|
+
import_fs48.default.rmSync(node9Dir, { recursive: true });
|
|
21824
|
+
if (import_fs48.default.existsSync(node9Dir)) {
|
|
21688
21825
|
console.error(
|
|
21689
21826
|
import_chalk30.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
21690
21827
|
);
|
|
@@ -21839,12 +21976,12 @@ Run "node9 addto claude" to register it as the statusLine.`
|
|
|
21839
21976
|
if (subcommand === "debug") {
|
|
21840
21977
|
const flagFile = import_path49.default.join(import_os43.default.homedir(), ".node9", "hud-debug");
|
|
21841
21978
|
if (state === "on") {
|
|
21842
|
-
|
|
21843
|
-
|
|
21979
|
+
import_fs48.default.mkdirSync(import_path49.default.dirname(flagFile), { recursive: true });
|
|
21980
|
+
import_fs48.default.writeFileSync(flagFile, "");
|
|
21844
21981
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
21845
21982
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
21846
21983
|
} else if (state === "off") {
|
|
21847
|
-
if (
|
|
21984
|
+
if (import_fs48.default.existsSync(flagFile)) import_fs48.default.unlinkSync(flagFile);
|
|
21848
21985
|
console.log("HUD debug logging disabled.");
|
|
21849
21986
|
} else {
|
|
21850
21987
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -21960,7 +22097,7 @@ if (process.argv[2] !== "daemon") {
|
|
|
21960
22097
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
21961
22098
|
const logPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log");
|
|
21962
22099
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
21963
|
-
|
|
22100
|
+
import_fs48.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
21964
22101
|
`);
|
|
21965
22102
|
}
|
|
21966
22103
|
process.exit(0);
|