@node9/proxy 1.35.0 → 1.35.2
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 +478 -467
- package/dist/cli.mjs +474 -463
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -185,8 +185,8 @@ function sanitizeConfig(raw) {
|
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
const lines = result.error.issues.map((issue) => {
|
|
188
|
-
const
|
|
189
|
-
return ` \u2022 ${
|
|
188
|
+
const path55 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
189
|
+
return ` \u2022 ${path55}: ${issue.message}`;
|
|
190
190
|
});
|
|
191
191
|
return {
|
|
192
192
|
sanitized,
|
|
@@ -1240,9 +1240,9 @@ function matchesPattern(text, patterns) {
|
|
|
1240
1240
|
const withoutDotSlash = text.replace(/^\.\//, "");
|
|
1241
1241
|
return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
|
|
1242
1242
|
}
|
|
1243
|
-
function getNestedValue(obj,
|
|
1243
|
+
function getNestedValue(obj, path55) {
|
|
1244
1244
|
if (!obj || typeof obj !== "object") return null;
|
|
1245
|
-
const segments =
|
|
1245
|
+
const segments = path55.split(".");
|
|
1246
1246
|
for (const seg of segments) {
|
|
1247
1247
|
if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
|
|
1248
1248
|
}
|
|
@@ -8136,7 +8136,7 @@ function binaryInPath(binary) {
|
|
|
8136
8136
|
return false;
|
|
8137
8137
|
}
|
|
8138
8138
|
function detectAgents(homeDir2 = os12.homedir()) {
|
|
8139
|
-
const
|
|
8139
|
+
const exists2 = (p) => {
|
|
8140
8140
|
try {
|
|
8141
8141
|
return fs13.existsSync(p);
|
|
8142
8142
|
} catch (err2) {
|
|
@@ -8150,7 +8150,7 @@ function detectAgents(homeDir2 = os12.homedir()) {
|
|
|
8150
8150
|
};
|
|
8151
8151
|
const desktopPath = claudeDesktopConfigPath(homeDir2);
|
|
8152
8152
|
return {
|
|
8153
|
-
claude:
|
|
8153
|
+
claude: exists2(path15.join(homeDir2, ".claude")) || exists2(path15.join(homeDir2, ".claude.json")),
|
|
8154
8154
|
// Antigravity (agy) shares the ~/.gemini root, so a bare
|
|
8155
8155
|
// `exists(~/.gemini)` would report the (EOL'd) Gemini CLI as
|
|
8156
8156
|
// installed on every agy machine — and `node9 init` would then
|
|
@@ -8160,35 +8160,35 @@ function detectAgents(homeDir2 = os12.homedir()) {
|
|
|
8160
8160
|
// creates ~/.gemini/settings.json on first run; agy does not touch
|
|
8161
8161
|
// it (it uses antigravity-cli/settings.json) — that file is the
|
|
8162
8162
|
// legacy-CLI discriminator.
|
|
8163
|
-
gemini:
|
|
8163
|
+
gemini: exists2(path15.join(homeDir2, ".gemini", "settings.json")) || binaryInPath("gemini"),
|
|
8164
8164
|
// agy creates ~/.gemini/antigravity-cli/ on first launch; the IDE
|
|
8165
8165
|
// creates antigravity-ide/. PATH fallback covers installed-but-
|
|
8166
8166
|
// never-launched (same class as opencode #186).
|
|
8167
|
-
antigravity:
|
|
8167
|
+
antigravity: exists2(path15.join(homeDir2, ".gemini", "antigravity-cli")) || exists2(path15.join(homeDir2, ".gemini", "antigravity-ide")) || binaryInPath("agy"),
|
|
8168
8168
|
// GitHub Copilot CLI creates ~/.copilot on first launch; PATH
|
|
8169
8169
|
// fallback covers installed-but-never-launched (same as opencode #186).
|
|
8170
|
-
copilot:
|
|
8171
|
-
cursor:
|
|
8172
|
-
codex:
|
|
8173
|
-
windsurf:
|
|
8174
|
-
vscode:
|
|
8175
|
-
claudeDesktop: desktopPath !== null &&
|
|
8170
|
+
copilot: exists2(path15.join(homeDir2, ".copilot")) || binaryInPath("copilot"),
|
|
8171
|
+
cursor: exists2(path15.join(homeDir2, ".cursor")),
|
|
8172
|
+
codex: exists2(path15.join(homeDir2, ".codex")),
|
|
8173
|
+
windsurf: exists2(path15.join(homeDir2, ".codeium", "windsurf")),
|
|
8174
|
+
vscode: exists2(path15.join(homeDir2, ".vscode")),
|
|
8175
|
+
claudeDesktop: desktopPath !== null && exists2(path15.dirname(desktopPath)),
|
|
8176
8176
|
// Opencode creates ~/.config/opencode lazily on first launch — fall back
|
|
8177
8177
|
// to a PATH lookup so installed-but-never-launched CLIs are still wired.
|
|
8178
|
-
opencode:
|
|
8178
|
+
opencode: exists2(path15.join(homeDir2, ".config", "opencode")) || binaryInPath("opencode"),
|
|
8179
8179
|
// Pi (https://pi.dev): config dir is ~/.pi/agent (CONFIG_DIR_NAME=".pi"
|
|
8180
8180
|
// + agentDir, verified against opensources/pi-main/packages/coding-agent/
|
|
8181
8181
|
// src/config.ts:449,475). The Bun-compiled binary path may create this
|
|
8182
8182
|
// dir lazily on first launch — same class of bug as opencode's #186
|
|
8183
8183
|
// (design R6) — so fall back to PATH lookup for installed-but-never-
|
|
8184
8184
|
// launched pi.
|
|
8185
|
-
pi:
|
|
8185
|
+
pi: exists2(path15.join(homeDir2, ".pi", "agent")) || binaryInPath("pi"),
|
|
8186
8186
|
// Hermes Agent (https://github.com/NousResearch/hermes-agent): home dir
|
|
8187
8187
|
// is $HERMES_HOME (default ~/.hermes) per hermes_constants.py:30. config.yaml
|
|
8188
8188
|
// appears after `hermes setup` has run; the directory alone exists from
|
|
8189
8189
|
// install time. PATH fallback covers the rare case where the user blew
|
|
8190
8190
|
// away ~/.hermes but kept the binary.
|
|
8191
|
-
hermes:
|
|
8191
|
+
hermes: exists2(hermesHomeDir(homeDir2)) || binaryInPath("hermes")
|
|
8192
8192
|
};
|
|
8193
8193
|
}
|
|
8194
8194
|
async function setupCursor() {
|
|
@@ -16904,9 +16904,9 @@ __export(tail_exports, {
|
|
|
16904
16904
|
});
|
|
16905
16905
|
import http2 from "http";
|
|
16906
16906
|
import chalk29 from "chalk";
|
|
16907
|
-
import
|
|
16908
|
-
import
|
|
16909
|
-
import
|
|
16907
|
+
import fs51 from "fs";
|
|
16908
|
+
import os46 from "os";
|
|
16909
|
+
import path52 from "path";
|
|
16910
16910
|
import readline6 from "readline";
|
|
16911
16911
|
import { spawn as spawn8 } from "child_process";
|
|
16912
16912
|
function shortenPathSummary(s) {
|
|
@@ -16930,20 +16930,20 @@ function getModelContextLimit(model) {
|
|
|
16930
16930
|
return 2e5;
|
|
16931
16931
|
}
|
|
16932
16932
|
function readSessionUsage() {
|
|
16933
|
-
const projectsDir =
|
|
16934
|
-
if (!
|
|
16933
|
+
const projectsDir = path52.join(os46.homedir(), ".claude", "projects");
|
|
16934
|
+
if (!fs51.existsSync(projectsDir)) return null;
|
|
16935
16935
|
let latestFile = null;
|
|
16936
16936
|
let latestMtime = 0;
|
|
16937
16937
|
try {
|
|
16938
|
-
for (const dir of
|
|
16939
|
-
const dirPath =
|
|
16938
|
+
for (const dir of fs51.readdirSync(projectsDir)) {
|
|
16939
|
+
const dirPath = path52.join(projectsDir, dir);
|
|
16940
16940
|
try {
|
|
16941
|
-
if (!
|
|
16942
|
-
for (const file of
|
|
16941
|
+
if (!fs51.statSync(dirPath).isDirectory()) continue;
|
|
16942
|
+
for (const file of fs51.readdirSync(dirPath)) {
|
|
16943
16943
|
if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
|
|
16944
|
-
const filePath =
|
|
16944
|
+
const filePath = path52.join(dirPath, file);
|
|
16945
16945
|
try {
|
|
16946
|
-
const mtime =
|
|
16946
|
+
const mtime = fs51.statSync(filePath).mtimeMs;
|
|
16947
16947
|
if (mtime > latestMtime) {
|
|
16948
16948
|
latestMtime = mtime;
|
|
16949
16949
|
latestFile = filePath;
|
|
@@ -16958,7 +16958,7 @@ function readSessionUsage() {
|
|
|
16958
16958
|
}
|
|
16959
16959
|
if (!latestFile) return null;
|
|
16960
16960
|
try {
|
|
16961
|
-
const lines =
|
|
16961
|
+
const lines = fs51.readFileSync(latestFile, "utf-8").split("\n");
|
|
16962
16962
|
let lastModel = "";
|
|
16963
16963
|
let lastInput = 0;
|
|
16964
16964
|
let lastOutput = 0;
|
|
@@ -17019,7 +17019,7 @@ function formatBase(activity) {
|
|
|
17019
17019
|
const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
|
|
17020
17020
|
const icon = getIcon(activity.tool);
|
|
17021
17021
|
const toolName = activity.tool.slice(0, 16).padEnd(16);
|
|
17022
|
-
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(
|
|
17022
|
+
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(os46.homedir(), "~");
|
|
17023
17023
|
const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
|
|
17024
17024
|
return `${chalk29.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${chalk29.white.bold(toolName)} ${chalk29.dim(argsPreview)}`;
|
|
17025
17025
|
}
|
|
@@ -17058,9 +17058,9 @@ function renderPending(activity) {
|
|
|
17058
17058
|
}
|
|
17059
17059
|
async function ensureDaemon() {
|
|
17060
17060
|
let pidPort = null;
|
|
17061
|
-
if (
|
|
17061
|
+
if (fs51.existsSync(PID_FILE)) {
|
|
17062
17062
|
try {
|
|
17063
|
-
const { port } = JSON.parse(
|
|
17063
|
+
const { port } = JSON.parse(fs51.readFileSync(PID_FILE, "utf-8"));
|
|
17064
17064
|
pidPort = port;
|
|
17065
17065
|
} catch {
|
|
17066
17066
|
console.error(chalk29.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
@@ -17216,9 +17216,9 @@ function buildRecoveryCardLines(req) {
|
|
|
17216
17216
|
];
|
|
17217
17217
|
}
|
|
17218
17218
|
function readApproversFromDisk() {
|
|
17219
|
-
const configPath =
|
|
17219
|
+
const configPath = path52.join(os46.homedir(), ".node9", "config.json");
|
|
17220
17220
|
try {
|
|
17221
|
-
const raw = JSON.parse(
|
|
17221
|
+
const raw = JSON.parse(fs51.readFileSync(configPath, "utf-8"));
|
|
17222
17222
|
const settings = raw.settings ?? {};
|
|
17223
17223
|
return settings.approvers ?? {};
|
|
17224
17224
|
} catch {
|
|
@@ -17234,15 +17234,15 @@ function approverStatusLine() {
|
|
|
17234
17234
|
return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
|
|
17235
17235
|
}
|
|
17236
17236
|
function toggleApprover(channel) {
|
|
17237
|
-
const configPath =
|
|
17237
|
+
const configPath = path52.join(os46.homedir(), ".node9", "config.json");
|
|
17238
17238
|
try {
|
|
17239
|
-
const raw = JSON.parse(
|
|
17239
|
+
const raw = JSON.parse(fs51.readFileSync(configPath, "utf-8"));
|
|
17240
17240
|
const settings = raw.settings ?? {};
|
|
17241
17241
|
const approvers = settings.approvers ?? {};
|
|
17242
17242
|
approvers[channel] = approvers[channel] === false;
|
|
17243
17243
|
settings.approvers = approvers;
|
|
17244
17244
|
raw.settings = settings;
|
|
17245
|
-
|
|
17245
|
+
fs51.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
|
|
17246
17246
|
} catch (err2) {
|
|
17247
17247
|
process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
|
|
17248
17248
|
`);
|
|
@@ -17414,8 +17414,8 @@ async function startTail(options = {}) {
|
|
|
17414
17414
|
}
|
|
17415
17415
|
postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
|
|
17416
17416
|
try {
|
|
17417
|
-
|
|
17418
|
-
|
|
17417
|
+
fs51.appendFileSync(
|
|
17418
|
+
path52.join(os46.homedir(), ".node9", "hook-debug.log"),
|
|
17419
17419
|
`[tail] POST /decision failed: ${String(err2)}
|
|
17420
17420
|
`
|
|
17421
17421
|
);
|
|
@@ -17479,9 +17479,9 @@ async function startTail(options = {}) {
|
|
|
17479
17479
|
};
|
|
17480
17480
|
process.stdin.on("keypress", onKeypress);
|
|
17481
17481
|
}
|
|
17482
|
-
const auditLog =
|
|
17482
|
+
const auditLog = path52.join(os46.homedir(), ".node9", "audit.log");
|
|
17483
17483
|
try {
|
|
17484
|
-
const unackedDlp =
|
|
17484
|
+
const unackedDlp = fs51.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
17485
17485
|
if (unackedDlp > 0) {
|
|
17486
17486
|
console.log("");
|
|
17487
17487
|
console.log(
|
|
@@ -17521,7 +17521,7 @@ async function startTail(options = {}) {
|
|
|
17521
17521
|
if (stallWarned) return;
|
|
17522
17522
|
if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
|
|
17523
17523
|
try {
|
|
17524
|
-
const auditMtime =
|
|
17524
|
+
const auditMtime = fs51.statSync(auditLog).mtimeMs;
|
|
17525
17525
|
if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
|
|
17526
17526
|
console.log("");
|
|
17527
17527
|
console.log(
|
|
@@ -17712,7 +17712,7 @@ var init_tail = __esm({
|
|
|
17712
17712
|
"use strict";
|
|
17713
17713
|
init_daemon2();
|
|
17714
17714
|
init_daemon();
|
|
17715
|
-
PID_FILE =
|
|
17715
|
+
PID_FILE = path52.join(os46.homedir(), ".node9", "daemon.pid");
|
|
17716
17716
|
ICONS = {
|
|
17717
17717
|
bash: "\u{1F4BB}",
|
|
17718
17718
|
shell: "\u{1F4BB}",
|
|
@@ -17760,9 +17760,9 @@ __export(hud_exports, {
|
|
|
17760
17760
|
main: () => main,
|
|
17761
17761
|
renderEnvironmentLine: () => renderEnvironmentLine
|
|
17762
17762
|
});
|
|
17763
|
-
import
|
|
17764
|
-
import
|
|
17765
|
-
import
|
|
17763
|
+
import fs52 from "fs";
|
|
17764
|
+
import path53 from "path";
|
|
17765
|
+
import os47 from "os";
|
|
17766
17766
|
import http3 from "http";
|
|
17767
17767
|
async function readStdin() {
|
|
17768
17768
|
const chunks = [];
|
|
@@ -17838,9 +17838,9 @@ function formatTimeLeft(resetsAt) {
|
|
|
17838
17838
|
return ` (${m}m left)`;
|
|
17839
17839
|
}
|
|
17840
17840
|
function safeReadJson(filePath) {
|
|
17841
|
-
if (!
|
|
17841
|
+
if (!fs52.existsSync(filePath)) return null;
|
|
17842
17842
|
try {
|
|
17843
|
-
return JSON.parse(
|
|
17843
|
+
return JSON.parse(fs52.readFileSync(filePath, "utf-8"));
|
|
17844
17844
|
} catch {
|
|
17845
17845
|
return null;
|
|
17846
17846
|
}
|
|
@@ -17861,12 +17861,12 @@ function countHooksInFile(filePath) {
|
|
|
17861
17861
|
return Object.keys(cfg.hooks).length;
|
|
17862
17862
|
}
|
|
17863
17863
|
function countRulesInDir(rulesDir) {
|
|
17864
|
-
if (!
|
|
17864
|
+
if (!fs52.existsSync(rulesDir)) return 0;
|
|
17865
17865
|
let count = 0;
|
|
17866
17866
|
try {
|
|
17867
|
-
for (const entry of
|
|
17867
|
+
for (const entry of fs52.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
17868
17868
|
if (entry.isDirectory()) {
|
|
17869
|
-
count += countRulesInDir(
|
|
17869
|
+
count += countRulesInDir(path53.join(rulesDir, entry.name));
|
|
17870
17870
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
17871
17871
|
count++;
|
|
17872
17872
|
}
|
|
@@ -17877,46 +17877,46 @@ function countRulesInDir(rulesDir) {
|
|
|
17877
17877
|
}
|
|
17878
17878
|
function isSamePath(a, b) {
|
|
17879
17879
|
try {
|
|
17880
|
-
return
|
|
17880
|
+
return path53.resolve(a) === path53.resolve(b);
|
|
17881
17881
|
} catch {
|
|
17882
17882
|
return false;
|
|
17883
17883
|
}
|
|
17884
17884
|
}
|
|
17885
17885
|
function countConfigs(cwd) {
|
|
17886
|
-
const homeDir2 =
|
|
17887
|
-
const claudeDir =
|
|
17886
|
+
const homeDir2 = os47.homedir();
|
|
17887
|
+
const claudeDir = path53.join(homeDir2, ".claude");
|
|
17888
17888
|
let claudeMdCount = 0;
|
|
17889
17889
|
let rulesCount = 0;
|
|
17890
17890
|
let hooksCount = 0;
|
|
17891
17891
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
17892
17892
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
17893
|
-
if (
|
|
17894
|
-
rulesCount += countRulesInDir(
|
|
17895
|
-
const userSettings =
|
|
17893
|
+
if (fs52.existsSync(path53.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
17894
|
+
rulesCount += countRulesInDir(path53.join(claudeDir, "rules"));
|
|
17895
|
+
const userSettings = path53.join(claudeDir, "settings.json");
|
|
17896
17896
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
17897
17897
|
hooksCount += countHooksInFile(userSettings);
|
|
17898
|
-
const userClaudeJson =
|
|
17898
|
+
const userClaudeJson = path53.join(homeDir2, ".claude.json");
|
|
17899
17899
|
for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
|
|
17900
17900
|
for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
|
|
17901
17901
|
userMcpServers.delete(name);
|
|
17902
17902
|
}
|
|
17903
17903
|
if (cwd) {
|
|
17904
|
-
if (
|
|
17905
|
-
if (
|
|
17906
|
-
const projectClaudeDir =
|
|
17904
|
+
if (fs52.existsSync(path53.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
17905
|
+
if (fs52.existsSync(path53.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
17906
|
+
const projectClaudeDir = path53.join(cwd, ".claude");
|
|
17907
17907
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
17908
17908
|
if (!overlapsUserScope) {
|
|
17909
|
-
if (
|
|
17910
|
-
rulesCount += countRulesInDir(
|
|
17911
|
-
const projSettings =
|
|
17909
|
+
if (fs52.existsSync(path53.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
17910
|
+
rulesCount += countRulesInDir(path53.join(projectClaudeDir, "rules"));
|
|
17911
|
+
const projSettings = path53.join(projectClaudeDir, "settings.json");
|
|
17912
17912
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
17913
17913
|
hooksCount += countHooksInFile(projSettings);
|
|
17914
17914
|
}
|
|
17915
|
-
if (
|
|
17916
|
-
const localSettings =
|
|
17915
|
+
if (fs52.existsSync(path53.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
17916
|
+
const localSettings = path53.join(projectClaudeDir, "settings.local.json");
|
|
17917
17917
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
17918
17918
|
hooksCount += countHooksInFile(localSettings);
|
|
17919
|
-
const mcpJsonServers = getMcpServerNames(
|
|
17919
|
+
const mcpJsonServers = getMcpServerNames(path53.join(cwd, ".mcp.json"));
|
|
17920
17920
|
const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
|
|
17921
17921
|
for (const name of disabledMcpJson) mcpJsonServers.delete(name);
|
|
17922
17922
|
for (const name of mcpJsonServers) projectMcpServers.add(name);
|
|
@@ -17949,12 +17949,12 @@ function readActiveShieldsHud() {
|
|
|
17949
17949
|
return shieldsCache.value;
|
|
17950
17950
|
}
|
|
17951
17951
|
try {
|
|
17952
|
-
const shieldsPath =
|
|
17953
|
-
if (!
|
|
17952
|
+
const shieldsPath = path53.join(os47.homedir(), ".node9", "shields.json");
|
|
17953
|
+
if (!fs52.existsSync(shieldsPath)) {
|
|
17954
17954
|
shieldsCache = { value: [], ts: now };
|
|
17955
17955
|
return [];
|
|
17956
17956
|
}
|
|
17957
|
-
const parsed = JSON.parse(
|
|
17957
|
+
const parsed = JSON.parse(fs52.readFileSync(shieldsPath, "utf-8"));
|
|
17958
17958
|
if (!Array.isArray(parsed.active)) {
|
|
17959
17959
|
shieldsCache = { value: [], ts: now };
|
|
17960
17960
|
return [];
|
|
@@ -18056,17 +18056,17 @@ function renderContextLine(stdin) {
|
|
|
18056
18056
|
async function main() {
|
|
18057
18057
|
try {
|
|
18058
18058
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
18059
|
-
if (
|
|
18059
|
+
if (fs52.existsSync(path53.join(os47.homedir(), ".node9", "hud-debug"))) {
|
|
18060
18060
|
try {
|
|
18061
|
-
const logPath =
|
|
18061
|
+
const logPath = path53.join(os47.homedir(), ".node9", "hud-debug.log");
|
|
18062
18062
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
18063
18063
|
let size = 0;
|
|
18064
18064
|
try {
|
|
18065
|
-
size =
|
|
18065
|
+
size = fs52.statSync(logPath).size;
|
|
18066
18066
|
} catch {
|
|
18067
18067
|
}
|
|
18068
18068
|
if (size < MAX_LOG_SIZE) {
|
|
18069
|
-
|
|
18069
|
+
fs52.appendFileSync(
|
|
18070
18070
|
logPath,
|
|
18071
18071
|
JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
|
|
18072
18072
|
);
|
|
@@ -18087,11 +18087,11 @@ async function main() {
|
|
|
18087
18087
|
try {
|
|
18088
18088
|
const cwd = stdin.cwd ?? process.cwd();
|
|
18089
18089
|
for (const configPath of [
|
|
18090
|
-
|
|
18091
|
-
|
|
18090
|
+
path53.join(cwd, "node9.config.json"),
|
|
18091
|
+
path53.join(os47.homedir(), ".node9", "config.json")
|
|
18092
18092
|
]) {
|
|
18093
|
-
if (!
|
|
18094
|
-
const cfg = JSON.parse(
|
|
18093
|
+
if (!fs52.existsSync(configPath)) continue;
|
|
18094
|
+
const cfg = JSON.parse(fs52.readFileSync(configPath, "utf-8"));
|
|
18095
18095
|
const hud = cfg.settings?.hud;
|
|
18096
18096
|
if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
|
|
18097
18097
|
}
|
|
@@ -18138,9 +18138,9 @@ init_setup();
|
|
|
18138
18138
|
init_daemon2();
|
|
18139
18139
|
import { Command } from "commander";
|
|
18140
18140
|
import chalk30 from "chalk";
|
|
18141
|
-
import
|
|
18142
|
-
import
|
|
18143
|
-
import
|
|
18141
|
+
import fs53 from "fs";
|
|
18142
|
+
import path54 from "path";
|
|
18143
|
+
import os48 from "os";
|
|
18144
18144
|
import { confirm as confirm2 } from "@inquirer/prompts";
|
|
18145
18145
|
|
|
18146
18146
|
// src/utils/duration.ts
|
|
@@ -19930,13 +19930,182 @@ function registerConfigShowCommand(program2) {
|
|
|
19930
19930
|
init_daemon();
|
|
19931
19931
|
init_config();
|
|
19932
19932
|
import chalk11 from "chalk";
|
|
19933
|
+
import fs39 from "fs";
|
|
19934
|
+
import path40 from "path";
|
|
19935
|
+
import os35 from "os";
|
|
19936
|
+
import { execSync } from "child_process";
|
|
19937
|
+
|
|
19938
|
+
// src/agent-wiring.ts
|
|
19939
|
+
init_setup();
|
|
19933
19940
|
import fs38 from "fs";
|
|
19934
19941
|
import path39 from "path";
|
|
19935
19942
|
import os34 from "os";
|
|
19936
|
-
import
|
|
19943
|
+
import * as yaml2 from "yaml";
|
|
19944
|
+
function readJson2(filePath) {
|
|
19945
|
+
if (!fs38.existsSync(filePath)) return null;
|
|
19946
|
+
try {
|
|
19947
|
+
return JSON.parse(fs38.readFileSync(filePath, "utf-8"));
|
|
19948
|
+
} catch {
|
|
19949
|
+
return "invalid";
|
|
19950
|
+
}
|
|
19951
|
+
}
|
|
19952
|
+
function matchersHaveNode9Hook(matchers) {
|
|
19953
|
+
return (matchers ?? []).some((m) => (m.hooks ?? []).some((h) => isNode9Hook(h.command)));
|
|
19954
|
+
}
|
|
19955
|
+
function flatHaveNode9Hook(entries) {
|
|
19956
|
+
return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
|
|
19957
|
+
}
|
|
19958
|
+
function readHookRoot(filePath, format) {
|
|
19959
|
+
if (!fs38.existsSync(filePath)) return "absent";
|
|
19960
|
+
let raw;
|
|
19961
|
+
try {
|
|
19962
|
+
raw = fs38.readFileSync(filePath, "utf-8");
|
|
19963
|
+
} catch {
|
|
19964
|
+
return "absent";
|
|
19965
|
+
}
|
|
19966
|
+
try {
|
|
19967
|
+
const parsed = format === "yaml" ? yaml2.parse(raw) : JSON.parse(raw);
|
|
19968
|
+
return parsed?.hooks ?? {};
|
|
19969
|
+
} catch {
|
|
19970
|
+
return "invalid";
|
|
19971
|
+
}
|
|
19972
|
+
}
|
|
19973
|
+
function eventWired(root, ev, format) {
|
|
19974
|
+
const arr = root[ev.key];
|
|
19975
|
+
if (format === "matcher") return matchersHaveNode9Hook(arr);
|
|
19976
|
+
return flatHaveNode9Hook(arr);
|
|
19977
|
+
}
|
|
19978
|
+
function readMcp(filePath) {
|
|
19979
|
+
const parsed = readJson2(filePath);
|
|
19980
|
+
if (parsed === null || parsed === "invalid") return { wrapped: [], present: false };
|
|
19981
|
+
const servers = parsed.mcpServers ?? {};
|
|
19982
|
+
const entries = Object.entries(servers);
|
|
19983
|
+
const present = entries.some(([, s]) => s?.command === "node9");
|
|
19984
|
+
const wrapped = entries.filter(([, s]) => s?.command === "node9" && Array.isArray(s.args) && s.args.length > 0).map(([name, s]) => `${name} \u2192 ${s.args.join(" ")}`);
|
|
19985
|
+
return { wrapped, present };
|
|
19986
|
+
}
|
|
19987
|
+
var exists = (p) => {
|
|
19988
|
+
try {
|
|
19989
|
+
return fs38.existsSync(p);
|
|
19990
|
+
} catch {
|
|
19991
|
+
return false;
|
|
19992
|
+
}
|
|
19993
|
+
};
|
|
19994
|
+
var ck = (key) => ({ key, kind: "check" });
|
|
19995
|
+
var lg = (key) => ({ key, kind: "log" });
|
|
19996
|
+
var DEFAULT_LABEL_PAD = 11;
|
|
19997
|
+
var hookLabelOf = (ev, pad) => `${ev.key.padEnd(pad)} (node9 ${ev.kind})`;
|
|
19998
|
+
var AGENT_SPECS = [
|
|
19999
|
+
{
|
|
20000
|
+
id: "claude",
|
|
20001
|
+
label: "Claude Code",
|
|
20002
|
+
setupCommand: "node9 setup claude",
|
|
20003
|
+
hookFile: (h) => path39.join(h, ".claude", "settings.json"),
|
|
20004
|
+
hookFormat: "matcher",
|
|
20005
|
+
hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
|
|
20006
|
+
mcpFile: (h) => path39.join(h, ".claude.json"),
|
|
20007
|
+
present: (h) => exists(path39.join(h, ".claude", "settings.json")) || exists(path39.join(h, ".claude.json"))
|
|
20008
|
+
},
|
|
20009
|
+
{
|
|
20010
|
+
id: "gemini",
|
|
20011
|
+
label: "Gemini CLI",
|
|
20012
|
+
setupCommand: "node9 setup gemini",
|
|
20013
|
+
hookFile: (h) => path39.join(h, ".gemini", "settings.json"),
|
|
20014
|
+
hookFormat: "matcher",
|
|
20015
|
+
hookEvents: [ck("BeforeTool"), lg("AfterTool")],
|
|
20016
|
+
mcpFile: (h) => path39.join(h, ".gemini", "settings.json"),
|
|
20017
|
+
present: (h) => exists(path39.join(h, ".gemini", "settings.json"))
|
|
20018
|
+
},
|
|
20019
|
+
{
|
|
20020
|
+
id: "codex",
|
|
20021
|
+
label: "Codex",
|
|
20022
|
+
setupCommand: "node9 setup codex",
|
|
20023
|
+
hookFile: (h) => path39.join(h, ".codex", "hooks.json"),
|
|
20024
|
+
hookFormat: "matcher",
|
|
20025
|
+
hookEvents: [ck("PreToolUse"), ck("UserPromptSubmit")],
|
|
20026
|
+
present: (h) => exists(path39.join(h, ".codex"))
|
|
20027
|
+
},
|
|
20028
|
+
{
|
|
20029
|
+
id: "antigravity",
|
|
20030
|
+
label: "Antigravity",
|
|
20031
|
+
setupCommand: "node9 setup antigravity",
|
|
20032
|
+
hookFile: (h) => path39.join(h, ".gemini", "config", "hooks.json"),
|
|
20033
|
+
hookFormat: "matcher",
|
|
20034
|
+
hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
|
|
20035
|
+
mcpFile: (h) => path39.join(h, ".gemini", "config", "mcp_config.json"),
|
|
20036
|
+
present: (h) => exists(path39.join(h, ".gemini", "config", "hooks.json")) || exists(path39.join(h, ".gemini", "antigravity-cli")) || exists(path39.join(h, ".gemini", "antigravity-ide"))
|
|
20037
|
+
},
|
|
20038
|
+
{
|
|
20039
|
+
id: "copilot",
|
|
20040
|
+
label: "GitHub Copilot",
|
|
20041
|
+
setupCommand: "node9 setup copilot",
|
|
20042
|
+
hookFile: (h) => path39.join(h, ".copilot", "hooks", "node9.json"),
|
|
20043
|
+
hookFormat: "flat",
|
|
20044
|
+
hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
|
|
20045
|
+
mcpFile: (h) => path39.join(h, ".copilot", "mcp-config.json"),
|
|
20046
|
+
present: (h) => exists(path39.join(h, ".copilot"))
|
|
20047
|
+
},
|
|
20048
|
+
{
|
|
20049
|
+
id: "cursor",
|
|
20050
|
+
label: "Cursor",
|
|
20051
|
+
setupCommand: "node9 setup cursor",
|
|
20052
|
+
// MCP-only — no hook file (see note above).
|
|
20053
|
+
hookFormat: "flat",
|
|
20054
|
+
hookEvents: [],
|
|
20055
|
+
mcpFile: (h) => path39.join(h, ".cursor", "mcp.json"),
|
|
20056
|
+
present: (h) => exists(path39.join(h, ".cursor", "mcp.json"))
|
|
20057
|
+
},
|
|
20058
|
+
{
|
|
20059
|
+
id: "hermes",
|
|
20060
|
+
label: "Hermes Agent",
|
|
20061
|
+
setupCommand: "node9 setup hermes",
|
|
20062
|
+
hookFile: (h) => hermesConfigPath(h),
|
|
20063
|
+
hookFormat: "yaml",
|
|
20064
|
+
hookEvents: [ck("pre_tool_call"), lg("post_tool_call")],
|
|
20065
|
+
labelPad: 14,
|
|
20066
|
+
// 'post_tool_call' is wider than the default
|
|
20067
|
+
present: (h) => exists(hermesConfigPath(h))
|
|
20068
|
+
}
|
|
20069
|
+
];
|
|
20070
|
+
function getAgentWiring(home = os34.homedir()) {
|
|
20071
|
+
const detected = detectAgents(home);
|
|
20072
|
+
return AGENT_SPECS.map((spec) => {
|
|
20073
|
+
const root = spec.hookFile ? readHookRoot(spec.hookFile(home), spec.hookFormat) : "absent";
|
|
20074
|
+
const primary = spec.hookEvents[0];
|
|
20075
|
+
const rootPresent = root !== "absent" && root !== "invalid";
|
|
20076
|
+
const pad = spec.labelPad ?? DEFAULT_LABEL_PAD;
|
|
20077
|
+
const hooks = spec.hookEvents.map((ev) => ({
|
|
20078
|
+
label: hookLabelOf(ev, pad),
|
|
20079
|
+
wired: rootPresent && eventWired(root, ev, spec.hookFormat)
|
|
20080
|
+
}));
|
|
20081
|
+
let wireState;
|
|
20082
|
+
if (root === "absent") wireState = "absent";
|
|
20083
|
+
else if (root === "invalid") wireState = "invalid";
|
|
20084
|
+
else wireState = primary && eventWired(root, primary, spec.hookFormat) ? "wired" : "unwired";
|
|
20085
|
+
const mcp = spec.mcpFile ? readMcp(spec.mcpFile(home)) : null;
|
|
20086
|
+
const anyHookWired = hooks.some((h) => h.wired);
|
|
20087
|
+
return {
|
|
20088
|
+
id: spec.id,
|
|
20089
|
+
label: spec.label,
|
|
20090
|
+
setupCommand: spec.setupCommand,
|
|
20091
|
+
installed: detected[spec.id],
|
|
20092
|
+
present: spec.present(home),
|
|
20093
|
+
hooks,
|
|
20094
|
+
wireState,
|
|
20095
|
+
hookLabel: primary ? `${primary.key} hook` : "MCP proxy",
|
|
20096
|
+
settingsPath: spec.hookFile ? spec.hookFile(home) : spec.mcpFile ? spec.mcpFile(home) : "",
|
|
20097
|
+
configFormat: spec.hookFormat === "yaml" ? "YAML" : "JSON",
|
|
20098
|
+
mcpServers: mcp ? mcp.wrapped : null,
|
|
20099
|
+
mcpProtected: mcp ? mcp.present : false,
|
|
20100
|
+
isProtected: anyHookWired || (mcp?.present ?? false)
|
|
20101
|
+
};
|
|
20102
|
+
});
|
|
20103
|
+
}
|
|
20104
|
+
|
|
20105
|
+
// src/cli/commands/doctor.ts
|
|
19937
20106
|
function registerDoctorCommand(program2, version2) {
|
|
19938
20107
|
program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
|
|
19939
|
-
const homeDir2 =
|
|
20108
|
+
const homeDir2 = os35.homedir();
|
|
19940
20109
|
let failures = 0;
|
|
19941
20110
|
function pass(msg) {
|
|
19942
20111
|
console.log(chalk11.green(" \u2705 ") + msg);
|
|
@@ -19985,10 +20154,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19985
20154
|
);
|
|
19986
20155
|
}
|
|
19987
20156
|
section("Configuration");
|
|
19988
|
-
const globalConfigPath =
|
|
19989
|
-
if (
|
|
20157
|
+
const globalConfigPath = path40.join(homeDir2, ".node9", "config.json");
|
|
20158
|
+
if (fs39.existsSync(globalConfigPath)) {
|
|
19990
20159
|
try {
|
|
19991
|
-
JSON.parse(
|
|
20160
|
+
JSON.parse(fs39.readFileSync(globalConfigPath, "utf-8"));
|
|
19992
20161
|
pass("~/.node9/config.json found and valid");
|
|
19993
20162
|
} catch {
|
|
19994
20163
|
fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
|
|
@@ -19996,10 +20165,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19996
20165
|
} else {
|
|
19997
20166
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
19998
20167
|
}
|
|
19999
|
-
const projectConfigPath =
|
|
20000
|
-
if (
|
|
20168
|
+
const projectConfigPath = path40.join(process.cwd(), "node9.config.json");
|
|
20169
|
+
if (fs39.existsSync(projectConfigPath)) {
|
|
20001
20170
|
try {
|
|
20002
|
-
JSON.parse(
|
|
20171
|
+
JSON.parse(fs39.readFileSync(projectConfigPath, "utf-8"));
|
|
20003
20172
|
pass("node9.config.json found and valid (project)");
|
|
20004
20173
|
} catch {
|
|
20005
20174
|
fail(
|
|
@@ -20008,8 +20177,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
20008
20177
|
);
|
|
20009
20178
|
}
|
|
20010
20179
|
}
|
|
20011
|
-
const credsPath =
|
|
20012
|
-
if (
|
|
20180
|
+
const credsPath = path40.join(homeDir2, ".node9", "credentials.json");
|
|
20181
|
+
if (fs39.existsSync(credsPath)) {
|
|
20013
20182
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
20014
20183
|
} else {
|
|
20015
20184
|
warn(
|
|
@@ -20018,62 +20187,25 @@ function registerDoctorCommand(program2, version2) {
|
|
|
20018
20187
|
);
|
|
20019
20188
|
}
|
|
20020
20189
|
section("Agent Hooks");
|
|
20021
|
-
const
|
|
20022
|
-
|
|
20023
|
-
|
|
20024
|
-
|
|
20025
|
-
|
|
20026
|
-
|
|
20027
|
-
);
|
|
20028
|
-
|
|
20029
|
-
|
|
20030
|
-
|
|
20031
|
-
|
|
20032
|
-
"Run: node9 setup claude"
|
|
20033
|
-
);
|
|
20034
|
-
} catch {
|
|
20035
|
-
fail("Claude Code \u2014 ~/.claude/settings.json is invalid JSON");
|
|
20036
|
-
}
|
|
20037
|
-
} else {
|
|
20038
|
-
warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
|
|
20039
|
-
}
|
|
20040
|
-
const geminiSettingsPath = path39.join(homeDir2, ".gemini", "settings.json");
|
|
20041
|
-
if (fs38.existsSync(geminiSettingsPath)) {
|
|
20042
|
-
try {
|
|
20043
|
-
const gs = JSON.parse(fs38.readFileSync(geminiSettingsPath, "utf-8"));
|
|
20044
|
-
const hasHook = gs.hooks?.BeforeTool?.some(
|
|
20045
|
-
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
20046
|
-
);
|
|
20047
|
-
if (hasHook) pass("Gemini CLI \u2014 BeforeTool hook active");
|
|
20048
|
-
else
|
|
20049
|
-
fail(
|
|
20050
|
-
"Gemini CLI \u2014 hooks file found but node9 hook missing",
|
|
20051
|
-
"Run: node9 setup gemini"
|
|
20052
|
-
);
|
|
20053
|
-
} catch {
|
|
20054
|
-
fail("Gemini CLI \u2014 ~/.gemini/settings.json is invalid JSON");
|
|
20190
|
+
const notConfigured = [];
|
|
20191
|
+
for (const a of getAgentWiring(homeDir2)) {
|
|
20192
|
+
const anyHookWired = a.hooks.some((h) => h.wired);
|
|
20193
|
+
if (a.isProtected) {
|
|
20194
|
+
pass(`${a.label} \u2014 ${anyHookWired ? `${a.hookLabel} active` : "MCP proxy active"}`);
|
|
20195
|
+
} else if (a.wireState === "invalid") {
|
|
20196
|
+
fail(`${a.label} \u2014 settings file is invalid JSON`, a.settingsPath);
|
|
20197
|
+
} else if (a.wireState === "unwired") {
|
|
20198
|
+
fail(`${a.label} \u2014 settings found but node9 hook missing`, `Run: ${a.setupCommand}`);
|
|
20199
|
+
} else {
|
|
20200
|
+
notConfigured.push(a.label);
|
|
20055
20201
|
}
|
|
20056
|
-
} else {
|
|
20057
|
-
warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
|
|
20058
20202
|
}
|
|
20059
|
-
|
|
20060
|
-
|
|
20061
|
-
|
|
20062
|
-
|
|
20063
|
-
|
|
20064
|
-
|
|
20065
|
-
);
|
|
20066
|
-
if (hasHook) pass("Cursor \u2014 preToolUse hook active");
|
|
20067
|
-
else
|
|
20068
|
-
fail(
|
|
20069
|
-
"Cursor \u2014 hooks file found but node9 hook missing",
|
|
20070
|
-
"Run: node9 setup cursor"
|
|
20071
|
-
);
|
|
20072
|
-
} catch {
|
|
20073
|
-
fail("Cursor \u2014 ~/.cursor/hooks.json is invalid JSON");
|
|
20074
|
-
}
|
|
20075
|
-
} else {
|
|
20076
|
-
warn("Cursor \u2014 not configured", "Run: node9 setup cursor (skip if not using Cursor)");
|
|
20203
|
+
if (notConfigured.length > 0) {
|
|
20204
|
+
console.log(
|
|
20205
|
+
chalk11.gray(
|
|
20206
|
+
` \xB7 Not configured: ${notConfigured.join(", ")} \u2014 run \`node9 setup <agent>\` if you use one`
|
|
20207
|
+
)
|
|
20208
|
+
);
|
|
20077
20209
|
}
|
|
20078
20210
|
section("Daemon (optional)");
|
|
20079
20211
|
if (isDaemonRunning()) {
|
|
@@ -20090,7 +20222,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
20090
20222
|
try {
|
|
20091
20223
|
const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
|
|
20092
20224
|
const cfg = getConfig();
|
|
20093
|
-
const creds =
|
|
20225
|
+
const creds = fs39.existsSync(path40.join(os35.homedir(), ".node9", "credentials.json"));
|
|
20094
20226
|
if (!creds) {
|
|
20095
20227
|
warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
|
|
20096
20228
|
} else if (!cfg.settings.approvers.cloud) {
|
|
@@ -20140,9 +20272,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
20140
20272
|
|
|
20141
20273
|
// src/cli/commands/audit.ts
|
|
20142
20274
|
import chalk12 from "chalk";
|
|
20143
|
-
import
|
|
20144
|
-
import
|
|
20145
|
-
import
|
|
20275
|
+
import fs40 from "fs";
|
|
20276
|
+
import path41 from "path";
|
|
20277
|
+
import os36 from "os";
|
|
20146
20278
|
function formatRelativeTime(timestamp) {
|
|
20147
20279
|
const diff = Date.now() - new Date(timestamp).getTime();
|
|
20148
20280
|
const sec = Math.floor(diff / 1e3);
|
|
@@ -20155,14 +20287,14 @@ function formatRelativeTime(timestamp) {
|
|
|
20155
20287
|
}
|
|
20156
20288
|
function registerAuditCommand(program2) {
|
|
20157
20289
|
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) => {
|
|
20158
|
-
const logPath =
|
|
20159
|
-
if (!
|
|
20290
|
+
const logPath = path41.join(os36.homedir(), ".node9", "audit.log");
|
|
20291
|
+
if (!fs40.existsSync(logPath)) {
|
|
20160
20292
|
console.log(
|
|
20161
20293
|
chalk12.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
20162
20294
|
);
|
|
20163
20295
|
return;
|
|
20164
20296
|
}
|
|
20165
|
-
const raw =
|
|
20297
|
+
const raw = fs40.readFileSync(logPath, "utf-8");
|
|
20166
20298
|
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
20167
20299
|
let entries = lines.flatMap((line) => {
|
|
20168
20300
|
try {
|
|
@@ -20221,9 +20353,9 @@ import chalk13 from "chalk";
|
|
|
20221
20353
|
init_costSync();
|
|
20222
20354
|
init_litellm();
|
|
20223
20355
|
init_cost_codex();
|
|
20224
|
-
import
|
|
20225
|
-
import
|
|
20226
|
-
import
|
|
20356
|
+
import fs41 from "fs";
|
|
20357
|
+
import os37 from "os";
|
|
20358
|
+
import path42 from "path";
|
|
20227
20359
|
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;
|
|
20228
20360
|
function buildTestTimestamps(allEntries) {
|
|
20229
20361
|
const testTs = /* @__PURE__ */ new Set();
|
|
@@ -20303,8 +20435,8 @@ function getDateRange(period, now) {
|
|
|
20303
20435
|
}
|
|
20304
20436
|
}
|
|
20305
20437
|
function parseAuditLog(logPath) {
|
|
20306
|
-
if (!
|
|
20307
|
-
const raw =
|
|
20438
|
+
if (!fs41.existsSync(logPath)) return [];
|
|
20439
|
+
const raw = fs41.readFileSync(logPath, "utf-8");
|
|
20308
20440
|
return raw.split("\n").flatMap((line) => {
|
|
20309
20441
|
if (!line.trim()) return [];
|
|
20310
20442
|
try {
|
|
@@ -20351,25 +20483,25 @@ function freezeClaudeCost(acc) {
|
|
|
20351
20483
|
};
|
|
20352
20484
|
}
|
|
20353
20485
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
20354
|
-
const projPath =
|
|
20486
|
+
const projPath = path42.join(projectsDir, proj);
|
|
20355
20487
|
let files;
|
|
20356
20488
|
try {
|
|
20357
|
-
const stat =
|
|
20489
|
+
const stat = fs41.statSync(projPath);
|
|
20358
20490
|
if (!stat.isDirectory()) return;
|
|
20359
|
-
files =
|
|
20491
|
+
files = fs41.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
20360
20492
|
} catch {
|
|
20361
20493
|
return;
|
|
20362
20494
|
}
|
|
20363
20495
|
const startMs = start.getTime();
|
|
20364
20496
|
for (const file of files) {
|
|
20365
|
-
const filePath =
|
|
20497
|
+
const filePath = path42.join(projPath, file);
|
|
20366
20498
|
try {
|
|
20367
|
-
if (
|
|
20499
|
+
if (fs41.statSync(filePath).mtimeMs < startMs) continue;
|
|
20368
20500
|
} catch {
|
|
20369
20501
|
continue;
|
|
20370
20502
|
}
|
|
20371
20503
|
try {
|
|
20372
|
-
const raw =
|
|
20504
|
+
const raw = fs41.readFileSync(filePath, "utf-8");
|
|
20373
20505
|
for (const line of raw.split("\n")) {
|
|
20374
20506
|
if (!line.trim()) continue;
|
|
20375
20507
|
let entry;
|
|
@@ -20419,10 +20551,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
20419
20551
|
}
|
|
20420
20552
|
function loadClaudeCost(start, end, projectsDir) {
|
|
20421
20553
|
const acc = emptyClaudeCostAccumulator();
|
|
20422
|
-
if (!
|
|
20554
|
+
if (!fs41.existsSync(projectsDir)) return freezeClaudeCost(acc);
|
|
20423
20555
|
let dirs;
|
|
20424
20556
|
try {
|
|
20425
|
-
dirs =
|
|
20557
|
+
dirs = fs41.readdirSync(projectsDir);
|
|
20426
20558
|
} catch {
|
|
20427
20559
|
return freezeClaudeCost(acc);
|
|
20428
20560
|
}
|
|
@@ -20434,7 +20566,7 @@ function loadClaudeCost(start, end, projectsDir) {
|
|
|
20434
20566
|
function processCodexCostFile(filePath, start, end, acc) {
|
|
20435
20567
|
let lines;
|
|
20436
20568
|
try {
|
|
20437
|
-
lines =
|
|
20569
|
+
lines = fs41.readFileSync(filePath, "utf-8").split("\n");
|
|
20438
20570
|
} catch {
|
|
20439
20571
|
return;
|
|
20440
20572
|
}
|
|
@@ -20489,31 +20621,31 @@ function processCodexCostFile(filePath, start, end, acc) {
|
|
|
20489
20621
|
}
|
|
20490
20622
|
function listCodexSessionFiles2(sessionsBase) {
|
|
20491
20623
|
const jsonlFiles = [];
|
|
20492
|
-
if (!
|
|
20624
|
+
if (!fs41.existsSync(sessionsBase)) return jsonlFiles;
|
|
20493
20625
|
try {
|
|
20494
|
-
for (const year of
|
|
20495
|
-
const yearPath =
|
|
20626
|
+
for (const year of fs41.readdirSync(sessionsBase)) {
|
|
20627
|
+
const yearPath = path42.join(sessionsBase, year);
|
|
20496
20628
|
try {
|
|
20497
|
-
if (!
|
|
20629
|
+
if (!fs41.statSync(yearPath).isDirectory()) continue;
|
|
20498
20630
|
} catch {
|
|
20499
20631
|
continue;
|
|
20500
20632
|
}
|
|
20501
|
-
for (const month of
|
|
20502
|
-
const monthPath =
|
|
20633
|
+
for (const month of fs41.readdirSync(yearPath)) {
|
|
20634
|
+
const monthPath = path42.join(yearPath, month);
|
|
20503
20635
|
try {
|
|
20504
|
-
if (!
|
|
20636
|
+
if (!fs41.statSync(monthPath).isDirectory()) continue;
|
|
20505
20637
|
} catch {
|
|
20506
20638
|
continue;
|
|
20507
20639
|
}
|
|
20508
|
-
for (const day of
|
|
20509
|
-
const dayPath =
|
|
20640
|
+
for (const day of fs41.readdirSync(monthPath)) {
|
|
20641
|
+
const dayPath = path42.join(monthPath, day);
|
|
20510
20642
|
try {
|
|
20511
|
-
if (!
|
|
20643
|
+
if (!fs41.statSync(dayPath).isDirectory()) continue;
|
|
20512
20644
|
} catch {
|
|
20513
20645
|
continue;
|
|
20514
20646
|
}
|
|
20515
|
-
for (const file of
|
|
20516
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
20647
|
+
for (const file of fs41.readdirSync(dayPath)) {
|
|
20648
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(path42.join(dayPath, file));
|
|
20517
20649
|
}
|
|
20518
20650
|
}
|
|
20519
20651
|
}
|
|
@@ -20578,13 +20710,13 @@ function freezeGeminiCost(acc) {
|
|
|
20578
20710
|
function processGeminiCostFile(filePath, projectKey, start, end, acc) {
|
|
20579
20711
|
const startMs = start.getTime();
|
|
20580
20712
|
try {
|
|
20581
|
-
if (
|
|
20713
|
+
if (fs41.statSync(filePath).mtimeMs < startMs) return;
|
|
20582
20714
|
} catch {
|
|
20583
20715
|
return;
|
|
20584
20716
|
}
|
|
20585
20717
|
let raw;
|
|
20586
20718
|
try {
|
|
20587
|
-
raw =
|
|
20719
|
+
raw = fs41.readFileSync(filePath, "utf-8");
|
|
20588
20720
|
} catch {
|
|
20589
20721
|
return;
|
|
20590
20722
|
}
|
|
@@ -20633,30 +20765,30 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
|
|
|
20633
20765
|
const out = [];
|
|
20634
20766
|
let dirs;
|
|
20635
20767
|
try {
|
|
20636
|
-
if (!
|
|
20637
|
-
dirs =
|
|
20768
|
+
if (!fs41.statSync(geminiTmpDir2).isDirectory()) return out;
|
|
20769
|
+
dirs = fs41.readdirSync(geminiTmpDir2);
|
|
20638
20770
|
} catch {
|
|
20639
20771
|
return out;
|
|
20640
20772
|
}
|
|
20641
20773
|
for (const proj of dirs) {
|
|
20642
|
-
const chatsDir =
|
|
20774
|
+
const chatsDir = path42.join(geminiTmpDir2, proj, "chats");
|
|
20643
20775
|
let files;
|
|
20644
20776
|
try {
|
|
20645
|
-
if (!
|
|
20646
|
-
files =
|
|
20777
|
+
if (!fs41.statSync(chatsDir).isDirectory()) continue;
|
|
20778
|
+
files = fs41.readdirSync(chatsDir);
|
|
20647
20779
|
} catch {
|
|
20648
20780
|
continue;
|
|
20649
20781
|
}
|
|
20650
20782
|
for (const f of files) {
|
|
20651
20783
|
if (!f.endsWith(".jsonl")) continue;
|
|
20652
|
-
out.push({ projectKey: proj, file:
|
|
20784
|
+
out.push({ projectKey: proj, file: path42.join(chatsDir, f) });
|
|
20653
20785
|
}
|
|
20654
20786
|
}
|
|
20655
20787
|
return out;
|
|
20656
20788
|
}
|
|
20657
20789
|
function loadGeminiCost(start, end, geminiTmpDir2) {
|
|
20658
20790
|
const acc = emptyGeminiAccumulator();
|
|
20659
|
-
if (!
|
|
20791
|
+
if (!fs41.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
|
|
20660
20792
|
for (const { projectKey, file } of listGeminiSessionFiles2(geminiTmpDir2)) {
|
|
20661
20793
|
processGeminiCostFile(file, projectKey, start, end, acc);
|
|
20662
20794
|
}
|
|
@@ -20664,11 +20796,11 @@ function loadGeminiCost(start, end, geminiTmpDir2) {
|
|
|
20664
20796
|
}
|
|
20665
20797
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
20666
20798
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
20667
|
-
const auditLogPath = opts.auditLogPath ??
|
|
20668
|
-
const claudeProjectsDir = opts.claudeProjectsDir ??
|
|
20669
|
-
const codexSessionsDir2 = opts.codexSessionsDir ??
|
|
20670
|
-
const geminiTmpDir2 = opts.geminiTmpDir ??
|
|
20671
|
-
const hasAuditFile =
|
|
20799
|
+
const auditLogPath = opts.auditLogPath ?? path42.join(os37.homedir(), ".node9", "audit.log");
|
|
20800
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? path42.join(os37.homedir(), ".claude", "projects");
|
|
20801
|
+
const codexSessionsDir2 = opts.codexSessionsDir ?? path42.join(os37.homedir(), ".codex", "sessions");
|
|
20802
|
+
const geminiTmpDir2 = opts.geminiTmpDir ?? path42.join(os37.homedir(), ".gemini", "tmp");
|
|
20803
|
+
const hasAuditFile = fs41.existsSync(auditLogPath);
|
|
20672
20804
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
|
|
20673
20805
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
20674
20806
|
const { start, end } = getDateRange(period, now);
|
|
@@ -21365,52 +21497,10 @@ function registerDaemonCommand(program2) {
|
|
|
21365
21497
|
// src/cli/commands/status.ts
|
|
21366
21498
|
init_core();
|
|
21367
21499
|
init_daemon();
|
|
21368
|
-
init_setup();
|
|
21369
21500
|
import chalk15 from "chalk";
|
|
21370
|
-
import
|
|
21371
|
-
import
|
|
21372
|
-
import
|
|
21373
|
-
import * as yaml2 from "yaml";
|
|
21374
|
-
function readHermesHooks(configPath) {
|
|
21375
|
-
if (!fs41.existsSync(configPath)) return null;
|
|
21376
|
-
let raw;
|
|
21377
|
-
try {
|
|
21378
|
-
raw = fs41.readFileSync(configPath, "utf-8");
|
|
21379
|
-
} catch {
|
|
21380
|
-
return null;
|
|
21381
|
-
}
|
|
21382
|
-
try {
|
|
21383
|
-
const cfg = yaml2.parse(raw);
|
|
21384
|
-
const has = (event) => (cfg?.hooks?.[event] ?? []).some(
|
|
21385
|
-
(e) => typeof e?.command === "string" && isNode9Hook(e.command)
|
|
21386
|
-
);
|
|
21387
|
-
return { pre: has("pre_tool_call"), post: has("post_tool_call") };
|
|
21388
|
-
} catch {
|
|
21389
|
-
console.error(
|
|
21390
|
-
chalk15.yellow(
|
|
21391
|
-
` \u26A0\uFE0F Hermes config.yaml at ${configPath} is not valid YAML \u2014 showing as unwired.`
|
|
21392
|
-
)
|
|
21393
|
-
);
|
|
21394
|
-
return { pre: false, post: false };
|
|
21395
|
-
}
|
|
21396
|
-
}
|
|
21397
|
-
function readJson2(filePath) {
|
|
21398
|
-
try {
|
|
21399
|
-
if (fs41.existsSync(filePath)) return JSON.parse(fs41.readFileSync(filePath, "utf-8"));
|
|
21400
|
-
} catch {
|
|
21401
|
-
}
|
|
21402
|
-
return null;
|
|
21403
|
-
}
|
|
21404
|
-
function matchersHaveNode9Hook(matchers) {
|
|
21405
|
-
return (matchers ?? []).some((m) => (m.hooks ?? []).some((h) => isNode9Hook(h.command)));
|
|
21406
|
-
}
|
|
21407
|
-
function flatHaveNode9Hook(entries) {
|
|
21408
|
-
return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
|
|
21409
|
-
}
|
|
21410
|
-
function wrappedMcpServers(servers) {
|
|
21411
|
-
if (!servers) return [];
|
|
21412
|
-
return Object.entries(servers).filter(([, s]) => s.command === "node9" && Array.isArray(s.args) && s.args.length > 0).map(([name, s]) => `${name} \u2192 ${s.args.join(" ")}`);
|
|
21413
|
-
}
|
|
21501
|
+
import fs42 from "fs";
|
|
21502
|
+
import path43 from "path";
|
|
21503
|
+
import os38 from "os";
|
|
21414
21504
|
function printAgentSection(label, hookPairs, wrapped) {
|
|
21415
21505
|
console.log(chalk15.bold(` ${label}`));
|
|
21416
21506
|
for (const { name, present } of hookPairs) {
|
|
@@ -21464,115 +21554,36 @@ function registerStatusCommand(program2) {
|
|
|
21464
21554
|
console.log("");
|
|
21465
21555
|
const modeLabel = settings.mode === "audit" ? chalk15.blue("audit") : settings.mode === "strict" ? chalk15.red("strict") : chalk15.white("standard");
|
|
21466
21556
|
console.log(` Mode: ${modeLabel}`);
|
|
21467
|
-
const projectConfig =
|
|
21468
|
-
const globalConfig =
|
|
21557
|
+
const projectConfig = path43.join(process.cwd(), "node9.config.json");
|
|
21558
|
+
const globalConfig = path43.join(os38.homedir(), ".node9", "config.json");
|
|
21469
21559
|
console.log(
|
|
21470
|
-
` Local: ${
|
|
21560
|
+
` Local: ${fs42.existsSync(projectConfig) ? chalk15.green("Active (node9.config.json)") : chalk15.gray("Not present")}`
|
|
21471
21561
|
);
|
|
21472
21562
|
console.log(
|
|
21473
|
-
` Global: ${
|
|
21563
|
+
` Global: ${fs42.existsSync(globalConfig) ? chalk15.green("Active (~/.node9/config.json)") : chalk15.gray("Not present")}`
|
|
21474
21564
|
);
|
|
21475
21565
|
if (mergedConfig.policy.sandboxPaths.length > 0) {
|
|
21476
21566
|
console.log(
|
|
21477
21567
|
` Sandbox: ${chalk15.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
|
|
21478
21568
|
);
|
|
21479
21569
|
}
|
|
21480
|
-
const
|
|
21481
|
-
|
|
21482
|
-
path42.join(homeDir2, ".claude", "settings.json")
|
|
21483
|
-
);
|
|
21484
|
-
const claudeConfig = readJson2(path42.join(homeDir2, ".claude.json"));
|
|
21485
|
-
const geminiSettings = readJson2(
|
|
21486
|
-
path42.join(homeDir2, ".gemini", "settings.json")
|
|
21487
|
-
);
|
|
21488
|
-
const cursorConfig = readJson2(path42.join(homeDir2, ".cursor", "mcp.json"));
|
|
21489
|
-
const antigravityHooks = readJson2(
|
|
21490
|
-
path42.join(homeDir2, ".gemini", "config", "hooks.json")
|
|
21491
|
-
);
|
|
21492
|
-
const antigravityMcp = readJson2(
|
|
21493
|
-
path42.join(homeDir2, ".gemini", "config", "mcp_config.json")
|
|
21494
|
-
);
|
|
21495
|
-
const antigravityPresent = antigravityHooks !== null || fs41.existsSync(path42.join(homeDir2, ".gemini", "antigravity-cli")) || fs41.existsSync(path42.join(homeDir2, ".gemini", "antigravity-ide"));
|
|
21496
|
-
const copilotHooks = readJson2(
|
|
21497
|
-
path42.join(homeDir2, ".copilot", "hooks", "node9.json")
|
|
21498
|
-
);
|
|
21499
|
-
const copilotMcp = readJson2(
|
|
21500
|
-
path42.join(homeDir2, ".copilot", "mcp-config.json")
|
|
21501
|
-
);
|
|
21502
|
-
const copilotPresent = fs41.existsSync(path42.join(homeDir2, ".copilot"));
|
|
21503
|
-
const hermesHooks = readHermesHooks(hermesConfigPath(homeDir2));
|
|
21504
|
-
const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig || antigravityPresent || copilotPresent || hermesHooks;
|
|
21505
|
-
if (agentFound) {
|
|
21570
|
+
const wiring = getAgentWiring(os38.homedir()).filter((a) => a.present);
|
|
21571
|
+
if (wiring.length > 0) {
|
|
21506
21572
|
console.log("");
|
|
21507
21573
|
console.log(chalk15.bold(" Agent Wiring:"));
|
|
21508
21574
|
console.log("");
|
|
21509
|
-
|
|
21510
|
-
|
|
21511
|
-
|
|
21512
|
-
|
|
21513
|
-
|
|
21514
|
-
|
|
21515
|
-
|
|
21516
|
-
|
|
21517
|
-
],
|
|
21518
|
-
wrappedMcpServers(claudeConfig?.mcpServers)
|
|
21519
|
-
);
|
|
21520
|
-
console.log("");
|
|
21521
|
-
}
|
|
21522
|
-
if (geminiSettings) {
|
|
21523
|
-
const beforeHook = matchersHaveNode9Hook(geminiSettings.hooks?.BeforeTool);
|
|
21524
|
-
const afterHook = matchersHaveNode9Hook(geminiSettings.hooks?.AfterTool);
|
|
21525
|
-
printAgentSection(
|
|
21526
|
-
"Gemini CLI",
|
|
21527
|
-
[
|
|
21528
|
-
{ name: "BeforeTool (node9 check)", present: beforeHook },
|
|
21529
|
-
{ name: "AfterTool (node9 log)", present: afterHook }
|
|
21530
|
-
],
|
|
21531
|
-
wrappedMcpServers(geminiSettings.mcpServers)
|
|
21532
|
-
);
|
|
21533
|
-
console.log("");
|
|
21534
|
-
}
|
|
21535
|
-
if (antigravityPresent) {
|
|
21536
|
-
const preHook = matchersHaveNode9Hook(antigravityHooks?.hooks?.PreToolUse);
|
|
21537
|
-
const postHook = matchersHaveNode9Hook(antigravityHooks?.hooks?.PostToolUse);
|
|
21538
|
-
printAgentSection(
|
|
21539
|
-
"Antigravity",
|
|
21540
|
-
[
|
|
21541
|
-
{ name: "PreToolUse (node9 check)", present: preHook },
|
|
21542
|
-
{ name: "PostToolUse (node9 log)", present: postHook }
|
|
21543
|
-
],
|
|
21544
|
-
wrappedMcpServers(antigravityMcp?.mcpServers)
|
|
21545
|
-
);
|
|
21546
|
-
console.log("");
|
|
21547
|
-
}
|
|
21548
|
-
if (copilotPresent) {
|
|
21549
|
-
const preHook = flatHaveNode9Hook(copilotHooks?.hooks?.PreToolUse);
|
|
21550
|
-
const postHook = flatHaveNode9Hook(copilotHooks?.hooks?.PostToolUse);
|
|
21551
|
-
const promptHook = flatHaveNode9Hook(copilotHooks?.hooks?.UserPromptSubmit);
|
|
21552
|
-
printAgentSection(
|
|
21553
|
-
"GitHub Copilot",
|
|
21554
|
-
[
|
|
21555
|
-
{ name: "PreToolUse (node9 check)", present: preHook },
|
|
21556
|
-
{ name: "PostToolUse (node9 log)", present: postHook },
|
|
21557
|
-
{ name: "UserPromptSubmit (node9 check)", present: promptHook }
|
|
21558
|
-
],
|
|
21559
|
-
wrappedMcpServers(copilotMcp?.mcpServers)
|
|
21560
|
-
);
|
|
21561
|
-
console.log("");
|
|
21562
|
-
}
|
|
21563
|
-
if (cursorConfig) {
|
|
21564
|
-
printAgentSection("Cursor", [], wrappedMcpServers(cursorConfig.mcpServers));
|
|
21565
|
-
console.log("");
|
|
21566
|
-
}
|
|
21567
|
-
if (hermesHooks) {
|
|
21575
|
+
for (const a of wiring) {
|
|
21576
|
+
if (a.wireState === "invalid") {
|
|
21577
|
+
console.error(
|
|
21578
|
+
chalk15.yellow(
|
|
21579
|
+
` \u26A0\uFE0F ${a.label} config at ${a.settingsPath} is not valid ${a.configFormat} \u2014 showing as unwired.`
|
|
21580
|
+
)
|
|
21581
|
+
);
|
|
21582
|
+
}
|
|
21568
21583
|
printAgentSection(
|
|
21569
|
-
|
|
21570
|
-
|
|
21571
|
-
|
|
21572
|
-
{ name: "post_tool_call (node9 log)", present: hermesHooks.post }
|
|
21573
|
-
],
|
|
21574
|
-
null
|
|
21575
|
-
// Hermes has no MCP surface
|
|
21584
|
+
a.label,
|
|
21585
|
+
a.hooks.map((h) => ({ name: h.label, present: h.wired })),
|
|
21586
|
+
a.mcpServers
|
|
21576
21587
|
);
|
|
21577
21588
|
console.log("");
|
|
21578
21589
|
}
|
|
@@ -21595,9 +21606,9 @@ init_setup();
|
|
|
21595
21606
|
init_shields();
|
|
21596
21607
|
init_service();
|
|
21597
21608
|
import chalk16 from "chalk";
|
|
21598
|
-
import
|
|
21599
|
-
import
|
|
21600
|
-
import
|
|
21609
|
+
import fs43 from "fs";
|
|
21610
|
+
import path44 from "path";
|
|
21611
|
+
import os39 from "os";
|
|
21601
21612
|
import https4 from "https";
|
|
21602
21613
|
var DEFAULT_SHIELDS = ["bash-safe", "filesystem", "project-jail"];
|
|
21603
21614
|
function buildTelemetryPayload(agents, firstInstall) {
|
|
@@ -21683,16 +21694,16 @@ function registerInitCommand(program2) {
|
|
|
21683
21694
|
}
|
|
21684
21695
|
console.log("");
|
|
21685
21696
|
}
|
|
21686
|
-
const configPath =
|
|
21687
|
-
const isFirstInstall = !
|
|
21688
|
-
if (
|
|
21697
|
+
const configPath = path44.join(os39.homedir(), ".node9", "config.json");
|
|
21698
|
+
const isFirstInstall = !fs43.existsSync(configPath);
|
|
21699
|
+
if (fs43.existsSync(configPath) && !options.force) {
|
|
21689
21700
|
try {
|
|
21690
|
-
const existing = JSON.parse(
|
|
21701
|
+
const existing = JSON.parse(fs43.readFileSync(configPath, "utf-8"));
|
|
21691
21702
|
const settings = existing.settings ?? {};
|
|
21692
21703
|
if (settings.mode !== chosenMode) {
|
|
21693
21704
|
settings.mode = chosenMode;
|
|
21694
21705
|
existing.settings = settings;
|
|
21695
|
-
|
|
21706
|
+
fs43.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
|
|
21696
21707
|
console.log(chalk16.green(`\u2705 Mode updated: ${chosenMode}`));
|
|
21697
21708
|
} else {
|
|
21698
21709
|
console.log(chalk16.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
|
|
@@ -21705,9 +21716,9 @@ function registerInitCommand(program2) {
|
|
|
21705
21716
|
...DEFAULT_CONFIG,
|
|
21706
21717
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
21707
21718
|
};
|
|
21708
|
-
const dir =
|
|
21709
|
-
if (!
|
|
21710
|
-
|
|
21719
|
+
const dir = path44.dirname(configPath);
|
|
21720
|
+
if (!fs43.existsSync(dir)) fs43.mkdirSync(dir, { recursive: true });
|
|
21721
|
+
fs43.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
|
|
21711
21722
|
console.log(chalk16.green(`\u2705 Config created: ${configPath}`));
|
|
21712
21723
|
console.log(chalk16.gray(` Mode: ${chosenMode}`));
|
|
21713
21724
|
}
|
|
@@ -21812,7 +21823,7 @@ function registerInitCommand(program2) {
|
|
|
21812
21823
|
}
|
|
21813
21824
|
|
|
21814
21825
|
// src/cli/commands/undo.ts
|
|
21815
|
-
import
|
|
21826
|
+
import path45 from "path";
|
|
21816
21827
|
import chalk18 from "chalk";
|
|
21817
21828
|
|
|
21818
21829
|
// src/tui/undo-navigator.ts
|
|
@@ -21971,7 +21982,7 @@ function findMatchingCwd(startDir, history) {
|
|
|
21971
21982
|
let dir = startDir;
|
|
21972
21983
|
while (true) {
|
|
21973
21984
|
if (cwds.has(dir)) return dir;
|
|
21974
|
-
const parent =
|
|
21985
|
+
const parent = path45.dirname(dir);
|
|
21975
21986
|
if (parent === dir) return null;
|
|
21976
21987
|
dir = parent;
|
|
21977
21988
|
}
|
|
@@ -22606,9 +22617,9 @@ function registerMcpGatewayCommand(program2) {
|
|
|
22606
22617
|
|
|
22607
22618
|
// src/mcp-server/index.ts
|
|
22608
22619
|
import readline5 from "readline";
|
|
22609
|
-
import
|
|
22610
|
-
import
|
|
22611
|
-
import
|
|
22620
|
+
import fs44 from "fs";
|
|
22621
|
+
import os40 from "os";
|
|
22622
|
+
import path46 from "path";
|
|
22612
22623
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
22613
22624
|
init_core();
|
|
22614
22625
|
init_daemon();
|
|
@@ -22859,13 +22870,13 @@ function handleStatus() {
|
|
|
22859
22870
|
lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
|
|
22860
22871
|
lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
|
|
22861
22872
|
lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
|
|
22862
|
-
const projectConfig =
|
|
22863
|
-
const globalConfig =
|
|
22873
|
+
const projectConfig = path46.join(process.cwd(), "node9.config.json");
|
|
22874
|
+
const globalConfig = path46.join(os40.homedir(), ".node9", "config.json");
|
|
22864
22875
|
lines.push(
|
|
22865
|
-
`Project config (node9.config.json): ${
|
|
22876
|
+
`Project config (node9.config.json): ${fs44.existsSync(projectConfig) ? "present" : "not found"}`
|
|
22866
22877
|
);
|
|
22867
22878
|
lines.push(
|
|
22868
|
-
`Global config (~/.node9/config.json): ${
|
|
22879
|
+
`Global config (~/.node9/config.json): ${fs44.existsSync(globalConfig) ? "present" : "not found"}`
|
|
22869
22880
|
);
|
|
22870
22881
|
return lines.join("\n");
|
|
22871
22882
|
}
|
|
@@ -22939,21 +22950,21 @@ function handleShieldDisable(args) {
|
|
|
22939
22950
|
writeActiveShields(active.filter((s) => s !== name));
|
|
22940
22951
|
return `Shield "${name}" disabled.`;
|
|
22941
22952
|
}
|
|
22942
|
-
var GLOBAL_CONFIG_PATH =
|
|
22953
|
+
var GLOBAL_CONFIG_PATH = path46.join(os40.homedir(), ".node9", "config.json");
|
|
22943
22954
|
var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
|
|
22944
22955
|
function readGlobalConfigRaw() {
|
|
22945
22956
|
try {
|
|
22946
|
-
if (
|
|
22947
|
-
return JSON.parse(
|
|
22957
|
+
if (fs44.existsSync(GLOBAL_CONFIG_PATH)) {
|
|
22958
|
+
return JSON.parse(fs44.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
|
|
22948
22959
|
}
|
|
22949
22960
|
} catch {
|
|
22950
22961
|
}
|
|
22951
22962
|
return {};
|
|
22952
22963
|
}
|
|
22953
22964
|
function writeGlobalConfigRaw(data) {
|
|
22954
|
-
const dir =
|
|
22955
|
-
if (!
|
|
22956
|
-
|
|
22965
|
+
const dir = path46.dirname(GLOBAL_CONFIG_PATH);
|
|
22966
|
+
if (!fs44.existsSync(dir)) fs44.mkdirSync(dir, { recursive: true });
|
|
22967
|
+
fs44.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
|
|
22957
22968
|
}
|
|
22958
22969
|
function handleApproverList() {
|
|
22959
22970
|
const config = getConfig();
|
|
@@ -22997,9 +23008,9 @@ function handleApproverSet(args) {
|
|
|
22997
23008
|
function handleAuditGet(args) {
|
|
22998
23009
|
const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
|
|
22999
23010
|
const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
|
|
23000
|
-
const auditPath =
|
|
23001
|
-
if (!
|
|
23002
|
-
const rawLines =
|
|
23011
|
+
const auditPath = path46.join(os40.homedir(), ".node9", "audit.log");
|
|
23012
|
+
if (!fs44.existsSync(auditPath)) return "No audit log found.";
|
|
23013
|
+
const rawLines = fs44.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
|
|
23003
23014
|
const parsed = [];
|
|
23004
23015
|
for (const line of rawLines) {
|
|
23005
23016
|
try {
|
|
@@ -23334,7 +23345,7 @@ function registerTrustCommand(program2) {
|
|
|
23334
23345
|
// src/cli/commands/mcp-pin.ts
|
|
23335
23346
|
init_mcp_pin();
|
|
23336
23347
|
import chalk21 from "chalk";
|
|
23337
|
-
import
|
|
23348
|
+
import fs45 from "fs";
|
|
23338
23349
|
function registerMcpPinCommand(program2) {
|
|
23339
23350
|
const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
|
|
23340
23351
|
const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
|
|
@@ -23345,7 +23356,7 @@ function registerMcpPinCommand(program2) {
|
|
|
23345
23356
|
let repoCorrupt = false;
|
|
23346
23357
|
if (found.source === "repo") {
|
|
23347
23358
|
try {
|
|
23348
|
-
const raw =
|
|
23359
|
+
const raw = fs45.readFileSync(found.path, "utf-8");
|
|
23349
23360
|
const parsed = JSON.parse(raw);
|
|
23350
23361
|
repoEntries = parsed.servers ?? {};
|
|
23351
23362
|
} catch {
|
|
@@ -23662,9 +23673,9 @@ init_litellm();
|
|
|
23662
23673
|
init_cost_gemini();
|
|
23663
23674
|
init_cost_codex();
|
|
23664
23675
|
import chalk24 from "chalk";
|
|
23665
|
-
import
|
|
23666
|
-
import
|
|
23667
|
-
import
|
|
23676
|
+
import fs46 from "fs";
|
|
23677
|
+
import path47 from "path";
|
|
23678
|
+
import os41 from "os";
|
|
23668
23679
|
function modelPrice(model) {
|
|
23669
23680
|
const t = pricingFor(model);
|
|
23670
23681
|
if (!t) return null;
|
|
@@ -23681,10 +23692,10 @@ function encodeProjectPath(projectPath) {
|
|
|
23681
23692
|
}
|
|
23682
23693
|
function sessionJsonlPath(projectPath, sessionId) {
|
|
23683
23694
|
const encoded = encodeProjectPath(projectPath);
|
|
23684
|
-
return
|
|
23695
|
+
return path47.join(os41.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
|
|
23685
23696
|
}
|
|
23686
23697
|
function projectLabel(projectPath) {
|
|
23687
|
-
return projectPath.replace(
|
|
23698
|
+
return projectPath.replace(os41.homedir(), "~");
|
|
23688
23699
|
}
|
|
23689
23700
|
function parseHistoryLines(lines) {
|
|
23690
23701
|
const entries = [];
|
|
@@ -23753,10 +23764,10 @@ function parseSessionLines(lines) {
|
|
|
23753
23764
|
return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
|
|
23754
23765
|
}
|
|
23755
23766
|
function loadAuditEntries(auditPath) {
|
|
23756
|
-
const aPath = auditPath ??
|
|
23767
|
+
const aPath = auditPath ?? path47.join(os41.homedir(), ".node9", "audit.log");
|
|
23757
23768
|
let raw;
|
|
23758
23769
|
try {
|
|
23759
|
-
raw =
|
|
23770
|
+
raw = fs46.readFileSync(aPath, "utf-8");
|
|
23760
23771
|
} catch {
|
|
23761
23772
|
return [];
|
|
23762
23773
|
}
|
|
@@ -23792,8 +23803,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
23792
23803
|
return result;
|
|
23793
23804
|
}
|
|
23794
23805
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
23795
|
-
const tmpDir =
|
|
23796
|
-
if (!
|
|
23806
|
+
const tmpDir = path47.join(os41.homedir(), ".gemini", "tmp");
|
|
23807
|
+
if (!fs46.existsSync(tmpDir)) return [];
|
|
23797
23808
|
const cutoff = days !== null ? (() => {
|
|
23798
23809
|
const d = /* @__PURE__ */ new Date();
|
|
23799
23810
|
d.setDate(d.getDate() - days);
|
|
@@ -23802,35 +23813,35 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
23802
23813
|
})() : null;
|
|
23803
23814
|
let slugDirs;
|
|
23804
23815
|
try {
|
|
23805
|
-
slugDirs =
|
|
23816
|
+
slugDirs = fs46.readdirSync(tmpDir);
|
|
23806
23817
|
} catch {
|
|
23807
23818
|
return [];
|
|
23808
23819
|
}
|
|
23809
23820
|
const summaries = [];
|
|
23810
23821
|
for (const slug of slugDirs) {
|
|
23811
|
-
const slugPath =
|
|
23822
|
+
const slugPath = path47.join(tmpDir, slug);
|
|
23812
23823
|
try {
|
|
23813
|
-
if (!
|
|
23824
|
+
if (!fs46.statSync(slugPath).isDirectory()) continue;
|
|
23814
23825
|
} catch {
|
|
23815
23826
|
continue;
|
|
23816
23827
|
}
|
|
23817
|
-
let projectRoot =
|
|
23828
|
+
let projectRoot = path47.join(os41.homedir(), slug);
|
|
23818
23829
|
try {
|
|
23819
|
-
projectRoot =
|
|
23830
|
+
projectRoot = fs46.readFileSync(path47.join(slugPath, ".project_root"), "utf-8").trim();
|
|
23820
23831
|
} catch {
|
|
23821
23832
|
}
|
|
23822
|
-
const chatsDir =
|
|
23823
|
-
if (!
|
|
23833
|
+
const chatsDir = path47.join(slugPath, "chats");
|
|
23834
|
+
if (!fs46.existsSync(chatsDir)) continue;
|
|
23824
23835
|
let chatFiles;
|
|
23825
23836
|
try {
|
|
23826
|
-
chatFiles =
|
|
23837
|
+
chatFiles = fs46.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
23827
23838
|
} catch {
|
|
23828
23839
|
continue;
|
|
23829
23840
|
}
|
|
23830
23841
|
for (const chatFile of chatFiles) {
|
|
23831
23842
|
let raw;
|
|
23832
23843
|
try {
|
|
23833
|
-
raw =
|
|
23844
|
+
raw = fs46.readFileSync(path47.join(chatsDir, chatFile), "utf-8");
|
|
23834
23845
|
} catch {
|
|
23835
23846
|
continue;
|
|
23836
23847
|
}
|
|
@@ -23910,8 +23921,8 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
23910
23921
|
return summaries;
|
|
23911
23922
|
}
|
|
23912
23923
|
function buildCodexSessions(days, allAuditEntries) {
|
|
23913
|
-
const sessionsBase =
|
|
23914
|
-
if (!
|
|
23924
|
+
const sessionsBase = path47.join(os41.homedir(), ".codex", "sessions");
|
|
23925
|
+
if (!fs46.existsSync(sessionsBase)) return [];
|
|
23915
23926
|
const cutoff = days !== null ? (() => {
|
|
23916
23927
|
const d = /* @__PURE__ */ new Date();
|
|
23917
23928
|
d.setDate(d.getDate() - days);
|
|
@@ -23920,29 +23931,29 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
23920
23931
|
})() : null;
|
|
23921
23932
|
const jsonlFiles = [];
|
|
23922
23933
|
try {
|
|
23923
|
-
for (const year of
|
|
23924
|
-
const yearPath =
|
|
23934
|
+
for (const year of fs46.readdirSync(sessionsBase)) {
|
|
23935
|
+
const yearPath = path47.join(sessionsBase, year);
|
|
23925
23936
|
try {
|
|
23926
|
-
if (!
|
|
23937
|
+
if (!fs46.statSync(yearPath).isDirectory()) continue;
|
|
23927
23938
|
} catch {
|
|
23928
23939
|
continue;
|
|
23929
23940
|
}
|
|
23930
|
-
for (const month of
|
|
23931
|
-
const monthPath =
|
|
23941
|
+
for (const month of fs46.readdirSync(yearPath)) {
|
|
23942
|
+
const monthPath = path47.join(yearPath, month);
|
|
23932
23943
|
try {
|
|
23933
|
-
if (!
|
|
23944
|
+
if (!fs46.statSync(monthPath).isDirectory()) continue;
|
|
23934
23945
|
} catch {
|
|
23935
23946
|
continue;
|
|
23936
23947
|
}
|
|
23937
|
-
for (const day of
|
|
23938
|
-
const dayPath =
|
|
23948
|
+
for (const day of fs46.readdirSync(monthPath)) {
|
|
23949
|
+
const dayPath = path47.join(monthPath, day);
|
|
23939
23950
|
try {
|
|
23940
|
-
if (!
|
|
23951
|
+
if (!fs46.statSync(dayPath).isDirectory()) continue;
|
|
23941
23952
|
} catch {
|
|
23942
23953
|
continue;
|
|
23943
23954
|
}
|
|
23944
|
-
for (const file of
|
|
23945
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
23955
|
+
for (const file of fs46.readdirSync(dayPath)) {
|
|
23956
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(path47.join(dayPath, file));
|
|
23946
23957
|
}
|
|
23947
23958
|
}
|
|
23948
23959
|
}
|
|
@@ -23954,7 +23965,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
23954
23965
|
for (const filePath of jsonlFiles) {
|
|
23955
23966
|
let lines;
|
|
23956
23967
|
try {
|
|
23957
|
-
lines =
|
|
23968
|
+
lines = fs46.readFileSync(filePath, "utf-8").split("\n");
|
|
23958
23969
|
} catch {
|
|
23959
23970
|
continue;
|
|
23960
23971
|
}
|
|
@@ -24040,10 +24051,10 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
24040
24051
|
return summaries;
|
|
24041
24052
|
}
|
|
24042
24053
|
function buildSessions(days, historyPath) {
|
|
24043
|
-
const hPath = historyPath ??
|
|
24054
|
+
const hPath = historyPath ?? path47.join(os41.homedir(), ".claude", "history.jsonl");
|
|
24044
24055
|
let historyRaw = "";
|
|
24045
24056
|
try {
|
|
24046
|
-
historyRaw =
|
|
24057
|
+
historyRaw = fs46.readFileSync(hPath, "utf-8");
|
|
24047
24058
|
} catch {
|
|
24048
24059
|
}
|
|
24049
24060
|
const cutoff = days !== null ? (() => {
|
|
@@ -24067,7 +24078,7 @@ function buildSessions(days, historyPath) {
|
|
|
24067
24078
|
const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
|
|
24068
24079
|
let sessionLines = [];
|
|
24069
24080
|
try {
|
|
24070
|
-
sessionLines =
|
|
24081
|
+
sessionLines = fs46.readFileSync(jsonlFile, "utf-8").split("\n");
|
|
24071
24082
|
} catch {
|
|
24072
24083
|
}
|
|
24073
24084
|
const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
|
|
@@ -24367,12 +24378,12 @@ function registerSessionsCommand(program2) {
|
|
|
24367
24378
|
|
|
24368
24379
|
// src/cli/commands/skill-pin.ts
|
|
24369
24380
|
import chalk25 from "chalk";
|
|
24370
|
-
import
|
|
24371
|
-
import
|
|
24372
|
-
import
|
|
24381
|
+
import fs47 from "fs";
|
|
24382
|
+
import os42 from "os";
|
|
24383
|
+
import path48 from "path";
|
|
24373
24384
|
function wipeSkillSessions() {
|
|
24374
24385
|
try {
|
|
24375
|
-
|
|
24386
|
+
fs47.rmSync(path48.join(os42.homedir(), ".node9", "skill-sessions"), {
|
|
24376
24387
|
recursive: true,
|
|
24377
24388
|
force: true
|
|
24378
24389
|
});
|
|
@@ -24454,15 +24465,15 @@ function registerSkillPinCommand(program2) {
|
|
|
24454
24465
|
}
|
|
24455
24466
|
|
|
24456
24467
|
// src/cli/commands/decisions.ts
|
|
24457
|
-
import
|
|
24458
|
-
import
|
|
24459
|
-
import
|
|
24468
|
+
import fs48 from "fs";
|
|
24469
|
+
import os43 from "os";
|
|
24470
|
+
import path49 from "path";
|
|
24460
24471
|
import chalk26 from "chalk";
|
|
24461
|
-
var DECISIONS_FILE2 =
|
|
24472
|
+
var DECISIONS_FILE2 = path49.join(os43.homedir(), ".node9", "decisions.json");
|
|
24462
24473
|
function readDecisions() {
|
|
24463
24474
|
try {
|
|
24464
|
-
if (!
|
|
24465
|
-
const raw =
|
|
24475
|
+
if (!fs48.existsSync(DECISIONS_FILE2)) return {};
|
|
24476
|
+
const raw = fs48.readFileSync(DECISIONS_FILE2, "utf-8");
|
|
24466
24477
|
const parsed = JSON.parse(raw);
|
|
24467
24478
|
const out = {};
|
|
24468
24479
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -24474,11 +24485,11 @@ function readDecisions() {
|
|
|
24474
24485
|
}
|
|
24475
24486
|
}
|
|
24476
24487
|
function writeDecisions(d) {
|
|
24477
|
-
const dir =
|
|
24478
|
-
if (!
|
|
24488
|
+
const dir = path49.dirname(DECISIONS_FILE2);
|
|
24489
|
+
if (!fs48.existsSync(dir)) fs48.mkdirSync(dir, { recursive: true });
|
|
24479
24490
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
24480
|
-
|
|
24481
|
-
|
|
24491
|
+
fs48.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
24492
|
+
fs48.renameSync(tmp, DECISIONS_FILE2);
|
|
24482
24493
|
}
|
|
24483
24494
|
function registerDecisionsCommand(program2) {
|
|
24484
24495
|
const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
|
|
@@ -24535,18 +24546,18 @@ Persistent decisions (${entries.length})
|
|
|
24535
24546
|
|
|
24536
24547
|
// src/cli/commands/dlp.ts
|
|
24537
24548
|
import chalk27 from "chalk";
|
|
24538
|
-
import
|
|
24539
|
-
import
|
|
24540
|
-
import
|
|
24541
|
-
var AUDIT_LOG =
|
|
24542
|
-
var RESOLVED_FILE =
|
|
24549
|
+
import fs49 from "fs";
|
|
24550
|
+
import path50 from "path";
|
|
24551
|
+
import os44 from "os";
|
|
24552
|
+
var AUDIT_LOG = path50.join(os44.homedir(), ".node9", "audit.log");
|
|
24553
|
+
var RESOLVED_FILE = path50.join(os44.homedir(), ".node9", "dlp-resolved.json");
|
|
24543
24554
|
var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
|
|
24544
24555
|
function stripAnsi(s) {
|
|
24545
24556
|
return s.replace(ANSI_RE, "");
|
|
24546
24557
|
}
|
|
24547
24558
|
function loadResolved() {
|
|
24548
24559
|
try {
|
|
24549
|
-
const raw = JSON.parse(
|
|
24560
|
+
const raw = JSON.parse(fs49.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
24550
24561
|
return new Set(raw);
|
|
24551
24562
|
} catch {
|
|
24552
24563
|
return /* @__PURE__ */ new Set();
|
|
@@ -24554,13 +24565,13 @@ function loadResolved() {
|
|
|
24554
24565
|
}
|
|
24555
24566
|
function saveResolved(resolved) {
|
|
24556
24567
|
try {
|
|
24557
|
-
|
|
24568
|
+
fs49.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
24558
24569
|
} catch {
|
|
24559
24570
|
}
|
|
24560
24571
|
}
|
|
24561
24572
|
function loadDlpFindings() {
|
|
24562
|
-
if (!
|
|
24563
|
-
return
|
|
24573
|
+
if (!fs49.existsSync(AUDIT_LOG)) return [];
|
|
24574
|
+
return fs49.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
24564
24575
|
if (!line.trim()) return [];
|
|
24565
24576
|
try {
|
|
24566
24577
|
const e = JSON.parse(line);
|
|
@@ -24659,14 +24670,14 @@ function registerDlpCommand(program2) {
|
|
|
24659
24670
|
// src/cli/commands/mask.ts
|
|
24660
24671
|
init_dlp();
|
|
24661
24672
|
import chalk28 from "chalk";
|
|
24662
|
-
import
|
|
24663
|
-
import
|
|
24664
|
-
import
|
|
24673
|
+
import fs50 from "fs";
|
|
24674
|
+
import path51 from "path";
|
|
24675
|
+
import os45 from "os";
|
|
24665
24676
|
function findJsonlFiles(dir) {
|
|
24666
24677
|
const results = [];
|
|
24667
|
-
if (!
|
|
24668
|
-
for (const entry of
|
|
24669
|
-
const full =
|
|
24678
|
+
if (!fs50.existsSync(dir)) return results;
|
|
24679
|
+
for (const entry of fs50.readdirSync(dir, { withFileTypes: true })) {
|
|
24680
|
+
const full = path51.join(dir, entry.name);
|
|
24670
24681
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
24671
24682
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
24672
24683
|
}
|
|
@@ -24709,7 +24720,7 @@ function redactJson(obj) {
|
|
|
24709
24720
|
function processFile(filePath, dryRun) {
|
|
24710
24721
|
let raw;
|
|
24711
24722
|
try {
|
|
24712
|
-
raw =
|
|
24723
|
+
raw = fs50.readFileSync(filePath, "utf-8");
|
|
24713
24724
|
} catch {
|
|
24714
24725
|
return { redactedLines: 0, patterns: [] };
|
|
24715
24726
|
}
|
|
@@ -24741,14 +24752,14 @@ function processFile(filePath, dryRun) {
|
|
|
24741
24752
|
}
|
|
24742
24753
|
}
|
|
24743
24754
|
if (!dryRun && redactedLines > 0) {
|
|
24744
|
-
|
|
24755
|
+
fs50.writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
24745
24756
|
}
|
|
24746
24757
|
return { redactedLines, patterns };
|
|
24747
24758
|
}
|
|
24748
24759
|
function processJsonFile(filePath, dryRun) {
|
|
24749
24760
|
let raw;
|
|
24750
24761
|
try {
|
|
24751
|
-
raw =
|
|
24762
|
+
raw = fs50.readFileSync(filePath, "utf-8");
|
|
24752
24763
|
} catch {
|
|
24753
24764
|
return { redactedLines: 0, patterns: [] };
|
|
24754
24765
|
}
|
|
@@ -24761,15 +24772,15 @@ function processJsonFile(filePath, dryRun) {
|
|
|
24761
24772
|
const { value, modified, found } = redactJson(parsed);
|
|
24762
24773
|
if (!modified) return { redactedLines: 0, patterns: [] };
|
|
24763
24774
|
if (!dryRun) {
|
|
24764
|
-
|
|
24775
|
+
fs50.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
|
|
24765
24776
|
}
|
|
24766
24777
|
return { redactedLines: 1, patterns: found };
|
|
24767
24778
|
}
|
|
24768
24779
|
function findJsonFiles(dir) {
|
|
24769
24780
|
const results = [];
|
|
24770
|
-
if (!
|
|
24771
|
-
for (const entry of
|
|
24772
|
-
const full =
|
|
24781
|
+
if (!fs50.existsSync(dir)) return results;
|
|
24782
|
+
for (const entry of fs50.readdirSync(dir, { withFileTypes: true })) {
|
|
24783
|
+
const full = path51.join(dir, entry.name);
|
|
24773
24784
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
24774
24785
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
24775
24786
|
}
|
|
@@ -24778,9 +24789,9 @@ function findJsonFiles(dir) {
|
|
|
24778
24789
|
function registerMaskCommand(program2) {
|
|
24779
24790
|
program2.command("mask").description("Redact plaintext secrets from local AI session history files").option("--dry-run", "show what would be redacted without making changes").option("--all", "scan all history (default: last 30 days)").action(async (options) => {
|
|
24780
24791
|
const dryRun = !!options.dryRun;
|
|
24781
|
-
const home =
|
|
24782
|
-
const claudeDir =
|
|
24783
|
-
const geminiDir =
|
|
24792
|
+
const home = os45.homedir();
|
|
24793
|
+
const claudeDir = path51.join(home, ".claude", "projects");
|
|
24794
|
+
const geminiDir = path51.join(home, ".gemini", "tmp");
|
|
24784
24795
|
const allFiles = [
|
|
24785
24796
|
...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
|
|
24786
24797
|
...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
|
|
@@ -24788,7 +24799,7 @@ function registerMaskCommand(program2) {
|
|
|
24788
24799
|
const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
24789
24800
|
const filtered = cutoff ? allFiles.filter((f) => {
|
|
24790
24801
|
try {
|
|
24791
|
-
return
|
|
24802
|
+
return fs50.statSync(f.path).mtime >= cutoff;
|
|
24792
24803
|
} catch {
|
|
24793
24804
|
return false;
|
|
24794
24805
|
}
|
|
@@ -24844,20 +24855,20 @@ function registerMaskCommand(program2) {
|
|
|
24844
24855
|
// src/cli.ts
|
|
24845
24856
|
init_blast();
|
|
24846
24857
|
var { version } = JSON.parse(
|
|
24847
|
-
|
|
24858
|
+
fs53.readFileSync(path54.join(__dirname, "../package.json"), "utf-8")
|
|
24848
24859
|
);
|
|
24849
24860
|
var program = new Command();
|
|
24850
24861
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
24851
24862
|
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) => {
|
|
24852
24863
|
const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
|
|
24853
|
-
const credPath =
|
|
24854
|
-
if (!
|
|
24855
|
-
|
|
24864
|
+
const credPath = path54.join(os48.homedir(), ".node9", "credentials.json");
|
|
24865
|
+
if (!fs53.existsSync(path54.dirname(credPath)))
|
|
24866
|
+
fs53.mkdirSync(path54.dirname(credPath), { recursive: true });
|
|
24856
24867
|
const profileName = options.profile || "default";
|
|
24857
24868
|
let existingCreds = {};
|
|
24858
24869
|
try {
|
|
24859
|
-
if (
|
|
24860
|
-
const raw = JSON.parse(
|
|
24870
|
+
if (fs53.existsSync(credPath)) {
|
|
24871
|
+
const raw = JSON.parse(fs53.readFileSync(credPath, "utf-8"));
|
|
24861
24872
|
if (raw.apiKey) {
|
|
24862
24873
|
existingCreds = {
|
|
24863
24874
|
default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
|
|
@@ -24869,14 +24880,14 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
24869
24880
|
} catch {
|
|
24870
24881
|
}
|
|
24871
24882
|
existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
|
|
24872
|
-
|
|
24883
|
+
fs53.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
|
|
24873
24884
|
let effectiveCloud = null;
|
|
24874
24885
|
if (profileName === "default") {
|
|
24875
|
-
const configPath =
|
|
24886
|
+
const configPath = path54.join(os48.homedir(), ".node9", "config.json");
|
|
24876
24887
|
let config = {};
|
|
24877
24888
|
try {
|
|
24878
|
-
if (
|
|
24879
|
-
config = JSON.parse(
|
|
24889
|
+
if (fs53.existsSync(configPath))
|
|
24890
|
+
config = JSON.parse(fs53.readFileSync(configPath, "utf-8"));
|
|
24880
24891
|
} catch {
|
|
24881
24892
|
}
|
|
24882
24893
|
if (!config.settings || typeof config.settings !== "object") config.settings = {};
|
|
@@ -24891,9 +24902,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
24891
24902
|
approvers.cloud = false;
|
|
24892
24903
|
}
|
|
24893
24904
|
s.approvers = approvers;
|
|
24894
|
-
if (!
|
|
24895
|
-
|
|
24896
|
-
|
|
24905
|
+
if (!fs53.existsSync(path54.dirname(configPath)))
|
|
24906
|
+
fs53.mkdirSync(path54.dirname(configPath), { recursive: true });
|
|
24907
|
+
fs53.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
24897
24908
|
effectiveCloud = approvers.cloud === true;
|
|
24898
24909
|
}
|
|
24899
24910
|
if (options.profile && profileName !== "default") {
|
|
@@ -25052,15 +25063,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
25052
25063
|
}
|
|
25053
25064
|
}
|
|
25054
25065
|
if (options.purge) {
|
|
25055
|
-
const node9Dir =
|
|
25056
|
-
if (
|
|
25066
|
+
const node9Dir = path54.join(os48.homedir(), ".node9");
|
|
25067
|
+
if (fs53.existsSync(node9Dir)) {
|
|
25057
25068
|
const confirmed = await confirm2({
|
|
25058
25069
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
25059
25070
|
default: false
|
|
25060
25071
|
});
|
|
25061
25072
|
if (confirmed) {
|
|
25062
|
-
|
|
25063
|
-
if (
|
|
25073
|
+
fs53.rmSync(node9Dir, { recursive: true });
|
|
25074
|
+
if (fs53.existsSync(node9Dir)) {
|
|
25064
25075
|
console.error(
|
|
25065
25076
|
chalk30.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
25066
25077
|
);
|
|
@@ -25175,7 +25186,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
|
|
|
25175
25186
|
});
|
|
25176
25187
|
program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
|
|
25177
25188
|
try {
|
|
25178
|
-
const dashboardPath =
|
|
25189
|
+
const dashboardPath = path54.join(__dirname, "dashboard.mjs");
|
|
25179
25190
|
const dynamicImport = new Function("id", "return import(id)");
|
|
25180
25191
|
const mod = await dynamicImport(`file://${dashboardPath}`);
|
|
25181
25192
|
await mod.startMonitor();
|
|
@@ -25213,14 +25224,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
|
|
|
25213
25224
|
Run "node9 addto claude" to register it as the statusLine.`
|
|
25214
25225
|
).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
|
|
25215
25226
|
if (subcommand === "debug") {
|
|
25216
|
-
const flagFile =
|
|
25227
|
+
const flagFile = path54.join(os48.homedir(), ".node9", "hud-debug");
|
|
25217
25228
|
if (state === "on") {
|
|
25218
|
-
|
|
25219
|
-
|
|
25229
|
+
fs53.mkdirSync(path54.dirname(flagFile), { recursive: true });
|
|
25230
|
+
fs53.writeFileSync(flagFile, "");
|
|
25220
25231
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
25221
25232
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
25222
25233
|
} else if (state === "off") {
|
|
25223
|
-
if (
|
|
25234
|
+
if (fs53.existsSync(flagFile)) fs53.unlinkSync(flagFile);
|
|
25224
25235
|
console.log("HUD debug logging disabled.");
|
|
25225
25236
|
} else {
|
|
25226
25237
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -25337,9 +25348,9 @@ if (process.argv[2] !== "daemon") {
|
|
|
25337
25348
|
const isCheckHook = process.argv[2] === "check";
|
|
25338
25349
|
if (isCheckHook) {
|
|
25339
25350
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
25340
|
-
const logPath =
|
|
25351
|
+
const logPath = path54.join(os48.homedir(), ".node9", "hook-debug.log");
|
|
25341
25352
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
25342
|
-
|
|
25353
|
+
fs53.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
25343
25354
|
`);
|
|
25344
25355
|
}
|
|
25345
25356
|
process.exit(0);
|