@node9/proxy 1.12.0 → 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/dist/cli.js +435 -391
- package/dist/cli.mjs +421 -377
- package/dist/index.js +9 -1
- package/dist/index.mjs +9 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -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({
|
|
@@ -8306,20 +8316,32 @@ function openBrowserLocal() {
|
|
|
8306
8316
|
async function autoStartDaemonAndWait(openBrowser2 = true) {
|
|
8307
8317
|
if (isTestingMode()) return false;
|
|
8308
8318
|
if (!import_path16.default.isAbsolute(process.argv[1])) return false;
|
|
8319
|
+
let resolvedArgv1;
|
|
8320
|
+
try {
|
|
8321
|
+
resolvedArgv1 = import_fs13.default.realpathSync(process.argv[1]);
|
|
8322
|
+
} catch {
|
|
8323
|
+
return false;
|
|
8324
|
+
}
|
|
8325
|
+
if (!resolvedArgv1.endsWith(".js")) return false;
|
|
8309
8326
|
try {
|
|
8310
|
-
const child = (0, import_child_process3.spawn)(process.execPath, [
|
|
8327
|
+
const child = (0, import_child_process3.spawn)(process.execPath, [resolvedArgv1, "daemon"], {
|
|
8311
8328
|
detached: true,
|
|
8312
8329
|
stdio: "ignore",
|
|
8313
8330
|
// NODE9_BROWSER_OPENED=1 tells the daemon we will open the browser ourselves
|
|
8314
8331
|
// (openBrowserLocal below), so it must not open a duplicate tab on first approval.
|
|
8315
|
-
|
|
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
|
+
}
|
|
8316
8338
|
});
|
|
8317
8339
|
child.unref();
|
|
8318
8340
|
for (let i = 0; i < 20; i++) {
|
|
8319
8341
|
await new Promise((r) => setTimeout(r, 250));
|
|
8320
8342
|
if (!isDaemonRunning()) continue;
|
|
8321
8343
|
try {
|
|
8322
|
-
const res = await fetch(
|
|
8344
|
+
const res = await fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/settings`, {
|
|
8323
8345
|
signal: AbortSignal.timeout(500)
|
|
8324
8346
|
});
|
|
8325
8347
|
if (res.ok) {
|
|
@@ -8335,12 +8357,13 @@ async function autoStartDaemonAndWait(openBrowser2 = true) {
|
|
|
8335
8357
|
}
|
|
8336
8358
|
return false;
|
|
8337
8359
|
}
|
|
8338
|
-
var import_child_process3, import_path16;
|
|
8360
|
+
var import_child_process3, import_path16, import_fs13;
|
|
8339
8361
|
var init_daemon_starter = __esm({
|
|
8340
8362
|
"src/cli/daemon-starter.ts"() {
|
|
8341
8363
|
"use strict";
|
|
8342
8364
|
import_child_process3 = require("child_process");
|
|
8343
8365
|
import_path16 = __toESM(require("path"));
|
|
8366
|
+
import_fs13 = __toESM(require("fs"));
|
|
8344
8367
|
init_daemon();
|
|
8345
8368
|
}
|
|
8346
8369
|
});
|
|
@@ -8634,13 +8657,13 @@ function buildRuleSources() {
|
|
|
8634
8657
|
function countScanFiles() {
|
|
8635
8658
|
let total = 0;
|
|
8636
8659
|
const claudeDir = import_path17.default.join(import_os12.default.homedir(), ".claude", "projects");
|
|
8637
|
-
if (
|
|
8660
|
+
if (import_fs14.default.existsSync(claudeDir)) {
|
|
8638
8661
|
try {
|
|
8639
|
-
for (const proj of
|
|
8662
|
+
for (const proj of import_fs14.default.readdirSync(claudeDir)) {
|
|
8640
8663
|
const p = import_path17.default.join(claudeDir, proj);
|
|
8641
8664
|
try {
|
|
8642
|
-
if (!
|
|
8643
|
-
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;
|
|
8644
8667
|
} catch {
|
|
8645
8668
|
continue;
|
|
8646
8669
|
}
|
|
@@ -8649,16 +8672,16 @@ function countScanFiles() {
|
|
|
8649
8672
|
}
|
|
8650
8673
|
}
|
|
8651
8674
|
const geminiDir = import_path17.default.join(import_os12.default.homedir(), ".gemini", "tmp");
|
|
8652
|
-
if (
|
|
8675
|
+
if (import_fs14.default.existsSync(geminiDir)) {
|
|
8653
8676
|
try {
|
|
8654
|
-
for (const slug of
|
|
8677
|
+
for (const slug of import_fs14.default.readdirSync(geminiDir)) {
|
|
8655
8678
|
const p = import_path17.default.join(geminiDir, slug);
|
|
8656
8679
|
try {
|
|
8657
|
-
if (!
|
|
8680
|
+
if (!import_fs14.default.statSync(p).isDirectory()) continue;
|
|
8658
8681
|
const chatsDir = import_path17.default.join(p, "chats");
|
|
8659
|
-
if (
|
|
8682
|
+
if (import_fs14.default.existsSync(chatsDir)) {
|
|
8660
8683
|
try {
|
|
8661
|
-
total +=
|
|
8684
|
+
total += import_fs14.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
|
|
8662
8685
|
} catch {
|
|
8663
8686
|
}
|
|
8664
8687
|
}
|
|
@@ -8670,21 +8693,21 @@ function countScanFiles() {
|
|
|
8670
8693
|
}
|
|
8671
8694
|
}
|
|
8672
8695
|
const codexDir = import_path17.default.join(import_os12.default.homedir(), ".codex", "sessions");
|
|
8673
|
-
if (
|
|
8696
|
+
if (import_fs14.default.existsSync(codexDir)) {
|
|
8674
8697
|
try {
|
|
8675
|
-
for (const year of
|
|
8698
|
+
for (const year of import_fs14.default.readdirSync(codexDir)) {
|
|
8676
8699
|
const yp = import_path17.default.join(codexDir, year);
|
|
8677
8700
|
try {
|
|
8678
|
-
if (!
|
|
8679
|
-
for (const month of
|
|
8701
|
+
if (!import_fs14.default.statSync(yp).isDirectory()) continue;
|
|
8702
|
+
for (const month of import_fs14.default.readdirSync(yp)) {
|
|
8680
8703
|
const mp = import_path17.default.join(yp, month);
|
|
8681
8704
|
try {
|
|
8682
|
-
if (!
|
|
8683
|
-
for (const day of
|
|
8705
|
+
if (!import_fs14.default.statSync(mp).isDirectory()) continue;
|
|
8706
|
+
for (const day of import_fs14.default.readdirSync(mp)) {
|
|
8684
8707
|
const dp = import_path17.default.join(mp, day);
|
|
8685
8708
|
try {
|
|
8686
|
-
if (!
|
|
8687
|
-
total +=
|
|
8709
|
+
if (!import_fs14.default.statSync(dp).isDirectory()) continue;
|
|
8710
|
+
total += import_fs14.default.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
|
|
8688
8711
|
} catch {
|
|
8689
8712
|
continue;
|
|
8690
8713
|
}
|
|
@@ -8702,17 +8725,18 @@ function countScanFiles() {
|
|
|
8702
8725
|
}
|
|
8703
8726
|
return total;
|
|
8704
8727
|
}
|
|
8705
|
-
function renderProgressBar(done, total) {
|
|
8728
|
+
function renderProgressBar(done, total, lines) {
|
|
8706
8729
|
const width = 28;
|
|
8707
8730
|
const pct = total > 0 ? done / total : 0;
|
|
8708
8731
|
const filled = Math.min(width, Math.round(pct * width));
|
|
8709
8732
|
const bar = "\u2588".repeat(filled) + "\u2591".repeat(width - filled);
|
|
8710
|
-
const
|
|
8733
|
+
const fileLabel = total > 0 ? `${done}/${total} files` : `${done} files`;
|
|
8734
|
+
const lineLabel = lines > 0 ? import_chalk2.default.dim(` ${lines.toLocaleString()} lines`) : "";
|
|
8711
8735
|
process.stdout.write(
|
|
8712
|
-
`\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} `
|
|
8713
8737
|
);
|
|
8714
8738
|
}
|
|
8715
|
-
function scanClaudeHistory(startDate, onProgress) {
|
|
8739
|
+
function scanClaudeHistory(startDate, onProgress, onLine) {
|
|
8716
8740
|
const projectsDir = import_path17.default.join(import_os12.default.homedir(), ".claude", "projects");
|
|
8717
8741
|
const result = {
|
|
8718
8742
|
filesScanned: 0,
|
|
@@ -8726,10 +8750,10 @@ function scanClaudeHistory(startDate, onProgress) {
|
|
|
8726
8750
|
firstDate: null,
|
|
8727
8751
|
lastDate: null
|
|
8728
8752
|
};
|
|
8729
|
-
if (!
|
|
8753
|
+
if (!import_fs14.default.existsSync(projectsDir)) return result;
|
|
8730
8754
|
let projDirs;
|
|
8731
8755
|
try {
|
|
8732
|
-
projDirs =
|
|
8756
|
+
projDirs = import_fs14.default.readdirSync(projectsDir);
|
|
8733
8757
|
} catch {
|
|
8734
8758
|
return result;
|
|
8735
8759
|
}
|
|
@@ -8737,14 +8761,14 @@ function scanClaudeHistory(startDate, onProgress) {
|
|
|
8737
8761
|
for (const proj of projDirs) {
|
|
8738
8762
|
const projPath = import_path17.default.join(projectsDir, proj);
|
|
8739
8763
|
try {
|
|
8740
|
-
if (!
|
|
8764
|
+
if (!import_fs14.default.statSync(projPath).isDirectory()) continue;
|
|
8741
8765
|
} catch {
|
|
8742
8766
|
continue;
|
|
8743
8767
|
}
|
|
8744
8768
|
const projLabel = decodeURIComponent(proj).replace(import_os12.default.homedir(), "~").slice(0, 40);
|
|
8745
8769
|
let files;
|
|
8746
8770
|
try {
|
|
8747
|
-
files =
|
|
8771
|
+
files = import_fs14.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
8748
8772
|
} catch {
|
|
8749
8773
|
continue;
|
|
8750
8774
|
}
|
|
@@ -8755,13 +8779,14 @@ function scanClaudeHistory(startDate, onProgress) {
|
|
|
8755
8779
|
const sessionId = file.replace(/\.jsonl$/, "");
|
|
8756
8780
|
let raw;
|
|
8757
8781
|
try {
|
|
8758
|
-
raw =
|
|
8782
|
+
raw = import_fs14.default.readFileSync(import_path17.default.join(projPath, file), "utf-8");
|
|
8759
8783
|
} catch {
|
|
8760
8784
|
continue;
|
|
8761
8785
|
}
|
|
8762
8786
|
const sessionCalls = [];
|
|
8763
8787
|
for (const line of raw.split("\n")) {
|
|
8764
8788
|
if (!line.trim()) continue;
|
|
8789
|
+
onLine?.();
|
|
8765
8790
|
let entry;
|
|
8766
8791
|
try {
|
|
8767
8792
|
entry = JSON.parse(line);
|
|
@@ -8907,7 +8932,7 @@ function scanClaudeHistory(startDate, onProgress) {
|
|
|
8907
8932
|
}
|
|
8908
8933
|
return result;
|
|
8909
8934
|
}
|
|
8910
|
-
function scanGeminiHistory(startDate, onProgress) {
|
|
8935
|
+
function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
8911
8936
|
const tmpDir = import_path17.default.join(import_os12.default.homedir(), ".gemini", "tmp");
|
|
8912
8937
|
const result = {
|
|
8913
8938
|
filesScanned: 0,
|
|
@@ -8921,10 +8946,10 @@ function scanGeminiHistory(startDate, onProgress) {
|
|
|
8921
8946
|
firstDate: null,
|
|
8922
8947
|
lastDate: null
|
|
8923
8948
|
};
|
|
8924
|
-
if (!
|
|
8949
|
+
if (!import_fs14.default.existsSync(tmpDir)) return result;
|
|
8925
8950
|
let slugDirs;
|
|
8926
8951
|
try {
|
|
8927
|
-
slugDirs =
|
|
8952
|
+
slugDirs = import_fs14.default.readdirSync(tmpDir);
|
|
8928
8953
|
} catch {
|
|
8929
8954
|
return result;
|
|
8930
8955
|
}
|
|
@@ -8932,20 +8957,20 @@ function scanGeminiHistory(startDate, onProgress) {
|
|
|
8932
8957
|
for (const slug of slugDirs) {
|
|
8933
8958
|
const slugPath = import_path17.default.join(tmpDir, slug);
|
|
8934
8959
|
try {
|
|
8935
|
-
if (!
|
|
8960
|
+
if (!import_fs14.default.statSync(slugPath).isDirectory()) continue;
|
|
8936
8961
|
} catch {
|
|
8937
8962
|
continue;
|
|
8938
8963
|
}
|
|
8939
8964
|
let projLabel = slug;
|
|
8940
8965
|
try {
|
|
8941
|
-
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);
|
|
8942
8967
|
} catch {
|
|
8943
8968
|
}
|
|
8944
8969
|
const chatsDir = import_path17.default.join(slugPath, "chats");
|
|
8945
|
-
if (!
|
|
8970
|
+
if (!import_fs14.default.existsSync(chatsDir)) continue;
|
|
8946
8971
|
let chatFiles;
|
|
8947
8972
|
try {
|
|
8948
|
-
chatFiles =
|
|
8973
|
+
chatFiles = import_fs14.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
8949
8974
|
} catch {
|
|
8950
8975
|
continue;
|
|
8951
8976
|
}
|
|
@@ -8955,7 +8980,7 @@ function scanGeminiHistory(startDate, onProgress) {
|
|
|
8955
8980
|
const sessionId = chatFile.replace(/\.json$/, "");
|
|
8956
8981
|
let raw;
|
|
8957
8982
|
try {
|
|
8958
|
-
raw =
|
|
8983
|
+
raw = import_fs14.default.readFileSync(import_path17.default.join(chatsDir, chatFile), "utf-8");
|
|
8959
8984
|
} catch {
|
|
8960
8985
|
continue;
|
|
8961
8986
|
}
|
|
@@ -8968,6 +8993,7 @@ function scanGeminiHistory(startDate, onProgress) {
|
|
|
8968
8993
|
}
|
|
8969
8994
|
result.sessions++;
|
|
8970
8995
|
for (const msg of session.messages ?? []) {
|
|
8996
|
+
onLine?.();
|
|
8971
8997
|
if (msg.type === "user") {
|
|
8972
8998
|
const content = msg.content;
|
|
8973
8999
|
const text = Array.isArray(content) ? content.map((c) => c.text ?? "").join("\n") : typeof content === "string" ? content : "";
|
|
@@ -9103,7 +9129,7 @@ function scanGeminiHistory(startDate, onProgress) {
|
|
|
9103
9129
|
}
|
|
9104
9130
|
return result;
|
|
9105
9131
|
}
|
|
9106
|
-
function scanCodexHistory(startDate, onProgress) {
|
|
9132
|
+
function scanCodexHistory(startDate, onProgress, onLine) {
|
|
9107
9133
|
const sessionsBase = import_path17.default.join(import_os12.default.homedir(), ".codex", "sessions");
|
|
9108
9134
|
const result = {
|
|
9109
9135
|
filesScanned: 0,
|
|
@@ -9117,31 +9143,31 @@ function scanCodexHistory(startDate, onProgress) {
|
|
|
9117
9143
|
firstDate: null,
|
|
9118
9144
|
lastDate: null
|
|
9119
9145
|
};
|
|
9120
|
-
if (!
|
|
9146
|
+
if (!import_fs14.default.existsSync(sessionsBase)) return result;
|
|
9121
9147
|
const jsonlFiles = [];
|
|
9122
9148
|
try {
|
|
9123
|
-
for (const year of
|
|
9149
|
+
for (const year of import_fs14.default.readdirSync(sessionsBase)) {
|
|
9124
9150
|
const yearPath = import_path17.default.join(sessionsBase, year);
|
|
9125
9151
|
try {
|
|
9126
|
-
if (!
|
|
9152
|
+
if (!import_fs14.default.statSync(yearPath).isDirectory()) continue;
|
|
9127
9153
|
} catch {
|
|
9128
9154
|
continue;
|
|
9129
9155
|
}
|
|
9130
|
-
for (const month of
|
|
9156
|
+
for (const month of import_fs14.default.readdirSync(yearPath)) {
|
|
9131
9157
|
const monthPath = import_path17.default.join(yearPath, month);
|
|
9132
9158
|
try {
|
|
9133
|
-
if (!
|
|
9159
|
+
if (!import_fs14.default.statSync(monthPath).isDirectory()) continue;
|
|
9134
9160
|
} catch {
|
|
9135
9161
|
continue;
|
|
9136
9162
|
}
|
|
9137
|
-
for (const day of
|
|
9163
|
+
for (const day of import_fs14.default.readdirSync(monthPath)) {
|
|
9138
9164
|
const dayPath = import_path17.default.join(monthPath, day);
|
|
9139
9165
|
try {
|
|
9140
|
-
if (!
|
|
9166
|
+
if (!import_fs14.default.statSync(dayPath).isDirectory()) continue;
|
|
9141
9167
|
} catch {
|
|
9142
9168
|
continue;
|
|
9143
9169
|
}
|
|
9144
|
-
for (const file of
|
|
9170
|
+
for (const file of import_fs14.default.readdirSync(dayPath)) {
|
|
9145
9171
|
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path17.default.join(dayPath, file));
|
|
9146
9172
|
}
|
|
9147
9173
|
}
|
|
@@ -9156,7 +9182,7 @@ function scanCodexHistory(startDate, onProgress) {
|
|
|
9156
9182
|
onProgress?.(result.filesScanned);
|
|
9157
9183
|
let lines;
|
|
9158
9184
|
try {
|
|
9159
|
-
lines =
|
|
9185
|
+
lines = import_fs14.default.readFileSync(filePath, "utf-8").split("\n");
|
|
9160
9186
|
} catch {
|
|
9161
9187
|
continue;
|
|
9162
9188
|
}
|
|
@@ -9170,6 +9196,7 @@ function scanCodexHistory(startDate, onProgress) {
|
|
|
9170
9196
|
let lastTotalOutput = 0;
|
|
9171
9197
|
for (const line of lines) {
|
|
9172
9198
|
if (!line.trim()) continue;
|
|
9199
|
+
onLine?.();
|
|
9173
9200
|
let entry;
|
|
9174
9201
|
try {
|
|
9175
9202
|
entry = JSON.parse(line);
|
|
@@ -9374,17 +9401,17 @@ function printRuleGroup(rule, topN, drillDown, previewWidth) {
|
|
|
9374
9401
|
}
|
|
9375
9402
|
}
|
|
9376
9403
|
function registerScanCommand(program2) {
|
|
9377
|
-
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) => {
|
|
9378
9405
|
const drillDown = options.drillDown ?? false;
|
|
9379
9406
|
const topN = drillDown ? Infinity : Math.max(1, parseInt(options.top, 10) || 5);
|
|
9380
9407
|
const previewWidth = 70;
|
|
9381
9408
|
const startDate = options.all ? null : (() => {
|
|
9382
9409
|
const d = /* @__PURE__ */ new Date();
|
|
9383
|
-
d.setDate(d.getDate() - (parseInt(options.days, 10) ||
|
|
9410
|
+
d.setDate(d.getDate() - (parseInt(options.days, 10) || 30));
|
|
9384
9411
|
d.setHours(0, 0, 0, 0);
|
|
9385
9412
|
return d;
|
|
9386
9413
|
})();
|
|
9387
|
-
const isInstalled =
|
|
9414
|
+
const isInstalled = import_fs14.default.existsSync(import_path17.default.join(import_os12.default.homedir(), ".node9", "audit.log"));
|
|
9388
9415
|
console.log("");
|
|
9389
9416
|
if (!isInstalled) {
|
|
9390
9417
|
console.log(
|
|
@@ -9401,19 +9428,32 @@ function registerScanCommand(program2) {
|
|
|
9401
9428
|
console.log("");
|
|
9402
9429
|
const totalFiles = countScanFiles();
|
|
9403
9430
|
let filesScanned = 0;
|
|
9431
|
+
let linesScanned = 0;
|
|
9432
|
+
let lastRender = 0;
|
|
9404
9433
|
const onProgress = (done) => {
|
|
9405
9434
|
filesScanned = done;
|
|
9406
|
-
renderProgressBar(filesScanned, totalFiles);
|
|
9435
|
+
renderProgressBar(filesScanned, totalFiles, linesScanned);
|
|
9436
|
+
lastRender = Date.now();
|
|
9407
9437
|
};
|
|
9408
|
-
|
|
9409
|
-
|
|
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);
|
|
9410
9448
|
const geminiScan = scanGeminiHistory(
|
|
9411
9449
|
startDate,
|
|
9412
|
-
(done) => onProgress(claudeScan.filesScanned + done)
|
|
9450
|
+
(done) => onProgress(claudeScan.filesScanned + done),
|
|
9451
|
+
onLine
|
|
9413
9452
|
);
|
|
9414
9453
|
const codexScan = scanCodexHistory(
|
|
9415
9454
|
startDate,
|
|
9416
|
-
(done) => onProgress(claudeScan.filesScanned + geminiScan.filesScanned + done)
|
|
9455
|
+
(done) => onProgress(claudeScan.filesScanned + geminiScan.filesScanned + done),
|
|
9456
|
+
onLine
|
|
9417
9457
|
);
|
|
9418
9458
|
const scan = mergeScans(mergeScans(claudeScan, geminiScan), codexScan);
|
|
9419
9459
|
const summary = buildScanSummary([
|
|
@@ -9431,7 +9471,7 @@ function registerScanCommand(program2) {
|
|
|
9431
9471
|
);
|
|
9432
9472
|
return;
|
|
9433
9473
|
}
|
|
9434
|
-
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`);
|
|
9435
9475
|
const dateRange = scan.firstDate && scan.lastDate ? import_chalk2.default.dim(` ${fmtTs(scan.firstDate)} \u2013 ${fmtTs(scan.lastDate)}`) : "";
|
|
9436
9476
|
const breakdownParts = [];
|
|
9437
9477
|
if (claudeScan.sessions > 0)
|
|
@@ -9609,38 +9649,42 @@ function registerScanCommand(program2) {
|
|
|
9609
9649
|
console.log(" " + import_chalk2.default.dim("\u2192 ") + import_chalk2.default.underline("https://node9.ai"));
|
|
9610
9650
|
}
|
|
9611
9651
|
console.log("");
|
|
9612
|
-
|
|
9613
|
-
|
|
9614
|
-
if (
|
|
9615
|
-
|
|
9616
|
-
|
|
9617
|
-
|
|
9618
|
-
|
|
9619
|
-
|
|
9620
|
-
|
|
9621
|
-
|
|
9622
|
-
|
|
9623
|
-
|
|
9624
|
-
|
|
9625
|
-
|
|
9626
|
-
|
|
9627
|
-
|
|
9628
|
-
|
|
9629
|
-
|
|
9630
|
-
|
|
9631
|
-
|
|
9632
|
-
} 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
|
+
}
|
|
9633
9672
|
}
|
|
9634
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("");
|
|
9635
9679
|
}
|
|
9636
9680
|
});
|
|
9637
9681
|
}
|
|
9638
|
-
var import_chalk2,
|
|
9682
|
+
var import_chalk2, import_fs14, import_path17, import_os12, CLAUDE_PRICING, GEMINI_PRICING, LOOP_TOOLS, LOOP_THRESHOLD, DEFAULT_RULE_NAMES;
|
|
9639
9683
|
var init_scan = __esm({
|
|
9640
9684
|
"src/cli/commands/scan.ts"() {
|
|
9641
9685
|
"use strict";
|
|
9642
9686
|
import_chalk2 = __toESM(require("chalk"));
|
|
9643
|
-
|
|
9687
|
+
import_fs14 = __toESM(require("fs"));
|
|
9644
9688
|
import_path17 = __toESM(require("path"));
|
|
9645
9689
|
import_os12 = __toESM(require("os"));
|
|
9646
9690
|
init_shields();
|
|
@@ -9778,11 +9822,11 @@ var init_suggestion_tracker = __esm({
|
|
|
9778
9822
|
});
|
|
9779
9823
|
|
|
9780
9824
|
// src/daemon/taint-store.ts
|
|
9781
|
-
var
|
|
9825
|
+
var import_fs15, import_path18, DEFAULT_TTL_MS, TaintStore;
|
|
9782
9826
|
var init_taint_store = __esm({
|
|
9783
9827
|
"src/daemon/taint-store.ts"() {
|
|
9784
9828
|
"use strict";
|
|
9785
|
-
|
|
9829
|
+
import_fs15 = __toESM(require("fs"));
|
|
9786
9830
|
import_path18 = __toESM(require("path"));
|
|
9787
9831
|
DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
9788
9832
|
TaintStore = class {
|
|
@@ -9848,7 +9892,7 @@ var init_taint_store = __esm({
|
|
|
9848
9892
|
/** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
|
|
9849
9893
|
_resolve(filePath) {
|
|
9850
9894
|
try {
|
|
9851
|
-
return
|
|
9895
|
+
return import_fs15.default.realpathSync.native(import_path18.default.resolve(filePath));
|
|
9852
9896
|
} catch {
|
|
9853
9897
|
return import_path18.default.resolve(filePath);
|
|
9854
9898
|
}
|
|
@@ -9968,8 +10012,8 @@ var init_session_history = __esm({
|
|
|
9968
10012
|
// src/daemon/state.ts
|
|
9969
10013
|
function loadInsightCounts() {
|
|
9970
10014
|
try {
|
|
9971
|
-
if (!
|
|
9972
|
-
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"));
|
|
9973
10017
|
for (const [tool, count] of Object.entries(data)) {
|
|
9974
10018
|
if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
|
|
9975
10019
|
}
|
|
@@ -10013,22 +10057,22 @@ function setCachedScanResult(result) {
|
|
|
10013
10057
|
}
|
|
10014
10058
|
function atomicWriteSync2(filePath, data, options) {
|
|
10015
10059
|
const dir = import_path19.default.dirname(filePath);
|
|
10016
|
-
if (!
|
|
10060
|
+
if (!import_fs16.default.existsSync(dir)) import_fs16.default.mkdirSync(dir, { recursive: true });
|
|
10017
10061
|
const tmpPath = `${filePath}.${(0, import_crypto6.randomUUID)()}.tmp`;
|
|
10018
10062
|
try {
|
|
10019
|
-
|
|
10063
|
+
import_fs16.default.writeFileSync(tmpPath, data, options);
|
|
10020
10064
|
} catch (err2) {
|
|
10021
10065
|
try {
|
|
10022
|
-
|
|
10066
|
+
import_fs16.default.unlinkSync(tmpPath);
|
|
10023
10067
|
} catch {
|
|
10024
10068
|
}
|
|
10025
10069
|
throw err2;
|
|
10026
10070
|
}
|
|
10027
10071
|
try {
|
|
10028
|
-
|
|
10072
|
+
import_fs16.default.renameSync(tmpPath, filePath);
|
|
10029
10073
|
} catch (err2) {
|
|
10030
10074
|
try {
|
|
10031
|
-
|
|
10075
|
+
import_fs16.default.unlinkSync(tmpPath);
|
|
10032
10076
|
} catch {
|
|
10033
10077
|
}
|
|
10034
10078
|
throw err2;
|
|
@@ -10053,15 +10097,15 @@ function appendAuditLog(data) {
|
|
|
10053
10097
|
source: "daemon"
|
|
10054
10098
|
};
|
|
10055
10099
|
const dir = import_path19.default.dirname(AUDIT_LOG_FILE);
|
|
10056
|
-
if (!
|
|
10057
|
-
|
|
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");
|
|
10058
10102
|
} catch {
|
|
10059
10103
|
}
|
|
10060
10104
|
}
|
|
10061
10105
|
function getAuditHistory(limit = 20) {
|
|
10062
10106
|
try {
|
|
10063
|
-
if (!
|
|
10064
|
-
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");
|
|
10065
10109
|
if (lines.length === 1 && lines[0] === "") return [];
|
|
10066
10110
|
return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
|
|
10067
10111
|
} catch {
|
|
@@ -10070,19 +10114,19 @@ function getAuditHistory(limit = 20) {
|
|
|
10070
10114
|
}
|
|
10071
10115
|
function getOrgName() {
|
|
10072
10116
|
try {
|
|
10073
|
-
if (
|
|
10117
|
+
if (import_fs16.default.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
|
|
10074
10118
|
} catch {
|
|
10075
10119
|
}
|
|
10076
10120
|
return null;
|
|
10077
10121
|
}
|
|
10078
10122
|
function hasStoredSlackKey() {
|
|
10079
|
-
return
|
|
10123
|
+
return import_fs16.default.existsSync(CREDENTIALS_FILE);
|
|
10080
10124
|
}
|
|
10081
10125
|
function writeGlobalSetting(key, value) {
|
|
10082
10126
|
let config = {};
|
|
10083
10127
|
try {
|
|
10084
|
-
if (
|
|
10085
|
-
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"));
|
|
10086
10130
|
}
|
|
10087
10131
|
} catch {
|
|
10088
10132
|
}
|
|
@@ -10094,8 +10138,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
10094
10138
|
try {
|
|
10095
10139
|
let trust = { entries: [] };
|
|
10096
10140
|
try {
|
|
10097
|
-
if (
|
|
10098
|
-
trust = JSON.parse(
|
|
10141
|
+
if (import_fs16.default.existsSync(TRUST_FILE2))
|
|
10142
|
+
trust = JSON.parse(import_fs16.default.readFileSync(TRUST_FILE2, "utf-8"));
|
|
10099
10143
|
} catch {
|
|
10100
10144
|
}
|
|
10101
10145
|
trust.entries = trust.entries.filter(
|
|
@@ -10112,8 +10156,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
10112
10156
|
}
|
|
10113
10157
|
function readPersistentDecisions() {
|
|
10114
10158
|
try {
|
|
10115
|
-
if (
|
|
10116
|
-
return JSON.parse(
|
|
10159
|
+
if (import_fs16.default.existsSync(DECISIONS_FILE)) {
|
|
10160
|
+
return JSON.parse(import_fs16.default.readFileSync(DECISIONS_FILE, "utf-8"));
|
|
10117
10161
|
}
|
|
10118
10162
|
} catch {
|
|
10119
10163
|
}
|
|
@@ -10150,7 +10194,7 @@ function estimateToolCost(tool, args) {
|
|
|
10150
10194
|
const filePath = a.file_path ?? a.path;
|
|
10151
10195
|
if (filePath) {
|
|
10152
10196
|
try {
|
|
10153
|
-
const bytes =
|
|
10197
|
+
const bytes = import_fs16.default.statSync(filePath).size;
|
|
10154
10198
|
return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
|
|
10155
10199
|
} catch {
|
|
10156
10200
|
}
|
|
@@ -10208,7 +10252,7 @@ function abandonPending() {
|
|
|
10208
10252
|
});
|
|
10209
10253
|
if (autoStarted) {
|
|
10210
10254
|
try {
|
|
10211
|
-
|
|
10255
|
+
import_fs16.default.unlinkSync(DAEMON_PID_FILE);
|
|
10212
10256
|
} catch {
|
|
10213
10257
|
}
|
|
10214
10258
|
setTimeout(() => {
|
|
@@ -10219,7 +10263,7 @@ function abandonPending() {
|
|
|
10219
10263
|
}
|
|
10220
10264
|
function startActivitySocket() {
|
|
10221
10265
|
try {
|
|
10222
|
-
|
|
10266
|
+
import_fs16.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
10223
10267
|
} catch {
|
|
10224
10268
|
}
|
|
10225
10269
|
const ACTIVITY_MAX_BYTES = 1024 * 1024;
|
|
@@ -10301,17 +10345,17 @@ function startActivitySocket() {
|
|
|
10301
10345
|
unixServer.listen(ACTIVITY_SOCKET_PATH2);
|
|
10302
10346
|
process.on("exit", () => {
|
|
10303
10347
|
try {
|
|
10304
|
-
|
|
10348
|
+
import_fs16.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
10305
10349
|
} catch {
|
|
10306
10350
|
}
|
|
10307
10351
|
});
|
|
10308
10352
|
}
|
|
10309
|
-
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;
|
|
10310
10354
|
var init_state2 = __esm({
|
|
10311
10355
|
"src/daemon/state.ts"() {
|
|
10312
10356
|
"use strict";
|
|
10313
10357
|
import_net2 = __toESM(require("net"));
|
|
10314
|
-
|
|
10358
|
+
import_fs16 = __toESM(require("fs"));
|
|
10315
10359
|
import_path19 = __toESM(require("path"));
|
|
10316
10360
|
import_os13 = __toESM(require("os"));
|
|
10317
10361
|
import_child_process4 = require("child_process");
|
|
@@ -10376,8 +10420,8 @@ var init_state2 = __esm({
|
|
|
10376
10420
|
function patchConfig(configPath, patch) {
|
|
10377
10421
|
let config = {};
|
|
10378
10422
|
try {
|
|
10379
|
-
if (
|
|
10380
|
-
config = JSON.parse(
|
|
10423
|
+
if (import_fs17.default.existsSync(configPath)) {
|
|
10424
|
+
config = JSON.parse(import_fs17.default.readFileSync(configPath, "utf8"));
|
|
10381
10425
|
}
|
|
10382
10426
|
} catch {
|
|
10383
10427
|
throw new Error(`Cannot read config at ${configPath} \u2014 file may be corrupted`);
|
|
@@ -10397,32 +10441,32 @@ function patchConfig(configPath, patch) {
|
|
|
10397
10441
|
}
|
|
10398
10442
|
}
|
|
10399
10443
|
const dir = import_path20.default.dirname(configPath);
|
|
10400
|
-
|
|
10444
|
+
import_fs17.default.mkdirSync(dir, { recursive: true });
|
|
10401
10445
|
const tmp = configPath + ".node9-tmp";
|
|
10402
10446
|
try {
|
|
10403
|
-
|
|
10447
|
+
import_fs17.default.writeFileSync(tmp, JSON.stringify(config, null, 2), { mode: 384 });
|
|
10404
10448
|
} catch (err2) {
|
|
10405
10449
|
try {
|
|
10406
|
-
|
|
10450
|
+
import_fs17.default.unlinkSync(tmp);
|
|
10407
10451
|
} catch {
|
|
10408
10452
|
}
|
|
10409
10453
|
throw err2;
|
|
10410
10454
|
}
|
|
10411
10455
|
try {
|
|
10412
|
-
|
|
10456
|
+
import_fs17.default.renameSync(tmp, configPath);
|
|
10413
10457
|
} catch (err2) {
|
|
10414
10458
|
try {
|
|
10415
|
-
|
|
10459
|
+
import_fs17.default.unlinkSync(tmp);
|
|
10416
10460
|
} catch {
|
|
10417
10461
|
}
|
|
10418
10462
|
throw err2;
|
|
10419
10463
|
}
|
|
10420
10464
|
}
|
|
10421
|
-
var
|
|
10465
|
+
var import_fs17, import_path20, import_os14, GLOBAL_CONFIG_PATH;
|
|
10422
10466
|
var init_patch = __esm({
|
|
10423
10467
|
"src/config/patch.ts"() {
|
|
10424
10468
|
"use strict";
|
|
10425
|
-
|
|
10469
|
+
import_fs17 = __toESM(require("fs"));
|
|
10426
10470
|
import_path20 = __toESM(require("path"));
|
|
10427
10471
|
import_os14 = __toESM(require("os"));
|
|
10428
10472
|
GLOBAL_CONFIG_PATH = import_path20.default.join(import_os14.default.homedir(), ".node9", "config.json");
|
|
@@ -10445,7 +10489,7 @@ function pricingFor(model) {
|
|
|
10445
10489
|
function parseJSONLFile(filePath) {
|
|
10446
10490
|
let content;
|
|
10447
10491
|
try {
|
|
10448
|
-
content =
|
|
10492
|
+
content = import_fs18.default.readFileSync(filePath, "utf8");
|
|
10449
10493
|
} catch {
|
|
10450
10494
|
return /* @__PURE__ */ new Map();
|
|
10451
10495
|
}
|
|
@@ -10498,24 +10542,24 @@ function parseJSONLFile(filePath) {
|
|
|
10498
10542
|
}
|
|
10499
10543
|
function collectEntries() {
|
|
10500
10544
|
const projectsDir = import_path21.default.join(import_os15.default.homedir(), ".claude", "projects");
|
|
10501
|
-
if (!
|
|
10545
|
+
if (!import_fs18.default.existsSync(projectsDir)) return [];
|
|
10502
10546
|
const combined = /* @__PURE__ */ new Map();
|
|
10503
10547
|
let dirs;
|
|
10504
10548
|
try {
|
|
10505
|
-
dirs =
|
|
10549
|
+
dirs = import_fs18.default.readdirSync(projectsDir);
|
|
10506
10550
|
} catch {
|
|
10507
10551
|
return [];
|
|
10508
10552
|
}
|
|
10509
10553
|
for (const dir of dirs) {
|
|
10510
10554
|
const dirPath = import_path21.default.join(projectsDir, dir);
|
|
10511
10555
|
try {
|
|
10512
|
-
if (!
|
|
10556
|
+
if (!import_fs18.default.statSync(dirPath).isDirectory()) continue;
|
|
10513
10557
|
} catch {
|
|
10514
10558
|
continue;
|
|
10515
10559
|
}
|
|
10516
10560
|
let files;
|
|
10517
10561
|
try {
|
|
10518
|
-
files =
|
|
10562
|
+
files = import_fs18.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
10519
10563
|
} catch {
|
|
10520
10564
|
continue;
|
|
10521
10565
|
}
|
|
@@ -10556,11 +10600,11 @@ async function syncCost() {
|
|
|
10556
10600
|
signal: AbortSignal.timeout(15e3)
|
|
10557
10601
|
});
|
|
10558
10602
|
if (!res.ok) {
|
|
10559
|
-
|
|
10603
|
+
import_fs18.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
|
|
10560
10604
|
`);
|
|
10561
10605
|
}
|
|
10562
10606
|
} catch (err2) {
|
|
10563
|
-
|
|
10607
|
+
import_fs18.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
|
|
10564
10608
|
`);
|
|
10565
10609
|
}
|
|
10566
10610
|
}
|
|
@@ -10573,11 +10617,11 @@ function startCostSync() {
|
|
|
10573
10617
|
}, SYNC_INTERVAL_MS);
|
|
10574
10618
|
timer.unref();
|
|
10575
10619
|
}
|
|
10576
|
-
var
|
|
10620
|
+
var import_fs18, import_path21, import_os15, SYNC_INTERVAL_MS, PRICING;
|
|
10577
10621
|
var init_costSync = __esm({
|
|
10578
10622
|
"src/costSync.ts"() {
|
|
10579
10623
|
"use strict";
|
|
10580
|
-
|
|
10624
|
+
import_fs18 = __toESM(require("fs"));
|
|
10581
10625
|
import_path21 = __toESM(require("path"));
|
|
10582
10626
|
import_os15 = __toESM(require("os"));
|
|
10583
10627
|
init_config();
|
|
@@ -10605,7 +10649,7 @@ function readCredentials() {
|
|
|
10605
10649
|
}
|
|
10606
10650
|
try {
|
|
10607
10651
|
const credPath = import_path22.default.join(import_os16.default.homedir(), ".node9", "credentials.json");
|
|
10608
|
-
const creds = JSON.parse(
|
|
10652
|
+
const creds = JSON.parse(import_fs19.default.readFileSync(credPath, "utf-8"));
|
|
10609
10653
|
const profileName = process.env.NODE9_PROFILE ?? "default";
|
|
10610
10654
|
const profile = creds[profileName];
|
|
10611
10655
|
if (typeof profile?.apiKey === "string" && profile.apiKey.length > 0) {
|
|
@@ -10668,8 +10712,8 @@ async function syncOnce() {
|
|
|
10668
10712
|
const rules = await fetchCloudRules(creds.apiKey, creds.apiUrl);
|
|
10669
10713
|
const cache = { fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), rules };
|
|
10670
10714
|
const dir = import_path22.default.dirname(rulesCacheFile());
|
|
10671
|
-
if (!
|
|
10672
|
-
|
|
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");
|
|
10673
10717
|
} catch {
|
|
10674
10718
|
}
|
|
10675
10719
|
}
|
|
@@ -10682,8 +10726,8 @@ async function runCloudSync() {
|
|
|
10682
10726
|
const rules = await fetchCloudRules(creds.apiKey, creds.apiUrl);
|
|
10683
10727
|
const cache = { fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), rules };
|
|
10684
10728
|
const dir = import_path22.default.dirname(rulesCacheFile());
|
|
10685
|
-
if (!
|
|
10686
|
-
|
|
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");
|
|
10687
10731
|
return { ok: true, rules: rules.length, fetchedAt: cache.fetchedAt };
|
|
10688
10732
|
} catch (err2) {
|
|
10689
10733
|
return { ok: false, reason: err2 instanceof Error ? err2.message : String(err2) };
|
|
@@ -10691,7 +10735,7 @@ async function runCloudSync() {
|
|
|
10691
10735
|
}
|
|
10692
10736
|
function getCloudSyncStatus() {
|
|
10693
10737
|
try {
|
|
10694
|
-
const raw = JSON.parse(
|
|
10738
|
+
const raw = JSON.parse(import_fs19.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
10695
10739
|
if (!Array.isArray(raw.rules) || typeof raw.fetchedAt !== "string") return { cached: false };
|
|
10696
10740
|
return { cached: true, rules: raw.rules.length, fetchedAt: raw.fetchedAt };
|
|
10697
10741
|
} catch {
|
|
@@ -10700,7 +10744,7 @@ function getCloudSyncStatus() {
|
|
|
10700
10744
|
}
|
|
10701
10745
|
function getCloudRules() {
|
|
10702
10746
|
try {
|
|
10703
|
-
const raw = JSON.parse(
|
|
10747
|
+
const raw = JSON.parse(import_fs19.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
10704
10748
|
return Array.isArray(raw.rules) ? raw.rules : null;
|
|
10705
10749
|
} catch {
|
|
10706
10750
|
return null;
|
|
@@ -10715,11 +10759,11 @@ function startCloudSync() {
|
|
|
10715
10759
|
const recurring = setInterval(() => void syncOnce(), intervalMs);
|
|
10716
10760
|
recurring.unref();
|
|
10717
10761
|
}
|
|
10718
|
-
var
|
|
10762
|
+
var import_fs19, import_https, import_os16, import_path22, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_HOURS;
|
|
10719
10763
|
var init_sync = __esm({
|
|
10720
10764
|
"src/daemon/sync.ts"() {
|
|
10721
10765
|
"use strict";
|
|
10722
|
-
|
|
10766
|
+
import_fs19 = __toESM(require("fs"));
|
|
10723
10767
|
import_https = __toESM(require("https"));
|
|
10724
10768
|
import_os16 = __toESM(require("os"));
|
|
10725
10769
|
import_path22 = __toESM(require("path"));
|
|
@@ -10734,45 +10778,45 @@ var init_sync = __esm({
|
|
|
10734
10778
|
// src/daemon/dlp-scanner.ts
|
|
10735
10779
|
function loadIndex() {
|
|
10736
10780
|
try {
|
|
10737
|
-
return JSON.parse(
|
|
10781
|
+
return JSON.parse(import_fs20.default.readFileSync(INDEX_FILE, "utf-8"));
|
|
10738
10782
|
} catch {
|
|
10739
10783
|
return {};
|
|
10740
10784
|
}
|
|
10741
10785
|
}
|
|
10742
10786
|
function saveIndex(index) {
|
|
10743
10787
|
try {
|
|
10744
|
-
|
|
10788
|
+
import_fs20.default.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
|
|
10745
10789
|
} catch {
|
|
10746
10790
|
}
|
|
10747
10791
|
}
|
|
10748
10792
|
function appendAuditEntry(entry) {
|
|
10749
10793
|
try {
|
|
10750
|
-
|
|
10794
|
+
import_fs20.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
10751
10795
|
} catch {
|
|
10752
10796
|
}
|
|
10753
10797
|
}
|
|
10754
10798
|
function runDlpScan() {
|
|
10755
|
-
if (!
|
|
10799
|
+
if (!import_fs20.default.existsSync(PROJECTS_DIR)) return;
|
|
10756
10800
|
const index = loadIndex();
|
|
10757
10801
|
let updated = false;
|
|
10758
10802
|
let projDirs;
|
|
10759
10803
|
try {
|
|
10760
|
-
projDirs =
|
|
10804
|
+
projDirs = import_fs20.default.readdirSync(PROJECTS_DIR);
|
|
10761
10805
|
} catch {
|
|
10762
10806
|
return;
|
|
10763
10807
|
}
|
|
10764
10808
|
for (const proj of projDirs) {
|
|
10765
10809
|
const projPath = import_path23.default.join(PROJECTS_DIR, proj);
|
|
10766
10810
|
try {
|
|
10767
|
-
if (!
|
|
10768
|
-
const real =
|
|
10811
|
+
if (!import_fs20.default.lstatSync(projPath).isDirectory()) continue;
|
|
10812
|
+
const real = import_fs20.default.realpathSync(projPath);
|
|
10769
10813
|
if (!real.startsWith(PROJECTS_DIR + import_path23.default.sep) && real !== PROJECTS_DIR) continue;
|
|
10770
10814
|
} catch {
|
|
10771
10815
|
continue;
|
|
10772
10816
|
}
|
|
10773
10817
|
let files;
|
|
10774
10818
|
try {
|
|
10775
|
-
files =
|
|
10819
|
+
files = import_fs20.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
10776
10820
|
} catch {
|
|
10777
10821
|
continue;
|
|
10778
10822
|
}
|
|
@@ -10781,21 +10825,21 @@ function runDlpScan() {
|
|
|
10781
10825
|
const lastOffset = index[filePath] ?? 0;
|
|
10782
10826
|
let size;
|
|
10783
10827
|
try {
|
|
10784
|
-
size =
|
|
10828
|
+
size = import_fs20.default.statSync(filePath).size;
|
|
10785
10829
|
} catch {
|
|
10786
10830
|
continue;
|
|
10787
10831
|
}
|
|
10788
10832
|
if (size <= lastOffset) continue;
|
|
10789
10833
|
let fd;
|
|
10790
10834
|
try {
|
|
10791
|
-
fd =
|
|
10835
|
+
fd = import_fs20.default.openSync(filePath, "r");
|
|
10792
10836
|
} catch {
|
|
10793
10837
|
continue;
|
|
10794
10838
|
}
|
|
10795
10839
|
try {
|
|
10796
10840
|
const chunkSize = size - lastOffset;
|
|
10797
10841
|
const buf = Buffer.alloc(chunkSize);
|
|
10798
|
-
|
|
10842
|
+
import_fs20.default.readSync(fd, buf, 0, chunkSize, lastOffset);
|
|
10799
10843
|
const chunk = buf.toString("utf-8");
|
|
10800
10844
|
for (const line of chunk.split("\n")) {
|
|
10801
10845
|
if (!line.trim()) continue;
|
|
@@ -10840,7 +10884,7 @@ Run: node9 report --period 30d`
|
|
|
10840
10884
|
updated = true;
|
|
10841
10885
|
} finally {
|
|
10842
10886
|
try {
|
|
10843
|
-
|
|
10887
|
+
import_fs20.default.closeSync(fd);
|
|
10844
10888
|
} catch {
|
|
10845
10889
|
}
|
|
10846
10890
|
}
|
|
@@ -10866,11 +10910,11 @@ function startDlpScanner() {
|
|
|
10866
10910
|
);
|
|
10867
10911
|
timer.unref();
|
|
10868
10912
|
}
|
|
10869
|
-
var
|
|
10913
|
+
var import_fs20, import_path23, import_os17, INDEX_FILE, PROJECTS_DIR;
|
|
10870
10914
|
var init_dlp_scanner = __esm({
|
|
10871
10915
|
"src/daemon/dlp-scanner.ts"() {
|
|
10872
10916
|
"use strict";
|
|
10873
|
-
|
|
10917
|
+
import_fs20 = __toESM(require("fs"));
|
|
10874
10918
|
import_path23 = __toESM(require("path"));
|
|
10875
10919
|
import_os17 = __toESM(require("os"));
|
|
10876
10920
|
init_dlp();
|
|
@@ -10888,8 +10932,8 @@ function getMcpToolsFile() {
|
|
|
10888
10932
|
function readMcpToolsConfig() {
|
|
10889
10933
|
try {
|
|
10890
10934
|
const file = getMcpToolsFile();
|
|
10891
|
-
if (!
|
|
10892
|
-
const raw =
|
|
10935
|
+
if (!import_fs21.default.existsSync(file)) return {};
|
|
10936
|
+
const raw = import_fs21.default.readFileSync(file, "utf-8");
|
|
10893
10937
|
return JSON.parse(raw);
|
|
10894
10938
|
} catch {
|
|
10895
10939
|
return {};
|
|
@@ -10899,10 +10943,10 @@ function writeMcpToolsConfig(config) {
|
|
|
10899
10943
|
try {
|
|
10900
10944
|
const file = getMcpToolsFile();
|
|
10901
10945
|
const dir = import_path24.default.dirname(file);
|
|
10902
|
-
if (!
|
|
10946
|
+
if (!import_fs21.default.existsSync(dir)) import_fs21.default.mkdirSync(dir, { recursive: true });
|
|
10903
10947
|
const tmpPath = `${file}.${import_os18.default.hostname()}.${process.pid}.tmp`;
|
|
10904
|
-
|
|
10905
|
-
|
|
10948
|
+
import_fs21.default.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
|
|
10949
|
+
import_fs21.default.renameSync(tmpPath, file);
|
|
10906
10950
|
} catch (e) {
|
|
10907
10951
|
console.error("Failed to write mcp-tools.json", e);
|
|
10908
10952
|
}
|
|
@@ -10941,11 +10985,11 @@ function approveServer(serverKey, disabledTools) {
|
|
|
10941
10985
|
writeMcpToolsConfig(config);
|
|
10942
10986
|
}
|
|
10943
10987
|
}
|
|
10944
|
-
var
|
|
10988
|
+
var import_fs21, import_path24, import_os18;
|
|
10945
10989
|
var init_mcp_tools = __esm({
|
|
10946
10990
|
"src/daemon/mcp-tools.ts"() {
|
|
10947
10991
|
"use strict";
|
|
10948
|
-
|
|
10992
|
+
import_fs21 = __toESM(require("fs"));
|
|
10949
10993
|
import_path24 = __toESM(require("path"));
|
|
10950
10994
|
import_os18 = __toESM(require("os"));
|
|
10951
10995
|
}
|
|
@@ -10971,7 +11015,7 @@ function startDaemon() {
|
|
|
10971
11015
|
idleTimer = setTimeout(() => {
|
|
10972
11016
|
if (autoStarted) {
|
|
10973
11017
|
try {
|
|
10974
|
-
|
|
11018
|
+
import_fs22.default.unlinkSync(DAEMON_PID_FILE);
|
|
10975
11019
|
} catch {
|
|
10976
11020
|
}
|
|
10977
11021
|
}
|
|
@@ -11507,7 +11551,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
11507
11551
|
const periodParam = reqUrl.searchParams.get("period") || "7d";
|
|
11508
11552
|
const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
|
|
11509
11553
|
const logPath = import_path25.default.join(import_os19.default.homedir(), ".node9", "audit.log");
|
|
11510
|
-
if (!
|
|
11554
|
+
if (!import_fs22.default.existsSync(logPath)) {
|
|
11511
11555
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
11512
11556
|
return res.end(
|
|
11513
11557
|
JSON.stringify({
|
|
@@ -11520,7 +11564,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
11520
11564
|
);
|
|
11521
11565
|
}
|
|
11522
11566
|
try {
|
|
11523
|
-
const raw =
|
|
11567
|
+
const raw = import_fs22.default.readFileSync(logPath, "utf-8");
|
|
11524
11568
|
const allEntries = raw.split("\n").flatMap((line) => {
|
|
11525
11569
|
if (!line.trim()) return [];
|
|
11526
11570
|
try {
|
|
@@ -11624,7 +11668,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
11624
11668
|
}
|
|
11625
11669
|
try {
|
|
11626
11670
|
const d = /* @__PURE__ */ new Date();
|
|
11627
|
-
d.setDate(d.getDate() -
|
|
11671
|
+
d.setDate(d.getDate() - 30);
|
|
11628
11672
|
d.setHours(0, 0, 0, 0);
|
|
11629
11673
|
const EMPTY_SCAN = {
|
|
11630
11674
|
filesScanned: 0,
|
|
@@ -11815,7 +11859,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
11815
11859
|
if (!validToken(req)) return res.writeHead(403).end();
|
|
11816
11860
|
try {
|
|
11817
11861
|
const { serverKey, disabledTools } = JSON.parse(await readBody(req));
|
|
11818
|
-
if (typeof serverKey !== "string" || !Array.isArray(disabledTools)) {
|
|
11862
|
+
if (typeof serverKey !== "string" || serverKey.length < 1 || serverKey.length > 256 || !/^[\w.-]+$/.test(serverKey) || !Array.isArray(disabledTools)) {
|
|
11819
11863
|
res.writeHead(400).end();
|
|
11820
11864
|
return;
|
|
11821
11865
|
}
|
|
@@ -11837,7 +11881,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
11837
11881
|
if (req.headers["x-node9-internal"] !== internalToken) return res.writeHead(403).end();
|
|
11838
11882
|
try {
|
|
11839
11883
|
const { serverKey, tools } = JSON.parse(await readBody(req));
|
|
11840
|
-
if (typeof serverKey !== "string" || !Array.isArray(tools)) {
|
|
11884
|
+
if (typeof serverKey !== "string" || serverKey.length < 1 || serverKey.length > 256 || !/^[\w.-]+$/.test(serverKey) || !Array.isArray(tools)) {
|
|
11841
11885
|
res.writeHead(400).end();
|
|
11842
11886
|
return;
|
|
11843
11887
|
}
|
|
@@ -11943,14 +11987,14 @@ data: ${JSON.stringify(item.data)}
|
|
|
11943
11987
|
server.on("error", (e) => {
|
|
11944
11988
|
if (e.code === "EADDRINUSE") {
|
|
11945
11989
|
try {
|
|
11946
|
-
if (
|
|
11947
|
-
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"));
|
|
11948
11992
|
process.kill(pid, 0);
|
|
11949
11993
|
return process.exit(0);
|
|
11950
11994
|
}
|
|
11951
11995
|
} catch {
|
|
11952
11996
|
try {
|
|
11953
|
-
|
|
11997
|
+
import_fs22.default.unlinkSync(DAEMON_PID_FILE);
|
|
11954
11998
|
} catch {
|
|
11955
11999
|
}
|
|
11956
12000
|
server.listen(DAEMON_PORT, DAEMON_HOST);
|
|
@@ -12009,12 +12053,12 @@ data: ${JSON.stringify(item.data)}
|
|
|
12009
12053
|
}
|
|
12010
12054
|
startActivitySocket();
|
|
12011
12055
|
}
|
|
12012
|
-
var import_http,
|
|
12056
|
+
var import_http, import_fs22, import_path25, import_os19, import_crypto7, import_child_process5, import_chalk3;
|
|
12013
12057
|
var init_server = __esm({
|
|
12014
12058
|
"src/daemon/server.ts"() {
|
|
12015
12059
|
"use strict";
|
|
12016
12060
|
import_http = __toESM(require("http"));
|
|
12017
|
-
|
|
12061
|
+
import_fs22 = __toESM(require("fs"));
|
|
12018
12062
|
import_path25 = __toESM(require("path"));
|
|
12019
12063
|
import_os19 = __toESM(require("os"));
|
|
12020
12064
|
import_crypto7 = require("crypto");
|
|
@@ -12040,8 +12084,8 @@ var init_server = __esm({
|
|
|
12040
12084
|
function resolveNode9Binary() {
|
|
12041
12085
|
try {
|
|
12042
12086
|
const script = process.argv[1];
|
|
12043
|
-
if (typeof script === "string" && import_path26.default.isAbsolute(script) &&
|
|
12044
|
-
return
|
|
12087
|
+
if (typeof script === "string" && import_path26.default.isAbsolute(script) && import_fs23.default.existsSync(script)) {
|
|
12088
|
+
return import_fs23.default.realpathSync(script);
|
|
12045
12089
|
}
|
|
12046
12090
|
} catch {
|
|
12047
12091
|
}
|
|
@@ -12099,8 +12143,8 @@ function launchdPlist(binaryPath) {
|
|
|
12099
12143
|
}
|
|
12100
12144
|
function installLaunchd(binaryPath) {
|
|
12101
12145
|
const dir = import_path26.default.dirname(LAUNCHD_PLIST);
|
|
12102
|
-
if (!
|
|
12103
|
-
|
|
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");
|
|
12104
12148
|
(0, import_child_process6.spawnSync)("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
|
|
12105
12149
|
const r = (0, import_child_process6.spawnSync)("launchctl", ["load", "-w", LAUNCHD_PLIST], {
|
|
12106
12150
|
encoding: "utf8",
|
|
@@ -12111,13 +12155,13 @@ function installLaunchd(binaryPath) {
|
|
|
12111
12155
|
}
|
|
12112
12156
|
}
|
|
12113
12157
|
function uninstallLaunchd() {
|
|
12114
|
-
if (
|
|
12158
|
+
if (import_fs23.default.existsSync(LAUNCHD_PLIST)) {
|
|
12115
12159
|
(0, import_child_process6.spawnSync)("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
|
|
12116
|
-
|
|
12160
|
+
import_fs23.default.unlinkSync(LAUNCHD_PLIST);
|
|
12117
12161
|
}
|
|
12118
12162
|
}
|
|
12119
12163
|
function isLaunchdInstalled() {
|
|
12120
|
-
return
|
|
12164
|
+
return import_fs23.default.existsSync(LAUNCHD_PLIST);
|
|
12121
12165
|
}
|
|
12122
12166
|
function systemdUnit(binaryPath) {
|
|
12123
12167
|
return `[Unit]
|
|
@@ -12137,10 +12181,10 @@ WantedBy=default.target
|
|
|
12137
12181
|
`;
|
|
12138
12182
|
}
|
|
12139
12183
|
function installSystemd(binaryPath) {
|
|
12140
|
-
if (!
|
|
12141
|
-
|
|
12184
|
+
if (!import_fs23.default.existsSync(SYSTEMD_UNIT_DIR)) {
|
|
12185
|
+
import_fs23.default.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
|
|
12142
12186
|
}
|
|
12143
|
-
|
|
12187
|
+
import_fs23.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
|
|
12144
12188
|
try {
|
|
12145
12189
|
(0, import_child_process6.execFileSync)("loginctl", ["enable-linger", import_os20.default.userInfo().username], { timeout: 3e3 });
|
|
12146
12190
|
} catch {
|
|
@@ -12162,23 +12206,23 @@ function installSystemd(binaryPath) {
|
|
|
12162
12206
|
}
|
|
12163
12207
|
}
|
|
12164
12208
|
function uninstallSystemd() {
|
|
12165
|
-
if (
|
|
12209
|
+
if (import_fs23.default.existsSync(SYSTEMD_UNIT)) {
|
|
12166
12210
|
(0, import_child_process6.spawnSync)("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
|
|
12167
12211
|
encoding: "utf8",
|
|
12168
12212
|
timeout: 5e3
|
|
12169
12213
|
});
|
|
12170
12214
|
(0, import_child_process6.spawnSync)("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
|
|
12171
|
-
|
|
12215
|
+
import_fs23.default.unlinkSync(SYSTEMD_UNIT);
|
|
12172
12216
|
}
|
|
12173
12217
|
}
|
|
12174
12218
|
function isSystemdInstalled() {
|
|
12175
|
-
return
|
|
12219
|
+
return import_fs23.default.existsSync(SYSTEMD_UNIT);
|
|
12176
12220
|
}
|
|
12177
12221
|
function stopRunningDaemon() {
|
|
12178
12222
|
const pidFile = import_path26.default.join(import_os20.default.homedir(), ".node9", "daemon.pid");
|
|
12179
|
-
if (!
|
|
12223
|
+
if (!import_fs23.default.existsSync(pidFile)) return;
|
|
12180
12224
|
try {
|
|
12181
|
-
const data = JSON.parse(
|
|
12225
|
+
const data = JSON.parse(import_fs23.default.readFileSync(pidFile, "utf-8"));
|
|
12182
12226
|
const pid = data.pid;
|
|
12183
12227
|
const MAX_PID2 = 4194304;
|
|
12184
12228
|
if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
|
|
@@ -12198,7 +12242,7 @@ function stopRunningDaemon() {
|
|
|
12198
12242
|
}
|
|
12199
12243
|
}
|
|
12200
12244
|
try {
|
|
12201
|
-
|
|
12245
|
+
import_fs23.default.unlinkSync(pidFile);
|
|
12202
12246
|
} catch {
|
|
12203
12247
|
}
|
|
12204
12248
|
} catch {
|
|
@@ -12268,11 +12312,11 @@ function isDaemonServiceInstalled() {
|
|
|
12268
12312
|
if (process.platform === "linux") return isSystemdInstalled();
|
|
12269
12313
|
return false;
|
|
12270
12314
|
}
|
|
12271
|
-
var
|
|
12315
|
+
var import_fs23, import_path26, import_os20, import_child_process6, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
|
|
12272
12316
|
var init_service = __esm({
|
|
12273
12317
|
"src/daemon/service.ts"() {
|
|
12274
12318
|
"use strict";
|
|
12275
|
-
|
|
12319
|
+
import_fs23 = __toESM(require("fs"));
|
|
12276
12320
|
import_path26 = __toESM(require("path"));
|
|
12277
12321
|
import_os20 = __toESM(require("os"));
|
|
12278
12322
|
import_child_process6 = require("child_process");
|
|
@@ -12285,9 +12329,9 @@ var init_service = __esm({
|
|
|
12285
12329
|
|
|
12286
12330
|
// src/daemon/index.ts
|
|
12287
12331
|
function stopDaemon() {
|
|
12288
|
-
if (!
|
|
12332
|
+
if (!import_fs24.default.existsSync(DAEMON_PID_FILE)) return console.log(import_chalk4.default.yellow("Not running."));
|
|
12289
12333
|
try {
|
|
12290
|
-
const data = JSON.parse(
|
|
12334
|
+
const data = JSON.parse(import_fs24.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
12291
12335
|
const pid = data.pid;
|
|
12292
12336
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
12293
12337
|
console.log(import_chalk4.default.gray("Cleaned up invalid PID file."));
|
|
@@ -12299,7 +12343,7 @@ function stopDaemon() {
|
|
|
12299
12343
|
console.log(import_chalk4.default.gray("Cleaned up stale PID file."));
|
|
12300
12344
|
} finally {
|
|
12301
12345
|
try {
|
|
12302
|
-
|
|
12346
|
+
import_fs24.default.unlinkSync(DAEMON_PID_FILE);
|
|
12303
12347
|
} catch {
|
|
12304
12348
|
}
|
|
12305
12349
|
}
|
|
@@ -12308,9 +12352,9 @@ function daemonStatus() {
|
|
|
12308
12352
|
const serviceInstalled = isDaemonServiceInstalled();
|
|
12309
12353
|
const serviceLabel = serviceInstalled ? import_chalk4.default.green("installed (starts on login)") : import_chalk4.default.yellow("not installed \u2014 run: node9 daemon install");
|
|
12310
12354
|
let processStatus;
|
|
12311
|
-
if (
|
|
12355
|
+
if (import_fs24.default.existsSync(DAEMON_PID_FILE)) {
|
|
12312
12356
|
try {
|
|
12313
|
-
const data = JSON.parse(
|
|
12357
|
+
const data = JSON.parse(import_fs24.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
12314
12358
|
const pid = data.pid;
|
|
12315
12359
|
const port = data.port;
|
|
12316
12360
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
@@ -12340,11 +12384,11 @@ function daemonStatus() {
|
|
|
12340
12384
|
console.log(` Service : ${serviceLabel}
|
|
12341
12385
|
`);
|
|
12342
12386
|
}
|
|
12343
|
-
var
|
|
12387
|
+
var import_fs24, import_chalk4, import_child_process7, MAX_PID;
|
|
12344
12388
|
var init_daemon2 = __esm({
|
|
12345
12389
|
"src/daemon/index.ts"() {
|
|
12346
12390
|
"use strict";
|
|
12347
|
-
|
|
12391
|
+
import_fs24 = __toESM(require("fs"));
|
|
12348
12392
|
import_chalk4 = __toESM(require("chalk"));
|
|
12349
12393
|
import_child_process7 = require("child_process");
|
|
12350
12394
|
init_server();
|
|
@@ -12377,19 +12421,19 @@ function getModelContextLimit(model) {
|
|
|
12377
12421
|
}
|
|
12378
12422
|
function readSessionUsage() {
|
|
12379
12423
|
const projectsDir = import_path42.default.join(import_os35.default.homedir(), ".claude", "projects");
|
|
12380
|
-
if (!
|
|
12424
|
+
if (!import_fs39.default.existsSync(projectsDir)) return null;
|
|
12381
12425
|
let latestFile = null;
|
|
12382
12426
|
let latestMtime = 0;
|
|
12383
12427
|
try {
|
|
12384
|
-
for (const dir of
|
|
12428
|
+
for (const dir of import_fs39.default.readdirSync(projectsDir)) {
|
|
12385
12429
|
const dirPath = import_path42.default.join(projectsDir, dir);
|
|
12386
12430
|
try {
|
|
12387
|
-
if (!
|
|
12388
|
-
for (const file of
|
|
12431
|
+
if (!import_fs39.default.statSync(dirPath).isDirectory()) continue;
|
|
12432
|
+
for (const file of import_fs39.default.readdirSync(dirPath)) {
|
|
12389
12433
|
if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
|
|
12390
12434
|
const filePath = import_path42.default.join(dirPath, file);
|
|
12391
12435
|
try {
|
|
12392
|
-
const mtime =
|
|
12436
|
+
const mtime = import_fs39.default.statSync(filePath).mtimeMs;
|
|
12393
12437
|
if (mtime > latestMtime) {
|
|
12394
12438
|
latestMtime = mtime;
|
|
12395
12439
|
latestFile = filePath;
|
|
@@ -12404,7 +12448,7 @@ function readSessionUsage() {
|
|
|
12404
12448
|
}
|
|
12405
12449
|
if (!latestFile) return null;
|
|
12406
12450
|
try {
|
|
12407
|
-
const lines =
|
|
12451
|
+
const lines = import_fs39.default.readFileSync(latestFile, "utf-8").split("\n");
|
|
12408
12452
|
let lastModel = "";
|
|
12409
12453
|
let lastInput = 0;
|
|
12410
12454
|
let lastOutput = 0;
|
|
@@ -12493,9 +12537,9 @@ function renderPending(activity) {
|
|
|
12493
12537
|
}
|
|
12494
12538
|
async function ensureDaemon() {
|
|
12495
12539
|
let pidPort = null;
|
|
12496
|
-
if (
|
|
12540
|
+
if (import_fs39.default.existsSync(PID_FILE)) {
|
|
12497
12541
|
try {
|
|
12498
|
-
const { port } = JSON.parse(
|
|
12542
|
+
const { port } = JSON.parse(import_fs39.default.readFileSync(PID_FILE, "utf-8"));
|
|
12499
12543
|
pidPort = port;
|
|
12500
12544
|
} catch {
|
|
12501
12545
|
console.error(import_chalk25.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
@@ -12650,7 +12694,7 @@ function buildRecoveryCardLines(req) {
|
|
|
12650
12694
|
function readApproversFromDisk() {
|
|
12651
12695
|
const configPath = import_path42.default.join(import_os35.default.homedir(), ".node9", "config.json");
|
|
12652
12696
|
try {
|
|
12653
|
-
const raw = JSON.parse(
|
|
12697
|
+
const raw = JSON.parse(import_fs39.default.readFileSync(configPath, "utf-8"));
|
|
12654
12698
|
const settings = raw.settings ?? {};
|
|
12655
12699
|
return settings.approvers ?? {};
|
|
12656
12700
|
} catch {
|
|
@@ -12668,13 +12712,13 @@ function approverStatusLine() {
|
|
|
12668
12712
|
function toggleApprover(channel) {
|
|
12669
12713
|
const configPath = import_path42.default.join(import_os35.default.homedir(), ".node9", "config.json");
|
|
12670
12714
|
try {
|
|
12671
|
-
const raw = JSON.parse(
|
|
12715
|
+
const raw = JSON.parse(import_fs39.default.readFileSync(configPath, "utf-8"));
|
|
12672
12716
|
const settings = raw.settings ?? {};
|
|
12673
12717
|
const approvers = settings.approvers ?? {};
|
|
12674
12718
|
approvers[channel] = approvers[channel] === false;
|
|
12675
12719
|
settings.approvers = approvers;
|
|
12676
12720
|
raw.settings = settings;
|
|
12677
|
-
|
|
12721
|
+
import_fs39.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
|
|
12678
12722
|
} catch (err2) {
|
|
12679
12723
|
process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
|
|
12680
12724
|
`);
|
|
@@ -12844,7 +12888,7 @@ async function startTail(options = {}) {
|
|
|
12844
12888
|
}
|
|
12845
12889
|
postDecisionHttp(req2.id, httpDecision, csrfToken, port, httpOpts).catch((err2) => {
|
|
12846
12890
|
try {
|
|
12847
|
-
|
|
12891
|
+
import_fs39.default.appendFileSync(
|
|
12848
12892
|
import_path42.default.join(import_os35.default.homedir(), ".node9", "hook-debug.log"),
|
|
12849
12893
|
`[tail] POST /decision failed: ${String(err2)}
|
|
12850
12894
|
`
|
|
@@ -12928,7 +12972,7 @@ async function startTail(options = {}) {
|
|
|
12928
12972
|
}
|
|
12929
12973
|
const auditLog = import_path42.default.join(import_os35.default.homedir(), ".node9", "audit.log");
|
|
12930
12974
|
try {
|
|
12931
|
-
const unackedDlp =
|
|
12975
|
+
const unackedDlp = import_fs39.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
12932
12976
|
if (unackedDlp > 0) {
|
|
12933
12977
|
console.log("");
|
|
12934
12978
|
console.log(
|
|
@@ -13113,13 +13157,13 @@ async function startTail(options = {}) {
|
|
|
13113
13157
|
process.exit(1);
|
|
13114
13158
|
});
|
|
13115
13159
|
}
|
|
13116
|
-
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;
|
|
13117
13161
|
var init_tail = __esm({
|
|
13118
13162
|
"src/tui/tail.ts"() {
|
|
13119
13163
|
"use strict";
|
|
13120
13164
|
import_http2 = __toESM(require("http"));
|
|
13121
13165
|
import_chalk25 = __toESM(require("chalk"));
|
|
13122
|
-
|
|
13166
|
+
import_fs39 = __toESM(require("fs"));
|
|
13123
13167
|
import_os35 = __toESM(require("os"));
|
|
13124
13168
|
import_path42 = __toESM(require("path"));
|
|
13125
13169
|
import_readline5 = __toESM(require("readline"));
|
|
@@ -13249,9 +13293,9 @@ function formatTimeLeft(resetsAt) {
|
|
|
13249
13293
|
return ` (${m}m left)`;
|
|
13250
13294
|
}
|
|
13251
13295
|
function safeReadJson(filePath) {
|
|
13252
|
-
if (!
|
|
13296
|
+
if (!import_fs40.default.existsSync(filePath)) return null;
|
|
13253
13297
|
try {
|
|
13254
|
-
return JSON.parse(
|
|
13298
|
+
return JSON.parse(import_fs40.default.readFileSync(filePath, "utf-8"));
|
|
13255
13299
|
} catch {
|
|
13256
13300
|
return null;
|
|
13257
13301
|
}
|
|
@@ -13272,10 +13316,10 @@ function countHooksInFile(filePath) {
|
|
|
13272
13316
|
return Object.keys(cfg.hooks).length;
|
|
13273
13317
|
}
|
|
13274
13318
|
function countRulesInDir(rulesDir) {
|
|
13275
|
-
if (!
|
|
13319
|
+
if (!import_fs40.default.existsSync(rulesDir)) return 0;
|
|
13276
13320
|
let count = 0;
|
|
13277
13321
|
try {
|
|
13278
|
-
for (const entry of
|
|
13322
|
+
for (const entry of import_fs40.default.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
13279
13323
|
if (entry.isDirectory()) {
|
|
13280
13324
|
count += countRulesInDir(import_path43.default.join(rulesDir, entry.name));
|
|
13281
13325
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -13301,7 +13345,7 @@ function countConfigs(cwd) {
|
|
|
13301
13345
|
let hooksCount = 0;
|
|
13302
13346
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
13303
13347
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
13304
|
-
if (
|
|
13348
|
+
if (import_fs40.default.existsSync(import_path43.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
13305
13349
|
rulesCount += countRulesInDir(import_path43.default.join(claudeDir, "rules"));
|
|
13306
13350
|
const userSettings = import_path43.default.join(claudeDir, "settings.json");
|
|
13307
13351
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
@@ -13312,18 +13356,18 @@ function countConfigs(cwd) {
|
|
|
13312
13356
|
userMcpServers.delete(name);
|
|
13313
13357
|
}
|
|
13314
13358
|
if (cwd) {
|
|
13315
|
-
if (
|
|
13316
|
-
if (
|
|
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++;
|
|
13317
13361
|
const projectClaudeDir = import_path43.default.join(cwd, ".claude");
|
|
13318
13362
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
13319
13363
|
if (!overlapsUserScope) {
|
|
13320
|
-
if (
|
|
13364
|
+
if (import_fs40.default.existsSync(import_path43.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
13321
13365
|
rulesCount += countRulesInDir(import_path43.default.join(projectClaudeDir, "rules"));
|
|
13322
13366
|
const projSettings = import_path43.default.join(projectClaudeDir, "settings.json");
|
|
13323
13367
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
13324
13368
|
hooksCount += countHooksInFile(projSettings);
|
|
13325
13369
|
}
|
|
13326
|
-
if (
|
|
13370
|
+
if (import_fs40.default.existsSync(import_path43.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
13327
13371
|
const localSettings = import_path43.default.join(projectClaudeDir, "settings.local.json");
|
|
13328
13372
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
13329
13373
|
hooksCount += countHooksInFile(localSettings);
|
|
@@ -13361,11 +13405,11 @@ function readActiveShieldsHud() {
|
|
|
13361
13405
|
}
|
|
13362
13406
|
try {
|
|
13363
13407
|
const shieldsPath = import_path43.default.join(import_os36.default.homedir(), ".node9", "shields.json");
|
|
13364
|
-
if (!
|
|
13408
|
+
if (!import_fs40.default.existsSync(shieldsPath)) {
|
|
13365
13409
|
shieldsCache = { value: [], ts: now };
|
|
13366
13410
|
return [];
|
|
13367
13411
|
}
|
|
13368
|
-
const parsed = JSON.parse(
|
|
13412
|
+
const parsed = JSON.parse(import_fs40.default.readFileSync(shieldsPath, "utf-8"));
|
|
13369
13413
|
if (!Array.isArray(parsed.active)) {
|
|
13370
13414
|
shieldsCache = { value: [], ts: now };
|
|
13371
13415
|
return [];
|
|
@@ -13467,17 +13511,17 @@ function renderContextLine(stdin) {
|
|
|
13467
13511
|
async function main() {
|
|
13468
13512
|
try {
|
|
13469
13513
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
13470
|
-
if (
|
|
13514
|
+
if (import_fs40.default.existsSync(import_path43.default.join(import_os36.default.homedir(), ".node9", "hud-debug"))) {
|
|
13471
13515
|
try {
|
|
13472
13516
|
const logPath = import_path43.default.join(import_os36.default.homedir(), ".node9", "hud-debug.log");
|
|
13473
13517
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
13474
13518
|
let size = 0;
|
|
13475
13519
|
try {
|
|
13476
|
-
size =
|
|
13520
|
+
size = import_fs40.default.statSync(logPath).size;
|
|
13477
13521
|
} catch {
|
|
13478
13522
|
}
|
|
13479
13523
|
if (size < MAX_LOG_SIZE) {
|
|
13480
|
-
|
|
13524
|
+
import_fs40.default.appendFileSync(
|
|
13481
13525
|
logPath,
|
|
13482
13526
|
JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
|
|
13483
13527
|
);
|
|
@@ -13501,8 +13545,8 @@ async function main() {
|
|
|
13501
13545
|
import_path43.default.join(cwd, "node9.config.json"),
|
|
13502
13546
|
import_path43.default.join(import_os36.default.homedir(), ".node9", "config.json")
|
|
13503
13547
|
]) {
|
|
13504
|
-
if (!
|
|
13505
|
-
const cfg = JSON.parse(
|
|
13548
|
+
if (!import_fs40.default.existsSync(configPath)) continue;
|
|
13549
|
+
const cfg = JSON.parse(import_fs40.default.readFileSync(configPath, "utf-8"));
|
|
13506
13550
|
const hud = cfg.settings?.hud;
|
|
13507
13551
|
if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
|
|
13508
13552
|
}
|
|
@@ -13520,11 +13564,11 @@ async function main() {
|
|
|
13520
13564
|
renderOffline();
|
|
13521
13565
|
}
|
|
13522
13566
|
}
|
|
13523
|
-
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;
|
|
13524
13568
|
var init_hud = __esm({
|
|
13525
13569
|
"src/cli/hud.ts"() {
|
|
13526
13570
|
"use strict";
|
|
13527
|
-
|
|
13571
|
+
import_fs40 = __toESM(require("fs"));
|
|
13528
13572
|
import_path43 = __toESM(require("path"));
|
|
13529
13573
|
import_os36 = __toESM(require("os"));
|
|
13530
13574
|
import_http3 = __toESM(require("http"));
|
|
@@ -14574,7 +14618,7 @@ function getAgentsStatus(homeDir2 = import_os11.default.homedir()) {
|
|
|
14574
14618
|
// src/cli.ts
|
|
14575
14619
|
init_daemon2();
|
|
14576
14620
|
var import_chalk26 = __toESM(require("chalk"));
|
|
14577
|
-
var
|
|
14621
|
+
var import_fs41 = __toESM(require("fs"));
|
|
14578
14622
|
var import_path44 = __toESM(require("path"));
|
|
14579
14623
|
var import_os37 = __toESM(require("os"));
|
|
14580
14624
|
var import_prompts2 = require("@inquirer/prompts");
|
|
@@ -14761,7 +14805,7 @@ init_daemon_starter();
|
|
|
14761
14805
|
|
|
14762
14806
|
// src/cli/commands/check.ts
|
|
14763
14807
|
var import_chalk6 = __toESM(require("chalk"));
|
|
14764
|
-
var
|
|
14808
|
+
var import_fs27 = __toESM(require("fs"));
|
|
14765
14809
|
var import_child_process10 = require("child_process");
|
|
14766
14810
|
var import_path29 = __toESM(require("path"));
|
|
14767
14811
|
var import_os23 = __toESM(require("os"));
|
|
@@ -14773,7 +14817,7 @@ init_policy();
|
|
|
14773
14817
|
// src/undo.ts
|
|
14774
14818
|
var import_child_process9 = require("child_process");
|
|
14775
14819
|
var import_crypto8 = __toESM(require("crypto"));
|
|
14776
|
-
var
|
|
14820
|
+
var import_fs25 = __toESM(require("fs"));
|
|
14777
14821
|
var import_net3 = __toESM(require("net"));
|
|
14778
14822
|
var import_path27 = __toESM(require("path"));
|
|
14779
14823
|
var import_os21 = __toESM(require("os"));
|
|
@@ -14803,16 +14847,16 @@ var MAX_SNAPSHOTS = 10;
|
|
|
14803
14847
|
var GIT_TIMEOUT = 15e3;
|
|
14804
14848
|
function readStack() {
|
|
14805
14849
|
try {
|
|
14806
|
-
if (
|
|
14807
|
-
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"));
|
|
14808
14852
|
} catch {
|
|
14809
14853
|
}
|
|
14810
14854
|
return [];
|
|
14811
14855
|
}
|
|
14812
14856
|
function writeStack(stack) {
|
|
14813
14857
|
const dir = import_path27.default.dirname(SNAPSHOT_STACK_PATH);
|
|
14814
|
-
if (!
|
|
14815
|
-
|
|
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));
|
|
14816
14860
|
}
|
|
14817
14861
|
function extractFilePath(args) {
|
|
14818
14862
|
if (!args || typeof args !== "object") return null;
|
|
@@ -14834,7 +14878,7 @@ function buildArgsSummary(tool, args) {
|
|
|
14834
14878
|
function findProjectRoot(filePath) {
|
|
14835
14879
|
let dir = import_path27.default.dirname(filePath);
|
|
14836
14880
|
while (true) {
|
|
14837
|
-
if (
|
|
14881
|
+
if (import_fs25.default.existsSync(import_path27.default.join(dir, ".git")) || import_fs25.default.existsSync(import_path27.default.join(dir, "package.json"))) {
|
|
14838
14882
|
return dir;
|
|
14839
14883
|
}
|
|
14840
14884
|
const parent = import_path27.default.dirname(dir);
|
|
@@ -14845,7 +14889,7 @@ function findProjectRoot(filePath) {
|
|
|
14845
14889
|
function normalizeCwdForHash(cwd) {
|
|
14846
14890
|
let normalized;
|
|
14847
14891
|
try {
|
|
14848
|
-
normalized =
|
|
14892
|
+
normalized = import_fs25.default.realpathSync(cwd);
|
|
14849
14893
|
} catch {
|
|
14850
14894
|
normalized = cwd;
|
|
14851
14895
|
}
|
|
@@ -14860,11 +14904,11 @@ function getShadowRepoDir(cwd) {
|
|
|
14860
14904
|
function cleanOrphanedIndexFiles(shadowDir) {
|
|
14861
14905
|
try {
|
|
14862
14906
|
const cutoff = Date.now() - 6e4;
|
|
14863
|
-
for (const f of
|
|
14907
|
+
for (const f of import_fs25.default.readdirSync(shadowDir)) {
|
|
14864
14908
|
if (f.startsWith("index_")) {
|
|
14865
14909
|
const fp = import_path27.default.join(shadowDir, f);
|
|
14866
14910
|
try {
|
|
14867
|
-
if (
|
|
14911
|
+
if (import_fs25.default.statSync(fp).mtimeMs < cutoff) import_fs25.default.unlinkSync(fp);
|
|
14868
14912
|
} catch {
|
|
14869
14913
|
}
|
|
14870
14914
|
}
|
|
@@ -14876,7 +14920,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
|
|
|
14876
14920
|
const hardcoded = [".git", ".node9"];
|
|
14877
14921
|
const lines = [...hardcoded, ...ignorePaths].join("\n");
|
|
14878
14922
|
try {
|
|
14879
|
-
|
|
14923
|
+
import_fs25.default.writeFileSync(import_path27.default.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
|
|
14880
14924
|
} catch {
|
|
14881
14925
|
}
|
|
14882
14926
|
}
|
|
@@ -14891,23 +14935,23 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
14891
14935
|
if (check.status === 0) {
|
|
14892
14936
|
const ptPath = import_path27.default.join(shadowDir, "project-path.txt");
|
|
14893
14937
|
try {
|
|
14894
|
-
const stored =
|
|
14938
|
+
const stored = import_fs25.default.readFileSync(ptPath, "utf8").trim();
|
|
14895
14939
|
if (stored === normalizedCwd) return true;
|
|
14896
14940
|
if (process.env.NODE9_DEBUG === "1")
|
|
14897
14941
|
console.error(
|
|
14898
14942
|
`[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
|
|
14899
14943
|
);
|
|
14900
|
-
|
|
14944
|
+
import_fs25.default.rmSync(shadowDir, { recursive: true, force: true });
|
|
14901
14945
|
} catch {
|
|
14902
14946
|
try {
|
|
14903
|
-
|
|
14947
|
+
import_fs25.default.writeFileSync(ptPath, normalizedCwd, "utf8");
|
|
14904
14948
|
} catch {
|
|
14905
14949
|
}
|
|
14906
14950
|
return true;
|
|
14907
14951
|
}
|
|
14908
14952
|
}
|
|
14909
14953
|
try {
|
|
14910
|
-
|
|
14954
|
+
import_fs25.default.mkdirSync(shadowDir, { recursive: true });
|
|
14911
14955
|
} catch {
|
|
14912
14956
|
}
|
|
14913
14957
|
const init = (0, import_child_process9.spawnSync)("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
|
|
@@ -14924,7 +14968,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
14924
14968
|
timeout: 3e3
|
|
14925
14969
|
});
|
|
14926
14970
|
try {
|
|
14927
|
-
|
|
14971
|
+
import_fs25.default.writeFileSync(import_path27.default.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
|
|
14928
14972
|
} catch {
|
|
14929
14973
|
}
|
|
14930
14974
|
return true;
|
|
@@ -15021,7 +15065,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
15021
15065
|
writeStack(stack);
|
|
15022
15066
|
const entry = stack[stack.length - 1];
|
|
15023
15067
|
notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
|
|
15024
|
-
|
|
15068
|
+
import_fs25.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
|
|
15025
15069
|
if (shouldGc) {
|
|
15026
15070
|
(0, import_child_process9.spawn)("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
|
|
15027
15071
|
}
|
|
@@ -15032,7 +15076,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
15032
15076
|
} finally {
|
|
15033
15077
|
if (indexFile) {
|
|
15034
15078
|
try {
|
|
15035
|
-
|
|
15079
|
+
import_fs25.default.unlinkSync(indexFile);
|
|
15036
15080
|
} catch {
|
|
15037
15081
|
}
|
|
15038
15082
|
}
|
|
@@ -15109,8 +15153,8 @@ function applyUndo(hash, cwd) {
|
|
|
15109
15153
|
}).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
|
|
15110
15154
|
for (const file of [...tracked, ...untracked]) {
|
|
15111
15155
|
const fullPath = import_path27.default.join(dir, file);
|
|
15112
|
-
if (!snapshotFiles.has(file) &&
|
|
15113
|
-
|
|
15156
|
+
if (!snapshotFiles.has(file) && import_fs25.default.existsSync(fullPath)) {
|
|
15157
|
+
import_fs25.default.unlinkSync(fullPath);
|
|
15114
15158
|
}
|
|
15115
15159
|
}
|
|
15116
15160
|
return true;
|
|
@@ -15123,7 +15167,7 @@ function applyUndo(hash, cwd) {
|
|
|
15123
15167
|
init_daemon_starter();
|
|
15124
15168
|
|
|
15125
15169
|
// src/skill-pin.ts
|
|
15126
|
-
var
|
|
15170
|
+
var import_fs26 = __toESM(require("fs"));
|
|
15127
15171
|
var import_path28 = __toESM(require("path"));
|
|
15128
15172
|
var import_os22 = __toESM(require("os"));
|
|
15129
15173
|
var import_crypto9 = __toESM(require("crypto"));
|
|
@@ -15142,7 +15186,7 @@ function walkDir(root) {
|
|
|
15142
15186
|
if (out.length >= MAX_FILES) return;
|
|
15143
15187
|
let entries;
|
|
15144
15188
|
try {
|
|
15145
|
-
entries =
|
|
15189
|
+
entries = import_fs26.default.readdirSync(dir, { withFileTypes: true });
|
|
15146
15190
|
} catch {
|
|
15147
15191
|
return;
|
|
15148
15192
|
}
|
|
@@ -15153,7 +15197,7 @@ function walkDir(root) {
|
|
|
15153
15197
|
const rel = relDir ? import_path28.default.posix.join(relDir, entry.name) : entry.name;
|
|
15154
15198
|
let lst;
|
|
15155
15199
|
try {
|
|
15156
|
-
lst =
|
|
15200
|
+
lst = import_fs26.default.lstatSync(full);
|
|
15157
15201
|
} catch {
|
|
15158
15202
|
continue;
|
|
15159
15203
|
}
|
|
@@ -15165,7 +15209,7 @@ function walkDir(root) {
|
|
|
15165
15209
|
if (!lst.isFile()) continue;
|
|
15166
15210
|
if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
|
|
15167
15211
|
try {
|
|
15168
|
-
const buf =
|
|
15212
|
+
const buf = import_fs26.default.readFileSync(full);
|
|
15169
15213
|
totalBytes += buf.length;
|
|
15170
15214
|
out.push({ rel, hash: sha256Bytes(buf) });
|
|
15171
15215
|
} catch {
|
|
@@ -15179,14 +15223,14 @@ function walkDir(root) {
|
|
|
15179
15223
|
function hashSkillRoot(absPath) {
|
|
15180
15224
|
let lst;
|
|
15181
15225
|
try {
|
|
15182
|
-
lst =
|
|
15226
|
+
lst = import_fs26.default.lstatSync(absPath);
|
|
15183
15227
|
} catch {
|
|
15184
15228
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
15185
15229
|
}
|
|
15186
15230
|
if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
|
|
15187
15231
|
if (lst.isFile()) {
|
|
15188
15232
|
try {
|
|
15189
|
-
return { exists: true, contentHash: sha256Bytes(
|
|
15233
|
+
return { exists: true, contentHash: sha256Bytes(import_fs26.default.readFileSync(absPath)), fileCount: 1 };
|
|
15190
15234
|
} catch {
|
|
15191
15235
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
15192
15236
|
}
|
|
@@ -15204,7 +15248,7 @@ function getRootKey(absPath) {
|
|
|
15204
15248
|
function readSkillPinsSafe() {
|
|
15205
15249
|
const filePath = getPinsFilePath();
|
|
15206
15250
|
try {
|
|
15207
|
-
const raw =
|
|
15251
|
+
const raw = import_fs26.default.readFileSync(filePath, "utf-8");
|
|
15208
15252
|
if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
15209
15253
|
const parsed = JSON.parse(raw);
|
|
15210
15254
|
if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
|
|
@@ -15224,10 +15268,10 @@ function readSkillPins() {
|
|
|
15224
15268
|
}
|
|
15225
15269
|
function writeSkillPins(data) {
|
|
15226
15270
|
const filePath = getPinsFilePath();
|
|
15227
|
-
|
|
15271
|
+
import_fs26.default.mkdirSync(import_path28.default.dirname(filePath), { recursive: true });
|
|
15228
15272
|
const tmp = `${filePath}.${import_crypto9.default.randomBytes(6).toString("hex")}.tmp`;
|
|
15229
|
-
|
|
15230
|
-
|
|
15273
|
+
import_fs26.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
15274
|
+
import_fs26.default.renameSync(tmp, filePath);
|
|
15231
15275
|
}
|
|
15232
15276
|
function removePin(rootKey) {
|
|
15233
15277
|
const pins = readSkillPins();
|
|
@@ -15275,7 +15319,7 @@ function defaultSkillRoots(_cwd) {
|
|
|
15275
15319
|
const roots = [];
|
|
15276
15320
|
let registries;
|
|
15277
15321
|
try {
|
|
15278
|
-
registries =
|
|
15322
|
+
registries = import_fs26.default.readdirSync(marketplaces, { withFileTypes: true });
|
|
15279
15323
|
} catch {
|
|
15280
15324
|
return [];
|
|
15281
15325
|
}
|
|
@@ -15284,7 +15328,7 @@ function defaultSkillRoots(_cwd) {
|
|
|
15284
15328
|
const pluginsDir = import_path28.default.join(marketplaces, registry.name, "plugins");
|
|
15285
15329
|
let plugins;
|
|
15286
15330
|
try {
|
|
15287
|
-
plugins =
|
|
15331
|
+
plugins = import_fs26.default.readdirSync(pluginsDir, { withFileTypes: true });
|
|
15288
15332
|
} catch {
|
|
15289
15333
|
continue;
|
|
15290
15334
|
}
|
|
@@ -15320,7 +15364,7 @@ function registerCheckCommand(program2) {
|
|
|
15320
15364
|
if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
|
|
15321
15365
|
const logPath = import_path29.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
|
|
15322
15366
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
15323
|
-
|
|
15367
|
+
import_fs27.default.appendFileSync(
|
|
15324
15368
|
logPath,
|
|
15325
15369
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
|
|
15326
15370
|
RAW: ${raw}
|
|
@@ -15335,8 +15379,8 @@ RAW: ${raw}
|
|
|
15335
15379
|
const scriptPath = process.argv[1];
|
|
15336
15380
|
if (typeof scriptPath !== "string" || !import_path29.default.isAbsolute(scriptPath))
|
|
15337
15381
|
throw new Error("node9: argv[1] is not an absolute path");
|
|
15338
|
-
const resolvedScript =
|
|
15339
|
-
const packageDist =
|
|
15382
|
+
const resolvedScript = import_fs27.default.realpathSync(scriptPath);
|
|
15383
|
+
const packageDist = import_fs27.default.realpathSync(import_path29.default.resolve(__dirname, "../.."));
|
|
15340
15384
|
if (!resolvedScript.startsWith(packageDist + import_path29.default.sep) && resolvedScript !== packageDist)
|
|
15341
15385
|
throw new Error(
|
|
15342
15386
|
`node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
|
|
@@ -15362,7 +15406,7 @@ RAW: ${raw}
|
|
|
15362
15406
|
const logPath = import_path29.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
|
|
15363
15407
|
const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
|
|
15364
15408
|
try {
|
|
15365
|
-
|
|
15409
|
+
import_fs27.default.appendFileSync(
|
|
15366
15410
|
logPath,
|
|
15367
15411
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
|
|
15368
15412
|
`
|
|
@@ -15373,9 +15417,9 @@ RAW: ${raw}
|
|
|
15373
15417
|
}
|
|
15374
15418
|
if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
|
|
15375
15419
|
const logPath = import_path29.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
|
|
15376
|
-
if (!
|
|
15377
|
-
|
|
15378
|
-
|
|
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}
|
|
15379
15423
|
`);
|
|
15380
15424
|
}
|
|
15381
15425
|
const toolName = sanitize2(payload.tool_name ?? payload.name ?? "");
|
|
@@ -15388,8 +15432,8 @@ RAW: ${raw}
|
|
|
15388
15432
|
const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
|
|
15389
15433
|
let ttyFd = null;
|
|
15390
15434
|
try {
|
|
15391
|
-
ttyFd =
|
|
15392
|
-
const writeTty = (line) =>
|
|
15435
|
+
ttyFd = import_fs27.default.openSync("/dev/tty", "w");
|
|
15436
|
+
const writeTty = (line) => import_fs27.default.writeSync(ttyFd, line + "\n");
|
|
15393
15437
|
if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
|
|
15394
15438
|
writeTty(import_chalk6.default.bgRed.white.bold(`
|
|
15395
15439
|
\u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
|
|
@@ -15408,7 +15452,7 @@ RAW: ${raw}
|
|
|
15408
15452
|
} finally {
|
|
15409
15453
|
if (ttyFd !== null)
|
|
15410
15454
|
try {
|
|
15411
|
-
|
|
15455
|
+
import_fs27.default.closeSync(ttyFd);
|
|
15412
15456
|
} catch {
|
|
15413
15457
|
}
|
|
15414
15458
|
}
|
|
@@ -15446,13 +15490,13 @@ RAW: ${raw}
|
|
|
15446
15490
|
const flagPath = import_path29.default.join(sessionsDir, `${safeSessionId}.json`);
|
|
15447
15491
|
let flag = null;
|
|
15448
15492
|
try {
|
|
15449
|
-
flag = JSON.parse(
|
|
15493
|
+
flag = JSON.parse(import_fs27.default.readFileSync(flagPath, "utf-8"));
|
|
15450
15494
|
} catch {
|
|
15451
15495
|
}
|
|
15452
15496
|
const writeFlag = (data2) => {
|
|
15453
15497
|
try {
|
|
15454
|
-
|
|
15455
|
-
|
|
15498
|
+
import_fs27.default.mkdirSync(sessionsDir, { recursive: true });
|
|
15499
|
+
import_fs27.default.writeFileSync(
|
|
15456
15500
|
flagPath,
|
|
15457
15501
|
JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
|
|
15458
15502
|
{ mode: 384 }
|
|
@@ -15463,8 +15507,8 @@ RAW: ${raw}
|
|
|
15463
15507
|
const sendSkillWarn = (detail, recoveryCmd) => {
|
|
15464
15508
|
let ttyFd = null;
|
|
15465
15509
|
try {
|
|
15466
|
-
ttyFd =
|
|
15467
|
-
const w = (line) =>
|
|
15510
|
+
ttyFd = import_fs27.default.openSync("/dev/tty", "w");
|
|
15511
|
+
const w = (line) => import_fs27.default.writeSync(ttyFd, line + "\n");
|
|
15468
15512
|
w(import_chalk6.default.yellow(`
|
|
15469
15513
|
\u26A0\uFE0F Node9: installed skill drift detected`));
|
|
15470
15514
|
w(import_chalk6.default.gray(` ${detail}`));
|
|
@@ -15479,7 +15523,7 @@ RAW: ${raw}
|
|
|
15479
15523
|
} finally {
|
|
15480
15524
|
if (ttyFd !== null)
|
|
15481
15525
|
try {
|
|
15482
|
-
|
|
15526
|
+
import_fs27.default.closeSync(ttyFd);
|
|
15483
15527
|
} catch {
|
|
15484
15528
|
}
|
|
15485
15529
|
}
|
|
@@ -15536,10 +15580,10 @@ RAW: ${raw}
|
|
|
15536
15580
|
}
|
|
15537
15581
|
try {
|
|
15538
15582
|
const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
15539
|
-
for (const name of
|
|
15583
|
+
for (const name of import_fs27.default.readdirSync(sessionsDir)) {
|
|
15540
15584
|
const p = import_path29.default.join(sessionsDir, name);
|
|
15541
15585
|
try {
|
|
15542
|
-
if (
|
|
15586
|
+
if (import_fs27.default.statSync(p).mtimeMs < cutoff) import_fs27.default.unlinkSync(p);
|
|
15543
15587
|
} catch {
|
|
15544
15588
|
}
|
|
15545
15589
|
}
|
|
@@ -15551,7 +15595,7 @@ RAW: ${raw}
|
|
|
15551
15595
|
try {
|
|
15552
15596
|
const dbg = import_path29.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
|
|
15553
15597
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
15554
|
-
|
|
15598
|
+
import_fs27.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
|
|
15555
15599
|
`);
|
|
15556
15600
|
} catch {
|
|
15557
15601
|
}
|
|
@@ -15573,12 +15617,12 @@ RAW: ${raw}
|
|
|
15573
15617
|
}
|
|
15574
15618
|
if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
|
|
15575
15619
|
try {
|
|
15576
|
-
const tty =
|
|
15577
|
-
|
|
15620
|
+
const tty = import_fs27.default.openSync("/dev/tty", "w");
|
|
15621
|
+
import_fs27.default.writeSync(
|
|
15578
15622
|
tty,
|
|
15579
15623
|
import_chalk6.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
|
|
15580
15624
|
);
|
|
15581
|
-
|
|
15625
|
+
import_fs27.default.closeSync(tty);
|
|
15582
15626
|
} catch {
|
|
15583
15627
|
}
|
|
15584
15628
|
const daemonReady = await autoStartDaemonAndWait();
|
|
@@ -15607,7 +15651,7 @@ RAW: ${raw}
|
|
|
15607
15651
|
if (process.env.NODE9_DEBUG === "1") {
|
|
15608
15652
|
const logPath = import_path29.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
|
|
15609
15653
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
15610
|
-
|
|
15654
|
+
import_fs27.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
|
|
15611
15655
|
`);
|
|
15612
15656
|
}
|
|
15613
15657
|
process.exit(0);
|
|
@@ -15641,7 +15685,7 @@ RAW: ${raw}
|
|
|
15641
15685
|
}
|
|
15642
15686
|
|
|
15643
15687
|
// src/cli/commands/log.ts
|
|
15644
|
-
var
|
|
15688
|
+
var import_fs28 = __toESM(require("fs"));
|
|
15645
15689
|
var import_path30 = __toESM(require("path"));
|
|
15646
15690
|
var import_os24 = __toESM(require("os"));
|
|
15647
15691
|
init_audit();
|
|
@@ -15719,9 +15763,9 @@ function registerLogCommand(program2) {
|
|
|
15719
15763
|
source: "post-hook"
|
|
15720
15764
|
};
|
|
15721
15765
|
const logPath = import_path30.default.join(import_os24.default.homedir(), ".node9", "audit.log");
|
|
15722
|
-
if (!
|
|
15723
|
-
|
|
15724
|
-
|
|
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");
|
|
15725
15769
|
if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
|
|
15726
15770
|
const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
15727
15771
|
if (command) {
|
|
@@ -15777,7 +15821,7 @@ function registerLogCommand(program2) {
|
|
|
15777
15821
|
`);
|
|
15778
15822
|
const debugPath = import_path30.default.join(import_os24.default.homedir(), ".node9", "hook-debug.log");
|
|
15779
15823
|
try {
|
|
15780
|
-
|
|
15824
|
+
import_fs28.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
|
|
15781
15825
|
`);
|
|
15782
15826
|
} catch {
|
|
15783
15827
|
}
|
|
@@ -16177,7 +16221,7 @@ function registerConfigShowCommand(program2) {
|
|
|
16177
16221
|
|
|
16178
16222
|
// src/cli/commands/doctor.ts
|
|
16179
16223
|
var import_chalk8 = __toESM(require("chalk"));
|
|
16180
|
-
var
|
|
16224
|
+
var import_fs29 = __toESM(require("fs"));
|
|
16181
16225
|
var import_path31 = __toESM(require("path"));
|
|
16182
16226
|
var import_os25 = __toESM(require("os"));
|
|
16183
16227
|
var import_child_process11 = require("child_process");
|
|
@@ -16234,9 +16278,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16234
16278
|
}
|
|
16235
16279
|
section("Configuration");
|
|
16236
16280
|
const globalConfigPath = import_path31.default.join(homeDir2, ".node9", "config.json");
|
|
16237
|
-
if (
|
|
16281
|
+
if (import_fs29.default.existsSync(globalConfigPath)) {
|
|
16238
16282
|
try {
|
|
16239
|
-
JSON.parse(
|
|
16283
|
+
JSON.parse(import_fs29.default.readFileSync(globalConfigPath, "utf-8"));
|
|
16240
16284
|
pass("~/.node9/config.json found and valid");
|
|
16241
16285
|
} catch {
|
|
16242
16286
|
fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
|
|
@@ -16245,9 +16289,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16245
16289
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
16246
16290
|
}
|
|
16247
16291
|
const projectConfigPath = import_path31.default.join(process.cwd(), "node9.config.json");
|
|
16248
|
-
if (
|
|
16292
|
+
if (import_fs29.default.existsSync(projectConfigPath)) {
|
|
16249
16293
|
try {
|
|
16250
|
-
JSON.parse(
|
|
16294
|
+
JSON.parse(import_fs29.default.readFileSync(projectConfigPath, "utf-8"));
|
|
16251
16295
|
pass("node9.config.json found and valid (project)");
|
|
16252
16296
|
} catch {
|
|
16253
16297
|
fail(
|
|
@@ -16257,7 +16301,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16257
16301
|
}
|
|
16258
16302
|
}
|
|
16259
16303
|
const credsPath = import_path31.default.join(homeDir2, ".node9", "credentials.json");
|
|
16260
|
-
if (
|
|
16304
|
+
if (import_fs29.default.existsSync(credsPath)) {
|
|
16261
16305
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
16262
16306
|
} else {
|
|
16263
16307
|
warn(
|
|
@@ -16267,9 +16311,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16267
16311
|
}
|
|
16268
16312
|
section("Agent Hooks");
|
|
16269
16313
|
const claudeSettingsPath = import_path31.default.join(homeDir2, ".claude", "settings.json");
|
|
16270
|
-
if (
|
|
16314
|
+
if (import_fs29.default.existsSync(claudeSettingsPath)) {
|
|
16271
16315
|
try {
|
|
16272
|
-
const cs = JSON.parse(
|
|
16316
|
+
const cs = JSON.parse(import_fs29.default.readFileSync(claudeSettingsPath, "utf-8"));
|
|
16273
16317
|
const hasHook = cs.hooks?.PreToolUse?.some(
|
|
16274
16318
|
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
16275
16319
|
);
|
|
@@ -16286,9 +16330,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16286
16330
|
warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
|
|
16287
16331
|
}
|
|
16288
16332
|
const geminiSettingsPath = import_path31.default.join(homeDir2, ".gemini", "settings.json");
|
|
16289
|
-
if (
|
|
16333
|
+
if (import_fs29.default.existsSync(geminiSettingsPath)) {
|
|
16290
16334
|
try {
|
|
16291
|
-
const gs = JSON.parse(
|
|
16335
|
+
const gs = JSON.parse(import_fs29.default.readFileSync(geminiSettingsPath, "utf-8"));
|
|
16292
16336
|
const hasHook = gs.hooks?.BeforeTool?.some(
|
|
16293
16337
|
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
16294
16338
|
);
|
|
@@ -16305,9 +16349,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16305
16349
|
warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
|
|
16306
16350
|
}
|
|
16307
16351
|
const cursorHooksPath = import_path31.default.join(homeDir2, ".cursor", "hooks.json");
|
|
16308
|
-
if (
|
|
16352
|
+
if (import_fs29.default.existsSync(cursorHooksPath)) {
|
|
16309
16353
|
try {
|
|
16310
|
-
const cur = JSON.parse(
|
|
16354
|
+
const cur = JSON.parse(import_fs29.default.readFileSync(cursorHooksPath, "utf-8"));
|
|
16311
16355
|
const hasHook = cur.hooks?.preToolUse?.some(
|
|
16312
16356
|
(h) => h.command?.includes("node9") || h.command?.includes("cli.js")
|
|
16313
16357
|
);
|
|
@@ -16345,7 +16389,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
16345
16389
|
|
|
16346
16390
|
// src/cli/commands/audit.ts
|
|
16347
16391
|
var import_chalk9 = __toESM(require("chalk"));
|
|
16348
|
-
var
|
|
16392
|
+
var import_fs30 = __toESM(require("fs"));
|
|
16349
16393
|
var import_path32 = __toESM(require("path"));
|
|
16350
16394
|
var import_os26 = __toESM(require("os"));
|
|
16351
16395
|
function formatRelativeTime(timestamp) {
|
|
@@ -16361,13 +16405,13 @@ function formatRelativeTime(timestamp) {
|
|
|
16361
16405
|
function registerAuditCommand(program2) {
|
|
16362
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) => {
|
|
16363
16407
|
const logPath = import_path32.default.join(import_os26.default.homedir(), ".node9", "audit.log");
|
|
16364
|
-
if (!
|
|
16408
|
+
if (!import_fs30.default.existsSync(logPath)) {
|
|
16365
16409
|
console.log(
|
|
16366
16410
|
import_chalk9.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
16367
16411
|
);
|
|
16368
16412
|
return;
|
|
16369
16413
|
}
|
|
16370
|
-
const raw =
|
|
16414
|
+
const raw = import_fs30.default.readFileSync(logPath, "utf-8");
|
|
16371
16415
|
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
16372
16416
|
let entries = lines.flatMap((line) => {
|
|
16373
16417
|
try {
|
|
@@ -16421,7 +16465,7 @@ function registerAuditCommand(program2) {
|
|
|
16421
16465
|
|
|
16422
16466
|
// src/cli/commands/report.ts
|
|
16423
16467
|
var import_chalk10 = __toESM(require("chalk"));
|
|
16424
|
-
var
|
|
16468
|
+
var import_fs31 = __toESM(require("fs"));
|
|
16425
16469
|
var import_path33 = __toESM(require("path"));
|
|
16426
16470
|
var import_os27 = __toESM(require("os"));
|
|
16427
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;
|
|
@@ -16470,8 +16514,8 @@ function getDateRange(period) {
|
|
|
16470
16514
|
}
|
|
16471
16515
|
}
|
|
16472
16516
|
function parseAuditLog(logPath) {
|
|
16473
|
-
if (!
|
|
16474
|
-
const raw =
|
|
16517
|
+
if (!import_fs31.default.existsSync(logPath)) return [];
|
|
16518
|
+
const raw = import_fs31.default.readFileSync(logPath, "utf-8");
|
|
16475
16519
|
return raw.split("\n").flatMap((line) => {
|
|
16476
16520
|
if (!line.trim()) return [];
|
|
16477
16521
|
try {
|
|
@@ -16551,10 +16595,10 @@ function loadClaudeCost(start, end) {
|
|
|
16551
16595
|
cacheReadTokens: 0
|
|
16552
16596
|
};
|
|
16553
16597
|
const projectsDir = import_path33.default.join(import_os27.default.homedir(), ".claude", "projects");
|
|
16554
|
-
if (!
|
|
16598
|
+
if (!import_fs31.default.existsSync(projectsDir)) return empty;
|
|
16555
16599
|
let dirs;
|
|
16556
16600
|
try {
|
|
16557
|
-
dirs =
|
|
16601
|
+
dirs = import_fs31.default.readdirSync(projectsDir);
|
|
16558
16602
|
} catch {
|
|
16559
16603
|
return empty;
|
|
16560
16604
|
}
|
|
@@ -16569,15 +16613,15 @@ function loadClaudeCost(start, end) {
|
|
|
16569
16613
|
const projPath = import_path33.default.join(projectsDir, proj);
|
|
16570
16614
|
let files;
|
|
16571
16615
|
try {
|
|
16572
|
-
const stat =
|
|
16616
|
+
const stat = import_fs31.default.statSync(projPath);
|
|
16573
16617
|
if (!stat.isDirectory()) continue;
|
|
16574
|
-
files =
|
|
16618
|
+
files = import_fs31.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
16575
16619
|
} catch {
|
|
16576
16620
|
continue;
|
|
16577
16621
|
}
|
|
16578
16622
|
for (const file of files) {
|
|
16579
16623
|
try {
|
|
16580
|
-
const raw =
|
|
16624
|
+
const raw = import_fs31.default.readFileSync(import_path33.default.join(projPath, file), "utf-8");
|
|
16581
16625
|
for (const line of raw.split("\n")) {
|
|
16582
16626
|
if (!line.trim()) continue;
|
|
16583
16627
|
let entry;
|
|
@@ -16622,31 +16666,31 @@ function loadCodexCost(start, end) {
|
|
|
16622
16666
|
const byDay = /* @__PURE__ */ new Map();
|
|
16623
16667
|
let total = 0;
|
|
16624
16668
|
let toolCalls = 0;
|
|
16625
|
-
if (!
|
|
16669
|
+
if (!import_fs31.default.existsSync(sessionsBase)) return { total, byDay, toolCalls };
|
|
16626
16670
|
const jsonlFiles = [];
|
|
16627
16671
|
try {
|
|
16628
|
-
for (const year of
|
|
16672
|
+
for (const year of import_fs31.default.readdirSync(sessionsBase)) {
|
|
16629
16673
|
const yearPath = import_path33.default.join(sessionsBase, year);
|
|
16630
16674
|
try {
|
|
16631
|
-
if (!
|
|
16675
|
+
if (!import_fs31.default.statSync(yearPath).isDirectory()) continue;
|
|
16632
16676
|
} catch {
|
|
16633
16677
|
continue;
|
|
16634
16678
|
}
|
|
16635
|
-
for (const month of
|
|
16679
|
+
for (const month of import_fs31.default.readdirSync(yearPath)) {
|
|
16636
16680
|
const monthPath = import_path33.default.join(yearPath, month);
|
|
16637
16681
|
try {
|
|
16638
|
-
if (!
|
|
16682
|
+
if (!import_fs31.default.statSync(monthPath).isDirectory()) continue;
|
|
16639
16683
|
} catch {
|
|
16640
16684
|
continue;
|
|
16641
16685
|
}
|
|
16642
|
-
for (const day of
|
|
16686
|
+
for (const day of import_fs31.default.readdirSync(monthPath)) {
|
|
16643
16687
|
const dayPath = import_path33.default.join(monthPath, day);
|
|
16644
16688
|
try {
|
|
16645
|
-
if (!
|
|
16689
|
+
if (!import_fs31.default.statSync(dayPath).isDirectory()) continue;
|
|
16646
16690
|
} catch {
|
|
16647
16691
|
continue;
|
|
16648
16692
|
}
|
|
16649
|
-
for (const file of
|
|
16693
|
+
for (const file of import_fs31.default.readdirSync(dayPath)) {
|
|
16650
16694
|
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path33.default.join(dayPath, file));
|
|
16651
16695
|
}
|
|
16652
16696
|
}
|
|
@@ -16658,7 +16702,7 @@ function loadCodexCost(start, end) {
|
|
|
16658
16702
|
for (const filePath of jsonlFiles) {
|
|
16659
16703
|
let lines;
|
|
16660
16704
|
try {
|
|
16661
|
-
lines =
|
|
16705
|
+
lines = import_fs31.default.readFileSync(filePath, "utf-8").split("\n");
|
|
16662
16706
|
} catch {
|
|
16663
16707
|
continue;
|
|
16664
16708
|
}
|
|
@@ -17213,14 +17257,14 @@ function registerDaemonCommand(program2) {
|
|
|
17213
17257
|
|
|
17214
17258
|
// src/cli/commands/status.ts
|
|
17215
17259
|
var import_chalk12 = __toESM(require("chalk"));
|
|
17216
|
-
var
|
|
17260
|
+
var import_fs32 = __toESM(require("fs"));
|
|
17217
17261
|
var import_path34 = __toESM(require("path"));
|
|
17218
17262
|
var import_os28 = __toESM(require("os"));
|
|
17219
17263
|
init_core();
|
|
17220
17264
|
init_daemon();
|
|
17221
17265
|
function readJson2(filePath) {
|
|
17222
17266
|
try {
|
|
17223
|
-
if (
|
|
17267
|
+
if (import_fs32.default.existsSync(filePath)) return JSON.parse(import_fs32.default.readFileSync(filePath, "utf-8"));
|
|
17224
17268
|
} catch {
|
|
17225
17269
|
}
|
|
17226
17270
|
return null;
|
|
@@ -17288,10 +17332,10 @@ function registerStatusCommand(program2) {
|
|
|
17288
17332
|
const projectConfig = import_path34.default.join(process.cwd(), "node9.config.json");
|
|
17289
17333
|
const globalConfig = import_path34.default.join(import_os28.default.homedir(), ".node9", "config.json");
|
|
17290
17334
|
console.log(
|
|
17291
|
-
` Local: ${
|
|
17335
|
+
` Local: ${import_fs32.default.existsSync(projectConfig) ? import_chalk12.default.green("Active (node9.config.json)") : import_chalk12.default.gray("Not present")}`
|
|
17292
17336
|
);
|
|
17293
17337
|
console.log(
|
|
17294
|
-
` Global: ${
|
|
17338
|
+
` Global: ${import_fs32.default.existsSync(globalConfig) ? import_chalk12.default.green("Active (~/.node9/config.json)") : import_chalk12.default.gray("Not present")}`
|
|
17295
17339
|
);
|
|
17296
17340
|
if (mergedConfig.policy.sandboxPaths.length > 0) {
|
|
17297
17341
|
console.log(
|
|
@@ -17365,7 +17409,7 @@ function registerStatusCommand(program2) {
|
|
|
17365
17409
|
|
|
17366
17410
|
// src/cli/commands/init.ts
|
|
17367
17411
|
var import_chalk13 = __toESM(require("chalk"));
|
|
17368
|
-
var
|
|
17412
|
+
var import_fs33 = __toESM(require("fs"));
|
|
17369
17413
|
var import_path35 = __toESM(require("path"));
|
|
17370
17414
|
var import_os29 = __toESM(require("os"));
|
|
17371
17415
|
var import_https3 = __toESM(require("https"));
|
|
@@ -17429,14 +17473,14 @@ function registerInitCommand(program2) {
|
|
|
17429
17473
|
console.log("");
|
|
17430
17474
|
}
|
|
17431
17475
|
const configPath = import_path35.default.join(import_os29.default.homedir(), ".node9", "config.json");
|
|
17432
|
-
if (
|
|
17476
|
+
if (import_fs33.default.existsSync(configPath) && !options.force) {
|
|
17433
17477
|
try {
|
|
17434
|
-
const existing = JSON.parse(
|
|
17478
|
+
const existing = JSON.parse(import_fs33.default.readFileSync(configPath, "utf-8"));
|
|
17435
17479
|
const settings = existing.settings ?? {};
|
|
17436
17480
|
if (settings.mode !== chosenMode) {
|
|
17437
17481
|
settings.mode = chosenMode;
|
|
17438
17482
|
existing.settings = settings;
|
|
17439
|
-
|
|
17483
|
+
import_fs33.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
|
|
17440
17484
|
console.log(import_chalk13.default.green(`\u2705 Mode updated: ${chosenMode}`));
|
|
17441
17485
|
} else {
|
|
17442
17486
|
console.log(import_chalk13.default.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
|
|
@@ -17450,8 +17494,8 @@ function registerInitCommand(program2) {
|
|
|
17450
17494
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
17451
17495
|
};
|
|
17452
17496
|
const dir = import_path35.default.dirname(configPath);
|
|
17453
|
-
if (!
|
|
17454
|
-
|
|
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");
|
|
17455
17499
|
console.log(import_chalk13.default.green(`\u2705 Config created: ${configPath}`));
|
|
17456
17500
|
console.log(import_chalk13.default.gray(` Mode: ${chosenMode}`));
|
|
17457
17501
|
}
|
|
@@ -17891,7 +17935,7 @@ init_orchestrator();
|
|
|
17891
17935
|
init_provenance();
|
|
17892
17936
|
|
|
17893
17937
|
// src/mcp-pin.ts
|
|
17894
|
-
var
|
|
17938
|
+
var import_fs34 = __toESM(require("fs"));
|
|
17895
17939
|
var import_path37 = __toESM(require("path"));
|
|
17896
17940
|
var import_os30 = __toESM(require("os"));
|
|
17897
17941
|
var import_crypto10 = __toESM(require("crypto"));
|
|
@@ -17913,7 +17957,7 @@ function getServerKey(upstreamCommand) {
|
|
|
17913
17957
|
function readMcpPinsSafe() {
|
|
17914
17958
|
const filePath = getPinsFilePath2();
|
|
17915
17959
|
try {
|
|
17916
|
-
const raw =
|
|
17960
|
+
const raw = import_fs34.default.readFileSync(filePath, "utf-8");
|
|
17917
17961
|
if (!raw.trim()) {
|
|
17918
17962
|
return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
17919
17963
|
}
|
|
@@ -17937,10 +17981,10 @@ function readMcpPins() {
|
|
|
17937
17981
|
}
|
|
17938
17982
|
function writeMcpPins(data) {
|
|
17939
17983
|
const filePath = getPinsFilePath2();
|
|
17940
|
-
|
|
17984
|
+
import_fs34.default.mkdirSync(import_path37.default.dirname(filePath), { recursive: true });
|
|
17941
17985
|
const tmp = `${filePath}.${import_crypto10.default.randomBytes(6).toString("hex")}.tmp`;
|
|
17942
|
-
|
|
17943
|
-
|
|
17986
|
+
import_fs34.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
17987
|
+
import_fs34.default.renameSync(tmp, filePath);
|
|
17944
17988
|
}
|
|
17945
17989
|
function checkPin(serverKey, currentHash) {
|
|
17946
17990
|
const result = readMcpPinsSafe();
|
|
@@ -18388,7 +18432,7 @@ function registerMcpGatewayCommand(program2) {
|
|
|
18388
18432
|
|
|
18389
18433
|
// src/mcp-server/index.ts
|
|
18390
18434
|
var import_readline4 = __toESM(require("readline"));
|
|
18391
|
-
var
|
|
18435
|
+
var import_fs35 = __toESM(require("fs"));
|
|
18392
18436
|
var import_os31 = __toESM(require("os"));
|
|
18393
18437
|
var import_path38 = __toESM(require("path"));
|
|
18394
18438
|
var import_child_process15 = require("child_process");
|
|
@@ -18644,10 +18688,10 @@ function handleStatus() {
|
|
|
18644
18688
|
const projectConfig = import_path38.default.join(process.cwd(), "node9.config.json");
|
|
18645
18689
|
const globalConfig = import_path38.default.join(import_os31.default.homedir(), ".node9", "config.json");
|
|
18646
18690
|
lines.push(
|
|
18647
|
-
`Project config (node9.config.json): ${
|
|
18691
|
+
`Project config (node9.config.json): ${import_fs35.default.existsSync(projectConfig) ? "present" : "not found"}`
|
|
18648
18692
|
);
|
|
18649
18693
|
lines.push(
|
|
18650
|
-
`Global config (~/.node9/config.json): ${
|
|
18694
|
+
`Global config (~/.node9/config.json): ${import_fs35.default.existsSync(globalConfig) ? "present" : "not found"}`
|
|
18651
18695
|
);
|
|
18652
18696
|
return lines.join("\n");
|
|
18653
18697
|
}
|
|
@@ -18725,8 +18769,8 @@ var GLOBAL_CONFIG_PATH2 = import_path38.default.join(import_os31.default.homedir
|
|
|
18725
18769
|
var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
|
|
18726
18770
|
function readGlobalConfigRaw() {
|
|
18727
18771
|
try {
|
|
18728
|
-
if (
|
|
18729
|
-
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"));
|
|
18730
18774
|
}
|
|
18731
18775
|
} catch {
|
|
18732
18776
|
}
|
|
@@ -18734,8 +18778,8 @@ function readGlobalConfigRaw() {
|
|
|
18734
18778
|
}
|
|
18735
18779
|
function writeGlobalConfigRaw(data) {
|
|
18736
18780
|
const dir = import_path38.default.dirname(GLOBAL_CONFIG_PATH2);
|
|
18737
|
-
if (!
|
|
18738
|
-
|
|
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");
|
|
18739
18783
|
}
|
|
18740
18784
|
function handleApproverList() {
|
|
18741
18785
|
const config = getConfig();
|
|
@@ -18780,8 +18824,8 @@ function handleAuditGet(args) {
|
|
|
18780
18824
|
const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
|
|
18781
18825
|
const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
|
|
18782
18826
|
const auditPath = import_path38.default.join(import_os31.default.homedir(), ".node9", "audit.log");
|
|
18783
|
-
if (!
|
|
18784
|
-
const rawLines =
|
|
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);
|
|
18785
18829
|
const parsed = [];
|
|
18786
18830
|
for (const line of rawLines) {
|
|
18787
18831
|
try {
|
|
@@ -19335,7 +19379,7 @@ init_scan();
|
|
|
19335
19379
|
|
|
19336
19380
|
// src/cli/commands/sessions.ts
|
|
19337
19381
|
var import_chalk22 = __toESM(require("chalk"));
|
|
19338
|
-
var
|
|
19382
|
+
var import_fs36 = __toESM(require("fs"));
|
|
19339
19383
|
var import_path39 = __toESM(require("path"));
|
|
19340
19384
|
var import_os32 = __toESM(require("os"));
|
|
19341
19385
|
var CLAUDE_PRICING3 = {
|
|
@@ -19453,7 +19497,7 @@ function loadAuditEntries(auditPath) {
|
|
|
19453
19497
|
const aPath = auditPath ?? import_path39.default.join(import_os32.default.homedir(), ".node9", "audit.log");
|
|
19454
19498
|
let raw;
|
|
19455
19499
|
try {
|
|
19456
|
-
raw =
|
|
19500
|
+
raw = import_fs36.default.readFileSync(aPath, "utf-8");
|
|
19457
19501
|
} catch {
|
|
19458
19502
|
return [];
|
|
19459
19503
|
}
|
|
@@ -19490,7 +19534,7 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
19490
19534
|
}
|
|
19491
19535
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
19492
19536
|
const tmpDir = import_path39.default.join(import_os32.default.homedir(), ".gemini", "tmp");
|
|
19493
|
-
if (!
|
|
19537
|
+
if (!import_fs36.default.existsSync(tmpDir)) return [];
|
|
19494
19538
|
const cutoff = days !== null ? (() => {
|
|
19495
19539
|
const d = /* @__PURE__ */ new Date();
|
|
19496
19540
|
d.setDate(d.getDate() - days);
|
|
@@ -19499,7 +19543,7 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
19499
19543
|
})() : null;
|
|
19500
19544
|
let slugDirs;
|
|
19501
19545
|
try {
|
|
19502
|
-
slugDirs =
|
|
19546
|
+
slugDirs = import_fs36.default.readdirSync(tmpDir);
|
|
19503
19547
|
} catch {
|
|
19504
19548
|
return [];
|
|
19505
19549
|
}
|
|
@@ -19507,27 +19551,27 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
19507
19551
|
for (const slug of slugDirs) {
|
|
19508
19552
|
const slugPath = import_path39.default.join(tmpDir, slug);
|
|
19509
19553
|
try {
|
|
19510
|
-
if (!
|
|
19554
|
+
if (!import_fs36.default.statSync(slugPath).isDirectory()) continue;
|
|
19511
19555
|
} catch {
|
|
19512
19556
|
continue;
|
|
19513
19557
|
}
|
|
19514
19558
|
let projectRoot = import_path39.default.join(import_os32.default.homedir(), slug);
|
|
19515
19559
|
try {
|
|
19516
|
-
projectRoot =
|
|
19560
|
+
projectRoot = import_fs36.default.readFileSync(import_path39.default.join(slugPath, ".project_root"), "utf-8").trim();
|
|
19517
19561
|
} catch {
|
|
19518
19562
|
}
|
|
19519
19563
|
const chatsDir = import_path39.default.join(slugPath, "chats");
|
|
19520
|
-
if (!
|
|
19564
|
+
if (!import_fs36.default.existsSync(chatsDir)) continue;
|
|
19521
19565
|
let chatFiles;
|
|
19522
19566
|
try {
|
|
19523
|
-
chatFiles =
|
|
19567
|
+
chatFiles = import_fs36.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
19524
19568
|
} catch {
|
|
19525
19569
|
continue;
|
|
19526
19570
|
}
|
|
19527
19571
|
for (const chatFile of chatFiles) {
|
|
19528
19572
|
let raw;
|
|
19529
19573
|
try {
|
|
19530
|
-
raw =
|
|
19574
|
+
raw = import_fs36.default.readFileSync(import_path39.default.join(chatsDir, chatFile), "utf-8");
|
|
19531
19575
|
} catch {
|
|
19532
19576
|
continue;
|
|
19533
19577
|
}
|
|
@@ -19608,7 +19652,7 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
19608
19652
|
}
|
|
19609
19653
|
function buildCodexSessions(days, allAuditEntries) {
|
|
19610
19654
|
const sessionsBase = import_path39.default.join(import_os32.default.homedir(), ".codex", "sessions");
|
|
19611
|
-
if (!
|
|
19655
|
+
if (!import_fs36.default.existsSync(sessionsBase)) return [];
|
|
19612
19656
|
const cutoff = days !== null ? (() => {
|
|
19613
19657
|
const d = /* @__PURE__ */ new Date();
|
|
19614
19658
|
d.setDate(d.getDate() - days);
|
|
@@ -19617,28 +19661,28 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
19617
19661
|
})() : null;
|
|
19618
19662
|
const jsonlFiles = [];
|
|
19619
19663
|
try {
|
|
19620
|
-
for (const year of
|
|
19664
|
+
for (const year of import_fs36.default.readdirSync(sessionsBase)) {
|
|
19621
19665
|
const yearPath = import_path39.default.join(sessionsBase, year);
|
|
19622
19666
|
try {
|
|
19623
|
-
if (!
|
|
19667
|
+
if (!import_fs36.default.statSync(yearPath).isDirectory()) continue;
|
|
19624
19668
|
} catch {
|
|
19625
19669
|
continue;
|
|
19626
19670
|
}
|
|
19627
|
-
for (const month of
|
|
19671
|
+
for (const month of import_fs36.default.readdirSync(yearPath)) {
|
|
19628
19672
|
const monthPath = import_path39.default.join(yearPath, month);
|
|
19629
19673
|
try {
|
|
19630
|
-
if (!
|
|
19674
|
+
if (!import_fs36.default.statSync(monthPath).isDirectory()) continue;
|
|
19631
19675
|
} catch {
|
|
19632
19676
|
continue;
|
|
19633
19677
|
}
|
|
19634
|
-
for (const day of
|
|
19678
|
+
for (const day of import_fs36.default.readdirSync(monthPath)) {
|
|
19635
19679
|
const dayPath = import_path39.default.join(monthPath, day);
|
|
19636
19680
|
try {
|
|
19637
|
-
if (!
|
|
19681
|
+
if (!import_fs36.default.statSync(dayPath).isDirectory()) continue;
|
|
19638
19682
|
} catch {
|
|
19639
19683
|
continue;
|
|
19640
19684
|
}
|
|
19641
|
-
for (const file of
|
|
19685
|
+
for (const file of import_fs36.default.readdirSync(dayPath)) {
|
|
19642
19686
|
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path39.default.join(dayPath, file));
|
|
19643
19687
|
}
|
|
19644
19688
|
}
|
|
@@ -19651,7 +19695,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
19651
19695
|
for (const filePath of jsonlFiles) {
|
|
19652
19696
|
let lines;
|
|
19653
19697
|
try {
|
|
19654
|
-
lines =
|
|
19698
|
+
lines = import_fs36.default.readFileSync(filePath, "utf-8").split("\n");
|
|
19655
19699
|
} catch {
|
|
19656
19700
|
continue;
|
|
19657
19701
|
}
|
|
@@ -19732,7 +19776,7 @@ function buildSessions(days, historyPath) {
|
|
|
19732
19776
|
const hPath = historyPath ?? import_path39.default.join(import_os32.default.homedir(), ".claude", "history.jsonl");
|
|
19733
19777
|
let historyRaw;
|
|
19734
19778
|
try {
|
|
19735
|
-
historyRaw =
|
|
19779
|
+
historyRaw = import_fs36.default.readFileSync(hPath, "utf-8");
|
|
19736
19780
|
} catch {
|
|
19737
19781
|
return [];
|
|
19738
19782
|
}
|
|
@@ -19757,7 +19801,7 @@ function buildSessions(days, historyPath) {
|
|
|
19757
19801
|
const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
|
|
19758
19802
|
let sessionLines = [];
|
|
19759
19803
|
try {
|
|
19760
|
-
sessionLines =
|
|
19804
|
+
sessionLines = import_fs36.default.readFileSync(jsonlFile, "utf-8").split("\n");
|
|
19761
19805
|
} catch {
|
|
19762
19806
|
}
|
|
19763
19807
|
const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
|
|
@@ -20024,7 +20068,7 @@ function registerSessionsCommand(program2) {
|
|
|
20024
20068
|
console.log(import_chalk22.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk22.default.dim(" \u2014 what your AI agent did"));
|
|
20025
20069
|
console.log("");
|
|
20026
20070
|
const historyPath = import_path39.default.join(import_os32.default.homedir(), ".claude", "history.jsonl");
|
|
20027
|
-
if (!
|
|
20071
|
+
if (!import_fs36.default.existsSync(historyPath)) {
|
|
20028
20072
|
console.log(import_chalk22.default.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
|
|
20029
20073
|
console.log(import_chalk22.default.gray(" Install Claude Code, run a few sessions, then try again.\n"));
|
|
20030
20074
|
return;
|
|
@@ -20061,12 +20105,12 @@ function registerSessionsCommand(program2) {
|
|
|
20061
20105
|
|
|
20062
20106
|
// src/cli/commands/skill-pin.ts
|
|
20063
20107
|
var import_chalk23 = __toESM(require("chalk"));
|
|
20064
|
-
var
|
|
20108
|
+
var import_fs37 = __toESM(require("fs"));
|
|
20065
20109
|
var import_os33 = __toESM(require("os"));
|
|
20066
20110
|
var import_path40 = __toESM(require("path"));
|
|
20067
20111
|
function wipeSkillSessions() {
|
|
20068
20112
|
try {
|
|
20069
|
-
|
|
20113
|
+
import_fs37.default.rmSync(import_path40.default.join(import_os33.default.homedir(), ".node9", "skill-sessions"), {
|
|
20070
20114
|
recursive: true,
|
|
20071
20115
|
force: true
|
|
20072
20116
|
});
|
|
@@ -20149,7 +20193,7 @@ function registerSkillPinCommand(program2) {
|
|
|
20149
20193
|
|
|
20150
20194
|
// src/cli/commands/dlp.ts
|
|
20151
20195
|
var import_chalk24 = __toESM(require("chalk"));
|
|
20152
|
-
var
|
|
20196
|
+
var import_fs38 = __toESM(require("fs"));
|
|
20153
20197
|
var import_path41 = __toESM(require("path"));
|
|
20154
20198
|
var import_os34 = __toESM(require("os"));
|
|
20155
20199
|
var AUDIT_LOG = import_path41.default.join(import_os34.default.homedir(), ".node9", "audit.log");
|
|
@@ -20160,7 +20204,7 @@ function stripAnsi(s) {
|
|
|
20160
20204
|
}
|
|
20161
20205
|
function loadResolved() {
|
|
20162
20206
|
try {
|
|
20163
|
-
const raw = JSON.parse(
|
|
20207
|
+
const raw = JSON.parse(import_fs38.default.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
20164
20208
|
return new Set(raw);
|
|
20165
20209
|
} catch {
|
|
20166
20210
|
return /* @__PURE__ */ new Set();
|
|
@@ -20168,13 +20212,13 @@ function loadResolved() {
|
|
|
20168
20212
|
}
|
|
20169
20213
|
function saveResolved(resolved) {
|
|
20170
20214
|
try {
|
|
20171
|
-
|
|
20215
|
+
import_fs38.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
20172
20216
|
} catch {
|
|
20173
20217
|
}
|
|
20174
20218
|
}
|
|
20175
20219
|
function loadDlpFindings() {
|
|
20176
|
-
if (!
|
|
20177
|
-
return
|
|
20220
|
+
if (!import_fs38.default.existsSync(AUDIT_LOG)) return [];
|
|
20221
|
+
return import_fs38.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
20178
20222
|
if (!line.trim()) return [];
|
|
20179
20223
|
try {
|
|
20180
20224
|
const e = JSON.parse(line);
|
|
@@ -20272,20 +20316,20 @@ function registerDlpCommand(program2) {
|
|
|
20272
20316
|
|
|
20273
20317
|
// src/cli.ts
|
|
20274
20318
|
var { version } = JSON.parse(
|
|
20275
|
-
|
|
20319
|
+
import_fs41.default.readFileSync(import_path44.default.join(__dirname, "../package.json"), "utf-8")
|
|
20276
20320
|
);
|
|
20277
20321
|
var program = new import_commander.Command();
|
|
20278
20322
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
20279
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) => {
|
|
20280
20324
|
const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
|
|
20281
20325
|
const credPath = import_path44.default.join(import_os37.default.homedir(), ".node9", "credentials.json");
|
|
20282
|
-
if (!
|
|
20283
|
-
|
|
20326
|
+
if (!import_fs41.default.existsSync(import_path44.default.dirname(credPath)))
|
|
20327
|
+
import_fs41.default.mkdirSync(import_path44.default.dirname(credPath), { recursive: true });
|
|
20284
20328
|
const profileName = options.profile || "default";
|
|
20285
20329
|
let existingCreds = {};
|
|
20286
20330
|
try {
|
|
20287
|
-
if (
|
|
20288
|
-
const raw = JSON.parse(
|
|
20331
|
+
if (import_fs41.default.existsSync(credPath)) {
|
|
20332
|
+
const raw = JSON.parse(import_fs41.default.readFileSync(credPath, "utf-8"));
|
|
20289
20333
|
if (raw.apiKey) {
|
|
20290
20334
|
existingCreds = {
|
|
20291
20335
|
default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
|
|
@@ -20297,13 +20341,13 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
20297
20341
|
} catch {
|
|
20298
20342
|
}
|
|
20299
20343
|
existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
|
|
20300
|
-
|
|
20344
|
+
import_fs41.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
|
|
20301
20345
|
if (profileName === "default") {
|
|
20302
20346
|
const configPath = import_path44.default.join(import_os37.default.homedir(), ".node9", "config.json");
|
|
20303
20347
|
let config = {};
|
|
20304
20348
|
try {
|
|
20305
|
-
if (
|
|
20306
|
-
config = JSON.parse(
|
|
20349
|
+
if (import_fs41.default.existsSync(configPath))
|
|
20350
|
+
config = JSON.parse(import_fs41.default.readFileSync(configPath, "utf-8"));
|
|
20307
20351
|
} catch {
|
|
20308
20352
|
}
|
|
20309
20353
|
if (!config.settings || typeof config.settings !== "object") config.settings = {};
|
|
@@ -20318,9 +20362,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
20318
20362
|
approvers.cloud = false;
|
|
20319
20363
|
}
|
|
20320
20364
|
s.approvers = approvers;
|
|
20321
|
-
if (!
|
|
20322
|
-
|
|
20323
|
-
|
|
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 });
|
|
20324
20368
|
}
|
|
20325
20369
|
if (options.profile && profileName !== "default") {
|
|
20326
20370
|
console.log(import_chalk26.default.green(`\u2705 Profile "${profileName}" saved`));
|
|
@@ -20458,14 +20502,14 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
20458
20502
|
}
|
|
20459
20503
|
if (options.purge) {
|
|
20460
20504
|
const node9Dir = import_path44.default.join(import_os37.default.homedir(), ".node9");
|
|
20461
|
-
if (
|
|
20505
|
+
if (import_fs41.default.existsSync(node9Dir)) {
|
|
20462
20506
|
const confirmed = await (0, import_prompts2.confirm)({
|
|
20463
20507
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
20464
20508
|
default: false
|
|
20465
20509
|
});
|
|
20466
20510
|
if (confirmed) {
|
|
20467
|
-
|
|
20468
|
-
if (
|
|
20511
|
+
import_fs41.default.rmSync(node9Dir, { recursive: true });
|
|
20512
|
+
if (import_fs41.default.existsSync(node9Dir)) {
|
|
20469
20513
|
console.error(
|
|
20470
20514
|
import_chalk26.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
20471
20515
|
);
|
|
@@ -20609,12 +20653,12 @@ Run "node9 addto claude" to register it as the statusLine.`
|
|
|
20609
20653
|
if (subcommand === "debug") {
|
|
20610
20654
|
const flagFile = import_path44.default.join(import_os37.default.homedir(), ".node9", "hud-debug");
|
|
20611
20655
|
if (state === "on") {
|
|
20612
|
-
|
|
20613
|
-
|
|
20656
|
+
import_fs41.default.mkdirSync(import_path44.default.dirname(flagFile), { recursive: true });
|
|
20657
|
+
import_fs41.default.writeFileSync(flagFile, "");
|
|
20614
20658
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
20615
20659
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
20616
20660
|
} else if (state === "off") {
|
|
20617
|
-
if (
|
|
20661
|
+
if (import_fs41.default.existsSync(flagFile)) import_fs41.default.unlinkSync(flagFile);
|
|
20618
20662
|
console.log("HUD debug logging disabled.");
|
|
20619
20663
|
} else {
|
|
20620
20664
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -20728,7 +20772,7 @@ if (process.argv[2] !== "daemon") {
|
|
|
20728
20772
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
20729
20773
|
const logPath = import_path44.default.join(import_os37.default.homedir(), ".node9", "hook-debug.log");
|
|
20730
20774
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
20731
|
-
|
|
20775
|
+
import_fs41.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
20732
20776
|
`);
|
|
20733
20777
|
}
|
|
20734
20778
|
process.exit(0);
|