@node9/proxy 1.11.13 → 1.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.js +676 -596
- package/dist/cli.mjs +662 -582
- package/dist/index.js +9 -1
- package/dist/index.mjs +9 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -168,8 +168,8 @@ function sanitizeConfig(raw) {
|
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
const lines = result.error.issues.map((issue) => {
|
|
171
|
-
const
|
|
172
|
-
return ` \u2022 ${
|
|
171
|
+
const path45 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
172
|
+
return ` \u2022 ${path45}: ${issue.message}`;
|
|
173
173
|
});
|
|
174
174
|
return {
|
|
175
175
|
sanitized,
|
|
@@ -2083,9 +2083,9 @@ function matchesPattern(text, patterns) {
|
|
|
2083
2083
|
const withoutDotSlash = text.replace(/^\.\//, "");
|
|
2084
2084
|
return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
|
|
2085
2085
|
}
|
|
2086
|
-
function getNestedValue(obj,
|
|
2086
|
+
function getNestedValue(obj, path45) {
|
|
2087
2087
|
if (!obj || typeof obj !== "object") return null;
|
|
2088
|
-
return
|
|
2088
|
+
return path45.split(".").reduce((prev, curr) => prev?.[curr], obj);
|
|
2089
2089
|
}
|
|
2090
2090
|
function normalizeCommandForPolicy(command) {
|
|
2091
2091
|
try {
|
|
@@ -2344,7 +2344,12 @@ async function evaluatePolicy(toolName, args, agent, cwd) {
|
|
|
2344
2344
|
pathTokens = analyzed.paths;
|
|
2345
2345
|
const INLINE_EXEC_PATTERN = /^(python3?|bash|sh|zsh|perl|ruby|node|php|lua)\s+(-c|-e|-eval)\s/i;
|
|
2346
2346
|
if (INLINE_EXEC_PATTERN.test(shellCommand.trim())) {
|
|
2347
|
-
return {
|
|
2347
|
+
return {
|
|
2348
|
+
decision: "review",
|
|
2349
|
+
blockedByLabel: "Node9 Standard (Inline Execution)",
|
|
2350
|
+
ruleDescription: "The AI is running code directly from the command line. Review the full script below before allowing it to execute.",
|
|
2351
|
+
tier: 3
|
|
2352
|
+
};
|
|
2348
2353
|
}
|
|
2349
2354
|
const evalVerdict = detectDangerousShellExec(shellCommand);
|
|
2350
2355
|
if (evalVerdict === "block") {
|
|
@@ -2352,6 +2357,7 @@ async function evaluatePolicy(toolName, args, agent, cwd) {
|
|
|
2352
2357
|
decision: "block",
|
|
2353
2358
|
blockedByLabel: "Node9: Eval Remote Execution",
|
|
2354
2359
|
reason: "eval of remote download (curl/wget) is a near-certain supply-chain attack",
|
|
2360
|
+
ruleDescription: "The AI is downloading a script from the internet and running it immediately without inspection. This is a common way malware gets installed.",
|
|
2355
2361
|
tier: 3
|
|
2356
2362
|
};
|
|
2357
2363
|
}
|
|
@@ -2360,6 +2366,7 @@ async function evaluatePolicy(toolName, args, agent, cwd) {
|
|
|
2360
2366
|
decision: "review",
|
|
2361
2367
|
blockedByLabel: "Node9: Eval Dynamic Content",
|
|
2362
2368
|
reason: "eval of dynamic content (variable or subshell expansion) requires approval",
|
|
2369
|
+
ruleDescription: "The AI is running a command that includes a variable or subshell expansion. The actual command executed at runtime may differ from what is shown here.",
|
|
2363
2370
|
tier: 3
|
|
2364
2371
|
};
|
|
2365
2372
|
}
|
|
@@ -2489,6 +2496,7 @@ async function evaluatePolicy(toolName, args, agent, cwd) {
|
|
|
2489
2496
|
blockedByLabel: `Project/Global Config \u2014 dangerous word: "${matchedDangerousWord}"`,
|
|
2490
2497
|
matchedWord: matchedDangerousWord,
|
|
2491
2498
|
matchedField,
|
|
2499
|
+
ruleDescription: `This command contains a flagged keyword ("${matchedDangerousWord}") from your node9 config. Review it before allowing.`,
|
|
2492
2500
|
tier: 6
|
|
2493
2501
|
};
|
|
2494
2502
|
}
|
|
@@ -2641,7 +2649,8 @@ async function explainPolicy(toolName, args) {
|
|
|
2641
2649
|
waterfall,
|
|
2642
2650
|
steps,
|
|
2643
2651
|
decision: "review",
|
|
2644
|
-
blockedByLabel: "Node9 Standard (Inline Execution)"
|
|
2652
|
+
blockedByLabel: "Node9 Standard (Inline Execution)",
|
|
2653
|
+
ruleDescription: "The AI is running code directly from the command line. Review the full script below before allowing it to execute."
|
|
2645
2654
|
};
|
|
2646
2655
|
}
|
|
2647
2656
|
steps.push({
|
|
@@ -2747,7 +2756,8 @@ async function explainPolicy(toolName, args) {
|
|
|
2747
2756
|
steps,
|
|
2748
2757
|
decision: "review",
|
|
2749
2758
|
blockedByLabel: `Project/Global Config \u2014 dangerous word: "${matchedDangerousWord}"`,
|
|
2750
|
-
matchedToken: matchedDangerousWord
|
|
2759
|
+
matchedToken: matchedDangerousWord,
|
|
2760
|
+
ruleDescription: `This command contains a flagged keyword ("${matchedDangerousWord}") from your node9 config. Review it before allowing.`
|
|
2751
2761
|
};
|
|
2752
2762
|
}
|
|
2753
2763
|
steps.push({
|
|
@@ -5266,6 +5276,10 @@ var init_ui = __esm({
|
|
|
5266
5276
|
border-color: rgba(83, 155, 245, 0.35);
|
|
5267
5277
|
background: rgba(83, 155, 245, 0.04);
|
|
5268
5278
|
}
|
|
5279
|
+
.pending-card.discovery-card {
|
|
5280
|
+
border-color: rgba(120, 100, 255, 0.45);
|
|
5281
|
+
background: rgba(100, 80, 255, 0.06);
|
|
5282
|
+
}
|
|
5269
5283
|
.pending-card-header {
|
|
5270
5284
|
display: flex;
|
|
5271
5285
|
align-items: center;
|
|
@@ -7452,7 +7466,7 @@ var init_ui = __esm({
|
|
|
7452
7466
|
});
|
|
7453
7467
|
|
|
7454
7468
|
try {
|
|
7455
|
-
await fetch('/mcp/approve', {
|
|
7469
|
+
const res = await fetch('/mcp/approve', {
|
|
7456
7470
|
method: 'POST',
|
|
7457
7471
|
headers: {
|
|
7458
7472
|
'Content-Type': 'application/json',
|
|
@@ -7460,9 +7474,19 @@ var init_ui = __esm({
|
|
|
7460
7474
|
},
|
|
7461
7475
|
body: JSON.stringify({ id, serverKey, disabledTools }),
|
|
7462
7476
|
});
|
|
7477
|
+
if (!res.ok) {
|
|
7478
|
+
showToast(
|
|
7479
|
+
'\u26A0\uFE0F',
|
|
7480
|
+
'Approval failed',
|
|
7481
|
+
\`Server responded with \${res.status}\`,
|
|
7482
|
+
'toast-block'
|
|
7483
|
+
);
|
|
7484
|
+
return;
|
|
7485
|
+
}
|
|
7463
7486
|
closeMcpReview();
|
|
7464
7487
|
refreshMcpTools();
|
|
7465
7488
|
} catch (err) {
|
|
7489
|
+
showToast('\u26A0\uFE0F', 'Approval failed', 'Network error \u2014 check the daemon', 'toast-block');
|
|
7466
7490
|
console.error('Failed to approve MCP server:', err);
|
|
7467
7491
|
}
|
|
7468
7492
|
}
|
|
@@ -8276,6 +8300,9 @@ var init_ui2 = __esm({
|
|
|
8276
8300
|
});
|
|
8277
8301
|
|
|
8278
8302
|
// src/cli/daemon-starter.ts
|
|
8303
|
+
function isTestingMode() {
|
|
8304
|
+
return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
|
|
8305
|
+
}
|
|
8279
8306
|
function openBrowserLocal() {
|
|
8280
8307
|
const url = `http://${DAEMON_HOST}:${DAEMON_PORT}/`;
|
|
8281
8308
|
try {
|
|
@@ -8286,26 +8313,41 @@ function openBrowserLocal() {
|
|
|
8286
8313
|
} catch {
|
|
8287
8314
|
}
|
|
8288
8315
|
}
|
|
8289
|
-
async function autoStartDaemonAndWait() {
|
|
8290
|
-
if (
|
|
8316
|
+
async function autoStartDaemonAndWait(openBrowser2 = true) {
|
|
8317
|
+
if (isTestingMode()) return false;
|
|
8318
|
+
if (!import_path16.default.isAbsolute(process.argv[1])) return false;
|
|
8319
|
+
let resolvedArgv1;
|
|
8291
8320
|
try {
|
|
8292
|
-
|
|
8321
|
+
resolvedArgv1 = import_fs13.default.realpathSync(process.argv[1]);
|
|
8322
|
+
} catch {
|
|
8323
|
+
return false;
|
|
8324
|
+
}
|
|
8325
|
+
if (!resolvedArgv1.endsWith(".js")) return false;
|
|
8326
|
+
try {
|
|
8327
|
+
const child = (0, import_child_process3.spawn)(process.execPath, [resolvedArgv1, "daemon"], {
|
|
8293
8328
|
detached: true,
|
|
8294
8329
|
stdio: "ignore",
|
|
8295
8330
|
// NODE9_BROWSER_OPENED=1 tells the daemon we will open the browser ourselves
|
|
8296
8331
|
// (openBrowserLocal below), so it must not open a duplicate tab on first approval.
|
|
8297
|
-
|
|
8332
|
+
// Only set NODE9_BROWSER_OPENED when we actually intend to open it here.
|
|
8333
|
+
env: {
|
|
8334
|
+
...process.env,
|
|
8335
|
+
NODE9_AUTO_STARTED: "1",
|
|
8336
|
+
...openBrowser2 && { NODE9_BROWSER_OPENED: "1" }
|
|
8337
|
+
}
|
|
8298
8338
|
});
|
|
8299
8339
|
child.unref();
|
|
8300
8340
|
for (let i = 0; i < 20; i++) {
|
|
8301
8341
|
await new Promise((r) => setTimeout(r, 250));
|
|
8302
8342
|
if (!isDaemonRunning()) continue;
|
|
8303
8343
|
try {
|
|
8304
|
-
const res = await fetch(
|
|
8344
|
+
const res = await fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/settings`, {
|
|
8305
8345
|
signal: AbortSignal.timeout(500)
|
|
8306
8346
|
});
|
|
8307
8347
|
if (res.ok) {
|
|
8308
|
-
|
|
8348
|
+
if (openBrowser2) {
|
|
8349
|
+
openBrowserLocal();
|
|
8350
|
+
}
|
|
8309
8351
|
return true;
|
|
8310
8352
|
}
|
|
8311
8353
|
} catch {
|
|
@@ -8315,11 +8357,13 @@ async function autoStartDaemonAndWait() {
|
|
|
8315
8357
|
}
|
|
8316
8358
|
return false;
|
|
8317
8359
|
}
|
|
8318
|
-
var import_child_process3;
|
|
8360
|
+
var import_child_process3, import_path16, import_fs13;
|
|
8319
8361
|
var init_daemon_starter = __esm({
|
|
8320
8362
|
"src/cli/daemon-starter.ts"() {
|
|
8321
8363
|
"use strict";
|
|
8322
8364
|
import_child_process3 = require("child_process");
|
|
8365
|
+
import_path16 = __toESM(require("path"));
|
|
8366
|
+
import_fs13 = __toESM(require("fs"));
|
|
8323
8367
|
init_daemon();
|
|
8324
8368
|
}
|
|
8325
8369
|
});
|
|
@@ -8612,14 +8656,14 @@ function buildRuleSources() {
|
|
|
8612
8656
|
}
|
|
8613
8657
|
function countScanFiles() {
|
|
8614
8658
|
let total = 0;
|
|
8615
|
-
const claudeDir =
|
|
8616
|
-
if (
|
|
8659
|
+
const claudeDir = import_path17.default.join(import_os12.default.homedir(), ".claude", "projects");
|
|
8660
|
+
if (import_fs14.default.existsSync(claudeDir)) {
|
|
8617
8661
|
try {
|
|
8618
|
-
for (const proj of
|
|
8619
|
-
const p =
|
|
8662
|
+
for (const proj of import_fs14.default.readdirSync(claudeDir)) {
|
|
8663
|
+
const p = import_path17.default.join(claudeDir, proj);
|
|
8620
8664
|
try {
|
|
8621
|
-
if (!
|
|
8622
|
-
total +=
|
|
8665
|
+
if (!import_fs14.default.statSync(p).isDirectory()) continue;
|
|
8666
|
+
total += import_fs14.default.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
|
|
8623
8667
|
} catch {
|
|
8624
8668
|
continue;
|
|
8625
8669
|
}
|
|
@@ -8627,17 +8671,17 @@ function countScanFiles() {
|
|
|
8627
8671
|
} catch {
|
|
8628
8672
|
}
|
|
8629
8673
|
}
|
|
8630
|
-
const geminiDir =
|
|
8631
|
-
if (
|
|
8674
|
+
const geminiDir = import_path17.default.join(import_os12.default.homedir(), ".gemini", "tmp");
|
|
8675
|
+
if (import_fs14.default.existsSync(geminiDir)) {
|
|
8632
8676
|
try {
|
|
8633
|
-
for (const slug of
|
|
8634
|
-
const p =
|
|
8677
|
+
for (const slug of import_fs14.default.readdirSync(geminiDir)) {
|
|
8678
|
+
const p = import_path17.default.join(geminiDir, slug);
|
|
8635
8679
|
try {
|
|
8636
|
-
if (!
|
|
8637
|
-
const chatsDir =
|
|
8638
|
-
if (
|
|
8680
|
+
if (!import_fs14.default.statSync(p).isDirectory()) continue;
|
|
8681
|
+
const chatsDir = import_path17.default.join(p, "chats");
|
|
8682
|
+
if (import_fs14.default.existsSync(chatsDir)) {
|
|
8639
8683
|
try {
|
|
8640
|
-
total +=
|
|
8684
|
+
total += import_fs14.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
|
|
8641
8685
|
} catch {
|
|
8642
8686
|
}
|
|
8643
8687
|
}
|
|
@@ -8648,22 +8692,22 @@ function countScanFiles() {
|
|
|
8648
8692
|
} catch {
|
|
8649
8693
|
}
|
|
8650
8694
|
}
|
|
8651
|
-
const codexDir =
|
|
8652
|
-
if (
|
|
8695
|
+
const codexDir = import_path17.default.join(import_os12.default.homedir(), ".codex", "sessions");
|
|
8696
|
+
if (import_fs14.default.existsSync(codexDir)) {
|
|
8653
8697
|
try {
|
|
8654
|
-
for (const year of
|
|
8655
|
-
const yp =
|
|
8698
|
+
for (const year of import_fs14.default.readdirSync(codexDir)) {
|
|
8699
|
+
const yp = import_path17.default.join(codexDir, year);
|
|
8656
8700
|
try {
|
|
8657
|
-
if (!
|
|
8658
|
-
for (const month of
|
|
8659
|
-
const mp =
|
|
8701
|
+
if (!import_fs14.default.statSync(yp).isDirectory()) continue;
|
|
8702
|
+
for (const month of import_fs14.default.readdirSync(yp)) {
|
|
8703
|
+
const mp = import_path17.default.join(yp, month);
|
|
8660
8704
|
try {
|
|
8661
|
-
if (!
|
|
8662
|
-
for (const day of
|
|
8663
|
-
const dp =
|
|
8705
|
+
if (!import_fs14.default.statSync(mp).isDirectory()) continue;
|
|
8706
|
+
for (const day of import_fs14.default.readdirSync(mp)) {
|
|
8707
|
+
const dp = import_path17.default.join(mp, day);
|
|
8664
8708
|
try {
|
|
8665
|
-
if (!
|
|
8666
|
-
total +=
|
|
8709
|
+
if (!import_fs14.default.statSync(dp).isDirectory()) continue;
|
|
8710
|
+
total += import_fs14.default.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
|
|
8667
8711
|
} catch {
|
|
8668
8712
|
continue;
|
|
8669
8713
|
}
|
|
@@ -8681,18 +8725,19 @@ function countScanFiles() {
|
|
|
8681
8725
|
}
|
|
8682
8726
|
return total;
|
|
8683
8727
|
}
|
|
8684
|
-
function renderProgressBar(done, total) {
|
|
8728
|
+
function renderProgressBar(done, total, lines) {
|
|
8685
8729
|
const width = 28;
|
|
8686
8730
|
const pct = total > 0 ? done / total : 0;
|
|
8687
8731
|
const filled = Math.min(width, Math.round(pct * width));
|
|
8688
8732
|
const bar = "\u2588".repeat(filled) + "\u2591".repeat(width - filled);
|
|
8689
|
-
const
|
|
8733
|
+
const fileLabel = total > 0 ? `${done}/${total} files` : `${done} files`;
|
|
8734
|
+
const lineLabel = lines > 0 ? import_chalk2.default.dim(` ${lines.toLocaleString()} lines`) : "";
|
|
8690
8735
|
process.stdout.write(
|
|
8691
|
-
`\r ${import_chalk2.default.cyan("Scanning")} [${import_chalk2.default.cyan(bar)}] ${import_chalk2.default.dim(
|
|
8736
|
+
`\r ${import_chalk2.default.cyan("Scanning")} [${import_chalk2.default.cyan(bar)}] ${import_chalk2.default.dim(fileLabel)}${lineLabel} `
|
|
8692
8737
|
);
|
|
8693
8738
|
}
|
|
8694
|
-
function scanClaudeHistory(startDate, onProgress) {
|
|
8695
|
-
const projectsDir =
|
|
8739
|
+
function scanClaudeHistory(startDate, onProgress, onLine) {
|
|
8740
|
+
const projectsDir = import_path17.default.join(import_os12.default.homedir(), ".claude", "projects");
|
|
8696
8741
|
const result = {
|
|
8697
8742
|
filesScanned: 0,
|
|
8698
8743
|
sessions: 0,
|
|
@@ -8705,25 +8750,25 @@ function scanClaudeHistory(startDate, onProgress) {
|
|
|
8705
8750
|
firstDate: null,
|
|
8706
8751
|
lastDate: null
|
|
8707
8752
|
};
|
|
8708
|
-
if (!
|
|
8753
|
+
if (!import_fs14.default.existsSync(projectsDir)) return result;
|
|
8709
8754
|
let projDirs;
|
|
8710
8755
|
try {
|
|
8711
|
-
projDirs =
|
|
8756
|
+
projDirs = import_fs14.default.readdirSync(projectsDir);
|
|
8712
8757
|
} catch {
|
|
8713
8758
|
return result;
|
|
8714
8759
|
}
|
|
8715
8760
|
const ruleSources = buildRuleSources();
|
|
8716
8761
|
for (const proj of projDirs) {
|
|
8717
|
-
const projPath =
|
|
8762
|
+
const projPath = import_path17.default.join(projectsDir, proj);
|
|
8718
8763
|
try {
|
|
8719
|
-
if (!
|
|
8764
|
+
if (!import_fs14.default.statSync(projPath).isDirectory()) continue;
|
|
8720
8765
|
} catch {
|
|
8721
8766
|
continue;
|
|
8722
8767
|
}
|
|
8723
8768
|
const projLabel = decodeURIComponent(proj).replace(import_os12.default.homedir(), "~").slice(0, 40);
|
|
8724
8769
|
let files;
|
|
8725
8770
|
try {
|
|
8726
|
-
files =
|
|
8771
|
+
files = import_fs14.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
8727
8772
|
} catch {
|
|
8728
8773
|
continue;
|
|
8729
8774
|
}
|
|
@@ -8734,13 +8779,14 @@ function scanClaudeHistory(startDate, onProgress) {
|
|
|
8734
8779
|
const sessionId = file.replace(/\.jsonl$/, "");
|
|
8735
8780
|
let raw;
|
|
8736
8781
|
try {
|
|
8737
|
-
raw =
|
|
8782
|
+
raw = import_fs14.default.readFileSync(import_path17.default.join(projPath, file), "utf-8");
|
|
8738
8783
|
} catch {
|
|
8739
8784
|
continue;
|
|
8740
8785
|
}
|
|
8741
8786
|
const sessionCalls = [];
|
|
8742
8787
|
for (const line of raw.split("\n")) {
|
|
8743
8788
|
if (!line.trim()) continue;
|
|
8789
|
+
onLine?.();
|
|
8744
8790
|
let entry;
|
|
8745
8791
|
try {
|
|
8746
8792
|
entry = JSON.parse(line);
|
|
@@ -8886,8 +8932,8 @@ function scanClaudeHistory(startDate, onProgress) {
|
|
|
8886
8932
|
}
|
|
8887
8933
|
return result;
|
|
8888
8934
|
}
|
|
8889
|
-
function scanGeminiHistory(startDate, onProgress) {
|
|
8890
|
-
const tmpDir =
|
|
8935
|
+
function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
8936
|
+
const tmpDir = import_path17.default.join(import_os12.default.homedir(), ".gemini", "tmp");
|
|
8891
8937
|
const result = {
|
|
8892
8938
|
filesScanned: 0,
|
|
8893
8939
|
sessions: 0,
|
|
@@ -8900,31 +8946,31 @@ function scanGeminiHistory(startDate, onProgress) {
|
|
|
8900
8946
|
firstDate: null,
|
|
8901
8947
|
lastDate: null
|
|
8902
8948
|
};
|
|
8903
|
-
if (!
|
|
8949
|
+
if (!import_fs14.default.existsSync(tmpDir)) return result;
|
|
8904
8950
|
let slugDirs;
|
|
8905
8951
|
try {
|
|
8906
|
-
slugDirs =
|
|
8952
|
+
slugDirs = import_fs14.default.readdirSync(tmpDir);
|
|
8907
8953
|
} catch {
|
|
8908
8954
|
return result;
|
|
8909
8955
|
}
|
|
8910
8956
|
const ruleSources = buildRuleSources();
|
|
8911
8957
|
for (const slug of slugDirs) {
|
|
8912
|
-
const slugPath =
|
|
8958
|
+
const slugPath = import_path17.default.join(tmpDir, slug);
|
|
8913
8959
|
try {
|
|
8914
|
-
if (!
|
|
8960
|
+
if (!import_fs14.default.statSync(slugPath).isDirectory()) continue;
|
|
8915
8961
|
} catch {
|
|
8916
8962
|
continue;
|
|
8917
8963
|
}
|
|
8918
8964
|
let projLabel = slug;
|
|
8919
8965
|
try {
|
|
8920
|
-
projLabel =
|
|
8966
|
+
projLabel = import_fs14.default.readFileSync(import_path17.default.join(slugPath, ".project_root"), "utf-8").trim().replace(import_os12.default.homedir(), "~").slice(0, 40);
|
|
8921
8967
|
} catch {
|
|
8922
8968
|
}
|
|
8923
|
-
const chatsDir =
|
|
8924
|
-
if (!
|
|
8969
|
+
const chatsDir = import_path17.default.join(slugPath, "chats");
|
|
8970
|
+
if (!import_fs14.default.existsSync(chatsDir)) continue;
|
|
8925
8971
|
let chatFiles;
|
|
8926
8972
|
try {
|
|
8927
|
-
chatFiles =
|
|
8973
|
+
chatFiles = import_fs14.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
8928
8974
|
} catch {
|
|
8929
8975
|
continue;
|
|
8930
8976
|
}
|
|
@@ -8934,7 +8980,7 @@ function scanGeminiHistory(startDate, onProgress) {
|
|
|
8934
8980
|
const sessionId = chatFile.replace(/\.json$/, "");
|
|
8935
8981
|
let raw;
|
|
8936
8982
|
try {
|
|
8937
|
-
raw =
|
|
8983
|
+
raw = import_fs14.default.readFileSync(import_path17.default.join(chatsDir, chatFile), "utf-8");
|
|
8938
8984
|
} catch {
|
|
8939
8985
|
continue;
|
|
8940
8986
|
}
|
|
@@ -8947,6 +8993,7 @@ function scanGeminiHistory(startDate, onProgress) {
|
|
|
8947
8993
|
}
|
|
8948
8994
|
result.sessions++;
|
|
8949
8995
|
for (const msg of session.messages ?? []) {
|
|
8996
|
+
onLine?.();
|
|
8950
8997
|
if (msg.type === "user") {
|
|
8951
8998
|
const content = msg.content;
|
|
8952
8999
|
const text = Array.isArray(content) ? content.map((c) => c.text ?? "").join("\n") : typeof content === "string" ? content : "";
|
|
@@ -9082,8 +9129,8 @@ function scanGeminiHistory(startDate, onProgress) {
|
|
|
9082
9129
|
}
|
|
9083
9130
|
return result;
|
|
9084
9131
|
}
|
|
9085
|
-
function scanCodexHistory(startDate, onProgress) {
|
|
9086
|
-
const sessionsBase =
|
|
9132
|
+
function scanCodexHistory(startDate, onProgress, onLine) {
|
|
9133
|
+
const sessionsBase = import_path17.default.join(import_os12.default.homedir(), ".codex", "sessions");
|
|
9087
9134
|
const result = {
|
|
9088
9135
|
filesScanned: 0,
|
|
9089
9136
|
sessions: 0,
|
|
@@ -9096,32 +9143,32 @@ function scanCodexHistory(startDate, onProgress) {
|
|
|
9096
9143
|
firstDate: null,
|
|
9097
9144
|
lastDate: null
|
|
9098
9145
|
};
|
|
9099
|
-
if (!
|
|
9146
|
+
if (!import_fs14.default.existsSync(sessionsBase)) return result;
|
|
9100
9147
|
const jsonlFiles = [];
|
|
9101
9148
|
try {
|
|
9102
|
-
for (const year of
|
|
9103
|
-
const yearPath =
|
|
9149
|
+
for (const year of import_fs14.default.readdirSync(sessionsBase)) {
|
|
9150
|
+
const yearPath = import_path17.default.join(sessionsBase, year);
|
|
9104
9151
|
try {
|
|
9105
|
-
if (!
|
|
9152
|
+
if (!import_fs14.default.statSync(yearPath).isDirectory()) continue;
|
|
9106
9153
|
} catch {
|
|
9107
9154
|
continue;
|
|
9108
9155
|
}
|
|
9109
|
-
for (const month of
|
|
9110
|
-
const monthPath =
|
|
9156
|
+
for (const month of import_fs14.default.readdirSync(yearPath)) {
|
|
9157
|
+
const monthPath = import_path17.default.join(yearPath, month);
|
|
9111
9158
|
try {
|
|
9112
|
-
if (!
|
|
9159
|
+
if (!import_fs14.default.statSync(monthPath).isDirectory()) continue;
|
|
9113
9160
|
} catch {
|
|
9114
9161
|
continue;
|
|
9115
9162
|
}
|
|
9116
|
-
for (const day of
|
|
9117
|
-
const dayPath =
|
|
9163
|
+
for (const day of import_fs14.default.readdirSync(monthPath)) {
|
|
9164
|
+
const dayPath = import_path17.default.join(monthPath, day);
|
|
9118
9165
|
try {
|
|
9119
|
-
if (!
|
|
9166
|
+
if (!import_fs14.default.statSync(dayPath).isDirectory()) continue;
|
|
9120
9167
|
} catch {
|
|
9121
9168
|
continue;
|
|
9122
9169
|
}
|
|
9123
|
-
for (const file of
|
|
9124
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
9170
|
+
for (const file of import_fs14.default.readdirSync(dayPath)) {
|
|
9171
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path17.default.join(dayPath, file));
|
|
9125
9172
|
}
|
|
9126
9173
|
}
|
|
9127
9174
|
}
|
|
@@ -9135,7 +9182,7 @@ function scanCodexHistory(startDate, onProgress) {
|
|
|
9135
9182
|
onProgress?.(result.filesScanned);
|
|
9136
9183
|
let lines;
|
|
9137
9184
|
try {
|
|
9138
|
-
lines =
|
|
9185
|
+
lines = import_fs14.default.readFileSync(filePath, "utf-8").split("\n");
|
|
9139
9186
|
} catch {
|
|
9140
9187
|
continue;
|
|
9141
9188
|
}
|
|
@@ -9149,6 +9196,7 @@ function scanCodexHistory(startDate, onProgress) {
|
|
|
9149
9196
|
let lastTotalOutput = 0;
|
|
9150
9197
|
for (const line of lines) {
|
|
9151
9198
|
if (!line.trim()) continue;
|
|
9199
|
+
onLine?.();
|
|
9152
9200
|
let entry;
|
|
9153
9201
|
try {
|
|
9154
9202
|
entry = JSON.parse(line);
|
|
@@ -9353,17 +9401,17 @@ function printRuleGroup(rule, topN, drillDown, previewWidth) {
|
|
|
9353
9401
|
}
|
|
9354
9402
|
}
|
|
9355
9403
|
function registerScanCommand(program2) {
|
|
9356
|
-
program2.command("scan").description("Forecast: scan agent history and show what node9 would catch if installed").option("--all", "Scan all history (default: last
|
|
9404
|
+
program2.command("scan").description("Forecast: scan agent history and show what node9 would catch if installed").option("--all", "Scan all history (default: last 30 days)").option("--days <n>", "Scan last N days of history", "30").option("--top <n>", "Max findings to show per rule (default: 5)", "5").option("--drill-down", "Show all findings with full commands and session IDs").action(async (options) => {
|
|
9357
9405
|
const drillDown = options.drillDown ?? false;
|
|
9358
9406
|
const topN = drillDown ? Infinity : Math.max(1, parseInt(options.top, 10) || 5);
|
|
9359
9407
|
const previewWidth = 70;
|
|
9360
9408
|
const startDate = options.all ? null : (() => {
|
|
9361
9409
|
const d = /* @__PURE__ */ new Date();
|
|
9362
|
-
d.setDate(d.getDate() - (parseInt(options.days, 10) ||
|
|
9410
|
+
d.setDate(d.getDate() - (parseInt(options.days, 10) || 30));
|
|
9363
9411
|
d.setHours(0, 0, 0, 0);
|
|
9364
9412
|
return d;
|
|
9365
9413
|
})();
|
|
9366
|
-
const isInstalled =
|
|
9414
|
+
const isInstalled = import_fs14.default.existsSync(import_path17.default.join(import_os12.default.homedir(), ".node9", "audit.log"));
|
|
9367
9415
|
console.log("");
|
|
9368
9416
|
if (!isInstalled) {
|
|
9369
9417
|
console.log(
|
|
@@ -9380,19 +9428,32 @@ function registerScanCommand(program2) {
|
|
|
9380
9428
|
console.log("");
|
|
9381
9429
|
const totalFiles = countScanFiles();
|
|
9382
9430
|
let filesScanned = 0;
|
|
9431
|
+
let linesScanned = 0;
|
|
9432
|
+
let lastRender = 0;
|
|
9383
9433
|
const onProgress = (done) => {
|
|
9384
9434
|
filesScanned = done;
|
|
9385
|
-
renderProgressBar(filesScanned, totalFiles);
|
|
9435
|
+
renderProgressBar(filesScanned, totalFiles, linesScanned);
|
|
9436
|
+
lastRender = Date.now();
|
|
9386
9437
|
};
|
|
9387
|
-
|
|
9388
|
-
|
|
9438
|
+
const onLine = () => {
|
|
9439
|
+
linesScanned++;
|
|
9440
|
+
const now = Date.now();
|
|
9441
|
+
if (now - lastRender >= 80) {
|
|
9442
|
+
lastRender = now;
|
|
9443
|
+
renderProgressBar(filesScanned, totalFiles, linesScanned);
|
|
9444
|
+
}
|
|
9445
|
+
};
|
|
9446
|
+
renderProgressBar(0, totalFiles, 0);
|
|
9447
|
+
const claudeScan = scanClaudeHistory(startDate, onProgress, onLine);
|
|
9389
9448
|
const geminiScan = scanGeminiHistory(
|
|
9390
9449
|
startDate,
|
|
9391
|
-
(done) => onProgress(claudeScan.filesScanned + done)
|
|
9450
|
+
(done) => onProgress(claudeScan.filesScanned + done),
|
|
9451
|
+
onLine
|
|
9392
9452
|
);
|
|
9393
9453
|
const codexScan = scanCodexHistory(
|
|
9394
9454
|
startDate,
|
|
9395
|
-
(done) => onProgress(claudeScan.filesScanned + geminiScan.filesScanned + done)
|
|
9455
|
+
(done) => onProgress(claudeScan.filesScanned + geminiScan.filesScanned + done),
|
|
9456
|
+
onLine
|
|
9396
9457
|
);
|
|
9397
9458
|
const scan = mergeScans(mergeScans(claudeScan, geminiScan), codexScan);
|
|
9398
9459
|
const summary = buildScanSummary([
|
|
@@ -9410,7 +9471,7 @@ function registerScanCommand(program2) {
|
|
|
9410
9471
|
);
|
|
9411
9472
|
return;
|
|
9412
9473
|
}
|
|
9413
|
-
const rangeLabel = options.all ? import_chalk2.default.dim("all time") : import_chalk2.default.dim(`last ${options.days ??
|
|
9474
|
+
const rangeLabel = options.all ? import_chalk2.default.dim("all time") : import_chalk2.default.dim(`last ${options.days ?? 30} days`);
|
|
9414
9475
|
const dateRange = scan.firstDate && scan.lastDate ? import_chalk2.default.dim(` ${fmtTs(scan.firstDate)} \u2013 ${fmtTs(scan.lastDate)}`) : "";
|
|
9415
9476
|
const breakdownParts = [];
|
|
9416
9477
|
if (claudeScan.sessions > 0)
|
|
@@ -9588,39 +9649,43 @@ function registerScanCommand(program2) {
|
|
|
9588
9649
|
console.log(" " + import_chalk2.default.dim("\u2192 ") + import_chalk2.default.underline("https://node9.ai"));
|
|
9589
9650
|
}
|
|
9590
9651
|
console.log("");
|
|
9591
|
-
|
|
9592
|
-
|
|
9593
|
-
if (
|
|
9594
|
-
|
|
9595
|
-
|
|
9596
|
-
|
|
9597
|
-
|
|
9598
|
-
|
|
9599
|
-
|
|
9600
|
-
|
|
9601
|
-
|
|
9602
|
-
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
|
|
9606
|
-
|
|
9607
|
-
|
|
9608
|
-
|
|
9609
|
-
|
|
9610
|
-
|
|
9611
|
-
} catch {
|
|
9652
|
+
const url = `http://${DAEMON_HOST}:${DAEMON_PORT}/`;
|
|
9653
|
+
if (!isTestingMode()) {
|
|
9654
|
+
if (isDaemonRunning()) {
|
|
9655
|
+
const internalToken = getInternalToken();
|
|
9656
|
+
if (internalToken) {
|
|
9657
|
+
try {
|
|
9658
|
+
const summary2 = buildScanSummary([
|
|
9659
|
+
{ id: "claude", label: "Claude", icon: "\u{1F916}", scan: claudeScan },
|
|
9660
|
+
{ id: "gemini", label: "Gemini", icon: "\u264A", scan: geminiScan },
|
|
9661
|
+
{ id: "codex", label: "Codex", icon: "\u{1F52E}", scan: codexScan }
|
|
9662
|
+
]);
|
|
9663
|
+
await fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/scan/push`, {
|
|
9664
|
+
method: "POST",
|
|
9665
|
+
headers: { "Content-Type": "application/json", "x-node9-internal": internalToken },
|
|
9666
|
+
body: JSON.stringify({ status: "complete", summary: summary2 }),
|
|
9667
|
+
signal: AbortSignal.timeout(3e3)
|
|
9668
|
+
});
|
|
9669
|
+
openBrowserLocal();
|
|
9670
|
+
} catch {
|
|
9671
|
+
}
|
|
9612
9672
|
}
|
|
9613
9673
|
}
|
|
9674
|
+
console.log(" " + import_chalk2.default.cyan("\u{1F310} View in browser:") + " " + import_chalk2.default.underline(url));
|
|
9675
|
+
if (!isDaemonRunning()) {
|
|
9676
|
+
console.log(" " + import_chalk2.default.dim(" run node9 daemon --background to activate"));
|
|
9677
|
+
}
|
|
9678
|
+
console.log("");
|
|
9614
9679
|
}
|
|
9615
9680
|
});
|
|
9616
9681
|
}
|
|
9617
|
-
var import_chalk2,
|
|
9682
|
+
var import_chalk2, import_fs14, import_path17, import_os12, CLAUDE_PRICING, GEMINI_PRICING, LOOP_TOOLS, LOOP_THRESHOLD, DEFAULT_RULE_NAMES;
|
|
9618
9683
|
var init_scan = __esm({
|
|
9619
9684
|
"src/cli/commands/scan.ts"() {
|
|
9620
9685
|
"use strict";
|
|
9621
9686
|
import_chalk2 = __toESM(require("chalk"));
|
|
9622
|
-
|
|
9623
|
-
|
|
9687
|
+
import_fs14 = __toESM(require("fs"));
|
|
9688
|
+
import_path17 = __toESM(require("path"));
|
|
9624
9689
|
import_os12 = __toESM(require("os"));
|
|
9625
9690
|
init_shields();
|
|
9626
9691
|
init_config();
|
|
@@ -9757,12 +9822,12 @@ var init_suggestion_tracker = __esm({
|
|
|
9757
9822
|
});
|
|
9758
9823
|
|
|
9759
9824
|
// src/daemon/taint-store.ts
|
|
9760
|
-
var
|
|
9825
|
+
var import_fs15, import_path18, DEFAULT_TTL_MS, TaintStore;
|
|
9761
9826
|
var init_taint_store = __esm({
|
|
9762
9827
|
"src/daemon/taint-store.ts"() {
|
|
9763
9828
|
"use strict";
|
|
9764
|
-
|
|
9765
|
-
|
|
9829
|
+
import_fs15 = __toESM(require("fs"));
|
|
9830
|
+
import_path18 = __toESM(require("path"));
|
|
9766
9831
|
DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
9767
9832
|
TaintStore = class {
|
|
9768
9833
|
records = /* @__PURE__ */ new Map();
|
|
@@ -9827,9 +9892,9 @@ var init_taint_store = __esm({
|
|
|
9827
9892
|
/** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
|
|
9828
9893
|
_resolve(filePath) {
|
|
9829
9894
|
try {
|
|
9830
|
-
return
|
|
9895
|
+
return import_fs15.default.realpathSync.native(import_path18.default.resolve(filePath));
|
|
9831
9896
|
} catch {
|
|
9832
|
-
return
|
|
9897
|
+
return import_path18.default.resolve(filePath);
|
|
9833
9898
|
}
|
|
9834
9899
|
}
|
|
9835
9900
|
};
|
|
@@ -9947,8 +10012,8 @@ var init_session_history = __esm({
|
|
|
9947
10012
|
// src/daemon/state.ts
|
|
9948
10013
|
function loadInsightCounts() {
|
|
9949
10014
|
try {
|
|
9950
|
-
if (!
|
|
9951
|
-
const data = JSON.parse(
|
|
10015
|
+
if (!import_fs16.default.existsSync(INSIGHT_COUNTS_FILE)) return;
|
|
10016
|
+
const data = JSON.parse(import_fs16.default.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
|
|
9952
10017
|
for (const [tool, count] of Object.entries(data)) {
|
|
9953
10018
|
if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
|
|
9954
10019
|
}
|
|
@@ -9991,23 +10056,23 @@ function setCachedScanResult(result) {
|
|
|
9991
10056
|
cachedScanTs = Date.now();
|
|
9992
10057
|
}
|
|
9993
10058
|
function atomicWriteSync2(filePath, data, options) {
|
|
9994
|
-
const dir =
|
|
9995
|
-
if (!
|
|
10059
|
+
const dir = import_path19.default.dirname(filePath);
|
|
10060
|
+
if (!import_fs16.default.existsSync(dir)) import_fs16.default.mkdirSync(dir, { recursive: true });
|
|
9996
10061
|
const tmpPath = `${filePath}.${(0, import_crypto6.randomUUID)()}.tmp`;
|
|
9997
10062
|
try {
|
|
9998
|
-
|
|
10063
|
+
import_fs16.default.writeFileSync(tmpPath, data, options);
|
|
9999
10064
|
} catch (err2) {
|
|
10000
10065
|
try {
|
|
10001
|
-
|
|
10066
|
+
import_fs16.default.unlinkSync(tmpPath);
|
|
10002
10067
|
} catch {
|
|
10003
10068
|
}
|
|
10004
10069
|
throw err2;
|
|
10005
10070
|
}
|
|
10006
10071
|
try {
|
|
10007
|
-
|
|
10072
|
+
import_fs16.default.renameSync(tmpPath, filePath);
|
|
10008
10073
|
} catch (err2) {
|
|
10009
10074
|
try {
|
|
10010
|
-
|
|
10075
|
+
import_fs16.default.unlinkSync(tmpPath);
|
|
10011
10076
|
} catch {
|
|
10012
10077
|
}
|
|
10013
10078
|
throw err2;
|
|
@@ -10031,16 +10096,16 @@ function appendAuditLog(data) {
|
|
|
10031
10096
|
decision: data.decision,
|
|
10032
10097
|
source: "daemon"
|
|
10033
10098
|
};
|
|
10034
|
-
const dir =
|
|
10035
|
-
if (!
|
|
10036
|
-
|
|
10099
|
+
const dir = import_path19.default.dirname(AUDIT_LOG_FILE);
|
|
10100
|
+
if (!import_fs16.default.existsSync(dir)) import_fs16.default.mkdirSync(dir, { recursive: true });
|
|
10101
|
+
import_fs16.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
10037
10102
|
} catch {
|
|
10038
10103
|
}
|
|
10039
10104
|
}
|
|
10040
10105
|
function getAuditHistory(limit = 20) {
|
|
10041
10106
|
try {
|
|
10042
|
-
if (!
|
|
10043
|
-
const lines =
|
|
10107
|
+
if (!import_fs16.default.existsSync(AUDIT_LOG_FILE)) return [];
|
|
10108
|
+
const lines = import_fs16.default.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
|
|
10044
10109
|
if (lines.length === 1 && lines[0] === "") return [];
|
|
10045
10110
|
return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
|
|
10046
10111
|
} catch {
|
|
@@ -10049,19 +10114,19 @@ function getAuditHistory(limit = 20) {
|
|
|
10049
10114
|
}
|
|
10050
10115
|
function getOrgName() {
|
|
10051
10116
|
try {
|
|
10052
|
-
if (
|
|
10117
|
+
if (import_fs16.default.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
|
|
10053
10118
|
} catch {
|
|
10054
10119
|
}
|
|
10055
10120
|
return null;
|
|
10056
10121
|
}
|
|
10057
10122
|
function hasStoredSlackKey() {
|
|
10058
|
-
return
|
|
10123
|
+
return import_fs16.default.existsSync(CREDENTIALS_FILE);
|
|
10059
10124
|
}
|
|
10060
10125
|
function writeGlobalSetting(key, value) {
|
|
10061
10126
|
let config = {};
|
|
10062
10127
|
try {
|
|
10063
|
-
if (
|
|
10064
|
-
config = JSON.parse(
|
|
10128
|
+
if (import_fs16.default.existsSync(GLOBAL_CONFIG_FILE)) {
|
|
10129
|
+
config = JSON.parse(import_fs16.default.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
|
|
10065
10130
|
}
|
|
10066
10131
|
} catch {
|
|
10067
10132
|
}
|
|
@@ -10073,8 +10138,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
10073
10138
|
try {
|
|
10074
10139
|
let trust = { entries: [] };
|
|
10075
10140
|
try {
|
|
10076
|
-
if (
|
|
10077
|
-
trust = JSON.parse(
|
|
10141
|
+
if (import_fs16.default.existsSync(TRUST_FILE2))
|
|
10142
|
+
trust = JSON.parse(import_fs16.default.readFileSync(TRUST_FILE2, "utf-8"));
|
|
10078
10143
|
} catch {
|
|
10079
10144
|
}
|
|
10080
10145
|
trust.entries = trust.entries.filter(
|
|
@@ -10091,8 +10156,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
10091
10156
|
}
|
|
10092
10157
|
function readPersistentDecisions() {
|
|
10093
10158
|
try {
|
|
10094
|
-
if (
|
|
10095
|
-
return JSON.parse(
|
|
10159
|
+
if (import_fs16.default.existsSync(DECISIONS_FILE)) {
|
|
10160
|
+
return JSON.parse(import_fs16.default.readFileSync(DECISIONS_FILE, "utf-8"));
|
|
10096
10161
|
}
|
|
10097
10162
|
} catch {
|
|
10098
10163
|
}
|
|
@@ -10129,7 +10194,7 @@ function estimateToolCost(tool, args) {
|
|
|
10129
10194
|
const filePath = a.file_path ?? a.path;
|
|
10130
10195
|
if (filePath) {
|
|
10131
10196
|
try {
|
|
10132
|
-
const bytes =
|
|
10197
|
+
const bytes = import_fs16.default.statSync(filePath).size;
|
|
10133
10198
|
return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
|
|
10134
10199
|
} catch {
|
|
10135
10200
|
}
|
|
@@ -10187,7 +10252,7 @@ function abandonPending() {
|
|
|
10187
10252
|
});
|
|
10188
10253
|
if (autoStarted) {
|
|
10189
10254
|
try {
|
|
10190
|
-
|
|
10255
|
+
import_fs16.default.unlinkSync(DAEMON_PID_FILE);
|
|
10191
10256
|
} catch {
|
|
10192
10257
|
}
|
|
10193
10258
|
setTimeout(() => {
|
|
@@ -10198,7 +10263,7 @@ function abandonPending() {
|
|
|
10198
10263
|
}
|
|
10199
10264
|
function startActivitySocket() {
|
|
10200
10265
|
try {
|
|
10201
|
-
|
|
10266
|
+
import_fs16.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
10202
10267
|
} catch {
|
|
10203
10268
|
}
|
|
10204
10269
|
const ACTIVITY_MAX_BYTES = 1024 * 1024;
|
|
@@ -10280,18 +10345,18 @@ function startActivitySocket() {
|
|
|
10280
10345
|
unixServer.listen(ACTIVITY_SOCKET_PATH2);
|
|
10281
10346
|
process.on("exit", () => {
|
|
10282
10347
|
try {
|
|
10283
|
-
|
|
10348
|
+
import_fs16.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
10284
10349
|
} catch {
|
|
10285
10350
|
}
|
|
10286
10351
|
});
|
|
10287
10352
|
}
|
|
10288
|
-
var import_net2,
|
|
10353
|
+
var import_net2, import_fs16, import_path19, import_os13, import_child_process4, import_crypto6, homeDir, DAEMON_PID_FILE, DECISIONS_FILE, AUDIT_LOG_FILE, TRUST_FILE2, GLOBAL_CONFIG_FILE, CREDENTIALS_FILE, INSIGHT_COUNTS_FILE, pending, sseClients, suggestionTracker, suggestions, 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, WRITE_TOOL_NAMES;
|
|
10289
10354
|
var init_state2 = __esm({
|
|
10290
10355
|
"src/daemon/state.ts"() {
|
|
10291
10356
|
"use strict";
|
|
10292
10357
|
import_net2 = __toESM(require("net"));
|
|
10293
|
-
|
|
10294
|
-
|
|
10358
|
+
import_fs16 = __toESM(require("fs"));
|
|
10359
|
+
import_path19 = __toESM(require("path"));
|
|
10295
10360
|
import_os13 = __toESM(require("os"));
|
|
10296
10361
|
import_child_process4 = require("child_process");
|
|
10297
10362
|
import_crypto6 = require("crypto");
|
|
@@ -10301,13 +10366,13 @@ var init_state2 = __esm({
|
|
|
10301
10366
|
init_session_counters();
|
|
10302
10367
|
init_session_history();
|
|
10303
10368
|
homeDir = import_os13.default.homedir();
|
|
10304
|
-
DAEMON_PID_FILE =
|
|
10305
|
-
DECISIONS_FILE =
|
|
10306
|
-
AUDIT_LOG_FILE =
|
|
10307
|
-
TRUST_FILE2 =
|
|
10308
|
-
GLOBAL_CONFIG_FILE =
|
|
10309
|
-
CREDENTIALS_FILE =
|
|
10310
|
-
INSIGHT_COUNTS_FILE =
|
|
10369
|
+
DAEMON_PID_FILE = import_path19.default.join(homeDir, ".node9", "daemon.pid");
|
|
10370
|
+
DECISIONS_FILE = import_path19.default.join(homeDir, ".node9", "decisions.json");
|
|
10371
|
+
AUDIT_LOG_FILE = import_path19.default.join(homeDir, ".node9", "audit.log");
|
|
10372
|
+
TRUST_FILE2 = import_path19.default.join(homeDir, ".node9", "trust.json");
|
|
10373
|
+
GLOBAL_CONFIG_FILE = import_path19.default.join(homeDir, ".node9", "config.json");
|
|
10374
|
+
CREDENTIALS_FILE = import_path19.default.join(homeDir, ".node9", "credentials.json");
|
|
10375
|
+
INSIGHT_COUNTS_FILE = import_path19.default.join(homeDir, ".node9", "insight-counts.json");
|
|
10311
10376
|
pending = /* @__PURE__ */ new Map();
|
|
10312
10377
|
sseClients = /* @__PURE__ */ new Set();
|
|
10313
10378
|
suggestionTracker = new SuggestionTracker(3);
|
|
@@ -10325,7 +10390,7 @@ var init_state2 = __esm({
|
|
|
10325
10390
|
"2h": 2 * 60 * 6e4
|
|
10326
10391
|
};
|
|
10327
10392
|
autoStarted = process.env.NODE9_AUTO_STARTED === "1";
|
|
10328
|
-
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
10393
|
+
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path19.default.join(import_os13.default.tmpdir(), "node9-activity.sock");
|
|
10329
10394
|
ACTIVITY_RING_SIZE = 100;
|
|
10330
10395
|
activityRing = [];
|
|
10331
10396
|
LARGE_RESPONSE_RING_SIZE = 20;
|
|
@@ -10355,8 +10420,8 @@ var init_state2 = __esm({
|
|
|
10355
10420
|
function patchConfig(configPath, patch) {
|
|
10356
10421
|
let config = {};
|
|
10357
10422
|
try {
|
|
10358
|
-
if (
|
|
10359
|
-
config = JSON.parse(
|
|
10423
|
+
if (import_fs17.default.existsSync(configPath)) {
|
|
10424
|
+
config = JSON.parse(import_fs17.default.readFileSync(configPath, "utf8"));
|
|
10360
10425
|
}
|
|
10361
10426
|
} catch {
|
|
10362
10427
|
throw new Error(`Cannot read config at ${configPath} \u2014 file may be corrupted`);
|
|
@@ -10375,36 +10440,36 @@ function patchConfig(configPath, patch) {
|
|
|
10375
10440
|
ignored.push(patch.toolName);
|
|
10376
10441
|
}
|
|
10377
10442
|
}
|
|
10378
|
-
const dir =
|
|
10379
|
-
|
|
10443
|
+
const dir = import_path20.default.dirname(configPath);
|
|
10444
|
+
import_fs17.default.mkdirSync(dir, { recursive: true });
|
|
10380
10445
|
const tmp = configPath + ".node9-tmp";
|
|
10381
10446
|
try {
|
|
10382
|
-
|
|
10447
|
+
import_fs17.default.writeFileSync(tmp, JSON.stringify(config, null, 2), { mode: 384 });
|
|
10383
10448
|
} catch (err2) {
|
|
10384
10449
|
try {
|
|
10385
|
-
|
|
10450
|
+
import_fs17.default.unlinkSync(tmp);
|
|
10386
10451
|
} catch {
|
|
10387
10452
|
}
|
|
10388
10453
|
throw err2;
|
|
10389
10454
|
}
|
|
10390
10455
|
try {
|
|
10391
|
-
|
|
10456
|
+
import_fs17.default.renameSync(tmp, configPath);
|
|
10392
10457
|
} catch (err2) {
|
|
10393
10458
|
try {
|
|
10394
|
-
|
|
10459
|
+
import_fs17.default.unlinkSync(tmp);
|
|
10395
10460
|
} catch {
|
|
10396
10461
|
}
|
|
10397
10462
|
throw err2;
|
|
10398
10463
|
}
|
|
10399
10464
|
}
|
|
10400
|
-
var
|
|
10465
|
+
var import_fs17, import_path20, import_os14, GLOBAL_CONFIG_PATH;
|
|
10401
10466
|
var init_patch = __esm({
|
|
10402
10467
|
"src/config/patch.ts"() {
|
|
10403
10468
|
"use strict";
|
|
10404
|
-
|
|
10405
|
-
|
|
10469
|
+
import_fs17 = __toESM(require("fs"));
|
|
10470
|
+
import_path20 = __toESM(require("path"));
|
|
10406
10471
|
import_os14 = __toESM(require("os"));
|
|
10407
|
-
GLOBAL_CONFIG_PATH =
|
|
10472
|
+
GLOBAL_CONFIG_PATH = import_path20.default.join(import_os14.default.homedir(), ".node9", "config.json");
|
|
10408
10473
|
}
|
|
10409
10474
|
});
|
|
10410
10475
|
|
|
@@ -10424,7 +10489,7 @@ function pricingFor(model) {
|
|
|
10424
10489
|
function parseJSONLFile(filePath) {
|
|
10425
10490
|
let content;
|
|
10426
10491
|
try {
|
|
10427
|
-
content =
|
|
10492
|
+
content = import_fs18.default.readFileSync(filePath, "utf8");
|
|
10428
10493
|
} catch {
|
|
10429
10494
|
return /* @__PURE__ */ new Map();
|
|
10430
10495
|
}
|
|
@@ -10476,30 +10541,30 @@ function parseJSONLFile(filePath) {
|
|
|
10476
10541
|
return daily;
|
|
10477
10542
|
}
|
|
10478
10543
|
function collectEntries() {
|
|
10479
|
-
const projectsDir =
|
|
10480
|
-
if (!
|
|
10544
|
+
const projectsDir = import_path21.default.join(import_os15.default.homedir(), ".claude", "projects");
|
|
10545
|
+
if (!import_fs18.default.existsSync(projectsDir)) return [];
|
|
10481
10546
|
const combined = /* @__PURE__ */ new Map();
|
|
10482
10547
|
let dirs;
|
|
10483
10548
|
try {
|
|
10484
|
-
dirs =
|
|
10549
|
+
dirs = import_fs18.default.readdirSync(projectsDir);
|
|
10485
10550
|
} catch {
|
|
10486
10551
|
return [];
|
|
10487
10552
|
}
|
|
10488
10553
|
for (const dir of dirs) {
|
|
10489
|
-
const dirPath =
|
|
10554
|
+
const dirPath = import_path21.default.join(projectsDir, dir);
|
|
10490
10555
|
try {
|
|
10491
|
-
if (!
|
|
10556
|
+
if (!import_fs18.default.statSync(dirPath).isDirectory()) continue;
|
|
10492
10557
|
} catch {
|
|
10493
10558
|
continue;
|
|
10494
10559
|
}
|
|
10495
10560
|
let files;
|
|
10496
10561
|
try {
|
|
10497
|
-
files =
|
|
10562
|
+
files = import_fs18.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
10498
10563
|
} catch {
|
|
10499
10564
|
continue;
|
|
10500
10565
|
}
|
|
10501
10566
|
for (const file of files) {
|
|
10502
|
-
const entries = parseJSONLFile(
|
|
10567
|
+
const entries = parseJSONLFile(import_path21.default.join(dirPath, file));
|
|
10503
10568
|
for (const [key, e] of entries) {
|
|
10504
10569
|
const prev = combined.get(key);
|
|
10505
10570
|
if (prev) {
|
|
@@ -10535,11 +10600,11 @@ async function syncCost() {
|
|
|
10535
10600
|
signal: AbortSignal.timeout(15e3)
|
|
10536
10601
|
});
|
|
10537
10602
|
if (!res.ok) {
|
|
10538
|
-
|
|
10603
|
+
import_fs18.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
|
|
10539
10604
|
`);
|
|
10540
10605
|
}
|
|
10541
10606
|
} catch (err2) {
|
|
10542
|
-
|
|
10607
|
+
import_fs18.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
|
|
10543
10608
|
`);
|
|
10544
10609
|
}
|
|
10545
10610
|
}
|
|
@@ -10552,12 +10617,12 @@ function startCostSync() {
|
|
|
10552
10617
|
}, SYNC_INTERVAL_MS);
|
|
10553
10618
|
timer.unref();
|
|
10554
10619
|
}
|
|
10555
|
-
var
|
|
10620
|
+
var import_fs18, import_path21, import_os15, SYNC_INTERVAL_MS, PRICING;
|
|
10556
10621
|
var init_costSync = __esm({
|
|
10557
10622
|
"src/costSync.ts"() {
|
|
10558
10623
|
"use strict";
|
|
10559
|
-
|
|
10560
|
-
|
|
10624
|
+
import_fs18 = __toESM(require("fs"));
|
|
10625
|
+
import_path21 = __toESM(require("path"));
|
|
10561
10626
|
import_os15 = __toESM(require("os"));
|
|
10562
10627
|
init_config();
|
|
10563
10628
|
init_audit();
|
|
@@ -10583,8 +10648,8 @@ function readCredentials() {
|
|
|
10583
10648
|
};
|
|
10584
10649
|
}
|
|
10585
10650
|
try {
|
|
10586
|
-
const credPath =
|
|
10587
|
-
const creds = JSON.parse(
|
|
10651
|
+
const credPath = import_path22.default.join(import_os16.default.homedir(), ".node9", "credentials.json");
|
|
10652
|
+
const creds = JSON.parse(import_fs19.default.readFileSync(credPath, "utf-8"));
|
|
10588
10653
|
const profileName = process.env.NODE9_PROFILE ?? "default";
|
|
10589
10654
|
const profile = creds[profileName];
|
|
10590
10655
|
if (typeof profile?.apiKey === "string" && profile.apiKey.length > 0) {
|
|
@@ -10646,9 +10711,9 @@ async function syncOnce() {
|
|
|
10646
10711
|
try {
|
|
10647
10712
|
const rules = await fetchCloudRules(creds.apiKey, creds.apiUrl);
|
|
10648
10713
|
const cache = { fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), rules };
|
|
10649
|
-
const dir =
|
|
10650
|
-
if (!
|
|
10651
|
-
|
|
10714
|
+
const dir = import_path22.default.dirname(rulesCacheFile());
|
|
10715
|
+
if (!import_fs19.default.existsSync(dir)) import_fs19.default.mkdirSync(dir, { recursive: true });
|
|
10716
|
+
import_fs19.default.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
|
|
10652
10717
|
} catch {
|
|
10653
10718
|
}
|
|
10654
10719
|
}
|
|
@@ -10660,9 +10725,9 @@ async function runCloudSync() {
|
|
|
10660
10725
|
try {
|
|
10661
10726
|
const rules = await fetchCloudRules(creds.apiKey, creds.apiUrl);
|
|
10662
10727
|
const cache = { fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), rules };
|
|
10663
|
-
const dir =
|
|
10664
|
-
if (!
|
|
10665
|
-
|
|
10728
|
+
const dir = import_path22.default.dirname(rulesCacheFile());
|
|
10729
|
+
if (!import_fs19.default.existsSync(dir)) import_fs19.default.mkdirSync(dir, { recursive: true });
|
|
10730
|
+
import_fs19.default.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
|
|
10666
10731
|
return { ok: true, rules: rules.length, fetchedAt: cache.fetchedAt };
|
|
10667
10732
|
} catch (err2) {
|
|
10668
10733
|
return { ok: false, reason: err2 instanceof Error ? err2.message : String(err2) };
|
|
@@ -10670,7 +10735,7 @@ async function runCloudSync() {
|
|
|
10670
10735
|
}
|
|
10671
10736
|
function getCloudSyncStatus() {
|
|
10672
10737
|
try {
|
|
10673
|
-
const raw = JSON.parse(
|
|
10738
|
+
const raw = JSON.parse(import_fs19.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
10674
10739
|
if (!Array.isArray(raw.rules) || typeof raw.fetchedAt !== "string") return { cached: false };
|
|
10675
10740
|
return { cached: true, rules: raw.rules.length, fetchedAt: raw.fetchedAt };
|
|
10676
10741
|
} catch {
|
|
@@ -10679,7 +10744,7 @@ function getCloudSyncStatus() {
|
|
|
10679
10744
|
}
|
|
10680
10745
|
function getCloudRules() {
|
|
10681
10746
|
try {
|
|
10682
|
-
const raw = JSON.parse(
|
|
10747
|
+
const raw = JSON.parse(import_fs19.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
10683
10748
|
return Array.isArray(raw.rules) ? raw.rules : null;
|
|
10684
10749
|
} catch {
|
|
10685
10750
|
return null;
|
|
@@ -10694,16 +10759,16 @@ function startCloudSync() {
|
|
|
10694
10759
|
const recurring = setInterval(() => void syncOnce(), intervalMs);
|
|
10695
10760
|
recurring.unref();
|
|
10696
10761
|
}
|
|
10697
|
-
var
|
|
10762
|
+
var import_fs19, import_https, import_os16, import_path22, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_HOURS;
|
|
10698
10763
|
var init_sync = __esm({
|
|
10699
10764
|
"src/daemon/sync.ts"() {
|
|
10700
10765
|
"use strict";
|
|
10701
|
-
|
|
10766
|
+
import_fs19 = __toESM(require("fs"));
|
|
10702
10767
|
import_https = __toESM(require("https"));
|
|
10703
10768
|
import_os16 = __toESM(require("os"));
|
|
10704
|
-
|
|
10769
|
+
import_path22 = __toESM(require("path"));
|
|
10705
10770
|
init_config();
|
|
10706
|
-
rulesCacheFile = () =>
|
|
10771
|
+
rulesCacheFile = () => import_path22.default.join(import_os16.default.homedir(), ".node9", "rules-cache.json");
|
|
10707
10772
|
DEFAULT_API_URL = "https://api.node9.ai/api/v1/policy";
|
|
10708
10773
|
DEFAULT_INTERVAL_HOURS = 5;
|
|
10709
10774
|
MIN_INTERVAL_HOURS = 1;
|
|
@@ -10713,68 +10778,68 @@ var init_sync = __esm({
|
|
|
10713
10778
|
// src/daemon/dlp-scanner.ts
|
|
10714
10779
|
function loadIndex() {
|
|
10715
10780
|
try {
|
|
10716
|
-
return JSON.parse(
|
|
10781
|
+
return JSON.parse(import_fs20.default.readFileSync(INDEX_FILE, "utf-8"));
|
|
10717
10782
|
} catch {
|
|
10718
10783
|
return {};
|
|
10719
10784
|
}
|
|
10720
10785
|
}
|
|
10721
10786
|
function saveIndex(index) {
|
|
10722
10787
|
try {
|
|
10723
|
-
|
|
10788
|
+
import_fs20.default.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
|
|
10724
10789
|
} catch {
|
|
10725
10790
|
}
|
|
10726
10791
|
}
|
|
10727
10792
|
function appendAuditEntry(entry) {
|
|
10728
10793
|
try {
|
|
10729
|
-
|
|
10794
|
+
import_fs20.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
10730
10795
|
} catch {
|
|
10731
10796
|
}
|
|
10732
10797
|
}
|
|
10733
10798
|
function runDlpScan() {
|
|
10734
|
-
if (!
|
|
10799
|
+
if (!import_fs20.default.existsSync(PROJECTS_DIR)) return;
|
|
10735
10800
|
const index = loadIndex();
|
|
10736
10801
|
let updated = false;
|
|
10737
10802
|
let projDirs;
|
|
10738
10803
|
try {
|
|
10739
|
-
projDirs =
|
|
10804
|
+
projDirs = import_fs20.default.readdirSync(PROJECTS_DIR);
|
|
10740
10805
|
} catch {
|
|
10741
10806
|
return;
|
|
10742
10807
|
}
|
|
10743
10808
|
for (const proj of projDirs) {
|
|
10744
|
-
const projPath =
|
|
10809
|
+
const projPath = import_path23.default.join(PROJECTS_DIR, proj);
|
|
10745
10810
|
try {
|
|
10746
|
-
if (!
|
|
10747
|
-
const real =
|
|
10748
|
-
if (!real.startsWith(PROJECTS_DIR +
|
|
10811
|
+
if (!import_fs20.default.lstatSync(projPath).isDirectory()) continue;
|
|
10812
|
+
const real = import_fs20.default.realpathSync(projPath);
|
|
10813
|
+
if (!real.startsWith(PROJECTS_DIR + import_path23.default.sep) && real !== PROJECTS_DIR) continue;
|
|
10749
10814
|
} catch {
|
|
10750
10815
|
continue;
|
|
10751
10816
|
}
|
|
10752
10817
|
let files;
|
|
10753
10818
|
try {
|
|
10754
|
-
files =
|
|
10819
|
+
files = import_fs20.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
10755
10820
|
} catch {
|
|
10756
10821
|
continue;
|
|
10757
10822
|
}
|
|
10758
10823
|
for (const file of files) {
|
|
10759
|
-
const filePath =
|
|
10824
|
+
const filePath = import_path23.default.join(projPath, file);
|
|
10760
10825
|
const lastOffset = index[filePath] ?? 0;
|
|
10761
10826
|
let size;
|
|
10762
10827
|
try {
|
|
10763
|
-
size =
|
|
10828
|
+
size = import_fs20.default.statSync(filePath).size;
|
|
10764
10829
|
} catch {
|
|
10765
10830
|
continue;
|
|
10766
10831
|
}
|
|
10767
10832
|
if (size <= lastOffset) continue;
|
|
10768
10833
|
let fd;
|
|
10769
10834
|
try {
|
|
10770
|
-
fd =
|
|
10835
|
+
fd = import_fs20.default.openSync(filePath, "r");
|
|
10771
10836
|
} catch {
|
|
10772
10837
|
continue;
|
|
10773
10838
|
}
|
|
10774
10839
|
try {
|
|
10775
10840
|
const chunkSize = size - lastOffset;
|
|
10776
10841
|
const buf = Buffer.alloc(chunkSize);
|
|
10777
|
-
|
|
10842
|
+
import_fs20.default.readSync(fd, buf, 0, chunkSize, lastOffset);
|
|
10778
10843
|
const chunk = buf.toString("utf-8");
|
|
10779
10844
|
for (const line of chunk.split("\n")) {
|
|
10780
10845
|
if (!line.trim()) continue;
|
|
@@ -10819,7 +10884,7 @@ Run: node9 report --period 30d`
|
|
|
10819
10884
|
updated = true;
|
|
10820
10885
|
} finally {
|
|
10821
10886
|
try {
|
|
10822
|
-
|
|
10887
|
+
import_fs20.default.closeSync(fd);
|
|
10823
10888
|
} catch {
|
|
10824
10889
|
}
|
|
10825
10890
|
}
|
|
@@ -10845,30 +10910,30 @@ function startDlpScanner() {
|
|
|
10845
10910
|
);
|
|
10846
10911
|
timer.unref();
|
|
10847
10912
|
}
|
|
10848
|
-
var
|
|
10913
|
+
var import_fs20, import_path23, import_os17, INDEX_FILE, PROJECTS_DIR;
|
|
10849
10914
|
var init_dlp_scanner = __esm({
|
|
10850
10915
|
"src/daemon/dlp-scanner.ts"() {
|
|
10851
10916
|
"use strict";
|
|
10852
|
-
|
|
10853
|
-
|
|
10917
|
+
import_fs20 = __toESM(require("fs"));
|
|
10918
|
+
import_path23 = __toESM(require("path"));
|
|
10854
10919
|
import_os17 = __toESM(require("os"));
|
|
10855
10920
|
init_dlp();
|
|
10856
10921
|
init_native();
|
|
10857
10922
|
init_state2();
|
|
10858
|
-
INDEX_FILE =
|
|
10859
|
-
PROJECTS_DIR =
|
|
10923
|
+
INDEX_FILE = import_path23.default.join(import_os17.default.homedir(), ".node9", "dlp-index.json");
|
|
10924
|
+
PROJECTS_DIR = import_path23.default.join(import_os17.default.homedir(), ".claude", "projects");
|
|
10860
10925
|
}
|
|
10861
10926
|
});
|
|
10862
10927
|
|
|
10863
10928
|
// src/daemon/mcp-tools.ts
|
|
10864
10929
|
function getMcpToolsFile() {
|
|
10865
|
-
return
|
|
10930
|
+
return import_path24.default.join(import_os18.default.homedir(), ".node9", "mcp-tools.json");
|
|
10866
10931
|
}
|
|
10867
10932
|
function readMcpToolsConfig() {
|
|
10868
10933
|
try {
|
|
10869
10934
|
const file = getMcpToolsFile();
|
|
10870
|
-
if (!
|
|
10871
|
-
const raw =
|
|
10935
|
+
if (!import_fs21.default.existsSync(file)) return {};
|
|
10936
|
+
const raw = import_fs21.default.readFileSync(file, "utf-8");
|
|
10872
10937
|
return JSON.parse(raw);
|
|
10873
10938
|
} catch {
|
|
10874
10939
|
return {};
|
|
@@ -10877,11 +10942,11 @@ function readMcpToolsConfig() {
|
|
|
10877
10942
|
function writeMcpToolsConfig(config) {
|
|
10878
10943
|
try {
|
|
10879
10944
|
const file = getMcpToolsFile();
|
|
10880
|
-
const dir =
|
|
10881
|
-
if (!
|
|
10945
|
+
const dir = import_path24.default.dirname(file);
|
|
10946
|
+
if (!import_fs21.default.existsSync(dir)) import_fs21.default.mkdirSync(dir, { recursive: true });
|
|
10882
10947
|
const tmpPath = `${file}.${import_os18.default.hostname()}.${process.pid}.tmp`;
|
|
10883
|
-
|
|
10884
|
-
|
|
10948
|
+
import_fs21.default.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
|
|
10949
|
+
import_fs21.default.renameSync(tmpPath, file);
|
|
10885
10950
|
} catch (e) {
|
|
10886
10951
|
console.error("Failed to write mcp-tools.json", e);
|
|
10887
10952
|
}
|
|
@@ -10920,12 +10985,12 @@ function approveServer(serverKey, disabledTools) {
|
|
|
10920
10985
|
writeMcpToolsConfig(config);
|
|
10921
10986
|
}
|
|
10922
10987
|
}
|
|
10923
|
-
var
|
|
10988
|
+
var import_fs21, import_path24, import_os18;
|
|
10924
10989
|
var init_mcp_tools = __esm({
|
|
10925
10990
|
"src/daemon/mcp-tools.ts"() {
|
|
10926
10991
|
"use strict";
|
|
10927
|
-
|
|
10928
|
-
|
|
10992
|
+
import_fs21 = __toESM(require("fs"));
|
|
10993
|
+
import_path24 = __toESM(require("path"));
|
|
10929
10994
|
import_os18 = __toESM(require("os"));
|
|
10930
10995
|
}
|
|
10931
10996
|
});
|
|
@@ -10950,7 +11015,7 @@ function startDaemon() {
|
|
|
10950
11015
|
idleTimer = setTimeout(() => {
|
|
10951
11016
|
if (autoStarted) {
|
|
10952
11017
|
try {
|
|
10953
|
-
|
|
11018
|
+
import_fs22.default.unlinkSync(DAEMON_PID_FILE);
|
|
10954
11019
|
} catch {
|
|
10955
11020
|
}
|
|
10956
11021
|
}
|
|
@@ -11121,7 +11186,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
11121
11186
|
status: "pending"
|
|
11122
11187
|
});
|
|
11123
11188
|
}
|
|
11124
|
-
const projectCwd = typeof cwd === "string" &&
|
|
11189
|
+
const projectCwd = typeof cwd === "string" && import_path25.default.isAbsolute(cwd) ? cwd : void 0;
|
|
11125
11190
|
const projectConfig = getConfig(projectCwd);
|
|
11126
11191
|
const browserEnabled = projectConfig.settings.approvers?.browser !== false;
|
|
11127
11192
|
const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
|
|
@@ -11485,8 +11550,8 @@ data: ${JSON.stringify(item.data)}
|
|
|
11485
11550
|
if (!validToken(req)) return res.writeHead(403).end();
|
|
11486
11551
|
const periodParam = reqUrl.searchParams.get("period") || "7d";
|
|
11487
11552
|
const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
|
|
11488
|
-
const logPath =
|
|
11489
|
-
if (!
|
|
11553
|
+
const logPath = import_path25.default.join(import_os19.default.homedir(), ".node9", "audit.log");
|
|
11554
|
+
if (!import_fs22.default.existsSync(logPath)) {
|
|
11490
11555
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
11491
11556
|
return res.end(
|
|
11492
11557
|
JSON.stringify({
|
|
@@ -11499,7 +11564,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
11499
11564
|
);
|
|
11500
11565
|
}
|
|
11501
11566
|
try {
|
|
11502
|
-
const raw =
|
|
11567
|
+
const raw = import_fs22.default.readFileSync(logPath, "utf-8");
|
|
11503
11568
|
const allEntries = raw.split("\n").flatMap((line) => {
|
|
11504
11569
|
if (!line.trim()) return [];
|
|
11505
11570
|
try {
|
|
@@ -11603,7 +11668,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
11603
11668
|
}
|
|
11604
11669
|
try {
|
|
11605
11670
|
const d = /* @__PURE__ */ new Date();
|
|
11606
|
-
d.setDate(d.getDate() -
|
|
11671
|
+
d.setDate(d.getDate() - 30);
|
|
11607
11672
|
d.setHours(0, 0, 0, 0);
|
|
11608
11673
|
const EMPTY_SCAN = {
|
|
11609
11674
|
filesScanned: 0,
|
|
@@ -11679,8 +11744,8 @@ data: ${JSON.stringify(item.data)}
|
|
|
11679
11744
|
const body = await readBody(req);
|
|
11680
11745
|
const data = body ? JSON.parse(body) : {};
|
|
11681
11746
|
const configPath = data.configPath ?? GLOBAL_CONFIG_PATH;
|
|
11682
|
-
const node9Dir =
|
|
11683
|
-
if (!
|
|
11747
|
+
const node9Dir = import_path25.default.dirname(GLOBAL_CONFIG_PATH);
|
|
11748
|
+
if (!import_path25.default.resolve(configPath).startsWith(node9Dir + import_path25.default.sep)) {
|
|
11684
11749
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
11685
11750
|
return res.end(
|
|
11686
11751
|
JSON.stringify({ error: "configPath must be within the node9 config directory" })
|
|
@@ -11794,11 +11859,16 @@ data: ${JSON.stringify(item.data)}
|
|
|
11794
11859
|
if (!validToken(req)) return res.writeHead(403).end();
|
|
11795
11860
|
try {
|
|
11796
11861
|
const { serverKey, disabledTools } = JSON.parse(await readBody(req));
|
|
11797
|
-
if (typeof serverKey !== "string" || !Array.isArray(disabledTools)) {
|
|
11862
|
+
if (typeof serverKey !== "string" || serverKey.length < 1 || serverKey.length > 256 || !/^[\w.-]+$/.test(serverKey) || !Array.isArray(disabledTools)) {
|
|
11798
11863
|
res.writeHead(400).end();
|
|
11799
11864
|
return;
|
|
11800
11865
|
}
|
|
11801
11866
|
approveServer(serverKey, disabledTools);
|
|
11867
|
+
appendAuditLog({
|
|
11868
|
+
toolName: `mcp-server:${serverKey}`,
|
|
11869
|
+
args: { disabledTools },
|
|
11870
|
+
decision: "allow"
|
|
11871
|
+
});
|
|
11802
11872
|
broadcast("mcp-tools-updated", { serverKey, disabledTools });
|
|
11803
11873
|
res.writeHead(200).end();
|
|
11804
11874
|
return;
|
|
@@ -11811,12 +11881,17 @@ data: ${JSON.stringify(item.data)}
|
|
|
11811
11881
|
if (req.headers["x-node9-internal"] !== internalToken) return res.writeHead(403).end();
|
|
11812
11882
|
try {
|
|
11813
11883
|
const { serverKey, tools } = JSON.parse(await readBody(req));
|
|
11814
|
-
if (typeof serverKey !== "string" || !Array.isArray(tools)) {
|
|
11884
|
+
if (typeof serverKey !== "string" || serverKey.length < 1 || serverKey.length > 256 || !/^[\w.-]+$/.test(serverKey) || !Array.isArray(tools)) {
|
|
11815
11885
|
res.writeHead(400).end();
|
|
11816
11886
|
return;
|
|
11817
11887
|
}
|
|
11818
11888
|
const status = updateServerDiscovery(serverKey, tools);
|
|
11819
11889
|
if (status === "new" || status === "drift") {
|
|
11890
|
+
appendAuditLog({
|
|
11891
|
+
toolName: `mcp-server:${serverKey}`,
|
|
11892
|
+
args: { toolCount: tools.length, status },
|
|
11893
|
+
decision: "mcp-discovered"
|
|
11894
|
+
});
|
|
11820
11895
|
const id = (0, import_crypto7.randomUUID)();
|
|
11821
11896
|
const entry = {
|
|
11822
11897
|
id,
|
|
@@ -11885,6 +11960,11 @@ data: ${JSON.stringify(item.data)}
|
|
|
11885
11960
|
}
|
|
11886
11961
|
clearTimeout(entry.timer);
|
|
11887
11962
|
approveServer(serverKey, disabledTools);
|
|
11963
|
+
appendAuditLog({
|
|
11964
|
+
toolName: `mcp-server:${serverKey}`,
|
|
11965
|
+
args: { disabledTools },
|
|
11966
|
+
decision: "allow"
|
|
11967
|
+
});
|
|
11888
11968
|
pending.delete(id);
|
|
11889
11969
|
broadcast("remove", { id, decision: "allow" });
|
|
11890
11970
|
res.writeHead(200).end();
|
|
@@ -11907,14 +11987,14 @@ data: ${JSON.stringify(item.data)}
|
|
|
11907
11987
|
server.on("error", (e) => {
|
|
11908
11988
|
if (e.code === "EADDRINUSE") {
|
|
11909
11989
|
try {
|
|
11910
|
-
if (
|
|
11911
|
-
const { pid } = JSON.parse(
|
|
11990
|
+
if (import_fs22.default.existsSync(DAEMON_PID_FILE)) {
|
|
11991
|
+
const { pid } = JSON.parse(import_fs22.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
11912
11992
|
process.kill(pid, 0);
|
|
11913
11993
|
return process.exit(0);
|
|
11914
11994
|
}
|
|
11915
11995
|
} catch {
|
|
11916
11996
|
try {
|
|
11917
|
-
|
|
11997
|
+
import_fs22.default.unlinkSync(DAEMON_PID_FILE);
|
|
11918
11998
|
} catch {
|
|
11919
11999
|
}
|
|
11920
12000
|
server.listen(DAEMON_PORT, DAEMON_HOST);
|
|
@@ -11973,13 +12053,13 @@ data: ${JSON.stringify(item.data)}
|
|
|
11973
12053
|
}
|
|
11974
12054
|
startActivitySocket();
|
|
11975
12055
|
}
|
|
11976
|
-
var import_http,
|
|
12056
|
+
var import_http, import_fs22, import_path25, import_os19, import_crypto7, import_child_process5, import_chalk3;
|
|
11977
12057
|
var init_server = __esm({
|
|
11978
12058
|
"src/daemon/server.ts"() {
|
|
11979
12059
|
"use strict";
|
|
11980
12060
|
import_http = __toESM(require("http"));
|
|
11981
|
-
|
|
11982
|
-
|
|
12061
|
+
import_fs22 = __toESM(require("fs"));
|
|
12062
|
+
import_path25 = __toESM(require("path"));
|
|
11983
12063
|
import_os19 = __toESM(require("os"));
|
|
11984
12064
|
import_crypto7 = require("crypto");
|
|
11985
12065
|
import_child_process5 = require("child_process");
|
|
@@ -12004,8 +12084,8 @@ var init_server = __esm({
|
|
|
12004
12084
|
function resolveNode9Binary() {
|
|
12005
12085
|
try {
|
|
12006
12086
|
const script = process.argv[1];
|
|
12007
|
-
if (typeof script === "string" &&
|
|
12008
|
-
return
|
|
12087
|
+
if (typeof script === "string" && import_path26.default.isAbsolute(script) && import_fs23.default.existsSync(script)) {
|
|
12088
|
+
return import_fs23.default.realpathSync(script);
|
|
12009
12089
|
}
|
|
12010
12090
|
} catch {
|
|
12011
12091
|
}
|
|
@@ -12023,11 +12103,11 @@ function xmlEscape(s) {
|
|
|
12023
12103
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
12024
12104
|
}
|
|
12025
12105
|
function launchdPlist(binaryPath) {
|
|
12026
|
-
const logDir =
|
|
12106
|
+
const logDir = import_path26.default.join(import_os20.default.homedir(), ".node9");
|
|
12027
12107
|
const nodePath = xmlEscape(process.execPath);
|
|
12028
12108
|
const scriptPath = xmlEscape(binaryPath);
|
|
12029
|
-
const outLog = xmlEscape(
|
|
12030
|
-
const errLog = xmlEscape(
|
|
12109
|
+
const outLog = xmlEscape(import_path26.default.join(logDir, "daemon.log"));
|
|
12110
|
+
const errLog = xmlEscape(import_path26.default.join(logDir, "daemon-error.log"));
|
|
12031
12111
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
12032
12112
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
12033
12113
|
<plist version="1.0">
|
|
@@ -12062,9 +12142,9 @@ function launchdPlist(binaryPath) {
|
|
|
12062
12142
|
`;
|
|
12063
12143
|
}
|
|
12064
12144
|
function installLaunchd(binaryPath) {
|
|
12065
|
-
const dir =
|
|
12066
|
-
if (!
|
|
12067
|
-
|
|
12145
|
+
const dir = import_path26.default.dirname(LAUNCHD_PLIST);
|
|
12146
|
+
if (!import_fs23.default.existsSync(dir)) import_fs23.default.mkdirSync(dir, { recursive: true });
|
|
12147
|
+
import_fs23.default.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
|
|
12068
12148
|
(0, import_child_process6.spawnSync)("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
|
|
12069
12149
|
const r = (0, import_child_process6.spawnSync)("launchctl", ["load", "-w", LAUNCHD_PLIST], {
|
|
12070
12150
|
encoding: "utf8",
|
|
@@ -12075,13 +12155,13 @@ function installLaunchd(binaryPath) {
|
|
|
12075
12155
|
}
|
|
12076
12156
|
}
|
|
12077
12157
|
function uninstallLaunchd() {
|
|
12078
|
-
if (
|
|
12158
|
+
if (import_fs23.default.existsSync(LAUNCHD_PLIST)) {
|
|
12079
12159
|
(0, import_child_process6.spawnSync)("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
|
|
12080
|
-
|
|
12160
|
+
import_fs23.default.unlinkSync(LAUNCHD_PLIST);
|
|
12081
12161
|
}
|
|
12082
12162
|
}
|
|
12083
12163
|
function isLaunchdInstalled() {
|
|
12084
|
-
return
|
|
12164
|
+
return import_fs23.default.existsSync(LAUNCHD_PLIST);
|
|
12085
12165
|
}
|
|
12086
12166
|
function systemdUnit(binaryPath) {
|
|
12087
12167
|
return `[Unit]
|
|
@@ -12101,10 +12181,10 @@ WantedBy=default.target
|
|
|
12101
12181
|
`;
|
|
12102
12182
|
}
|
|
12103
12183
|
function installSystemd(binaryPath) {
|
|
12104
|
-
if (!
|
|
12105
|
-
|
|
12184
|
+
if (!import_fs23.default.existsSync(SYSTEMD_UNIT_DIR)) {
|
|
12185
|
+
import_fs23.default.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
|
|
12106
12186
|
}
|
|
12107
|
-
|
|
12187
|
+
import_fs23.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
|
|
12108
12188
|
try {
|
|
12109
12189
|
(0, import_child_process6.execFileSync)("loginctl", ["enable-linger", import_os20.default.userInfo().username], { timeout: 3e3 });
|
|
12110
12190
|
} catch {
|
|
@@ -12126,23 +12206,23 @@ function installSystemd(binaryPath) {
|
|
|
12126
12206
|
}
|
|
12127
12207
|
}
|
|
12128
12208
|
function uninstallSystemd() {
|
|
12129
|
-
if (
|
|
12209
|
+
if (import_fs23.default.existsSync(SYSTEMD_UNIT)) {
|
|
12130
12210
|
(0, import_child_process6.spawnSync)("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
|
|
12131
12211
|
encoding: "utf8",
|
|
12132
12212
|
timeout: 5e3
|
|
12133
12213
|
});
|
|
12134
12214
|
(0, import_child_process6.spawnSync)("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
|
|
12135
|
-
|
|
12215
|
+
import_fs23.default.unlinkSync(SYSTEMD_UNIT);
|
|
12136
12216
|
}
|
|
12137
12217
|
}
|
|
12138
12218
|
function isSystemdInstalled() {
|
|
12139
|
-
return
|
|
12219
|
+
return import_fs23.default.existsSync(SYSTEMD_UNIT);
|
|
12140
12220
|
}
|
|
12141
12221
|
function stopRunningDaemon() {
|
|
12142
|
-
const pidFile =
|
|
12143
|
-
if (!
|
|
12222
|
+
const pidFile = import_path26.default.join(import_os20.default.homedir(), ".node9", "daemon.pid");
|
|
12223
|
+
if (!import_fs23.default.existsSync(pidFile)) return;
|
|
12144
12224
|
try {
|
|
12145
|
-
const data = JSON.parse(
|
|
12225
|
+
const data = JSON.parse(import_fs23.default.readFileSync(pidFile, "utf-8"));
|
|
12146
12226
|
const pid = data.pid;
|
|
12147
12227
|
const MAX_PID2 = 4194304;
|
|
12148
12228
|
if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
|
|
@@ -12162,7 +12242,7 @@ function stopRunningDaemon() {
|
|
|
12162
12242
|
}
|
|
12163
12243
|
}
|
|
12164
12244
|
try {
|
|
12165
|
-
|
|
12245
|
+
import_fs23.default.unlinkSync(pidFile);
|
|
12166
12246
|
} catch {
|
|
12167
12247
|
}
|
|
12168
12248
|
} catch {
|
|
@@ -12232,26 +12312,26 @@ function isDaemonServiceInstalled() {
|
|
|
12232
12312
|
if (process.platform === "linux") return isSystemdInstalled();
|
|
12233
12313
|
return false;
|
|
12234
12314
|
}
|
|
12235
|
-
var
|
|
12315
|
+
var import_fs23, import_path26, import_os20, import_child_process6, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
|
|
12236
12316
|
var init_service = __esm({
|
|
12237
12317
|
"src/daemon/service.ts"() {
|
|
12238
12318
|
"use strict";
|
|
12239
|
-
|
|
12240
|
-
|
|
12319
|
+
import_fs23 = __toESM(require("fs"));
|
|
12320
|
+
import_path26 = __toESM(require("path"));
|
|
12241
12321
|
import_os20 = __toESM(require("os"));
|
|
12242
12322
|
import_child_process6 = require("child_process");
|
|
12243
12323
|
LAUNCHD_LABEL = "ai.node9.daemon";
|
|
12244
|
-
LAUNCHD_PLIST =
|
|
12245
|
-
SYSTEMD_UNIT_DIR =
|
|
12246
|
-
SYSTEMD_UNIT =
|
|
12324
|
+
LAUNCHD_PLIST = import_path26.default.join(import_os20.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
12325
|
+
SYSTEMD_UNIT_DIR = import_path26.default.join(import_os20.default.homedir(), ".config", "systemd", "user");
|
|
12326
|
+
SYSTEMD_UNIT = import_path26.default.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
|
|
12247
12327
|
}
|
|
12248
12328
|
});
|
|
12249
12329
|
|
|
12250
12330
|
// src/daemon/index.ts
|
|
12251
12331
|
function stopDaemon() {
|
|
12252
|
-
if (!
|
|
12332
|
+
if (!import_fs24.default.existsSync(DAEMON_PID_FILE)) return console.log(import_chalk4.default.yellow("Not running."));
|
|
12253
12333
|
try {
|
|
12254
|
-
const data = JSON.parse(
|
|
12334
|
+
const data = JSON.parse(import_fs24.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
12255
12335
|
const pid = data.pid;
|
|
12256
12336
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
12257
12337
|
console.log(import_chalk4.default.gray("Cleaned up invalid PID file."));
|
|
@@ -12263,7 +12343,7 @@ function stopDaemon() {
|
|
|
12263
12343
|
console.log(import_chalk4.default.gray("Cleaned up stale PID file."));
|
|
12264
12344
|
} finally {
|
|
12265
12345
|
try {
|
|
12266
|
-
|
|
12346
|
+
import_fs24.default.unlinkSync(DAEMON_PID_FILE);
|
|
12267
12347
|
} catch {
|
|
12268
12348
|
}
|
|
12269
12349
|
}
|
|
@@ -12272,9 +12352,9 @@ function daemonStatus() {
|
|
|
12272
12352
|
const serviceInstalled = isDaemonServiceInstalled();
|
|
12273
12353
|
const serviceLabel = serviceInstalled ? import_chalk4.default.green("installed (starts on login)") : import_chalk4.default.yellow("not installed \u2014 run: node9 daemon install");
|
|
12274
12354
|
let processStatus;
|
|
12275
|
-
if (
|
|
12355
|
+
if (import_fs24.default.existsSync(DAEMON_PID_FILE)) {
|
|
12276
12356
|
try {
|
|
12277
|
-
const data = JSON.parse(
|
|
12357
|
+
const data = JSON.parse(import_fs24.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
12278
12358
|
const pid = data.pid;
|
|
12279
12359
|
const port = data.port;
|
|
12280
12360
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
@@ -12304,11 +12384,11 @@ function daemonStatus() {
|
|
|
12304
12384
|
console.log(` Service : ${serviceLabel}
|
|
12305
12385
|
`);
|
|
12306
12386
|
}
|
|
12307
|
-
var
|
|
12387
|
+
var import_fs24, import_chalk4, import_child_process7, MAX_PID;
|
|
12308
12388
|
var init_daemon2 = __esm({
|
|
12309
12389
|
"src/daemon/index.ts"() {
|
|
12310
12390
|
"use strict";
|
|
12311
|
-
|
|
12391
|
+
import_fs24 = __toESM(require("fs"));
|
|
12312
12392
|
import_chalk4 = __toESM(require("chalk"));
|
|
12313
12393
|
import_child_process7 = require("child_process");
|
|
12314
12394
|
init_server();
|
|
@@ -12340,20 +12420,20 @@ function getModelContextLimit(model) {
|
|
|
12340
12420
|
return 2e5;
|
|
12341
12421
|
}
|
|
12342
12422
|
function readSessionUsage() {
|
|
12343
|
-
const projectsDir =
|
|
12344
|
-
if (!
|
|
12423
|
+
const projectsDir = import_path42.default.join(import_os35.default.homedir(), ".claude", "projects");
|
|
12424
|
+
if (!import_fs39.default.existsSync(projectsDir)) return null;
|
|
12345
12425
|
let latestFile = null;
|
|
12346
12426
|
let latestMtime = 0;
|
|
12347
12427
|
try {
|
|
12348
|
-
for (const dir of
|
|
12349
|
-
const dirPath =
|
|
12428
|
+
for (const dir of import_fs39.default.readdirSync(projectsDir)) {
|
|
12429
|
+
const dirPath = import_path42.default.join(projectsDir, dir);
|
|
12350
12430
|
try {
|
|
12351
|
-
if (!
|
|
12352
|
-
for (const file of
|
|
12431
|
+
if (!import_fs39.default.statSync(dirPath).isDirectory()) continue;
|
|
12432
|
+
for (const file of import_fs39.default.readdirSync(dirPath)) {
|
|
12353
12433
|
if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
|
|
12354
|
-
const filePath =
|
|
12434
|
+
const filePath = import_path42.default.join(dirPath, file);
|
|
12355
12435
|
try {
|
|
12356
|
-
const mtime =
|
|
12436
|
+
const mtime = import_fs39.default.statSync(filePath).mtimeMs;
|
|
12357
12437
|
if (mtime > latestMtime) {
|
|
12358
12438
|
latestMtime = mtime;
|
|
12359
12439
|
latestFile = filePath;
|
|
@@ -12368,7 +12448,7 @@ function readSessionUsage() {
|
|
|
12368
12448
|
}
|
|
12369
12449
|
if (!latestFile) return null;
|
|
12370
12450
|
try {
|
|
12371
|
-
const lines =
|
|
12451
|
+
const lines = import_fs39.default.readFileSync(latestFile, "utf-8").split("\n");
|
|
12372
12452
|
let lastModel = "";
|
|
12373
12453
|
let lastInput = 0;
|
|
12374
12454
|
let lastOutput = 0;
|
|
@@ -12457,9 +12537,9 @@ function renderPending(activity) {
|
|
|
12457
12537
|
}
|
|
12458
12538
|
async function ensureDaemon() {
|
|
12459
12539
|
let pidPort = null;
|
|
12460
|
-
if (
|
|
12540
|
+
if (import_fs39.default.existsSync(PID_FILE)) {
|
|
12461
12541
|
try {
|
|
12462
|
-
const { port } = JSON.parse(
|
|
12542
|
+
const { port } = JSON.parse(import_fs39.default.readFileSync(PID_FILE, "utf-8"));
|
|
12463
12543
|
pidPort = port;
|
|
12464
12544
|
} catch {
|
|
12465
12545
|
console.error(import_chalk25.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
@@ -12612,9 +12692,9 @@ function buildRecoveryCardLines(req) {
|
|
|
12612
12692
|
];
|
|
12613
12693
|
}
|
|
12614
12694
|
function readApproversFromDisk() {
|
|
12615
|
-
const configPath =
|
|
12695
|
+
const configPath = import_path42.default.join(import_os35.default.homedir(), ".node9", "config.json");
|
|
12616
12696
|
try {
|
|
12617
|
-
const raw = JSON.parse(
|
|
12697
|
+
const raw = JSON.parse(import_fs39.default.readFileSync(configPath, "utf-8"));
|
|
12618
12698
|
const settings = raw.settings ?? {};
|
|
12619
12699
|
return settings.approvers ?? {};
|
|
12620
12700
|
} catch {
|
|
@@ -12630,15 +12710,15 @@ function approverStatusLine() {
|
|
|
12630
12710
|
return `${fmt("native", "native")} ${fmt("browser", "browser")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
|
|
12631
12711
|
}
|
|
12632
12712
|
function toggleApprover(channel) {
|
|
12633
|
-
const configPath =
|
|
12713
|
+
const configPath = import_path42.default.join(import_os35.default.homedir(), ".node9", "config.json");
|
|
12634
12714
|
try {
|
|
12635
|
-
const raw = JSON.parse(
|
|
12715
|
+
const raw = JSON.parse(import_fs39.default.readFileSync(configPath, "utf-8"));
|
|
12636
12716
|
const settings = raw.settings ?? {};
|
|
12637
12717
|
const approvers = settings.approvers ?? {};
|
|
12638
12718
|
approvers[channel] = approvers[channel] === false;
|
|
12639
12719
|
settings.approvers = approvers;
|
|
12640
12720
|
raw.settings = settings;
|
|
12641
|
-
|
|
12721
|
+
import_fs39.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
|
|
12642
12722
|
} catch (err2) {
|
|
12643
12723
|
process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
|
|
12644
12724
|
`);
|
|
@@ -12808,8 +12888,8 @@ async function startTail(options = {}) {
|
|
|
12808
12888
|
}
|
|
12809
12889
|
postDecisionHttp(req2.id, httpDecision, csrfToken, port, httpOpts).catch((err2) => {
|
|
12810
12890
|
try {
|
|
12811
|
-
|
|
12812
|
-
|
|
12891
|
+
import_fs39.default.appendFileSync(
|
|
12892
|
+
import_path42.default.join(import_os35.default.homedir(), ".node9", "hook-debug.log"),
|
|
12813
12893
|
`[tail] POST /decision failed: ${String(err2)}
|
|
12814
12894
|
`
|
|
12815
12895
|
);
|
|
@@ -12890,9 +12970,9 @@ async function startTail(options = {}) {
|
|
|
12890
12970
|
}
|
|
12891
12971
|
} catch {
|
|
12892
12972
|
}
|
|
12893
|
-
const auditLog =
|
|
12973
|
+
const auditLog = import_path42.default.join(import_os35.default.homedir(), ".node9", "audit.log");
|
|
12894
12974
|
try {
|
|
12895
|
-
const unackedDlp =
|
|
12975
|
+
const unackedDlp = import_fs39.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
12896
12976
|
if (unackedDlp > 0) {
|
|
12897
12977
|
console.log("");
|
|
12898
12978
|
console.log(
|
|
@@ -13077,21 +13157,21 @@ async function startTail(options = {}) {
|
|
|
13077
13157
|
process.exit(1);
|
|
13078
13158
|
});
|
|
13079
13159
|
}
|
|
13080
|
-
var import_http2, import_chalk25,
|
|
13160
|
+
var import_http2, import_chalk25, import_fs39, import_os35, import_path42, import_readline5, import_child_process16, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
|
|
13081
13161
|
var init_tail = __esm({
|
|
13082
13162
|
"src/tui/tail.ts"() {
|
|
13083
13163
|
"use strict";
|
|
13084
13164
|
import_http2 = __toESM(require("http"));
|
|
13085
13165
|
import_chalk25 = __toESM(require("chalk"));
|
|
13086
|
-
|
|
13166
|
+
import_fs39 = __toESM(require("fs"));
|
|
13087
13167
|
import_os35 = __toESM(require("os"));
|
|
13088
|
-
|
|
13168
|
+
import_path42 = __toESM(require("path"));
|
|
13089
13169
|
import_readline5 = __toESM(require("readline"));
|
|
13090
13170
|
import_child_process16 = require("child_process");
|
|
13091
13171
|
init_daemon2();
|
|
13092
13172
|
init_daemon();
|
|
13093
13173
|
init_core();
|
|
13094
|
-
PID_FILE =
|
|
13174
|
+
PID_FILE = import_path42.default.join(import_os35.default.homedir(), ".node9", "daemon.pid");
|
|
13095
13175
|
ICONS = {
|
|
13096
13176
|
bash: "\u{1F4BB}",
|
|
13097
13177
|
shell: "\u{1F4BB}",
|
|
@@ -13213,9 +13293,9 @@ function formatTimeLeft(resetsAt) {
|
|
|
13213
13293
|
return ` (${m}m left)`;
|
|
13214
13294
|
}
|
|
13215
13295
|
function safeReadJson(filePath) {
|
|
13216
|
-
if (!
|
|
13296
|
+
if (!import_fs40.default.existsSync(filePath)) return null;
|
|
13217
13297
|
try {
|
|
13218
|
-
return JSON.parse(
|
|
13298
|
+
return JSON.parse(import_fs40.default.readFileSync(filePath, "utf-8"));
|
|
13219
13299
|
} catch {
|
|
13220
13300
|
return null;
|
|
13221
13301
|
}
|
|
@@ -13236,12 +13316,12 @@ function countHooksInFile(filePath) {
|
|
|
13236
13316
|
return Object.keys(cfg.hooks).length;
|
|
13237
13317
|
}
|
|
13238
13318
|
function countRulesInDir(rulesDir) {
|
|
13239
|
-
if (!
|
|
13319
|
+
if (!import_fs40.default.existsSync(rulesDir)) return 0;
|
|
13240
13320
|
let count = 0;
|
|
13241
13321
|
try {
|
|
13242
|
-
for (const entry of
|
|
13322
|
+
for (const entry of import_fs40.default.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
13243
13323
|
if (entry.isDirectory()) {
|
|
13244
|
-
count += countRulesInDir(
|
|
13324
|
+
count += countRulesInDir(import_path43.default.join(rulesDir, entry.name));
|
|
13245
13325
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
13246
13326
|
count++;
|
|
13247
13327
|
}
|
|
@@ -13252,46 +13332,46 @@ function countRulesInDir(rulesDir) {
|
|
|
13252
13332
|
}
|
|
13253
13333
|
function isSamePath(a, b) {
|
|
13254
13334
|
try {
|
|
13255
|
-
return
|
|
13335
|
+
return import_path43.default.resolve(a) === import_path43.default.resolve(b);
|
|
13256
13336
|
} catch {
|
|
13257
13337
|
return false;
|
|
13258
13338
|
}
|
|
13259
13339
|
}
|
|
13260
13340
|
function countConfigs(cwd) {
|
|
13261
13341
|
const homeDir2 = import_os36.default.homedir();
|
|
13262
|
-
const claudeDir =
|
|
13342
|
+
const claudeDir = import_path43.default.join(homeDir2, ".claude");
|
|
13263
13343
|
let claudeMdCount = 0;
|
|
13264
13344
|
let rulesCount = 0;
|
|
13265
13345
|
let hooksCount = 0;
|
|
13266
13346
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
13267
13347
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
13268
|
-
if (
|
|
13269
|
-
rulesCount += countRulesInDir(
|
|
13270
|
-
const userSettings =
|
|
13348
|
+
if (import_fs40.default.existsSync(import_path43.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
13349
|
+
rulesCount += countRulesInDir(import_path43.default.join(claudeDir, "rules"));
|
|
13350
|
+
const userSettings = import_path43.default.join(claudeDir, "settings.json");
|
|
13271
13351
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
13272
13352
|
hooksCount += countHooksInFile(userSettings);
|
|
13273
|
-
const userClaudeJson =
|
|
13353
|
+
const userClaudeJson = import_path43.default.join(homeDir2, ".claude.json");
|
|
13274
13354
|
for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
|
|
13275
13355
|
for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
|
|
13276
13356
|
userMcpServers.delete(name);
|
|
13277
13357
|
}
|
|
13278
13358
|
if (cwd) {
|
|
13279
|
-
if (
|
|
13280
|
-
if (
|
|
13281
|
-
const projectClaudeDir =
|
|
13359
|
+
if (import_fs40.default.existsSync(import_path43.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
13360
|
+
if (import_fs40.default.existsSync(import_path43.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
13361
|
+
const projectClaudeDir = import_path43.default.join(cwd, ".claude");
|
|
13282
13362
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
13283
13363
|
if (!overlapsUserScope) {
|
|
13284
|
-
if (
|
|
13285
|
-
rulesCount += countRulesInDir(
|
|
13286
|
-
const projSettings =
|
|
13364
|
+
if (import_fs40.default.existsSync(import_path43.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
13365
|
+
rulesCount += countRulesInDir(import_path43.default.join(projectClaudeDir, "rules"));
|
|
13366
|
+
const projSettings = import_path43.default.join(projectClaudeDir, "settings.json");
|
|
13287
13367
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
13288
13368
|
hooksCount += countHooksInFile(projSettings);
|
|
13289
13369
|
}
|
|
13290
|
-
if (
|
|
13291
|
-
const localSettings =
|
|
13370
|
+
if (import_fs40.default.existsSync(import_path43.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
13371
|
+
const localSettings = import_path43.default.join(projectClaudeDir, "settings.local.json");
|
|
13292
13372
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
13293
13373
|
hooksCount += countHooksInFile(localSettings);
|
|
13294
|
-
const mcpJsonServers = getMcpServerNames(
|
|
13374
|
+
const mcpJsonServers = getMcpServerNames(import_path43.default.join(cwd, ".mcp.json"));
|
|
13295
13375
|
const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
|
|
13296
13376
|
for (const name of disabledMcpJson) mcpJsonServers.delete(name);
|
|
13297
13377
|
for (const name of mcpJsonServers) projectMcpServers.add(name);
|
|
@@ -13324,12 +13404,12 @@ function readActiveShieldsHud() {
|
|
|
13324
13404
|
return shieldsCache.value;
|
|
13325
13405
|
}
|
|
13326
13406
|
try {
|
|
13327
|
-
const shieldsPath =
|
|
13328
|
-
if (!
|
|
13407
|
+
const shieldsPath = import_path43.default.join(import_os36.default.homedir(), ".node9", "shields.json");
|
|
13408
|
+
if (!import_fs40.default.existsSync(shieldsPath)) {
|
|
13329
13409
|
shieldsCache = { value: [], ts: now };
|
|
13330
13410
|
return [];
|
|
13331
13411
|
}
|
|
13332
|
-
const parsed = JSON.parse(
|
|
13412
|
+
const parsed = JSON.parse(import_fs40.default.readFileSync(shieldsPath, "utf-8"));
|
|
13333
13413
|
if (!Array.isArray(parsed.active)) {
|
|
13334
13414
|
shieldsCache = { value: [], ts: now };
|
|
13335
13415
|
return [];
|
|
@@ -13431,17 +13511,17 @@ function renderContextLine(stdin) {
|
|
|
13431
13511
|
async function main() {
|
|
13432
13512
|
try {
|
|
13433
13513
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
13434
|
-
if (
|
|
13514
|
+
if (import_fs40.default.existsSync(import_path43.default.join(import_os36.default.homedir(), ".node9", "hud-debug"))) {
|
|
13435
13515
|
try {
|
|
13436
|
-
const logPath =
|
|
13516
|
+
const logPath = import_path43.default.join(import_os36.default.homedir(), ".node9", "hud-debug.log");
|
|
13437
13517
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
13438
13518
|
let size = 0;
|
|
13439
13519
|
try {
|
|
13440
|
-
size =
|
|
13520
|
+
size = import_fs40.default.statSync(logPath).size;
|
|
13441
13521
|
} catch {
|
|
13442
13522
|
}
|
|
13443
13523
|
if (size < MAX_LOG_SIZE) {
|
|
13444
|
-
|
|
13524
|
+
import_fs40.default.appendFileSync(
|
|
13445
13525
|
logPath,
|
|
13446
13526
|
JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
|
|
13447
13527
|
);
|
|
@@ -13462,11 +13542,11 @@ async function main() {
|
|
|
13462
13542
|
try {
|
|
13463
13543
|
const cwd = stdin.cwd ?? process.cwd();
|
|
13464
13544
|
for (const configPath of [
|
|
13465
|
-
|
|
13466
|
-
|
|
13545
|
+
import_path43.default.join(cwd, "node9.config.json"),
|
|
13546
|
+
import_path43.default.join(import_os36.default.homedir(), ".node9", "config.json")
|
|
13467
13547
|
]) {
|
|
13468
|
-
if (!
|
|
13469
|
-
const cfg = JSON.parse(
|
|
13548
|
+
if (!import_fs40.default.existsSync(configPath)) continue;
|
|
13549
|
+
const cfg = JSON.parse(import_fs40.default.readFileSync(configPath, "utf-8"));
|
|
13470
13550
|
const hud = cfg.settings?.hud;
|
|
13471
13551
|
if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
|
|
13472
13552
|
}
|
|
@@ -13484,12 +13564,12 @@ async function main() {
|
|
|
13484
13564
|
renderOffline();
|
|
13485
13565
|
}
|
|
13486
13566
|
}
|
|
13487
|
-
var
|
|
13567
|
+
var import_fs40, import_path43, import_os36, import_http3, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
|
|
13488
13568
|
var init_hud = __esm({
|
|
13489
13569
|
"src/cli/hud.ts"() {
|
|
13490
13570
|
"use strict";
|
|
13491
|
-
|
|
13492
|
-
|
|
13571
|
+
import_fs40 = __toESM(require("fs"));
|
|
13572
|
+
import_path43 = __toESM(require("path"));
|
|
13493
13573
|
import_os36 = __toESM(require("os"));
|
|
13494
13574
|
import_http3 = __toESM(require("http"));
|
|
13495
13575
|
init_daemon();
|
|
@@ -14538,8 +14618,8 @@ function getAgentsStatus(homeDir2 = import_os11.default.homedir()) {
|
|
|
14538
14618
|
// src/cli.ts
|
|
14539
14619
|
init_daemon2();
|
|
14540
14620
|
var import_chalk26 = __toESM(require("chalk"));
|
|
14541
|
-
var
|
|
14542
|
-
var
|
|
14621
|
+
var import_fs41 = __toESM(require("fs"));
|
|
14622
|
+
var import_path44 = __toESM(require("path"));
|
|
14543
14623
|
var import_os37 = __toESM(require("os"));
|
|
14544
14624
|
var import_prompts2 = require("@inquirer/prompts");
|
|
14545
14625
|
|
|
@@ -14725,9 +14805,9 @@ init_daemon_starter();
|
|
|
14725
14805
|
|
|
14726
14806
|
// src/cli/commands/check.ts
|
|
14727
14807
|
var import_chalk6 = __toESM(require("chalk"));
|
|
14728
|
-
var
|
|
14808
|
+
var import_fs27 = __toESM(require("fs"));
|
|
14729
14809
|
var import_child_process10 = require("child_process");
|
|
14730
|
-
var
|
|
14810
|
+
var import_path29 = __toESM(require("path"));
|
|
14731
14811
|
var import_os23 = __toESM(require("os"));
|
|
14732
14812
|
init_orchestrator();
|
|
14733
14813
|
init_daemon();
|
|
@@ -14737,11 +14817,11 @@ init_policy();
|
|
|
14737
14817
|
// src/undo.ts
|
|
14738
14818
|
var import_child_process9 = require("child_process");
|
|
14739
14819
|
var import_crypto8 = __toESM(require("crypto"));
|
|
14740
|
-
var
|
|
14820
|
+
var import_fs25 = __toESM(require("fs"));
|
|
14741
14821
|
var import_net3 = __toESM(require("net"));
|
|
14742
|
-
var
|
|
14822
|
+
var import_path27 = __toESM(require("path"));
|
|
14743
14823
|
var import_os21 = __toESM(require("os"));
|
|
14744
|
-
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
14824
|
+
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path27.default.join(import_os21.default.tmpdir(), "node9-activity.sock");
|
|
14745
14825
|
function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
14746
14826
|
try {
|
|
14747
14827
|
const payload = JSON.stringify({
|
|
@@ -14761,22 +14841,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
|
14761
14841
|
} catch {
|
|
14762
14842
|
}
|
|
14763
14843
|
}
|
|
14764
|
-
var SNAPSHOT_STACK_PATH =
|
|
14765
|
-
var UNDO_LATEST_PATH =
|
|
14844
|
+
var SNAPSHOT_STACK_PATH = import_path27.default.join(import_os21.default.homedir(), ".node9", "snapshots.json");
|
|
14845
|
+
var UNDO_LATEST_PATH = import_path27.default.join(import_os21.default.homedir(), ".node9", "undo_latest.txt");
|
|
14766
14846
|
var MAX_SNAPSHOTS = 10;
|
|
14767
14847
|
var GIT_TIMEOUT = 15e3;
|
|
14768
14848
|
function readStack() {
|
|
14769
14849
|
try {
|
|
14770
|
-
if (
|
|
14771
|
-
return JSON.parse(
|
|
14850
|
+
if (import_fs25.default.existsSync(SNAPSHOT_STACK_PATH))
|
|
14851
|
+
return JSON.parse(import_fs25.default.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
|
|
14772
14852
|
} catch {
|
|
14773
14853
|
}
|
|
14774
14854
|
return [];
|
|
14775
14855
|
}
|
|
14776
14856
|
function writeStack(stack) {
|
|
14777
|
-
const dir =
|
|
14778
|
-
if (!
|
|
14779
|
-
|
|
14857
|
+
const dir = import_path27.default.dirname(SNAPSHOT_STACK_PATH);
|
|
14858
|
+
if (!import_fs25.default.existsSync(dir)) import_fs25.default.mkdirSync(dir, { recursive: true });
|
|
14859
|
+
import_fs25.default.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
|
|
14780
14860
|
}
|
|
14781
14861
|
function extractFilePath(args) {
|
|
14782
14862
|
if (!args || typeof args !== "object") return null;
|
|
@@ -14796,12 +14876,12 @@ function buildArgsSummary(tool, args) {
|
|
|
14796
14876
|
return "";
|
|
14797
14877
|
}
|
|
14798
14878
|
function findProjectRoot(filePath) {
|
|
14799
|
-
let dir =
|
|
14879
|
+
let dir = import_path27.default.dirname(filePath);
|
|
14800
14880
|
while (true) {
|
|
14801
|
-
if (
|
|
14881
|
+
if (import_fs25.default.existsSync(import_path27.default.join(dir, ".git")) || import_fs25.default.existsSync(import_path27.default.join(dir, "package.json"))) {
|
|
14802
14882
|
return dir;
|
|
14803
14883
|
}
|
|
14804
|
-
const parent =
|
|
14884
|
+
const parent = import_path27.default.dirname(dir);
|
|
14805
14885
|
if (parent === dir) return process.cwd();
|
|
14806
14886
|
dir = parent;
|
|
14807
14887
|
}
|
|
@@ -14809,7 +14889,7 @@ function findProjectRoot(filePath) {
|
|
|
14809
14889
|
function normalizeCwdForHash(cwd) {
|
|
14810
14890
|
let normalized;
|
|
14811
14891
|
try {
|
|
14812
|
-
normalized =
|
|
14892
|
+
normalized = import_fs25.default.realpathSync(cwd);
|
|
14813
14893
|
} catch {
|
|
14814
14894
|
normalized = cwd;
|
|
14815
14895
|
}
|
|
@@ -14819,16 +14899,16 @@ function normalizeCwdForHash(cwd) {
|
|
|
14819
14899
|
}
|
|
14820
14900
|
function getShadowRepoDir(cwd) {
|
|
14821
14901
|
const hash = import_crypto8.default.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
|
|
14822
|
-
return
|
|
14902
|
+
return import_path27.default.join(import_os21.default.homedir(), ".node9", "snapshots", hash);
|
|
14823
14903
|
}
|
|
14824
14904
|
function cleanOrphanedIndexFiles(shadowDir) {
|
|
14825
14905
|
try {
|
|
14826
14906
|
const cutoff = Date.now() - 6e4;
|
|
14827
|
-
for (const f of
|
|
14907
|
+
for (const f of import_fs25.default.readdirSync(shadowDir)) {
|
|
14828
14908
|
if (f.startsWith("index_")) {
|
|
14829
|
-
const fp =
|
|
14909
|
+
const fp = import_path27.default.join(shadowDir, f);
|
|
14830
14910
|
try {
|
|
14831
|
-
if (
|
|
14911
|
+
if (import_fs25.default.statSync(fp).mtimeMs < cutoff) import_fs25.default.unlinkSync(fp);
|
|
14832
14912
|
} catch {
|
|
14833
14913
|
}
|
|
14834
14914
|
}
|
|
@@ -14840,7 +14920,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
|
|
|
14840
14920
|
const hardcoded = [".git", ".node9"];
|
|
14841
14921
|
const lines = [...hardcoded, ...ignorePaths].join("\n");
|
|
14842
14922
|
try {
|
|
14843
|
-
|
|
14923
|
+
import_fs25.default.writeFileSync(import_path27.default.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
|
|
14844
14924
|
} catch {
|
|
14845
14925
|
}
|
|
14846
14926
|
}
|
|
@@ -14853,25 +14933,25 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
14853
14933
|
timeout: 3e3
|
|
14854
14934
|
});
|
|
14855
14935
|
if (check.status === 0) {
|
|
14856
|
-
const ptPath =
|
|
14936
|
+
const ptPath = import_path27.default.join(shadowDir, "project-path.txt");
|
|
14857
14937
|
try {
|
|
14858
|
-
const stored =
|
|
14938
|
+
const stored = import_fs25.default.readFileSync(ptPath, "utf8").trim();
|
|
14859
14939
|
if (stored === normalizedCwd) return true;
|
|
14860
14940
|
if (process.env.NODE9_DEBUG === "1")
|
|
14861
14941
|
console.error(
|
|
14862
14942
|
`[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
|
|
14863
14943
|
);
|
|
14864
|
-
|
|
14944
|
+
import_fs25.default.rmSync(shadowDir, { recursive: true, force: true });
|
|
14865
14945
|
} catch {
|
|
14866
14946
|
try {
|
|
14867
|
-
|
|
14947
|
+
import_fs25.default.writeFileSync(ptPath, normalizedCwd, "utf8");
|
|
14868
14948
|
} catch {
|
|
14869
14949
|
}
|
|
14870
14950
|
return true;
|
|
14871
14951
|
}
|
|
14872
14952
|
}
|
|
14873
14953
|
try {
|
|
14874
|
-
|
|
14954
|
+
import_fs25.default.mkdirSync(shadowDir, { recursive: true });
|
|
14875
14955
|
} catch {
|
|
14876
14956
|
}
|
|
14877
14957
|
const init = (0, import_child_process9.spawnSync)("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
|
|
@@ -14880,7 +14960,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
14880
14960
|
if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
|
|
14881
14961
|
return false;
|
|
14882
14962
|
}
|
|
14883
|
-
const configFile =
|
|
14963
|
+
const configFile = import_path27.default.join(shadowDir, "config");
|
|
14884
14964
|
(0, import_child_process9.spawnSync)("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
|
|
14885
14965
|
timeout: 3e3
|
|
14886
14966
|
});
|
|
@@ -14888,7 +14968,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
14888
14968
|
timeout: 3e3
|
|
14889
14969
|
});
|
|
14890
14970
|
try {
|
|
14891
|
-
|
|
14971
|
+
import_fs25.default.writeFileSync(import_path27.default.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
|
|
14892
14972
|
} catch {
|
|
14893
14973
|
}
|
|
14894
14974
|
return true;
|
|
@@ -14908,12 +14988,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
14908
14988
|
let indexFile = null;
|
|
14909
14989
|
try {
|
|
14910
14990
|
const rawFilePath = extractFilePath(args);
|
|
14911
|
-
const absFilePath = rawFilePath &&
|
|
14991
|
+
const absFilePath = rawFilePath && import_path27.default.isAbsolute(rawFilePath) ? rawFilePath : null;
|
|
14912
14992
|
const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
|
|
14913
14993
|
const shadowDir = getShadowRepoDir(cwd);
|
|
14914
14994
|
if (!ensureShadowRepo(shadowDir, cwd)) return null;
|
|
14915
14995
|
writeShadowExcludes(shadowDir, ignorePaths);
|
|
14916
|
-
indexFile =
|
|
14996
|
+
indexFile = import_path27.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
|
|
14917
14997
|
const shadowEnv = {
|
|
14918
14998
|
...process.env,
|
|
14919
14999
|
GIT_DIR: shadowDir,
|
|
@@ -14985,7 +15065,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
14985
15065
|
writeStack(stack);
|
|
14986
15066
|
const entry = stack[stack.length - 1];
|
|
14987
15067
|
notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
|
|
14988
|
-
|
|
15068
|
+
import_fs25.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
|
|
14989
15069
|
if (shouldGc) {
|
|
14990
15070
|
(0, import_child_process9.spawn)("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
|
|
14991
15071
|
}
|
|
@@ -14996,7 +15076,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
14996
15076
|
} finally {
|
|
14997
15077
|
if (indexFile) {
|
|
14998
15078
|
try {
|
|
14999
|
-
|
|
15079
|
+
import_fs25.default.unlinkSync(indexFile);
|
|
15000
15080
|
} catch {
|
|
15001
15081
|
}
|
|
15002
15082
|
}
|
|
@@ -15072,9 +15152,9 @@ function applyUndo(hash, cwd) {
|
|
|
15072
15152
|
timeout: GIT_TIMEOUT
|
|
15073
15153
|
}).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
|
|
15074
15154
|
for (const file of [...tracked, ...untracked]) {
|
|
15075
|
-
const fullPath =
|
|
15076
|
-
if (!snapshotFiles.has(file) &&
|
|
15077
|
-
|
|
15155
|
+
const fullPath = import_path27.default.join(dir, file);
|
|
15156
|
+
if (!snapshotFiles.has(file) && import_fs25.default.existsSync(fullPath)) {
|
|
15157
|
+
import_fs25.default.unlinkSync(fullPath);
|
|
15078
15158
|
}
|
|
15079
15159
|
}
|
|
15080
15160
|
return true;
|
|
@@ -15087,12 +15167,12 @@ function applyUndo(hash, cwd) {
|
|
|
15087
15167
|
init_daemon_starter();
|
|
15088
15168
|
|
|
15089
15169
|
// src/skill-pin.ts
|
|
15090
|
-
var
|
|
15091
|
-
var
|
|
15170
|
+
var import_fs26 = __toESM(require("fs"));
|
|
15171
|
+
var import_path28 = __toESM(require("path"));
|
|
15092
15172
|
var import_os22 = __toESM(require("os"));
|
|
15093
15173
|
var import_crypto9 = __toESM(require("crypto"));
|
|
15094
15174
|
function getPinsFilePath() {
|
|
15095
|
-
return
|
|
15175
|
+
return import_path28.default.join(import_os22.default.homedir(), ".node9", "skill-pins.json");
|
|
15096
15176
|
}
|
|
15097
15177
|
var MAX_FILES = 5e3;
|
|
15098
15178
|
var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
|
|
@@ -15106,18 +15186,18 @@ function walkDir(root) {
|
|
|
15106
15186
|
if (out.length >= MAX_FILES) return;
|
|
15107
15187
|
let entries;
|
|
15108
15188
|
try {
|
|
15109
|
-
entries =
|
|
15189
|
+
entries = import_fs26.default.readdirSync(dir, { withFileTypes: true });
|
|
15110
15190
|
} catch {
|
|
15111
15191
|
return;
|
|
15112
15192
|
}
|
|
15113
15193
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
15114
15194
|
for (const entry of entries) {
|
|
15115
15195
|
if (out.length >= MAX_FILES) return;
|
|
15116
|
-
const full =
|
|
15117
|
-
const rel = relDir ?
|
|
15196
|
+
const full = import_path28.default.join(dir, entry.name);
|
|
15197
|
+
const rel = relDir ? import_path28.default.posix.join(relDir, entry.name) : entry.name;
|
|
15118
15198
|
let lst;
|
|
15119
15199
|
try {
|
|
15120
|
-
lst =
|
|
15200
|
+
lst = import_fs26.default.lstatSync(full);
|
|
15121
15201
|
} catch {
|
|
15122
15202
|
continue;
|
|
15123
15203
|
}
|
|
@@ -15129,7 +15209,7 @@ function walkDir(root) {
|
|
|
15129
15209
|
if (!lst.isFile()) continue;
|
|
15130
15210
|
if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
|
|
15131
15211
|
try {
|
|
15132
|
-
const buf =
|
|
15212
|
+
const buf = import_fs26.default.readFileSync(full);
|
|
15133
15213
|
totalBytes += buf.length;
|
|
15134
15214
|
out.push({ rel, hash: sha256Bytes(buf) });
|
|
15135
15215
|
} catch {
|
|
@@ -15143,14 +15223,14 @@ function walkDir(root) {
|
|
|
15143
15223
|
function hashSkillRoot(absPath) {
|
|
15144
15224
|
let lst;
|
|
15145
15225
|
try {
|
|
15146
|
-
lst =
|
|
15226
|
+
lst = import_fs26.default.lstatSync(absPath);
|
|
15147
15227
|
} catch {
|
|
15148
15228
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
15149
15229
|
}
|
|
15150
15230
|
if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
|
|
15151
15231
|
if (lst.isFile()) {
|
|
15152
15232
|
try {
|
|
15153
|
-
return { exists: true, contentHash: sha256Bytes(
|
|
15233
|
+
return { exists: true, contentHash: sha256Bytes(import_fs26.default.readFileSync(absPath)), fileCount: 1 };
|
|
15154
15234
|
} catch {
|
|
15155
15235
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
15156
15236
|
}
|
|
@@ -15168,7 +15248,7 @@ function getRootKey(absPath) {
|
|
|
15168
15248
|
function readSkillPinsSafe() {
|
|
15169
15249
|
const filePath = getPinsFilePath();
|
|
15170
15250
|
try {
|
|
15171
|
-
const raw =
|
|
15251
|
+
const raw = import_fs26.default.readFileSync(filePath, "utf-8");
|
|
15172
15252
|
if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
15173
15253
|
const parsed = JSON.parse(raw);
|
|
15174
15254
|
if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
|
|
@@ -15188,10 +15268,10 @@ function readSkillPins() {
|
|
|
15188
15268
|
}
|
|
15189
15269
|
function writeSkillPins(data) {
|
|
15190
15270
|
const filePath = getPinsFilePath();
|
|
15191
|
-
|
|
15271
|
+
import_fs26.default.mkdirSync(import_path28.default.dirname(filePath), { recursive: true });
|
|
15192
15272
|
const tmp = `${filePath}.${import_crypto9.default.randomBytes(6).toString("hex")}.tmp`;
|
|
15193
|
-
|
|
15194
|
-
|
|
15273
|
+
import_fs26.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
15274
|
+
import_fs26.default.renameSync(tmp, filePath);
|
|
15195
15275
|
}
|
|
15196
15276
|
function removePin(rootKey) {
|
|
15197
15277
|
const pins = readSkillPins();
|
|
@@ -15235,36 +15315,36 @@ function verifyAndPinRoots(roots) {
|
|
|
15235
15315
|
return { kind: "verified" };
|
|
15236
15316
|
}
|
|
15237
15317
|
function defaultSkillRoots(_cwd) {
|
|
15238
|
-
const marketplaces =
|
|
15318
|
+
const marketplaces = import_path28.default.join(import_os22.default.homedir(), ".claude", "plugins", "marketplaces");
|
|
15239
15319
|
const roots = [];
|
|
15240
15320
|
let registries;
|
|
15241
15321
|
try {
|
|
15242
|
-
registries =
|
|
15322
|
+
registries = import_fs26.default.readdirSync(marketplaces, { withFileTypes: true });
|
|
15243
15323
|
} catch {
|
|
15244
15324
|
return [];
|
|
15245
15325
|
}
|
|
15246
15326
|
for (const registry of registries) {
|
|
15247
15327
|
if (!registry.isDirectory()) continue;
|
|
15248
|
-
const pluginsDir =
|
|
15328
|
+
const pluginsDir = import_path28.default.join(marketplaces, registry.name, "plugins");
|
|
15249
15329
|
let plugins;
|
|
15250
15330
|
try {
|
|
15251
|
-
plugins =
|
|
15331
|
+
plugins = import_fs26.default.readdirSync(pluginsDir, { withFileTypes: true });
|
|
15252
15332
|
} catch {
|
|
15253
15333
|
continue;
|
|
15254
15334
|
}
|
|
15255
15335
|
for (const plugin of plugins) {
|
|
15256
15336
|
if (!plugin.isDirectory()) continue;
|
|
15257
|
-
roots.push(
|
|
15337
|
+
roots.push(import_path28.default.join(pluginsDir, plugin.name));
|
|
15258
15338
|
}
|
|
15259
15339
|
}
|
|
15260
15340
|
return roots;
|
|
15261
15341
|
}
|
|
15262
15342
|
function resolveUserSkillRoot(entry, cwd) {
|
|
15263
15343
|
if (!entry) return null;
|
|
15264
|
-
if (entry.startsWith("~/") || entry === "~") return
|
|
15265
|
-
if (
|
|
15266
|
-
if (!cwd || !
|
|
15267
|
-
return
|
|
15344
|
+
if (entry.startsWith("~/") || entry === "~") return import_path28.default.join(import_os22.default.homedir(), entry.slice(1));
|
|
15345
|
+
if (import_path28.default.isAbsolute(entry)) return entry;
|
|
15346
|
+
if (!cwd || !import_path28.default.isAbsolute(cwd)) return null;
|
|
15347
|
+
return import_path28.default.join(cwd, entry);
|
|
15268
15348
|
}
|
|
15269
15349
|
|
|
15270
15350
|
// src/cli/commands/check.ts
|
|
@@ -15282,9 +15362,9 @@ function registerCheckCommand(program2) {
|
|
|
15282
15362
|
} catch (err2) {
|
|
15283
15363
|
const tempConfig = getConfig();
|
|
15284
15364
|
if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
|
|
15285
|
-
const logPath =
|
|
15365
|
+
const logPath = import_path29.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
|
|
15286
15366
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
15287
|
-
|
|
15367
|
+
import_fs27.default.appendFileSync(
|
|
15288
15368
|
logPath,
|
|
15289
15369
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
|
|
15290
15370
|
RAW: ${raw}
|
|
@@ -15297,11 +15377,11 @@ RAW: ${raw}
|
|
|
15297
15377
|
if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
|
|
15298
15378
|
try {
|
|
15299
15379
|
const scriptPath = process.argv[1];
|
|
15300
|
-
if (typeof scriptPath !== "string" || !
|
|
15380
|
+
if (typeof scriptPath !== "string" || !import_path29.default.isAbsolute(scriptPath))
|
|
15301
15381
|
throw new Error("node9: argv[1] is not an absolute path");
|
|
15302
|
-
const resolvedScript =
|
|
15303
|
-
const packageDist =
|
|
15304
|
-
if (!resolvedScript.startsWith(packageDist +
|
|
15382
|
+
const resolvedScript = import_fs27.default.realpathSync(scriptPath);
|
|
15383
|
+
const packageDist = import_fs27.default.realpathSync(import_path29.default.resolve(__dirname, "../.."));
|
|
15384
|
+
if (!resolvedScript.startsWith(packageDist + import_path29.default.sep) && resolvedScript !== packageDist)
|
|
15305
15385
|
throw new Error(
|
|
15306
15386
|
`node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
|
|
15307
15387
|
);
|
|
@@ -15323,10 +15403,10 @@ RAW: ${raw}
|
|
|
15323
15403
|
});
|
|
15324
15404
|
d.unref();
|
|
15325
15405
|
} catch (spawnErr) {
|
|
15326
|
-
const logPath =
|
|
15406
|
+
const logPath = import_path29.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
|
|
15327
15407
|
const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
|
|
15328
15408
|
try {
|
|
15329
|
-
|
|
15409
|
+
import_fs27.default.appendFileSync(
|
|
15330
15410
|
logPath,
|
|
15331
15411
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
|
|
15332
15412
|
`
|
|
@@ -15336,10 +15416,10 @@ RAW: ${raw}
|
|
|
15336
15416
|
}
|
|
15337
15417
|
}
|
|
15338
15418
|
if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
|
|
15339
|
-
const logPath =
|
|
15340
|
-
if (!
|
|
15341
|
-
|
|
15342
|
-
|
|
15419
|
+
const logPath = import_path29.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
|
|
15420
|
+
if (!import_fs27.default.existsSync(import_path29.default.dirname(logPath)))
|
|
15421
|
+
import_fs27.default.mkdirSync(import_path29.default.dirname(logPath), { recursive: true });
|
|
15422
|
+
import_fs27.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
|
|
15343
15423
|
`);
|
|
15344
15424
|
}
|
|
15345
15425
|
const toolName = sanitize2(payload.tool_name ?? payload.name ?? "");
|
|
@@ -15352,8 +15432,8 @@ RAW: ${raw}
|
|
|
15352
15432
|
const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
|
|
15353
15433
|
let ttyFd = null;
|
|
15354
15434
|
try {
|
|
15355
|
-
ttyFd =
|
|
15356
|
-
const writeTty = (line) =>
|
|
15435
|
+
ttyFd = import_fs27.default.openSync("/dev/tty", "w");
|
|
15436
|
+
const writeTty = (line) => import_fs27.default.writeSync(ttyFd, line + "\n");
|
|
15357
15437
|
if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
|
|
15358
15438
|
writeTty(import_chalk6.default.bgRed.white.bold(`
|
|
15359
15439
|
\u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
|
|
@@ -15372,7 +15452,7 @@ RAW: ${raw}
|
|
|
15372
15452
|
} finally {
|
|
15373
15453
|
if (ttyFd !== null)
|
|
15374
15454
|
try {
|
|
15375
|
-
|
|
15455
|
+
import_fs27.default.closeSync(ttyFd);
|
|
15376
15456
|
} catch {
|
|
15377
15457
|
}
|
|
15378
15458
|
}
|
|
@@ -15406,17 +15486,17 @@ RAW: ${raw}
|
|
|
15406
15486
|
const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
|
|
15407
15487
|
if (skillPinCfg.enabled && safeSessionId) {
|
|
15408
15488
|
try {
|
|
15409
|
-
const sessionsDir =
|
|
15410
|
-
const flagPath =
|
|
15489
|
+
const sessionsDir = import_path29.default.join(import_os23.default.homedir(), ".node9", "skill-sessions");
|
|
15490
|
+
const flagPath = import_path29.default.join(sessionsDir, `${safeSessionId}.json`);
|
|
15411
15491
|
let flag = null;
|
|
15412
15492
|
try {
|
|
15413
|
-
flag = JSON.parse(
|
|
15493
|
+
flag = JSON.parse(import_fs27.default.readFileSync(flagPath, "utf-8"));
|
|
15414
15494
|
} catch {
|
|
15415
15495
|
}
|
|
15416
15496
|
const writeFlag = (data2) => {
|
|
15417
15497
|
try {
|
|
15418
|
-
|
|
15419
|
-
|
|
15498
|
+
import_fs27.default.mkdirSync(sessionsDir, { recursive: true });
|
|
15499
|
+
import_fs27.default.writeFileSync(
|
|
15420
15500
|
flagPath,
|
|
15421
15501
|
JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
|
|
15422
15502
|
{ mode: 384 }
|
|
@@ -15427,8 +15507,8 @@ RAW: ${raw}
|
|
|
15427
15507
|
const sendSkillWarn = (detail, recoveryCmd) => {
|
|
15428
15508
|
let ttyFd = null;
|
|
15429
15509
|
try {
|
|
15430
|
-
ttyFd =
|
|
15431
|
-
const w = (line) =>
|
|
15510
|
+
ttyFd = import_fs27.default.openSync("/dev/tty", "w");
|
|
15511
|
+
const w = (line) => import_fs27.default.writeSync(ttyFd, line + "\n");
|
|
15432
15512
|
w(import_chalk6.default.yellow(`
|
|
15433
15513
|
\u26A0\uFE0F Node9: installed skill drift detected`));
|
|
15434
15514
|
w(import_chalk6.default.gray(` ${detail}`));
|
|
@@ -15443,7 +15523,7 @@ RAW: ${raw}
|
|
|
15443
15523
|
} finally {
|
|
15444
15524
|
if (ttyFd !== null)
|
|
15445
15525
|
try {
|
|
15446
|
-
|
|
15526
|
+
import_fs27.default.closeSync(ttyFd);
|
|
15447
15527
|
} catch {
|
|
15448
15528
|
}
|
|
15449
15529
|
}
|
|
@@ -15459,7 +15539,7 @@ RAW: ${raw}
|
|
|
15459
15539
|
return;
|
|
15460
15540
|
}
|
|
15461
15541
|
if (!flag || flag.state !== "verified" && flag.state !== "warned") {
|
|
15462
|
-
const absoluteCwd = typeof payload.cwd === "string" &&
|
|
15542
|
+
const absoluteCwd = typeof payload.cwd === "string" && import_path29.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
|
|
15463
15543
|
const extraRoots = skillPinCfg.roots;
|
|
15464
15544
|
const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
|
|
15465
15545
|
const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
|
|
@@ -15500,10 +15580,10 @@ RAW: ${raw}
|
|
|
15500
15580
|
}
|
|
15501
15581
|
try {
|
|
15502
15582
|
const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
15503
|
-
for (const name of
|
|
15504
|
-
const p =
|
|
15583
|
+
for (const name of import_fs27.default.readdirSync(sessionsDir)) {
|
|
15584
|
+
const p = import_path29.default.join(sessionsDir, name);
|
|
15505
15585
|
try {
|
|
15506
|
-
if (
|
|
15586
|
+
if (import_fs27.default.statSync(p).mtimeMs < cutoff) import_fs27.default.unlinkSync(p);
|
|
15507
15587
|
} catch {
|
|
15508
15588
|
}
|
|
15509
15589
|
}
|
|
@@ -15513,9 +15593,9 @@ RAW: ${raw}
|
|
|
15513
15593
|
} catch (err2) {
|
|
15514
15594
|
if (process.env.NODE9_DEBUG === "1") {
|
|
15515
15595
|
try {
|
|
15516
|
-
const dbg =
|
|
15596
|
+
const dbg = import_path29.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
|
|
15517
15597
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
15518
|
-
|
|
15598
|
+
import_fs27.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
|
|
15519
15599
|
`);
|
|
15520
15600
|
} catch {
|
|
15521
15601
|
}
|
|
@@ -15525,7 +15605,7 @@ RAW: ${raw}
|
|
|
15525
15605
|
if (shouldSnapshot(toolName, toolInput, config)) {
|
|
15526
15606
|
await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
|
|
15527
15607
|
}
|
|
15528
|
-
const safeCwdForAuth = typeof payload.cwd === "string" &&
|
|
15608
|
+
const safeCwdForAuth = typeof payload.cwd === "string" && import_path29.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
|
|
15529
15609
|
const result = await authorizeHeadless(toolName, toolInput, meta, {
|
|
15530
15610
|
cwd: safeCwdForAuth
|
|
15531
15611
|
});
|
|
@@ -15537,12 +15617,12 @@ RAW: ${raw}
|
|
|
15537
15617
|
}
|
|
15538
15618
|
if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
|
|
15539
15619
|
try {
|
|
15540
|
-
const tty =
|
|
15541
|
-
|
|
15620
|
+
const tty = import_fs27.default.openSync("/dev/tty", "w");
|
|
15621
|
+
import_fs27.default.writeSync(
|
|
15542
15622
|
tty,
|
|
15543
15623
|
import_chalk6.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
|
|
15544
15624
|
);
|
|
15545
|
-
|
|
15625
|
+
import_fs27.default.closeSync(tty);
|
|
15546
15626
|
} catch {
|
|
15547
15627
|
}
|
|
15548
15628
|
const daemonReady = await autoStartDaemonAndWait();
|
|
@@ -15569,9 +15649,9 @@ RAW: ${raw}
|
|
|
15569
15649
|
});
|
|
15570
15650
|
} catch (err2) {
|
|
15571
15651
|
if (process.env.NODE9_DEBUG === "1") {
|
|
15572
|
-
const logPath =
|
|
15652
|
+
const logPath = import_path29.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
|
|
15573
15653
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
15574
|
-
|
|
15654
|
+
import_fs27.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
|
|
15575
15655
|
`);
|
|
15576
15656
|
}
|
|
15577
15657
|
process.exit(0);
|
|
@@ -15605,8 +15685,8 @@ RAW: ${raw}
|
|
|
15605
15685
|
}
|
|
15606
15686
|
|
|
15607
15687
|
// src/cli/commands/log.ts
|
|
15608
|
-
var
|
|
15609
|
-
var
|
|
15688
|
+
var import_fs28 = __toESM(require("fs"));
|
|
15689
|
+
var import_path30 = __toESM(require("path"));
|
|
15610
15690
|
var import_os24 = __toESM(require("os"));
|
|
15611
15691
|
init_audit();
|
|
15612
15692
|
init_config();
|
|
@@ -15682,10 +15762,10 @@ function registerLogCommand(program2) {
|
|
|
15682
15762
|
decision: "allowed",
|
|
15683
15763
|
source: "post-hook"
|
|
15684
15764
|
};
|
|
15685
|
-
const logPath =
|
|
15686
|
-
if (!
|
|
15687
|
-
|
|
15688
|
-
|
|
15765
|
+
const logPath = import_path30.default.join(import_os24.default.homedir(), ".node9", "audit.log");
|
|
15766
|
+
if (!import_fs28.default.existsSync(import_path30.default.dirname(logPath)))
|
|
15767
|
+
import_fs28.default.mkdirSync(import_path30.default.dirname(logPath), { recursive: true });
|
|
15768
|
+
import_fs28.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
|
|
15689
15769
|
if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
|
|
15690
15770
|
const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
15691
15771
|
if (command) {
|
|
@@ -15718,7 +15798,7 @@ function registerLogCommand(program2) {
|
|
|
15718
15798
|
}
|
|
15719
15799
|
}
|
|
15720
15800
|
}
|
|
15721
|
-
const safeCwd = typeof payload.cwd === "string" &&
|
|
15801
|
+
const safeCwd = typeof payload.cwd === "string" && import_path30.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
|
|
15722
15802
|
const config = getConfig(safeCwd);
|
|
15723
15803
|
if ((tool === "Bash" || tool === "bash") && config.settings.enableUndo !== false) {
|
|
15724
15804
|
const bashCommand = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
@@ -15739,9 +15819,9 @@ function registerLogCommand(program2) {
|
|
|
15739
15819
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
15740
15820
|
process.stderr.write(`[Node9] audit log error: ${msg}
|
|
15741
15821
|
`);
|
|
15742
|
-
const debugPath =
|
|
15822
|
+
const debugPath = import_path30.default.join(import_os24.default.homedir(), ".node9", "hook-debug.log");
|
|
15743
15823
|
try {
|
|
15744
|
-
|
|
15824
|
+
import_fs28.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
|
|
15745
15825
|
`);
|
|
15746
15826
|
} catch {
|
|
15747
15827
|
}
|
|
@@ -16141,8 +16221,8 @@ function registerConfigShowCommand(program2) {
|
|
|
16141
16221
|
|
|
16142
16222
|
// src/cli/commands/doctor.ts
|
|
16143
16223
|
var import_chalk8 = __toESM(require("chalk"));
|
|
16144
|
-
var
|
|
16145
|
-
var
|
|
16224
|
+
var import_fs29 = __toESM(require("fs"));
|
|
16225
|
+
var import_path31 = __toESM(require("path"));
|
|
16146
16226
|
var import_os25 = __toESM(require("os"));
|
|
16147
16227
|
var import_child_process11 = require("child_process");
|
|
16148
16228
|
init_daemon();
|
|
@@ -16197,10 +16277,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16197
16277
|
);
|
|
16198
16278
|
}
|
|
16199
16279
|
section("Configuration");
|
|
16200
|
-
const globalConfigPath =
|
|
16201
|
-
if (
|
|
16280
|
+
const globalConfigPath = import_path31.default.join(homeDir2, ".node9", "config.json");
|
|
16281
|
+
if (import_fs29.default.existsSync(globalConfigPath)) {
|
|
16202
16282
|
try {
|
|
16203
|
-
JSON.parse(
|
|
16283
|
+
JSON.parse(import_fs29.default.readFileSync(globalConfigPath, "utf-8"));
|
|
16204
16284
|
pass("~/.node9/config.json found and valid");
|
|
16205
16285
|
} catch {
|
|
16206
16286
|
fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
|
|
@@ -16208,10 +16288,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16208
16288
|
} else {
|
|
16209
16289
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
16210
16290
|
}
|
|
16211
|
-
const projectConfigPath =
|
|
16212
|
-
if (
|
|
16291
|
+
const projectConfigPath = import_path31.default.join(process.cwd(), "node9.config.json");
|
|
16292
|
+
if (import_fs29.default.existsSync(projectConfigPath)) {
|
|
16213
16293
|
try {
|
|
16214
|
-
JSON.parse(
|
|
16294
|
+
JSON.parse(import_fs29.default.readFileSync(projectConfigPath, "utf-8"));
|
|
16215
16295
|
pass("node9.config.json found and valid (project)");
|
|
16216
16296
|
} catch {
|
|
16217
16297
|
fail(
|
|
@@ -16220,8 +16300,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16220
16300
|
);
|
|
16221
16301
|
}
|
|
16222
16302
|
}
|
|
16223
|
-
const credsPath =
|
|
16224
|
-
if (
|
|
16303
|
+
const credsPath = import_path31.default.join(homeDir2, ".node9", "credentials.json");
|
|
16304
|
+
if (import_fs29.default.existsSync(credsPath)) {
|
|
16225
16305
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
16226
16306
|
} else {
|
|
16227
16307
|
warn(
|
|
@@ -16230,10 +16310,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16230
16310
|
);
|
|
16231
16311
|
}
|
|
16232
16312
|
section("Agent Hooks");
|
|
16233
|
-
const claudeSettingsPath =
|
|
16234
|
-
if (
|
|
16313
|
+
const claudeSettingsPath = import_path31.default.join(homeDir2, ".claude", "settings.json");
|
|
16314
|
+
if (import_fs29.default.existsSync(claudeSettingsPath)) {
|
|
16235
16315
|
try {
|
|
16236
|
-
const cs = JSON.parse(
|
|
16316
|
+
const cs = JSON.parse(import_fs29.default.readFileSync(claudeSettingsPath, "utf-8"));
|
|
16237
16317
|
const hasHook = cs.hooks?.PreToolUse?.some(
|
|
16238
16318
|
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
16239
16319
|
);
|
|
@@ -16249,10 +16329,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16249
16329
|
} else {
|
|
16250
16330
|
warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
|
|
16251
16331
|
}
|
|
16252
|
-
const geminiSettingsPath =
|
|
16253
|
-
if (
|
|
16332
|
+
const geminiSettingsPath = import_path31.default.join(homeDir2, ".gemini", "settings.json");
|
|
16333
|
+
if (import_fs29.default.existsSync(geminiSettingsPath)) {
|
|
16254
16334
|
try {
|
|
16255
|
-
const gs = JSON.parse(
|
|
16335
|
+
const gs = JSON.parse(import_fs29.default.readFileSync(geminiSettingsPath, "utf-8"));
|
|
16256
16336
|
const hasHook = gs.hooks?.BeforeTool?.some(
|
|
16257
16337
|
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
16258
16338
|
);
|
|
@@ -16268,10 +16348,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16268
16348
|
} else {
|
|
16269
16349
|
warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
|
|
16270
16350
|
}
|
|
16271
|
-
const cursorHooksPath =
|
|
16272
|
-
if (
|
|
16351
|
+
const cursorHooksPath = import_path31.default.join(homeDir2, ".cursor", "hooks.json");
|
|
16352
|
+
if (import_fs29.default.existsSync(cursorHooksPath)) {
|
|
16273
16353
|
try {
|
|
16274
|
-
const cur = JSON.parse(
|
|
16354
|
+
const cur = JSON.parse(import_fs29.default.readFileSync(cursorHooksPath, "utf-8"));
|
|
16275
16355
|
const hasHook = cur.hooks?.preToolUse?.some(
|
|
16276
16356
|
(h) => h.command?.includes("node9") || h.command?.includes("cli.js")
|
|
16277
16357
|
);
|
|
@@ -16309,8 +16389,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16309
16389
|
|
|
16310
16390
|
// src/cli/commands/audit.ts
|
|
16311
16391
|
var import_chalk9 = __toESM(require("chalk"));
|
|
16312
|
-
var
|
|
16313
|
-
var
|
|
16392
|
+
var import_fs30 = __toESM(require("fs"));
|
|
16393
|
+
var import_path32 = __toESM(require("path"));
|
|
16314
16394
|
var import_os26 = __toESM(require("os"));
|
|
16315
16395
|
function formatRelativeTime(timestamp) {
|
|
16316
16396
|
const diff = Date.now() - new Date(timestamp).getTime();
|
|
@@ -16324,14 +16404,14 @@ function formatRelativeTime(timestamp) {
|
|
|
16324
16404
|
}
|
|
16325
16405
|
function registerAuditCommand(program2) {
|
|
16326
16406
|
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) => {
|
|
16327
|
-
const logPath =
|
|
16328
|
-
if (!
|
|
16407
|
+
const logPath = import_path32.default.join(import_os26.default.homedir(), ".node9", "audit.log");
|
|
16408
|
+
if (!import_fs30.default.existsSync(logPath)) {
|
|
16329
16409
|
console.log(
|
|
16330
16410
|
import_chalk9.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
16331
16411
|
);
|
|
16332
16412
|
return;
|
|
16333
16413
|
}
|
|
16334
|
-
const raw =
|
|
16414
|
+
const raw = import_fs30.default.readFileSync(logPath, "utf-8");
|
|
16335
16415
|
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
16336
16416
|
let entries = lines.flatMap((line) => {
|
|
16337
16417
|
try {
|
|
@@ -16385,8 +16465,8 @@ function registerAuditCommand(program2) {
|
|
|
16385
16465
|
|
|
16386
16466
|
// src/cli/commands/report.ts
|
|
16387
16467
|
var import_chalk10 = __toESM(require("chalk"));
|
|
16388
|
-
var
|
|
16389
|
-
var
|
|
16468
|
+
var import_fs31 = __toESM(require("fs"));
|
|
16469
|
+
var import_path33 = __toESM(require("path"));
|
|
16390
16470
|
var import_os27 = __toESM(require("os"));
|
|
16391
16471
|
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;
|
|
16392
16472
|
function buildTestTimestamps(allEntries) {
|
|
@@ -16434,8 +16514,8 @@ function getDateRange(period) {
|
|
|
16434
16514
|
}
|
|
16435
16515
|
}
|
|
16436
16516
|
function parseAuditLog(logPath) {
|
|
16437
|
-
if (!
|
|
16438
|
-
const raw =
|
|
16517
|
+
if (!import_fs31.default.existsSync(logPath)) return [];
|
|
16518
|
+
const raw = import_fs31.default.readFileSync(logPath, "utf-8");
|
|
16439
16519
|
return raw.split("\n").flatMap((line) => {
|
|
16440
16520
|
if (!line.trim()) return [];
|
|
16441
16521
|
try {
|
|
@@ -16514,11 +16594,11 @@ function loadClaudeCost(start, end) {
|
|
|
16514
16594
|
cacheWriteTokens: 0,
|
|
16515
16595
|
cacheReadTokens: 0
|
|
16516
16596
|
};
|
|
16517
|
-
const projectsDir =
|
|
16518
|
-
if (!
|
|
16597
|
+
const projectsDir = import_path33.default.join(import_os27.default.homedir(), ".claude", "projects");
|
|
16598
|
+
if (!import_fs31.default.existsSync(projectsDir)) return empty;
|
|
16519
16599
|
let dirs;
|
|
16520
16600
|
try {
|
|
16521
|
-
dirs =
|
|
16601
|
+
dirs = import_fs31.default.readdirSync(projectsDir);
|
|
16522
16602
|
} catch {
|
|
16523
16603
|
return empty;
|
|
16524
16604
|
}
|
|
@@ -16530,18 +16610,18 @@ function loadClaudeCost(start, end) {
|
|
|
16530
16610
|
const byDay = /* @__PURE__ */ new Map();
|
|
16531
16611
|
const byModel = /* @__PURE__ */ new Map();
|
|
16532
16612
|
for (const proj of dirs) {
|
|
16533
|
-
const projPath =
|
|
16613
|
+
const projPath = import_path33.default.join(projectsDir, proj);
|
|
16534
16614
|
let files;
|
|
16535
16615
|
try {
|
|
16536
|
-
const stat =
|
|
16616
|
+
const stat = import_fs31.default.statSync(projPath);
|
|
16537
16617
|
if (!stat.isDirectory()) continue;
|
|
16538
|
-
files =
|
|
16618
|
+
files = import_fs31.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
16539
16619
|
} catch {
|
|
16540
16620
|
continue;
|
|
16541
16621
|
}
|
|
16542
16622
|
for (const file of files) {
|
|
16543
16623
|
try {
|
|
16544
|
-
const raw =
|
|
16624
|
+
const raw = import_fs31.default.readFileSync(import_path33.default.join(projPath, file), "utf-8");
|
|
16545
16625
|
for (const line of raw.split("\n")) {
|
|
16546
16626
|
if (!line.trim()) continue;
|
|
16547
16627
|
let entry;
|
|
@@ -16582,36 +16662,36 @@ function loadClaudeCost(start, end) {
|
|
|
16582
16662
|
return { total, byDay, byModel, inputTokens, outputTokens, cacheWriteTokens, cacheReadTokens };
|
|
16583
16663
|
}
|
|
16584
16664
|
function loadCodexCost(start, end) {
|
|
16585
|
-
const sessionsBase =
|
|
16665
|
+
const sessionsBase = import_path33.default.join(import_os27.default.homedir(), ".codex", "sessions");
|
|
16586
16666
|
const byDay = /* @__PURE__ */ new Map();
|
|
16587
16667
|
let total = 0;
|
|
16588
16668
|
let toolCalls = 0;
|
|
16589
|
-
if (!
|
|
16669
|
+
if (!import_fs31.default.existsSync(sessionsBase)) return { total, byDay, toolCalls };
|
|
16590
16670
|
const jsonlFiles = [];
|
|
16591
16671
|
try {
|
|
16592
|
-
for (const year of
|
|
16593
|
-
const yearPath =
|
|
16672
|
+
for (const year of import_fs31.default.readdirSync(sessionsBase)) {
|
|
16673
|
+
const yearPath = import_path33.default.join(sessionsBase, year);
|
|
16594
16674
|
try {
|
|
16595
|
-
if (!
|
|
16675
|
+
if (!import_fs31.default.statSync(yearPath).isDirectory()) continue;
|
|
16596
16676
|
} catch {
|
|
16597
16677
|
continue;
|
|
16598
16678
|
}
|
|
16599
|
-
for (const month of
|
|
16600
|
-
const monthPath =
|
|
16679
|
+
for (const month of import_fs31.default.readdirSync(yearPath)) {
|
|
16680
|
+
const monthPath = import_path33.default.join(yearPath, month);
|
|
16601
16681
|
try {
|
|
16602
|
-
if (!
|
|
16682
|
+
if (!import_fs31.default.statSync(monthPath).isDirectory()) continue;
|
|
16603
16683
|
} catch {
|
|
16604
16684
|
continue;
|
|
16605
16685
|
}
|
|
16606
|
-
for (const day of
|
|
16607
|
-
const dayPath =
|
|
16686
|
+
for (const day of import_fs31.default.readdirSync(monthPath)) {
|
|
16687
|
+
const dayPath = import_path33.default.join(monthPath, day);
|
|
16608
16688
|
try {
|
|
16609
|
-
if (!
|
|
16689
|
+
if (!import_fs31.default.statSync(dayPath).isDirectory()) continue;
|
|
16610
16690
|
} catch {
|
|
16611
16691
|
continue;
|
|
16612
16692
|
}
|
|
16613
|
-
for (const file of
|
|
16614
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
16693
|
+
for (const file of import_fs31.default.readdirSync(dayPath)) {
|
|
16694
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path33.default.join(dayPath, file));
|
|
16615
16695
|
}
|
|
16616
16696
|
}
|
|
16617
16697
|
}
|
|
@@ -16622,7 +16702,7 @@ function loadCodexCost(start, end) {
|
|
|
16622
16702
|
for (const filePath of jsonlFiles) {
|
|
16623
16703
|
let lines;
|
|
16624
16704
|
try {
|
|
16625
|
-
lines =
|
|
16705
|
+
lines = import_fs31.default.readFileSync(filePath, "utf-8").split("\n");
|
|
16626
16706
|
} catch {
|
|
16627
16707
|
continue;
|
|
16628
16708
|
}
|
|
@@ -16672,7 +16752,7 @@ function registerReportCommand(program2) {
|
|
|
16672
16752
|
const period = ["today", "7d", "30d", "month"].includes(
|
|
16673
16753
|
options.period
|
|
16674
16754
|
) ? options.period : "7d";
|
|
16675
|
-
const logPath =
|
|
16755
|
+
const logPath = import_path33.default.join(import_os27.default.homedir(), ".node9", "audit.log");
|
|
16676
16756
|
const allEntries = parseAuditLog(logPath);
|
|
16677
16757
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
16678
16758
|
if (unackedDlp.length > 0) {
|
|
@@ -17177,14 +17257,14 @@ function registerDaemonCommand(program2) {
|
|
|
17177
17257
|
|
|
17178
17258
|
// src/cli/commands/status.ts
|
|
17179
17259
|
var import_chalk12 = __toESM(require("chalk"));
|
|
17180
|
-
var
|
|
17181
|
-
var
|
|
17260
|
+
var import_fs32 = __toESM(require("fs"));
|
|
17261
|
+
var import_path34 = __toESM(require("path"));
|
|
17182
17262
|
var import_os28 = __toESM(require("os"));
|
|
17183
17263
|
init_core();
|
|
17184
17264
|
init_daemon();
|
|
17185
17265
|
function readJson2(filePath) {
|
|
17186
17266
|
try {
|
|
17187
|
-
if (
|
|
17267
|
+
if (import_fs32.default.existsSync(filePath)) return JSON.parse(import_fs32.default.readFileSync(filePath, "utf-8"));
|
|
17188
17268
|
} catch {
|
|
17189
17269
|
}
|
|
17190
17270
|
return null;
|
|
@@ -17249,13 +17329,13 @@ function registerStatusCommand(program2) {
|
|
|
17249
17329
|
console.log("");
|
|
17250
17330
|
const modeLabel = settings.mode === "audit" ? import_chalk12.default.blue("audit") : settings.mode === "strict" ? import_chalk12.default.red("strict") : import_chalk12.default.white("standard");
|
|
17251
17331
|
console.log(` Mode: ${modeLabel}`);
|
|
17252
|
-
const projectConfig =
|
|
17253
|
-
const globalConfig =
|
|
17332
|
+
const projectConfig = import_path34.default.join(process.cwd(), "node9.config.json");
|
|
17333
|
+
const globalConfig = import_path34.default.join(import_os28.default.homedir(), ".node9", "config.json");
|
|
17254
17334
|
console.log(
|
|
17255
|
-
` Local: ${
|
|
17335
|
+
` Local: ${import_fs32.default.existsSync(projectConfig) ? import_chalk12.default.green("Active (node9.config.json)") : import_chalk12.default.gray("Not present")}`
|
|
17256
17336
|
);
|
|
17257
17337
|
console.log(
|
|
17258
|
-
` Global: ${
|
|
17338
|
+
` Global: ${import_fs32.default.existsSync(globalConfig) ? import_chalk12.default.green("Active (~/.node9/config.json)") : import_chalk12.default.gray("Not present")}`
|
|
17259
17339
|
);
|
|
17260
17340
|
if (mergedConfig.policy.sandboxPaths.length > 0) {
|
|
17261
17341
|
console.log(
|
|
@@ -17264,13 +17344,13 @@ function registerStatusCommand(program2) {
|
|
|
17264
17344
|
}
|
|
17265
17345
|
const homeDir2 = import_os28.default.homedir();
|
|
17266
17346
|
const claudeSettings = readJson2(
|
|
17267
|
-
|
|
17347
|
+
import_path34.default.join(homeDir2, ".claude", "settings.json")
|
|
17268
17348
|
);
|
|
17269
|
-
const claudeConfig = readJson2(
|
|
17349
|
+
const claudeConfig = readJson2(import_path34.default.join(homeDir2, ".claude.json"));
|
|
17270
17350
|
const geminiSettings = readJson2(
|
|
17271
|
-
|
|
17351
|
+
import_path34.default.join(homeDir2, ".gemini", "settings.json")
|
|
17272
17352
|
);
|
|
17273
|
-
const cursorConfig = readJson2(
|
|
17353
|
+
const cursorConfig = readJson2(import_path34.default.join(homeDir2, ".cursor", "mcp.json"));
|
|
17274
17354
|
const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig;
|
|
17275
17355
|
if (agentFound) {
|
|
17276
17356
|
console.log("");
|
|
@@ -17329,8 +17409,8 @@ function registerStatusCommand(program2) {
|
|
|
17329
17409
|
|
|
17330
17410
|
// src/cli/commands/init.ts
|
|
17331
17411
|
var import_chalk13 = __toESM(require("chalk"));
|
|
17332
|
-
var
|
|
17333
|
-
var
|
|
17412
|
+
var import_fs33 = __toESM(require("fs"));
|
|
17413
|
+
var import_path35 = __toESM(require("path"));
|
|
17334
17414
|
var import_os29 = __toESM(require("os"));
|
|
17335
17415
|
var import_https3 = __toESM(require("https"));
|
|
17336
17416
|
init_core();
|
|
@@ -17392,15 +17472,15 @@ function registerInitCommand(program2) {
|
|
|
17392
17472
|
}
|
|
17393
17473
|
console.log("");
|
|
17394
17474
|
}
|
|
17395
|
-
const configPath =
|
|
17396
|
-
if (
|
|
17475
|
+
const configPath = import_path35.default.join(import_os29.default.homedir(), ".node9", "config.json");
|
|
17476
|
+
if (import_fs33.default.existsSync(configPath) && !options.force) {
|
|
17397
17477
|
try {
|
|
17398
|
-
const existing = JSON.parse(
|
|
17478
|
+
const existing = JSON.parse(import_fs33.default.readFileSync(configPath, "utf-8"));
|
|
17399
17479
|
const settings = existing.settings ?? {};
|
|
17400
17480
|
if (settings.mode !== chosenMode) {
|
|
17401
17481
|
settings.mode = chosenMode;
|
|
17402
17482
|
existing.settings = settings;
|
|
17403
|
-
|
|
17483
|
+
import_fs33.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
|
|
17404
17484
|
console.log(import_chalk13.default.green(`\u2705 Mode updated: ${chosenMode}`));
|
|
17405
17485
|
} else {
|
|
17406
17486
|
console.log(import_chalk13.default.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
|
|
@@ -17413,9 +17493,9 @@ function registerInitCommand(program2) {
|
|
|
17413
17493
|
...DEFAULT_CONFIG,
|
|
17414
17494
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
17415
17495
|
};
|
|
17416
|
-
const dir =
|
|
17417
|
-
if (!
|
|
17418
|
-
|
|
17496
|
+
const dir = import_path35.default.dirname(configPath);
|
|
17497
|
+
if (!import_fs33.default.existsSync(dir)) import_fs33.default.mkdirSync(dir, { recursive: true });
|
|
17498
|
+
import_fs33.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
|
|
17419
17499
|
console.log(import_chalk13.default.green(`\u2705 Config created: ${configPath}`));
|
|
17420
17500
|
console.log(import_chalk13.default.gray(` Mode: ${chosenMode}`));
|
|
17421
17501
|
}
|
|
@@ -17500,7 +17580,7 @@ function registerInitCommand(program2) {
|
|
|
17500
17580
|
}
|
|
17501
17581
|
|
|
17502
17582
|
// src/cli/commands/undo.ts
|
|
17503
|
-
var
|
|
17583
|
+
var import_path36 = __toESM(require("path"));
|
|
17504
17584
|
var import_chalk15 = __toESM(require("chalk"));
|
|
17505
17585
|
|
|
17506
17586
|
// src/tui/undo-navigator.ts
|
|
@@ -17659,7 +17739,7 @@ function findMatchingCwd(startDir, history) {
|
|
|
17659
17739
|
let dir = startDir;
|
|
17660
17740
|
while (true) {
|
|
17661
17741
|
if (cwds.has(dir)) return dir;
|
|
17662
|
-
const parent =
|
|
17742
|
+
const parent = import_path36.default.dirname(dir);
|
|
17663
17743
|
if (parent === dir) return null;
|
|
17664
17744
|
dir = parent;
|
|
17665
17745
|
}
|
|
@@ -17855,12 +17935,12 @@ init_orchestrator();
|
|
|
17855
17935
|
init_provenance();
|
|
17856
17936
|
|
|
17857
17937
|
// src/mcp-pin.ts
|
|
17858
|
-
var
|
|
17859
|
-
var
|
|
17938
|
+
var import_fs34 = __toESM(require("fs"));
|
|
17939
|
+
var import_path37 = __toESM(require("path"));
|
|
17860
17940
|
var import_os30 = __toESM(require("os"));
|
|
17861
17941
|
var import_crypto10 = __toESM(require("crypto"));
|
|
17862
17942
|
function getPinsFilePath2() {
|
|
17863
|
-
return
|
|
17943
|
+
return import_path37.default.join(import_os30.default.homedir(), ".node9", "mcp-pins.json");
|
|
17864
17944
|
}
|
|
17865
17945
|
function hashToolDefinitions(tools) {
|
|
17866
17946
|
const sorted = [...tools].sort((a, b) => {
|
|
@@ -17877,7 +17957,7 @@ function getServerKey(upstreamCommand) {
|
|
|
17877
17957
|
function readMcpPinsSafe() {
|
|
17878
17958
|
const filePath = getPinsFilePath2();
|
|
17879
17959
|
try {
|
|
17880
|
-
const raw =
|
|
17960
|
+
const raw = import_fs34.default.readFileSync(filePath, "utf-8");
|
|
17881
17961
|
if (!raw.trim()) {
|
|
17882
17962
|
return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
17883
17963
|
}
|
|
@@ -17901,10 +17981,10 @@ function readMcpPins() {
|
|
|
17901
17981
|
}
|
|
17902
17982
|
function writeMcpPins(data) {
|
|
17903
17983
|
const filePath = getPinsFilePath2();
|
|
17904
|
-
|
|
17984
|
+
import_fs34.default.mkdirSync(import_path37.default.dirname(filePath), { recursive: true });
|
|
17905
17985
|
const tmp = `${filePath}.${import_crypto10.default.randomBytes(6).toString("hex")}.tmp`;
|
|
17906
|
-
|
|
17907
|
-
|
|
17986
|
+
import_fs34.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
17987
|
+
import_fs34.default.renameSync(tmp, filePath);
|
|
17908
17988
|
}
|
|
17909
17989
|
function checkPin(serverKey, currentHash) {
|
|
17910
17990
|
const result = readMcpPinsSafe();
|
|
@@ -18352,9 +18432,9 @@ function registerMcpGatewayCommand(program2) {
|
|
|
18352
18432
|
|
|
18353
18433
|
// src/mcp-server/index.ts
|
|
18354
18434
|
var import_readline4 = __toESM(require("readline"));
|
|
18355
|
-
var
|
|
18435
|
+
var import_fs35 = __toESM(require("fs"));
|
|
18356
18436
|
var import_os31 = __toESM(require("os"));
|
|
18357
|
-
var
|
|
18437
|
+
var import_path38 = __toESM(require("path"));
|
|
18358
18438
|
var import_child_process15 = require("child_process");
|
|
18359
18439
|
init_core();
|
|
18360
18440
|
init_daemon();
|
|
@@ -18605,13 +18685,13 @@ function handleStatus() {
|
|
|
18605
18685
|
lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
|
|
18606
18686
|
lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
|
|
18607
18687
|
lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
|
|
18608
|
-
const projectConfig =
|
|
18609
|
-
const globalConfig =
|
|
18688
|
+
const projectConfig = import_path38.default.join(process.cwd(), "node9.config.json");
|
|
18689
|
+
const globalConfig = import_path38.default.join(import_os31.default.homedir(), ".node9", "config.json");
|
|
18610
18690
|
lines.push(
|
|
18611
|
-
`Project config (node9.config.json): ${
|
|
18691
|
+
`Project config (node9.config.json): ${import_fs35.default.existsSync(projectConfig) ? "present" : "not found"}`
|
|
18612
18692
|
);
|
|
18613
18693
|
lines.push(
|
|
18614
|
-
`Global config (~/.node9/config.json): ${
|
|
18694
|
+
`Global config (~/.node9/config.json): ${import_fs35.default.existsSync(globalConfig) ? "present" : "not found"}`
|
|
18615
18695
|
);
|
|
18616
18696
|
return lines.join("\n");
|
|
18617
18697
|
}
|
|
@@ -18685,21 +18765,21 @@ function handleShieldDisable(args) {
|
|
|
18685
18765
|
writeActiveShields(active.filter((s) => s !== name));
|
|
18686
18766
|
return `Shield "${name}" disabled.`;
|
|
18687
18767
|
}
|
|
18688
|
-
var GLOBAL_CONFIG_PATH2 =
|
|
18768
|
+
var GLOBAL_CONFIG_PATH2 = import_path38.default.join(import_os31.default.homedir(), ".node9", "config.json");
|
|
18689
18769
|
var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
|
|
18690
18770
|
function readGlobalConfigRaw() {
|
|
18691
18771
|
try {
|
|
18692
|
-
if (
|
|
18693
|
-
return JSON.parse(
|
|
18772
|
+
if (import_fs35.default.existsSync(GLOBAL_CONFIG_PATH2)) {
|
|
18773
|
+
return JSON.parse(import_fs35.default.readFileSync(GLOBAL_CONFIG_PATH2, "utf-8"));
|
|
18694
18774
|
}
|
|
18695
18775
|
} catch {
|
|
18696
18776
|
}
|
|
18697
18777
|
return {};
|
|
18698
18778
|
}
|
|
18699
18779
|
function writeGlobalConfigRaw(data) {
|
|
18700
|
-
const dir =
|
|
18701
|
-
if (!
|
|
18702
|
-
|
|
18780
|
+
const dir = import_path38.default.dirname(GLOBAL_CONFIG_PATH2);
|
|
18781
|
+
if (!import_fs35.default.existsSync(dir)) import_fs35.default.mkdirSync(dir, { recursive: true });
|
|
18782
|
+
import_fs35.default.writeFileSync(GLOBAL_CONFIG_PATH2, JSON.stringify(data, null, 2) + "\n");
|
|
18703
18783
|
}
|
|
18704
18784
|
function handleApproverList() {
|
|
18705
18785
|
const config = getConfig();
|
|
@@ -18743,9 +18823,9 @@ function handleApproverSet(args) {
|
|
|
18743
18823
|
function handleAuditGet(args) {
|
|
18744
18824
|
const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
|
|
18745
18825
|
const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
|
|
18746
|
-
const auditPath =
|
|
18747
|
-
if (!
|
|
18748
|
-
const rawLines =
|
|
18826
|
+
const auditPath = import_path38.default.join(import_os31.default.homedir(), ".node9", "audit.log");
|
|
18827
|
+
if (!import_fs35.default.existsSync(auditPath)) return "No audit log found.";
|
|
18828
|
+
const rawLines = import_fs35.default.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
|
|
18749
18829
|
const parsed = [];
|
|
18750
18830
|
for (const line of rawLines) {
|
|
18751
18831
|
try {
|
|
@@ -19299,8 +19379,8 @@ init_scan();
|
|
|
19299
19379
|
|
|
19300
19380
|
// src/cli/commands/sessions.ts
|
|
19301
19381
|
var import_chalk22 = __toESM(require("chalk"));
|
|
19302
|
-
var
|
|
19303
|
-
var
|
|
19382
|
+
var import_fs36 = __toESM(require("fs"));
|
|
19383
|
+
var import_path39 = __toESM(require("path"));
|
|
19304
19384
|
var import_os32 = __toESM(require("os"));
|
|
19305
19385
|
var CLAUDE_PRICING3 = {
|
|
19306
19386
|
"claude-opus-4-6": { i: 5e-6, o: 25e-6, cw: 625e-8, cr: 5e-7 },
|
|
@@ -19342,7 +19422,7 @@ function encodeProjectPath(projectPath) {
|
|
|
19342
19422
|
}
|
|
19343
19423
|
function sessionJsonlPath(projectPath, sessionId) {
|
|
19344
19424
|
const encoded = encodeProjectPath(projectPath);
|
|
19345
|
-
return
|
|
19425
|
+
return import_path39.default.join(import_os32.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
|
|
19346
19426
|
}
|
|
19347
19427
|
function projectLabel(projectPath) {
|
|
19348
19428
|
return projectPath.replace(import_os32.default.homedir(), "~");
|
|
@@ -19414,10 +19494,10 @@ function parseSessionLines(lines) {
|
|
|
19414
19494
|
return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
|
|
19415
19495
|
}
|
|
19416
19496
|
function loadAuditEntries(auditPath) {
|
|
19417
|
-
const aPath = auditPath ??
|
|
19497
|
+
const aPath = auditPath ?? import_path39.default.join(import_os32.default.homedir(), ".node9", "audit.log");
|
|
19418
19498
|
let raw;
|
|
19419
19499
|
try {
|
|
19420
|
-
raw =
|
|
19500
|
+
raw = import_fs36.default.readFileSync(aPath, "utf-8");
|
|
19421
19501
|
} catch {
|
|
19422
19502
|
return [];
|
|
19423
19503
|
}
|
|
@@ -19453,8 +19533,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
19453
19533
|
return result;
|
|
19454
19534
|
}
|
|
19455
19535
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
19456
|
-
const tmpDir =
|
|
19457
|
-
if (!
|
|
19536
|
+
const tmpDir = import_path39.default.join(import_os32.default.homedir(), ".gemini", "tmp");
|
|
19537
|
+
if (!import_fs36.default.existsSync(tmpDir)) return [];
|
|
19458
19538
|
const cutoff = days !== null ? (() => {
|
|
19459
19539
|
const d = /* @__PURE__ */ new Date();
|
|
19460
19540
|
d.setDate(d.getDate() - days);
|
|
@@ -19463,35 +19543,35 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
19463
19543
|
})() : null;
|
|
19464
19544
|
let slugDirs;
|
|
19465
19545
|
try {
|
|
19466
|
-
slugDirs =
|
|
19546
|
+
slugDirs = import_fs36.default.readdirSync(tmpDir);
|
|
19467
19547
|
} catch {
|
|
19468
19548
|
return [];
|
|
19469
19549
|
}
|
|
19470
19550
|
const summaries = [];
|
|
19471
19551
|
for (const slug of slugDirs) {
|
|
19472
|
-
const slugPath =
|
|
19552
|
+
const slugPath = import_path39.default.join(tmpDir, slug);
|
|
19473
19553
|
try {
|
|
19474
|
-
if (!
|
|
19554
|
+
if (!import_fs36.default.statSync(slugPath).isDirectory()) continue;
|
|
19475
19555
|
} catch {
|
|
19476
19556
|
continue;
|
|
19477
19557
|
}
|
|
19478
|
-
let projectRoot =
|
|
19558
|
+
let projectRoot = import_path39.default.join(import_os32.default.homedir(), slug);
|
|
19479
19559
|
try {
|
|
19480
|
-
projectRoot =
|
|
19560
|
+
projectRoot = import_fs36.default.readFileSync(import_path39.default.join(slugPath, ".project_root"), "utf-8").trim();
|
|
19481
19561
|
} catch {
|
|
19482
19562
|
}
|
|
19483
|
-
const chatsDir =
|
|
19484
|
-
if (!
|
|
19563
|
+
const chatsDir = import_path39.default.join(slugPath, "chats");
|
|
19564
|
+
if (!import_fs36.default.existsSync(chatsDir)) continue;
|
|
19485
19565
|
let chatFiles;
|
|
19486
19566
|
try {
|
|
19487
|
-
chatFiles =
|
|
19567
|
+
chatFiles = import_fs36.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
19488
19568
|
} catch {
|
|
19489
19569
|
continue;
|
|
19490
19570
|
}
|
|
19491
19571
|
for (const chatFile of chatFiles) {
|
|
19492
19572
|
let raw;
|
|
19493
19573
|
try {
|
|
19494
|
-
raw =
|
|
19574
|
+
raw = import_fs36.default.readFileSync(import_path39.default.join(chatsDir, chatFile), "utf-8");
|
|
19495
19575
|
} catch {
|
|
19496
19576
|
continue;
|
|
19497
19577
|
}
|
|
@@ -19571,8 +19651,8 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
19571
19651
|
return summaries;
|
|
19572
19652
|
}
|
|
19573
19653
|
function buildCodexSessions(days, allAuditEntries) {
|
|
19574
|
-
const sessionsBase =
|
|
19575
|
-
if (!
|
|
19654
|
+
const sessionsBase = import_path39.default.join(import_os32.default.homedir(), ".codex", "sessions");
|
|
19655
|
+
if (!import_fs36.default.existsSync(sessionsBase)) return [];
|
|
19576
19656
|
const cutoff = days !== null ? (() => {
|
|
19577
19657
|
const d = /* @__PURE__ */ new Date();
|
|
19578
19658
|
d.setDate(d.getDate() - days);
|
|
@@ -19581,29 +19661,29 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
19581
19661
|
})() : null;
|
|
19582
19662
|
const jsonlFiles = [];
|
|
19583
19663
|
try {
|
|
19584
|
-
for (const year of
|
|
19585
|
-
const yearPath =
|
|
19664
|
+
for (const year of import_fs36.default.readdirSync(sessionsBase)) {
|
|
19665
|
+
const yearPath = import_path39.default.join(sessionsBase, year);
|
|
19586
19666
|
try {
|
|
19587
|
-
if (!
|
|
19667
|
+
if (!import_fs36.default.statSync(yearPath).isDirectory()) continue;
|
|
19588
19668
|
} catch {
|
|
19589
19669
|
continue;
|
|
19590
19670
|
}
|
|
19591
|
-
for (const month of
|
|
19592
|
-
const monthPath =
|
|
19671
|
+
for (const month of import_fs36.default.readdirSync(yearPath)) {
|
|
19672
|
+
const monthPath = import_path39.default.join(yearPath, month);
|
|
19593
19673
|
try {
|
|
19594
|
-
if (!
|
|
19674
|
+
if (!import_fs36.default.statSync(monthPath).isDirectory()) continue;
|
|
19595
19675
|
} catch {
|
|
19596
19676
|
continue;
|
|
19597
19677
|
}
|
|
19598
|
-
for (const day of
|
|
19599
|
-
const dayPath =
|
|
19678
|
+
for (const day of import_fs36.default.readdirSync(monthPath)) {
|
|
19679
|
+
const dayPath = import_path39.default.join(monthPath, day);
|
|
19600
19680
|
try {
|
|
19601
|
-
if (!
|
|
19681
|
+
if (!import_fs36.default.statSync(dayPath).isDirectory()) continue;
|
|
19602
19682
|
} catch {
|
|
19603
19683
|
continue;
|
|
19604
19684
|
}
|
|
19605
|
-
for (const file of
|
|
19606
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
19685
|
+
for (const file of import_fs36.default.readdirSync(dayPath)) {
|
|
19686
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path39.default.join(dayPath, file));
|
|
19607
19687
|
}
|
|
19608
19688
|
}
|
|
19609
19689
|
}
|
|
@@ -19615,7 +19695,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
19615
19695
|
for (const filePath of jsonlFiles) {
|
|
19616
19696
|
let lines;
|
|
19617
19697
|
try {
|
|
19618
|
-
lines =
|
|
19698
|
+
lines = import_fs36.default.readFileSync(filePath, "utf-8").split("\n");
|
|
19619
19699
|
} catch {
|
|
19620
19700
|
continue;
|
|
19621
19701
|
}
|
|
@@ -19693,10 +19773,10 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
19693
19773
|
return summaries;
|
|
19694
19774
|
}
|
|
19695
19775
|
function buildSessions(days, historyPath) {
|
|
19696
|
-
const hPath = historyPath ??
|
|
19776
|
+
const hPath = historyPath ?? import_path39.default.join(import_os32.default.homedir(), ".claude", "history.jsonl");
|
|
19697
19777
|
let historyRaw;
|
|
19698
19778
|
try {
|
|
19699
|
-
historyRaw =
|
|
19779
|
+
historyRaw = import_fs36.default.readFileSync(hPath, "utf-8");
|
|
19700
19780
|
} catch {
|
|
19701
19781
|
return [];
|
|
19702
19782
|
}
|
|
@@ -19721,7 +19801,7 @@ function buildSessions(days, historyPath) {
|
|
|
19721
19801
|
const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
|
|
19722
19802
|
let sessionLines = [];
|
|
19723
19803
|
try {
|
|
19724
|
-
sessionLines =
|
|
19804
|
+
sessionLines = import_fs36.default.readFileSync(jsonlFile, "utf-8").split("\n");
|
|
19725
19805
|
} catch {
|
|
19726
19806
|
}
|
|
19727
19807
|
const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
|
|
@@ -19987,8 +20067,8 @@ function registerSessionsCommand(program2) {
|
|
|
19987
20067
|
console.log("");
|
|
19988
20068
|
console.log(import_chalk22.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk22.default.dim(" \u2014 what your AI agent did"));
|
|
19989
20069
|
console.log("");
|
|
19990
|
-
const historyPath =
|
|
19991
|
-
if (!
|
|
20070
|
+
const historyPath = import_path39.default.join(import_os32.default.homedir(), ".claude", "history.jsonl");
|
|
20071
|
+
if (!import_fs36.default.existsSync(historyPath)) {
|
|
19992
20072
|
console.log(import_chalk22.default.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
|
|
19993
20073
|
console.log(import_chalk22.default.gray(" Install Claude Code, run a few sessions, then try again.\n"));
|
|
19994
20074
|
return;
|
|
@@ -20025,12 +20105,12 @@ function registerSessionsCommand(program2) {
|
|
|
20025
20105
|
|
|
20026
20106
|
// src/cli/commands/skill-pin.ts
|
|
20027
20107
|
var import_chalk23 = __toESM(require("chalk"));
|
|
20028
|
-
var
|
|
20108
|
+
var import_fs37 = __toESM(require("fs"));
|
|
20029
20109
|
var import_os33 = __toESM(require("os"));
|
|
20030
|
-
var
|
|
20110
|
+
var import_path40 = __toESM(require("path"));
|
|
20031
20111
|
function wipeSkillSessions() {
|
|
20032
20112
|
try {
|
|
20033
|
-
|
|
20113
|
+
import_fs37.default.rmSync(import_path40.default.join(import_os33.default.homedir(), ".node9", "skill-sessions"), {
|
|
20034
20114
|
recursive: true,
|
|
20035
20115
|
force: true
|
|
20036
20116
|
});
|
|
@@ -20113,18 +20193,18 @@ function registerSkillPinCommand(program2) {
|
|
|
20113
20193
|
|
|
20114
20194
|
// src/cli/commands/dlp.ts
|
|
20115
20195
|
var import_chalk24 = __toESM(require("chalk"));
|
|
20116
|
-
var
|
|
20117
|
-
var
|
|
20196
|
+
var import_fs38 = __toESM(require("fs"));
|
|
20197
|
+
var import_path41 = __toESM(require("path"));
|
|
20118
20198
|
var import_os34 = __toESM(require("os"));
|
|
20119
|
-
var AUDIT_LOG =
|
|
20120
|
-
var RESOLVED_FILE =
|
|
20199
|
+
var AUDIT_LOG = import_path41.default.join(import_os34.default.homedir(), ".node9", "audit.log");
|
|
20200
|
+
var RESOLVED_FILE = import_path41.default.join(import_os34.default.homedir(), ".node9", "dlp-resolved.json");
|
|
20121
20201
|
var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
|
|
20122
20202
|
function stripAnsi(s) {
|
|
20123
20203
|
return s.replace(ANSI_RE, "");
|
|
20124
20204
|
}
|
|
20125
20205
|
function loadResolved() {
|
|
20126
20206
|
try {
|
|
20127
|
-
const raw = JSON.parse(
|
|
20207
|
+
const raw = JSON.parse(import_fs38.default.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
20128
20208
|
return new Set(raw);
|
|
20129
20209
|
} catch {
|
|
20130
20210
|
return /* @__PURE__ */ new Set();
|
|
@@ -20132,13 +20212,13 @@ function loadResolved() {
|
|
|
20132
20212
|
}
|
|
20133
20213
|
function saveResolved(resolved) {
|
|
20134
20214
|
try {
|
|
20135
|
-
|
|
20215
|
+
import_fs38.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
20136
20216
|
} catch {
|
|
20137
20217
|
}
|
|
20138
20218
|
}
|
|
20139
20219
|
function loadDlpFindings() {
|
|
20140
|
-
if (!
|
|
20141
|
-
return
|
|
20220
|
+
if (!import_fs38.default.existsSync(AUDIT_LOG)) return [];
|
|
20221
|
+
return import_fs38.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
20142
20222
|
if (!line.trim()) return [];
|
|
20143
20223
|
try {
|
|
20144
20224
|
const e = JSON.parse(line);
|
|
@@ -20236,20 +20316,20 @@ function registerDlpCommand(program2) {
|
|
|
20236
20316
|
|
|
20237
20317
|
// src/cli.ts
|
|
20238
20318
|
var { version } = JSON.parse(
|
|
20239
|
-
|
|
20319
|
+
import_fs41.default.readFileSync(import_path44.default.join(__dirname, "../package.json"), "utf-8")
|
|
20240
20320
|
);
|
|
20241
20321
|
var program = new import_commander.Command();
|
|
20242
20322
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
20243
20323
|
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) => {
|
|
20244
20324
|
const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
|
|
20245
|
-
const credPath =
|
|
20246
|
-
if (!
|
|
20247
|
-
|
|
20325
|
+
const credPath = import_path44.default.join(import_os37.default.homedir(), ".node9", "credentials.json");
|
|
20326
|
+
if (!import_fs41.default.existsSync(import_path44.default.dirname(credPath)))
|
|
20327
|
+
import_fs41.default.mkdirSync(import_path44.default.dirname(credPath), { recursive: true });
|
|
20248
20328
|
const profileName = options.profile || "default";
|
|
20249
20329
|
let existingCreds = {};
|
|
20250
20330
|
try {
|
|
20251
|
-
if (
|
|
20252
|
-
const raw = JSON.parse(
|
|
20331
|
+
if (import_fs41.default.existsSync(credPath)) {
|
|
20332
|
+
const raw = JSON.parse(import_fs41.default.readFileSync(credPath, "utf-8"));
|
|
20253
20333
|
if (raw.apiKey) {
|
|
20254
20334
|
existingCreds = {
|
|
20255
20335
|
default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
|
|
@@ -20261,13 +20341,13 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
20261
20341
|
} catch {
|
|
20262
20342
|
}
|
|
20263
20343
|
existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
|
|
20264
|
-
|
|
20344
|
+
import_fs41.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
|
|
20265
20345
|
if (profileName === "default") {
|
|
20266
|
-
const configPath =
|
|
20346
|
+
const configPath = import_path44.default.join(import_os37.default.homedir(), ".node9", "config.json");
|
|
20267
20347
|
let config = {};
|
|
20268
20348
|
try {
|
|
20269
|
-
if (
|
|
20270
|
-
config = JSON.parse(
|
|
20349
|
+
if (import_fs41.default.existsSync(configPath))
|
|
20350
|
+
config = JSON.parse(import_fs41.default.readFileSync(configPath, "utf-8"));
|
|
20271
20351
|
} catch {
|
|
20272
20352
|
}
|
|
20273
20353
|
if (!config.settings || typeof config.settings !== "object") config.settings = {};
|
|
@@ -20282,9 +20362,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
20282
20362
|
approvers.cloud = false;
|
|
20283
20363
|
}
|
|
20284
20364
|
s.approvers = approvers;
|
|
20285
|
-
if (!
|
|
20286
|
-
|
|
20287
|
-
|
|
20365
|
+
if (!import_fs41.default.existsSync(import_path44.default.dirname(configPath)))
|
|
20366
|
+
import_fs41.default.mkdirSync(import_path44.default.dirname(configPath), { recursive: true });
|
|
20367
|
+
import_fs41.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
20288
20368
|
}
|
|
20289
20369
|
if (options.profile && profileName !== "default") {
|
|
20290
20370
|
console.log(import_chalk26.default.green(`\u2705 Profile "${profileName}" saved`));
|
|
@@ -20421,15 +20501,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
20421
20501
|
}
|
|
20422
20502
|
}
|
|
20423
20503
|
if (options.purge) {
|
|
20424
|
-
const node9Dir =
|
|
20425
|
-
if (
|
|
20504
|
+
const node9Dir = import_path44.default.join(import_os37.default.homedir(), ".node9");
|
|
20505
|
+
if (import_fs41.default.existsSync(node9Dir)) {
|
|
20426
20506
|
const confirmed = await (0, import_prompts2.confirm)({
|
|
20427
20507
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
20428
20508
|
default: false
|
|
20429
20509
|
});
|
|
20430
20510
|
if (confirmed) {
|
|
20431
|
-
|
|
20432
|
-
if (
|
|
20511
|
+
import_fs41.default.rmSync(node9Dir, { recursive: true });
|
|
20512
|
+
if (import_fs41.default.existsSync(node9Dir)) {
|
|
20433
20513
|
console.error(
|
|
20434
20514
|
import_chalk26.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
20435
20515
|
);
|
|
@@ -20571,14 +20651,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
|
|
|
20571
20651
|
Run "node9 addto claude" to register it as the statusLine.`
|
|
20572
20652
|
).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
|
|
20573
20653
|
if (subcommand === "debug") {
|
|
20574
|
-
const flagFile =
|
|
20654
|
+
const flagFile = import_path44.default.join(import_os37.default.homedir(), ".node9", "hud-debug");
|
|
20575
20655
|
if (state === "on") {
|
|
20576
|
-
|
|
20577
|
-
|
|
20656
|
+
import_fs41.default.mkdirSync(import_path44.default.dirname(flagFile), { recursive: true });
|
|
20657
|
+
import_fs41.default.writeFileSync(flagFile, "");
|
|
20578
20658
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
20579
20659
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
20580
20660
|
} else if (state === "off") {
|
|
20581
|
-
if (
|
|
20661
|
+
if (import_fs41.default.existsSync(flagFile)) import_fs41.default.unlinkSync(flagFile);
|
|
20582
20662
|
console.log("HUD debug logging disabled.");
|
|
20583
20663
|
} else {
|
|
20584
20664
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -20690,9 +20770,9 @@ if (process.argv[2] !== "daemon") {
|
|
|
20690
20770
|
const isCheckHook = process.argv[2] === "check";
|
|
20691
20771
|
if (isCheckHook) {
|
|
20692
20772
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
20693
|
-
const logPath =
|
|
20773
|
+
const logPath = import_path44.default.join(import_os37.default.homedir(), ".node9", "hook-debug.log");
|
|
20694
20774
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
20695
|
-
|
|
20775
|
+
import_fs41.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
20696
20776
|
`);
|
|
20697
20777
|
}
|
|
20698
20778
|
process.exit(0);
|