@node9/proxy 1.35.0 → 1.35.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 +452 -354
- package/dist/cli.mjs +448 -350
- 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
|
}
|
|
@@ -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,149 @@ 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 jsonWire(filePath, read) {
|
|
19959
|
+
const parsed = readJson2(filePath);
|
|
19960
|
+
if (parsed === null) return "absent";
|
|
19961
|
+
if (parsed === "invalid") return "invalid";
|
|
19962
|
+
return read(parsed) ? "wired" : "unwired";
|
|
19963
|
+
}
|
|
19964
|
+
function hermesWire(home) {
|
|
19965
|
+
const configPath = hermesConfigPath(home);
|
|
19966
|
+
if (!fs38.existsSync(configPath)) return "absent";
|
|
19967
|
+
let raw;
|
|
19968
|
+
try {
|
|
19969
|
+
raw = fs38.readFileSync(configPath, "utf-8");
|
|
19970
|
+
} catch {
|
|
19971
|
+
return "absent";
|
|
19972
|
+
}
|
|
19973
|
+
try {
|
|
19974
|
+
const cfg = yaml2.parse(raw);
|
|
19975
|
+
const pre = (cfg?.hooks?.pre_tool_call ?? []).some(
|
|
19976
|
+
(e) => typeof e?.command === "string" && isNode9Hook(e.command)
|
|
19977
|
+
);
|
|
19978
|
+
return pre ? "wired" : "unwired";
|
|
19979
|
+
} catch {
|
|
19980
|
+
return "invalid";
|
|
19981
|
+
}
|
|
19982
|
+
}
|
|
19983
|
+
var AGENT_SPECS = [
|
|
19984
|
+
{
|
|
19985
|
+
id: "claude",
|
|
19986
|
+
label: "Claude Code",
|
|
19987
|
+
hookLabel: "PreToolUse hook",
|
|
19988
|
+
setupCommand: "node9 setup claude",
|
|
19989
|
+
settingsPath: (h) => path39.join(h, ".claude", "settings.json"),
|
|
19990
|
+
wireState: (h) => jsonWire(
|
|
19991
|
+
path39.join(h, ".claude", "settings.json"),
|
|
19992
|
+
(p) => matchersHaveNode9Hook(p.hooks?.PreToolUse)
|
|
19993
|
+
)
|
|
19994
|
+
},
|
|
19995
|
+
{
|
|
19996
|
+
id: "gemini",
|
|
19997
|
+
label: "Gemini CLI",
|
|
19998
|
+
hookLabel: "BeforeTool hook",
|
|
19999
|
+
setupCommand: "node9 setup gemini",
|
|
20000
|
+
settingsPath: (h) => path39.join(h, ".gemini", "settings.json"),
|
|
20001
|
+
wireState: (h) => jsonWire(
|
|
20002
|
+
path39.join(h, ".gemini", "settings.json"),
|
|
20003
|
+
(p) => matchersHaveNode9Hook(p.hooks?.BeforeTool)
|
|
20004
|
+
)
|
|
20005
|
+
},
|
|
20006
|
+
{
|
|
20007
|
+
id: "codex",
|
|
20008
|
+
label: "Codex",
|
|
20009
|
+
hookLabel: "PreToolUse hook",
|
|
20010
|
+
setupCommand: "node9 setup codex",
|
|
20011
|
+
settingsPath: (h) => path39.join(h, ".codex", "hooks.json"),
|
|
20012
|
+
wireState: (h) => jsonWire(
|
|
20013
|
+
path39.join(h, ".codex", "hooks.json"),
|
|
20014
|
+
(p) => matchersHaveNode9Hook(p.hooks?.PreToolUse)
|
|
20015
|
+
)
|
|
20016
|
+
},
|
|
20017
|
+
{
|
|
20018
|
+
id: "antigravity",
|
|
20019
|
+
label: "Antigravity",
|
|
20020
|
+
hookLabel: "PreToolUse hook",
|
|
20021
|
+
setupCommand: "node9 setup antigravity",
|
|
20022
|
+
settingsPath: (h) => path39.join(h, ".gemini", "config", "hooks.json"),
|
|
20023
|
+
wireState: (h) => jsonWire(
|
|
20024
|
+
path39.join(h, ".gemini", "config", "hooks.json"),
|
|
20025
|
+
(p) => matchersHaveNode9Hook(p.hooks?.PreToolUse)
|
|
20026
|
+
)
|
|
20027
|
+
},
|
|
20028
|
+
{
|
|
20029
|
+
id: "copilot",
|
|
20030
|
+
label: "GitHub Copilot",
|
|
20031
|
+
hookLabel: "PreToolUse hook",
|
|
20032
|
+
setupCommand: "node9 setup copilot",
|
|
20033
|
+
settingsPath: (h) => path39.join(h, ".copilot", "hooks", "node9.json"),
|
|
20034
|
+
wireState: (h) => jsonWire(
|
|
20035
|
+
path39.join(h, ".copilot", "hooks", "node9.json"),
|
|
20036
|
+
(p) => flatHaveNode9Hook(p.hooks?.PreToolUse)
|
|
20037
|
+
)
|
|
20038
|
+
},
|
|
20039
|
+
{
|
|
20040
|
+
id: "cursor",
|
|
20041
|
+
label: "Cursor",
|
|
20042
|
+
hookLabel: "preToolUse hook",
|
|
20043
|
+
setupCommand: "node9 setup cursor",
|
|
20044
|
+
settingsPath: (h) => path39.join(h, ".cursor", "hooks.json"),
|
|
20045
|
+
wireState: (h) => jsonWire(
|
|
20046
|
+
path39.join(h, ".cursor", "hooks.json"),
|
|
20047
|
+
(p) => flatHaveNode9Hook(p.hooks?.preToolUse)
|
|
20048
|
+
)
|
|
20049
|
+
},
|
|
20050
|
+
{
|
|
20051
|
+
id: "hermes",
|
|
20052
|
+
label: "Hermes Agent",
|
|
20053
|
+
hookLabel: "pre_tool_call hook",
|
|
20054
|
+
setupCommand: "node9 setup hermes",
|
|
20055
|
+
settingsPath: (h) => hermesConfigPath(h),
|
|
20056
|
+
wireState: (h) => hermesWire(h)
|
|
20057
|
+
}
|
|
20058
|
+
];
|
|
20059
|
+
function getAgentWiring(home = os34.homedir()) {
|
|
20060
|
+
const detected = detectAgents(home);
|
|
20061
|
+
return AGENT_SPECS.map((spec) => ({
|
|
20062
|
+
id: spec.id,
|
|
20063
|
+
label: spec.label,
|
|
20064
|
+
hookLabel: spec.hookLabel,
|
|
20065
|
+
setupCommand: spec.setupCommand,
|
|
20066
|
+
settingsPath: spec.settingsPath(home),
|
|
20067
|
+
installed: detected[spec.id],
|
|
20068
|
+
wireState: spec.wireState(home)
|
|
20069
|
+
}));
|
|
20070
|
+
}
|
|
20071
|
+
|
|
20072
|
+
// src/cli/commands/doctor.ts
|
|
19937
20073
|
function registerDoctorCommand(program2, version2) {
|
|
19938
20074
|
program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
|
|
19939
|
-
const homeDir2 =
|
|
20075
|
+
const homeDir2 = os35.homedir();
|
|
19940
20076
|
let failures = 0;
|
|
19941
20077
|
function pass(msg) {
|
|
19942
20078
|
console.log(chalk11.green(" \u2705 ") + msg);
|
|
@@ -19985,10 +20121,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19985
20121
|
);
|
|
19986
20122
|
}
|
|
19987
20123
|
section("Configuration");
|
|
19988
|
-
const globalConfigPath =
|
|
19989
|
-
if (
|
|
20124
|
+
const globalConfigPath = path40.join(homeDir2, ".node9", "config.json");
|
|
20125
|
+
if (fs39.existsSync(globalConfigPath)) {
|
|
19990
20126
|
try {
|
|
19991
|
-
JSON.parse(
|
|
20127
|
+
JSON.parse(fs39.readFileSync(globalConfigPath, "utf-8"));
|
|
19992
20128
|
pass("~/.node9/config.json found and valid");
|
|
19993
20129
|
} catch {
|
|
19994
20130
|
fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
|
|
@@ -19996,10 +20132,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19996
20132
|
} else {
|
|
19997
20133
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
19998
20134
|
}
|
|
19999
|
-
const projectConfigPath =
|
|
20000
|
-
if (
|
|
20135
|
+
const projectConfigPath = path40.join(process.cwd(), "node9.config.json");
|
|
20136
|
+
if (fs39.existsSync(projectConfigPath)) {
|
|
20001
20137
|
try {
|
|
20002
|
-
JSON.parse(
|
|
20138
|
+
JSON.parse(fs39.readFileSync(projectConfigPath, "utf-8"));
|
|
20003
20139
|
pass("node9.config.json found and valid (project)");
|
|
20004
20140
|
} catch {
|
|
20005
20141
|
fail(
|
|
@@ -20008,8 +20144,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
20008
20144
|
);
|
|
20009
20145
|
}
|
|
20010
20146
|
}
|
|
20011
|
-
const credsPath =
|
|
20012
|
-
if (
|
|
20147
|
+
const credsPath = path40.join(homeDir2, ".node9", "credentials.json");
|
|
20148
|
+
if (fs39.existsSync(credsPath)) {
|
|
20013
20149
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
20014
20150
|
} else {
|
|
20015
20151
|
warn(
|
|
@@ -20018,62 +20154,24 @@ function registerDoctorCommand(program2, version2) {
|
|
|
20018
20154
|
);
|
|
20019
20155
|
}
|
|
20020
20156
|
section("Agent Hooks");
|
|
20021
|
-
const
|
|
20022
|
-
|
|
20023
|
-
|
|
20024
|
-
|
|
20025
|
-
|
|
20026
|
-
|
|
20027
|
-
|
|
20028
|
-
|
|
20029
|
-
|
|
20030
|
-
|
|
20031
|
-
"Claude Code \u2014 hooks file found but node9 hook missing",
|
|
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");
|
|
20157
|
+
const notConfigured = [];
|
|
20158
|
+
for (const a of getAgentWiring(homeDir2)) {
|
|
20159
|
+
if (a.wireState === "wired") {
|
|
20160
|
+
pass(`${a.label} \u2014 ${a.hookLabel} active`);
|
|
20161
|
+
} else if (a.wireState === "unwired") {
|
|
20162
|
+
fail(`${a.label} \u2014 settings found but node9 hook missing`, `Run: ${a.setupCommand}`);
|
|
20163
|
+
} else if (a.wireState === "invalid") {
|
|
20164
|
+
fail(`${a.label} \u2014 settings file is invalid JSON`, a.settingsPath);
|
|
20165
|
+
} else {
|
|
20166
|
+
notConfigured.push(a.label);
|
|
20055
20167
|
}
|
|
20056
|
-
} else {
|
|
20057
|
-
warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
|
|
20058
20168
|
}
|
|
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)");
|
|
20169
|
+
if (notConfigured.length > 0) {
|
|
20170
|
+
console.log(
|
|
20171
|
+
chalk11.gray(
|
|
20172
|
+
` \xB7 Not configured: ${notConfigured.join(", ")} \u2014 run \`node9 setup <agent>\` if you use one`
|
|
20173
|
+
)
|
|
20174
|
+
);
|
|
20077
20175
|
}
|
|
20078
20176
|
section("Daemon (optional)");
|
|
20079
20177
|
if (isDaemonRunning()) {
|
|
@@ -20090,7 +20188,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
20090
20188
|
try {
|
|
20091
20189
|
const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
|
|
20092
20190
|
const cfg = getConfig();
|
|
20093
|
-
const creds =
|
|
20191
|
+
const creds = fs39.existsSync(path40.join(os35.homedir(), ".node9", "credentials.json"));
|
|
20094
20192
|
if (!creds) {
|
|
20095
20193
|
warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
|
|
20096
20194
|
} else if (!cfg.settings.approvers.cloud) {
|
|
@@ -20140,9 +20238,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
20140
20238
|
|
|
20141
20239
|
// src/cli/commands/audit.ts
|
|
20142
20240
|
import chalk12 from "chalk";
|
|
20143
|
-
import
|
|
20144
|
-
import
|
|
20145
|
-
import
|
|
20241
|
+
import fs40 from "fs";
|
|
20242
|
+
import path41 from "path";
|
|
20243
|
+
import os36 from "os";
|
|
20146
20244
|
function formatRelativeTime(timestamp) {
|
|
20147
20245
|
const diff = Date.now() - new Date(timestamp).getTime();
|
|
20148
20246
|
const sec = Math.floor(diff / 1e3);
|
|
@@ -20155,14 +20253,14 @@ function formatRelativeTime(timestamp) {
|
|
|
20155
20253
|
}
|
|
20156
20254
|
function registerAuditCommand(program2) {
|
|
20157
20255
|
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 (!
|
|
20256
|
+
const logPath = path41.join(os36.homedir(), ".node9", "audit.log");
|
|
20257
|
+
if (!fs40.existsSync(logPath)) {
|
|
20160
20258
|
console.log(
|
|
20161
20259
|
chalk12.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
20162
20260
|
);
|
|
20163
20261
|
return;
|
|
20164
20262
|
}
|
|
20165
|
-
const raw =
|
|
20263
|
+
const raw = fs40.readFileSync(logPath, "utf-8");
|
|
20166
20264
|
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
20167
20265
|
let entries = lines.flatMap((line) => {
|
|
20168
20266
|
try {
|
|
@@ -20221,9 +20319,9 @@ import chalk13 from "chalk";
|
|
|
20221
20319
|
init_costSync();
|
|
20222
20320
|
init_litellm();
|
|
20223
20321
|
init_cost_codex();
|
|
20224
|
-
import
|
|
20225
|
-
import
|
|
20226
|
-
import
|
|
20322
|
+
import fs41 from "fs";
|
|
20323
|
+
import os37 from "os";
|
|
20324
|
+
import path42 from "path";
|
|
20227
20325
|
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
20326
|
function buildTestTimestamps(allEntries) {
|
|
20229
20327
|
const testTs = /* @__PURE__ */ new Set();
|
|
@@ -20303,8 +20401,8 @@ function getDateRange(period, now) {
|
|
|
20303
20401
|
}
|
|
20304
20402
|
}
|
|
20305
20403
|
function parseAuditLog(logPath) {
|
|
20306
|
-
if (!
|
|
20307
|
-
const raw =
|
|
20404
|
+
if (!fs41.existsSync(logPath)) return [];
|
|
20405
|
+
const raw = fs41.readFileSync(logPath, "utf-8");
|
|
20308
20406
|
return raw.split("\n").flatMap((line) => {
|
|
20309
20407
|
if (!line.trim()) return [];
|
|
20310
20408
|
try {
|
|
@@ -20351,25 +20449,25 @@ function freezeClaudeCost(acc) {
|
|
|
20351
20449
|
};
|
|
20352
20450
|
}
|
|
20353
20451
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
20354
|
-
const projPath =
|
|
20452
|
+
const projPath = path42.join(projectsDir, proj);
|
|
20355
20453
|
let files;
|
|
20356
20454
|
try {
|
|
20357
|
-
const stat =
|
|
20455
|
+
const stat = fs41.statSync(projPath);
|
|
20358
20456
|
if (!stat.isDirectory()) return;
|
|
20359
|
-
files =
|
|
20457
|
+
files = fs41.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
20360
20458
|
} catch {
|
|
20361
20459
|
return;
|
|
20362
20460
|
}
|
|
20363
20461
|
const startMs = start.getTime();
|
|
20364
20462
|
for (const file of files) {
|
|
20365
|
-
const filePath =
|
|
20463
|
+
const filePath = path42.join(projPath, file);
|
|
20366
20464
|
try {
|
|
20367
|
-
if (
|
|
20465
|
+
if (fs41.statSync(filePath).mtimeMs < startMs) continue;
|
|
20368
20466
|
} catch {
|
|
20369
20467
|
continue;
|
|
20370
20468
|
}
|
|
20371
20469
|
try {
|
|
20372
|
-
const raw =
|
|
20470
|
+
const raw = fs41.readFileSync(filePath, "utf-8");
|
|
20373
20471
|
for (const line of raw.split("\n")) {
|
|
20374
20472
|
if (!line.trim()) continue;
|
|
20375
20473
|
let entry;
|
|
@@ -20419,10 +20517,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
20419
20517
|
}
|
|
20420
20518
|
function loadClaudeCost(start, end, projectsDir) {
|
|
20421
20519
|
const acc = emptyClaudeCostAccumulator();
|
|
20422
|
-
if (!
|
|
20520
|
+
if (!fs41.existsSync(projectsDir)) return freezeClaudeCost(acc);
|
|
20423
20521
|
let dirs;
|
|
20424
20522
|
try {
|
|
20425
|
-
dirs =
|
|
20523
|
+
dirs = fs41.readdirSync(projectsDir);
|
|
20426
20524
|
} catch {
|
|
20427
20525
|
return freezeClaudeCost(acc);
|
|
20428
20526
|
}
|
|
@@ -20434,7 +20532,7 @@ function loadClaudeCost(start, end, projectsDir) {
|
|
|
20434
20532
|
function processCodexCostFile(filePath, start, end, acc) {
|
|
20435
20533
|
let lines;
|
|
20436
20534
|
try {
|
|
20437
|
-
lines =
|
|
20535
|
+
lines = fs41.readFileSync(filePath, "utf-8").split("\n");
|
|
20438
20536
|
} catch {
|
|
20439
20537
|
return;
|
|
20440
20538
|
}
|
|
@@ -20489,31 +20587,31 @@ function processCodexCostFile(filePath, start, end, acc) {
|
|
|
20489
20587
|
}
|
|
20490
20588
|
function listCodexSessionFiles2(sessionsBase) {
|
|
20491
20589
|
const jsonlFiles = [];
|
|
20492
|
-
if (!
|
|
20590
|
+
if (!fs41.existsSync(sessionsBase)) return jsonlFiles;
|
|
20493
20591
|
try {
|
|
20494
|
-
for (const year of
|
|
20495
|
-
const yearPath =
|
|
20592
|
+
for (const year of fs41.readdirSync(sessionsBase)) {
|
|
20593
|
+
const yearPath = path42.join(sessionsBase, year);
|
|
20496
20594
|
try {
|
|
20497
|
-
if (!
|
|
20595
|
+
if (!fs41.statSync(yearPath).isDirectory()) continue;
|
|
20498
20596
|
} catch {
|
|
20499
20597
|
continue;
|
|
20500
20598
|
}
|
|
20501
|
-
for (const month of
|
|
20502
|
-
const monthPath =
|
|
20599
|
+
for (const month of fs41.readdirSync(yearPath)) {
|
|
20600
|
+
const monthPath = path42.join(yearPath, month);
|
|
20503
20601
|
try {
|
|
20504
|
-
if (!
|
|
20602
|
+
if (!fs41.statSync(monthPath).isDirectory()) continue;
|
|
20505
20603
|
} catch {
|
|
20506
20604
|
continue;
|
|
20507
20605
|
}
|
|
20508
|
-
for (const day of
|
|
20509
|
-
const dayPath =
|
|
20606
|
+
for (const day of fs41.readdirSync(monthPath)) {
|
|
20607
|
+
const dayPath = path42.join(monthPath, day);
|
|
20510
20608
|
try {
|
|
20511
|
-
if (!
|
|
20609
|
+
if (!fs41.statSync(dayPath).isDirectory()) continue;
|
|
20512
20610
|
} catch {
|
|
20513
20611
|
continue;
|
|
20514
20612
|
}
|
|
20515
|
-
for (const file of
|
|
20516
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
20613
|
+
for (const file of fs41.readdirSync(dayPath)) {
|
|
20614
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(path42.join(dayPath, file));
|
|
20517
20615
|
}
|
|
20518
20616
|
}
|
|
20519
20617
|
}
|
|
@@ -20578,13 +20676,13 @@ function freezeGeminiCost(acc) {
|
|
|
20578
20676
|
function processGeminiCostFile(filePath, projectKey, start, end, acc) {
|
|
20579
20677
|
const startMs = start.getTime();
|
|
20580
20678
|
try {
|
|
20581
|
-
if (
|
|
20679
|
+
if (fs41.statSync(filePath).mtimeMs < startMs) return;
|
|
20582
20680
|
} catch {
|
|
20583
20681
|
return;
|
|
20584
20682
|
}
|
|
20585
20683
|
let raw;
|
|
20586
20684
|
try {
|
|
20587
|
-
raw =
|
|
20685
|
+
raw = fs41.readFileSync(filePath, "utf-8");
|
|
20588
20686
|
} catch {
|
|
20589
20687
|
return;
|
|
20590
20688
|
}
|
|
@@ -20633,30 +20731,30 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
|
|
|
20633
20731
|
const out = [];
|
|
20634
20732
|
let dirs;
|
|
20635
20733
|
try {
|
|
20636
|
-
if (!
|
|
20637
|
-
dirs =
|
|
20734
|
+
if (!fs41.statSync(geminiTmpDir2).isDirectory()) return out;
|
|
20735
|
+
dirs = fs41.readdirSync(geminiTmpDir2);
|
|
20638
20736
|
} catch {
|
|
20639
20737
|
return out;
|
|
20640
20738
|
}
|
|
20641
20739
|
for (const proj of dirs) {
|
|
20642
|
-
const chatsDir =
|
|
20740
|
+
const chatsDir = path42.join(geminiTmpDir2, proj, "chats");
|
|
20643
20741
|
let files;
|
|
20644
20742
|
try {
|
|
20645
|
-
if (!
|
|
20646
|
-
files =
|
|
20743
|
+
if (!fs41.statSync(chatsDir).isDirectory()) continue;
|
|
20744
|
+
files = fs41.readdirSync(chatsDir);
|
|
20647
20745
|
} catch {
|
|
20648
20746
|
continue;
|
|
20649
20747
|
}
|
|
20650
20748
|
for (const f of files) {
|
|
20651
20749
|
if (!f.endsWith(".jsonl")) continue;
|
|
20652
|
-
out.push({ projectKey: proj, file:
|
|
20750
|
+
out.push({ projectKey: proj, file: path42.join(chatsDir, f) });
|
|
20653
20751
|
}
|
|
20654
20752
|
}
|
|
20655
20753
|
return out;
|
|
20656
20754
|
}
|
|
20657
20755
|
function loadGeminiCost(start, end, geminiTmpDir2) {
|
|
20658
20756
|
const acc = emptyGeminiAccumulator();
|
|
20659
|
-
if (!
|
|
20757
|
+
if (!fs41.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
|
|
20660
20758
|
for (const { projectKey, file } of listGeminiSessionFiles2(geminiTmpDir2)) {
|
|
20661
20759
|
processGeminiCostFile(file, projectKey, start, end, acc);
|
|
20662
20760
|
}
|
|
@@ -20664,11 +20762,11 @@ function loadGeminiCost(start, end, geminiTmpDir2) {
|
|
|
20664
20762
|
}
|
|
20665
20763
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
20666
20764
|
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 =
|
|
20765
|
+
const auditLogPath = opts.auditLogPath ?? path42.join(os37.homedir(), ".node9", "audit.log");
|
|
20766
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? path42.join(os37.homedir(), ".claude", "projects");
|
|
20767
|
+
const codexSessionsDir2 = opts.codexSessionsDir ?? path42.join(os37.homedir(), ".codex", "sessions");
|
|
20768
|
+
const geminiTmpDir2 = opts.geminiTmpDir ?? path42.join(os37.homedir(), ".gemini", "tmp");
|
|
20769
|
+
const hasAuditFile = fs41.existsSync(auditLogPath);
|
|
20672
20770
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
|
|
20673
20771
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
20674
20772
|
const { start, end } = getDateRange(period, now);
|
|
@@ -21367,20 +21465,20 @@ init_core();
|
|
|
21367
21465
|
init_daemon();
|
|
21368
21466
|
init_setup();
|
|
21369
21467
|
import chalk15 from "chalk";
|
|
21370
|
-
import
|
|
21371
|
-
import
|
|
21372
|
-
import
|
|
21373
|
-
import * as
|
|
21468
|
+
import fs42 from "fs";
|
|
21469
|
+
import path43 from "path";
|
|
21470
|
+
import os38 from "os";
|
|
21471
|
+
import * as yaml3 from "yaml";
|
|
21374
21472
|
function readHermesHooks(configPath) {
|
|
21375
|
-
if (!
|
|
21473
|
+
if (!fs42.existsSync(configPath)) return null;
|
|
21376
21474
|
let raw;
|
|
21377
21475
|
try {
|
|
21378
|
-
raw =
|
|
21476
|
+
raw = fs42.readFileSync(configPath, "utf-8");
|
|
21379
21477
|
} catch {
|
|
21380
21478
|
return null;
|
|
21381
21479
|
}
|
|
21382
21480
|
try {
|
|
21383
|
-
const cfg =
|
|
21481
|
+
const cfg = yaml3.parse(raw);
|
|
21384
21482
|
const has = (event) => (cfg?.hooks?.[event] ?? []).some(
|
|
21385
21483
|
(e) => typeof e?.command === "string" && isNode9Hook(e.command)
|
|
21386
21484
|
);
|
|
@@ -21394,17 +21492,17 @@ function readHermesHooks(configPath) {
|
|
|
21394
21492
|
return { pre: false, post: false };
|
|
21395
21493
|
}
|
|
21396
21494
|
}
|
|
21397
|
-
function
|
|
21495
|
+
function readJson3(filePath) {
|
|
21398
21496
|
try {
|
|
21399
|
-
if (
|
|
21497
|
+
if (fs42.existsSync(filePath)) return JSON.parse(fs42.readFileSync(filePath, "utf-8"));
|
|
21400
21498
|
} catch {
|
|
21401
21499
|
}
|
|
21402
21500
|
return null;
|
|
21403
21501
|
}
|
|
21404
|
-
function
|
|
21502
|
+
function matchersHaveNode9Hook2(matchers) {
|
|
21405
21503
|
return (matchers ?? []).some((m) => (m.hooks ?? []).some((h) => isNode9Hook(h.command)));
|
|
21406
21504
|
}
|
|
21407
|
-
function
|
|
21505
|
+
function flatHaveNode9Hook2(entries) {
|
|
21408
21506
|
return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
|
|
21409
21507
|
}
|
|
21410
21508
|
function wrappedMcpServers(servers) {
|
|
@@ -21464,42 +21562,42 @@ function registerStatusCommand(program2) {
|
|
|
21464
21562
|
console.log("");
|
|
21465
21563
|
const modeLabel = settings.mode === "audit" ? chalk15.blue("audit") : settings.mode === "strict" ? chalk15.red("strict") : chalk15.white("standard");
|
|
21466
21564
|
console.log(` Mode: ${modeLabel}`);
|
|
21467
|
-
const projectConfig =
|
|
21468
|
-
const globalConfig =
|
|
21565
|
+
const projectConfig = path43.join(process.cwd(), "node9.config.json");
|
|
21566
|
+
const globalConfig = path43.join(os38.homedir(), ".node9", "config.json");
|
|
21469
21567
|
console.log(
|
|
21470
|
-
` Local: ${
|
|
21568
|
+
` Local: ${fs42.existsSync(projectConfig) ? chalk15.green("Active (node9.config.json)") : chalk15.gray("Not present")}`
|
|
21471
21569
|
);
|
|
21472
21570
|
console.log(
|
|
21473
|
-
` Global: ${
|
|
21571
|
+
` Global: ${fs42.existsSync(globalConfig) ? chalk15.green("Active (~/.node9/config.json)") : chalk15.gray("Not present")}`
|
|
21474
21572
|
);
|
|
21475
21573
|
if (mergedConfig.policy.sandboxPaths.length > 0) {
|
|
21476
21574
|
console.log(
|
|
21477
21575
|
` Sandbox: ${chalk15.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
|
|
21478
21576
|
);
|
|
21479
21577
|
}
|
|
21480
|
-
const homeDir2 =
|
|
21481
|
-
const claudeSettings =
|
|
21482
|
-
|
|
21578
|
+
const homeDir2 = os38.homedir();
|
|
21579
|
+
const claudeSettings = readJson3(
|
|
21580
|
+
path43.join(homeDir2, ".claude", "settings.json")
|
|
21483
21581
|
);
|
|
21484
|
-
const claudeConfig =
|
|
21485
|
-
const geminiSettings =
|
|
21486
|
-
|
|
21582
|
+
const claudeConfig = readJson3(path43.join(homeDir2, ".claude.json"));
|
|
21583
|
+
const geminiSettings = readJson3(
|
|
21584
|
+
path43.join(homeDir2, ".gemini", "settings.json")
|
|
21487
21585
|
);
|
|
21488
|
-
const cursorConfig =
|
|
21489
|
-
const antigravityHooks =
|
|
21490
|
-
|
|
21586
|
+
const cursorConfig = readJson3(path43.join(homeDir2, ".cursor", "mcp.json"));
|
|
21587
|
+
const antigravityHooks = readJson3(
|
|
21588
|
+
path43.join(homeDir2, ".gemini", "config", "hooks.json")
|
|
21491
21589
|
);
|
|
21492
|
-
const antigravityMcp =
|
|
21493
|
-
|
|
21590
|
+
const antigravityMcp = readJson3(
|
|
21591
|
+
path43.join(homeDir2, ".gemini", "config", "mcp_config.json")
|
|
21494
21592
|
);
|
|
21495
|
-
const antigravityPresent = antigravityHooks !== null ||
|
|
21496
|
-
const copilotHooks =
|
|
21497
|
-
|
|
21593
|
+
const antigravityPresent = antigravityHooks !== null || fs42.existsSync(path43.join(homeDir2, ".gemini", "antigravity-cli")) || fs42.existsSync(path43.join(homeDir2, ".gemini", "antigravity-ide"));
|
|
21594
|
+
const copilotHooks = readJson3(
|
|
21595
|
+
path43.join(homeDir2, ".copilot", "hooks", "node9.json")
|
|
21498
21596
|
);
|
|
21499
|
-
const copilotMcp =
|
|
21500
|
-
|
|
21597
|
+
const copilotMcp = readJson3(
|
|
21598
|
+
path43.join(homeDir2, ".copilot", "mcp-config.json")
|
|
21501
21599
|
);
|
|
21502
|
-
const copilotPresent =
|
|
21600
|
+
const copilotPresent = fs42.existsSync(path43.join(homeDir2, ".copilot"));
|
|
21503
21601
|
const hermesHooks = readHermesHooks(hermesConfigPath(homeDir2));
|
|
21504
21602
|
const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig || antigravityPresent || copilotPresent || hermesHooks;
|
|
21505
21603
|
if (agentFound) {
|
|
@@ -21507,8 +21605,8 @@ function registerStatusCommand(program2) {
|
|
|
21507
21605
|
console.log(chalk15.bold(" Agent Wiring:"));
|
|
21508
21606
|
console.log("");
|
|
21509
21607
|
if (claudeSettings || claudeConfig) {
|
|
21510
|
-
const preHook =
|
|
21511
|
-
const postHook =
|
|
21608
|
+
const preHook = matchersHaveNode9Hook2(claudeSettings?.hooks?.PreToolUse);
|
|
21609
|
+
const postHook = matchersHaveNode9Hook2(claudeSettings?.hooks?.PostToolUse);
|
|
21512
21610
|
printAgentSection(
|
|
21513
21611
|
"Claude Code",
|
|
21514
21612
|
[
|
|
@@ -21520,8 +21618,8 @@ function registerStatusCommand(program2) {
|
|
|
21520
21618
|
console.log("");
|
|
21521
21619
|
}
|
|
21522
21620
|
if (geminiSettings) {
|
|
21523
|
-
const beforeHook =
|
|
21524
|
-
const afterHook =
|
|
21621
|
+
const beforeHook = matchersHaveNode9Hook2(geminiSettings.hooks?.BeforeTool);
|
|
21622
|
+
const afterHook = matchersHaveNode9Hook2(geminiSettings.hooks?.AfterTool);
|
|
21525
21623
|
printAgentSection(
|
|
21526
21624
|
"Gemini CLI",
|
|
21527
21625
|
[
|
|
@@ -21533,8 +21631,8 @@ function registerStatusCommand(program2) {
|
|
|
21533
21631
|
console.log("");
|
|
21534
21632
|
}
|
|
21535
21633
|
if (antigravityPresent) {
|
|
21536
|
-
const preHook =
|
|
21537
|
-
const postHook =
|
|
21634
|
+
const preHook = matchersHaveNode9Hook2(antigravityHooks?.hooks?.PreToolUse);
|
|
21635
|
+
const postHook = matchersHaveNode9Hook2(antigravityHooks?.hooks?.PostToolUse);
|
|
21538
21636
|
printAgentSection(
|
|
21539
21637
|
"Antigravity",
|
|
21540
21638
|
[
|
|
@@ -21546,9 +21644,9 @@ function registerStatusCommand(program2) {
|
|
|
21546
21644
|
console.log("");
|
|
21547
21645
|
}
|
|
21548
21646
|
if (copilotPresent) {
|
|
21549
|
-
const preHook =
|
|
21550
|
-
const postHook =
|
|
21551
|
-
const promptHook =
|
|
21647
|
+
const preHook = flatHaveNode9Hook2(copilotHooks?.hooks?.PreToolUse);
|
|
21648
|
+
const postHook = flatHaveNode9Hook2(copilotHooks?.hooks?.PostToolUse);
|
|
21649
|
+
const promptHook = flatHaveNode9Hook2(copilotHooks?.hooks?.UserPromptSubmit);
|
|
21552
21650
|
printAgentSection(
|
|
21553
21651
|
"GitHub Copilot",
|
|
21554
21652
|
[
|
|
@@ -21595,9 +21693,9 @@ init_setup();
|
|
|
21595
21693
|
init_shields();
|
|
21596
21694
|
init_service();
|
|
21597
21695
|
import chalk16 from "chalk";
|
|
21598
|
-
import
|
|
21599
|
-
import
|
|
21600
|
-
import
|
|
21696
|
+
import fs43 from "fs";
|
|
21697
|
+
import path44 from "path";
|
|
21698
|
+
import os39 from "os";
|
|
21601
21699
|
import https4 from "https";
|
|
21602
21700
|
var DEFAULT_SHIELDS = ["bash-safe", "filesystem", "project-jail"];
|
|
21603
21701
|
function buildTelemetryPayload(agents, firstInstall) {
|
|
@@ -21683,16 +21781,16 @@ function registerInitCommand(program2) {
|
|
|
21683
21781
|
}
|
|
21684
21782
|
console.log("");
|
|
21685
21783
|
}
|
|
21686
|
-
const configPath =
|
|
21687
|
-
const isFirstInstall = !
|
|
21688
|
-
if (
|
|
21784
|
+
const configPath = path44.join(os39.homedir(), ".node9", "config.json");
|
|
21785
|
+
const isFirstInstall = !fs43.existsSync(configPath);
|
|
21786
|
+
if (fs43.existsSync(configPath) && !options.force) {
|
|
21689
21787
|
try {
|
|
21690
|
-
const existing = JSON.parse(
|
|
21788
|
+
const existing = JSON.parse(fs43.readFileSync(configPath, "utf-8"));
|
|
21691
21789
|
const settings = existing.settings ?? {};
|
|
21692
21790
|
if (settings.mode !== chosenMode) {
|
|
21693
21791
|
settings.mode = chosenMode;
|
|
21694
21792
|
existing.settings = settings;
|
|
21695
|
-
|
|
21793
|
+
fs43.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
|
|
21696
21794
|
console.log(chalk16.green(`\u2705 Mode updated: ${chosenMode}`));
|
|
21697
21795
|
} else {
|
|
21698
21796
|
console.log(chalk16.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
|
|
@@ -21705,9 +21803,9 @@ function registerInitCommand(program2) {
|
|
|
21705
21803
|
...DEFAULT_CONFIG,
|
|
21706
21804
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
21707
21805
|
};
|
|
21708
|
-
const dir =
|
|
21709
|
-
if (!
|
|
21710
|
-
|
|
21806
|
+
const dir = path44.dirname(configPath);
|
|
21807
|
+
if (!fs43.existsSync(dir)) fs43.mkdirSync(dir, { recursive: true });
|
|
21808
|
+
fs43.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
|
|
21711
21809
|
console.log(chalk16.green(`\u2705 Config created: ${configPath}`));
|
|
21712
21810
|
console.log(chalk16.gray(` Mode: ${chosenMode}`));
|
|
21713
21811
|
}
|
|
@@ -21812,7 +21910,7 @@ function registerInitCommand(program2) {
|
|
|
21812
21910
|
}
|
|
21813
21911
|
|
|
21814
21912
|
// src/cli/commands/undo.ts
|
|
21815
|
-
import
|
|
21913
|
+
import path45 from "path";
|
|
21816
21914
|
import chalk18 from "chalk";
|
|
21817
21915
|
|
|
21818
21916
|
// src/tui/undo-navigator.ts
|
|
@@ -21971,7 +22069,7 @@ function findMatchingCwd(startDir, history) {
|
|
|
21971
22069
|
let dir = startDir;
|
|
21972
22070
|
while (true) {
|
|
21973
22071
|
if (cwds.has(dir)) return dir;
|
|
21974
|
-
const parent =
|
|
22072
|
+
const parent = path45.dirname(dir);
|
|
21975
22073
|
if (parent === dir) return null;
|
|
21976
22074
|
dir = parent;
|
|
21977
22075
|
}
|
|
@@ -22606,9 +22704,9 @@ function registerMcpGatewayCommand(program2) {
|
|
|
22606
22704
|
|
|
22607
22705
|
// src/mcp-server/index.ts
|
|
22608
22706
|
import readline5 from "readline";
|
|
22609
|
-
import
|
|
22610
|
-
import
|
|
22611
|
-
import
|
|
22707
|
+
import fs44 from "fs";
|
|
22708
|
+
import os40 from "os";
|
|
22709
|
+
import path46 from "path";
|
|
22612
22710
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
22613
22711
|
init_core();
|
|
22614
22712
|
init_daemon();
|
|
@@ -22859,13 +22957,13 @@ function handleStatus() {
|
|
|
22859
22957
|
lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
|
|
22860
22958
|
lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
|
|
22861
22959
|
lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
|
|
22862
|
-
const projectConfig =
|
|
22863
|
-
const globalConfig =
|
|
22960
|
+
const projectConfig = path46.join(process.cwd(), "node9.config.json");
|
|
22961
|
+
const globalConfig = path46.join(os40.homedir(), ".node9", "config.json");
|
|
22864
22962
|
lines.push(
|
|
22865
|
-
`Project config (node9.config.json): ${
|
|
22963
|
+
`Project config (node9.config.json): ${fs44.existsSync(projectConfig) ? "present" : "not found"}`
|
|
22866
22964
|
);
|
|
22867
22965
|
lines.push(
|
|
22868
|
-
`Global config (~/.node9/config.json): ${
|
|
22966
|
+
`Global config (~/.node9/config.json): ${fs44.existsSync(globalConfig) ? "present" : "not found"}`
|
|
22869
22967
|
);
|
|
22870
22968
|
return lines.join("\n");
|
|
22871
22969
|
}
|
|
@@ -22939,21 +23037,21 @@ function handleShieldDisable(args) {
|
|
|
22939
23037
|
writeActiveShields(active.filter((s) => s !== name));
|
|
22940
23038
|
return `Shield "${name}" disabled.`;
|
|
22941
23039
|
}
|
|
22942
|
-
var GLOBAL_CONFIG_PATH =
|
|
23040
|
+
var GLOBAL_CONFIG_PATH = path46.join(os40.homedir(), ".node9", "config.json");
|
|
22943
23041
|
var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
|
|
22944
23042
|
function readGlobalConfigRaw() {
|
|
22945
23043
|
try {
|
|
22946
|
-
if (
|
|
22947
|
-
return JSON.parse(
|
|
23044
|
+
if (fs44.existsSync(GLOBAL_CONFIG_PATH)) {
|
|
23045
|
+
return JSON.parse(fs44.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
|
|
22948
23046
|
}
|
|
22949
23047
|
} catch {
|
|
22950
23048
|
}
|
|
22951
23049
|
return {};
|
|
22952
23050
|
}
|
|
22953
23051
|
function writeGlobalConfigRaw(data) {
|
|
22954
|
-
const dir =
|
|
22955
|
-
if (!
|
|
22956
|
-
|
|
23052
|
+
const dir = path46.dirname(GLOBAL_CONFIG_PATH);
|
|
23053
|
+
if (!fs44.existsSync(dir)) fs44.mkdirSync(dir, { recursive: true });
|
|
23054
|
+
fs44.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
|
|
22957
23055
|
}
|
|
22958
23056
|
function handleApproverList() {
|
|
22959
23057
|
const config = getConfig();
|
|
@@ -22997,9 +23095,9 @@ function handleApproverSet(args) {
|
|
|
22997
23095
|
function handleAuditGet(args) {
|
|
22998
23096
|
const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
|
|
22999
23097
|
const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
|
|
23000
|
-
const auditPath =
|
|
23001
|
-
if (!
|
|
23002
|
-
const rawLines =
|
|
23098
|
+
const auditPath = path46.join(os40.homedir(), ".node9", "audit.log");
|
|
23099
|
+
if (!fs44.existsSync(auditPath)) return "No audit log found.";
|
|
23100
|
+
const rawLines = fs44.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
|
|
23003
23101
|
const parsed = [];
|
|
23004
23102
|
for (const line of rawLines) {
|
|
23005
23103
|
try {
|
|
@@ -23334,7 +23432,7 @@ function registerTrustCommand(program2) {
|
|
|
23334
23432
|
// src/cli/commands/mcp-pin.ts
|
|
23335
23433
|
init_mcp_pin();
|
|
23336
23434
|
import chalk21 from "chalk";
|
|
23337
|
-
import
|
|
23435
|
+
import fs45 from "fs";
|
|
23338
23436
|
function registerMcpPinCommand(program2) {
|
|
23339
23437
|
const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
|
|
23340
23438
|
const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
|
|
@@ -23345,7 +23443,7 @@ function registerMcpPinCommand(program2) {
|
|
|
23345
23443
|
let repoCorrupt = false;
|
|
23346
23444
|
if (found.source === "repo") {
|
|
23347
23445
|
try {
|
|
23348
|
-
const raw =
|
|
23446
|
+
const raw = fs45.readFileSync(found.path, "utf-8");
|
|
23349
23447
|
const parsed = JSON.parse(raw);
|
|
23350
23448
|
repoEntries = parsed.servers ?? {};
|
|
23351
23449
|
} catch {
|
|
@@ -23662,9 +23760,9 @@ init_litellm();
|
|
|
23662
23760
|
init_cost_gemini();
|
|
23663
23761
|
init_cost_codex();
|
|
23664
23762
|
import chalk24 from "chalk";
|
|
23665
|
-
import
|
|
23666
|
-
import
|
|
23667
|
-
import
|
|
23763
|
+
import fs46 from "fs";
|
|
23764
|
+
import path47 from "path";
|
|
23765
|
+
import os41 from "os";
|
|
23668
23766
|
function modelPrice(model) {
|
|
23669
23767
|
const t = pricingFor(model);
|
|
23670
23768
|
if (!t) return null;
|
|
@@ -23681,10 +23779,10 @@ function encodeProjectPath(projectPath) {
|
|
|
23681
23779
|
}
|
|
23682
23780
|
function sessionJsonlPath(projectPath, sessionId) {
|
|
23683
23781
|
const encoded = encodeProjectPath(projectPath);
|
|
23684
|
-
return
|
|
23782
|
+
return path47.join(os41.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
|
|
23685
23783
|
}
|
|
23686
23784
|
function projectLabel(projectPath) {
|
|
23687
|
-
return projectPath.replace(
|
|
23785
|
+
return projectPath.replace(os41.homedir(), "~");
|
|
23688
23786
|
}
|
|
23689
23787
|
function parseHistoryLines(lines) {
|
|
23690
23788
|
const entries = [];
|
|
@@ -23753,10 +23851,10 @@ function parseSessionLines(lines) {
|
|
|
23753
23851
|
return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
|
|
23754
23852
|
}
|
|
23755
23853
|
function loadAuditEntries(auditPath) {
|
|
23756
|
-
const aPath = auditPath ??
|
|
23854
|
+
const aPath = auditPath ?? path47.join(os41.homedir(), ".node9", "audit.log");
|
|
23757
23855
|
let raw;
|
|
23758
23856
|
try {
|
|
23759
|
-
raw =
|
|
23857
|
+
raw = fs46.readFileSync(aPath, "utf-8");
|
|
23760
23858
|
} catch {
|
|
23761
23859
|
return [];
|
|
23762
23860
|
}
|
|
@@ -23792,8 +23890,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
23792
23890
|
return result;
|
|
23793
23891
|
}
|
|
23794
23892
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
23795
|
-
const tmpDir =
|
|
23796
|
-
if (!
|
|
23893
|
+
const tmpDir = path47.join(os41.homedir(), ".gemini", "tmp");
|
|
23894
|
+
if (!fs46.existsSync(tmpDir)) return [];
|
|
23797
23895
|
const cutoff = days !== null ? (() => {
|
|
23798
23896
|
const d = /* @__PURE__ */ new Date();
|
|
23799
23897
|
d.setDate(d.getDate() - days);
|
|
@@ -23802,35 +23900,35 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
23802
23900
|
})() : null;
|
|
23803
23901
|
let slugDirs;
|
|
23804
23902
|
try {
|
|
23805
|
-
slugDirs =
|
|
23903
|
+
slugDirs = fs46.readdirSync(tmpDir);
|
|
23806
23904
|
} catch {
|
|
23807
23905
|
return [];
|
|
23808
23906
|
}
|
|
23809
23907
|
const summaries = [];
|
|
23810
23908
|
for (const slug of slugDirs) {
|
|
23811
|
-
const slugPath =
|
|
23909
|
+
const slugPath = path47.join(tmpDir, slug);
|
|
23812
23910
|
try {
|
|
23813
|
-
if (!
|
|
23911
|
+
if (!fs46.statSync(slugPath).isDirectory()) continue;
|
|
23814
23912
|
} catch {
|
|
23815
23913
|
continue;
|
|
23816
23914
|
}
|
|
23817
|
-
let projectRoot =
|
|
23915
|
+
let projectRoot = path47.join(os41.homedir(), slug);
|
|
23818
23916
|
try {
|
|
23819
|
-
projectRoot =
|
|
23917
|
+
projectRoot = fs46.readFileSync(path47.join(slugPath, ".project_root"), "utf-8").trim();
|
|
23820
23918
|
} catch {
|
|
23821
23919
|
}
|
|
23822
|
-
const chatsDir =
|
|
23823
|
-
if (!
|
|
23920
|
+
const chatsDir = path47.join(slugPath, "chats");
|
|
23921
|
+
if (!fs46.existsSync(chatsDir)) continue;
|
|
23824
23922
|
let chatFiles;
|
|
23825
23923
|
try {
|
|
23826
|
-
chatFiles =
|
|
23924
|
+
chatFiles = fs46.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
23827
23925
|
} catch {
|
|
23828
23926
|
continue;
|
|
23829
23927
|
}
|
|
23830
23928
|
for (const chatFile of chatFiles) {
|
|
23831
23929
|
let raw;
|
|
23832
23930
|
try {
|
|
23833
|
-
raw =
|
|
23931
|
+
raw = fs46.readFileSync(path47.join(chatsDir, chatFile), "utf-8");
|
|
23834
23932
|
} catch {
|
|
23835
23933
|
continue;
|
|
23836
23934
|
}
|
|
@@ -23910,8 +24008,8 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
23910
24008
|
return summaries;
|
|
23911
24009
|
}
|
|
23912
24010
|
function buildCodexSessions(days, allAuditEntries) {
|
|
23913
|
-
const sessionsBase =
|
|
23914
|
-
if (!
|
|
24011
|
+
const sessionsBase = path47.join(os41.homedir(), ".codex", "sessions");
|
|
24012
|
+
if (!fs46.existsSync(sessionsBase)) return [];
|
|
23915
24013
|
const cutoff = days !== null ? (() => {
|
|
23916
24014
|
const d = /* @__PURE__ */ new Date();
|
|
23917
24015
|
d.setDate(d.getDate() - days);
|
|
@@ -23920,29 +24018,29 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
23920
24018
|
})() : null;
|
|
23921
24019
|
const jsonlFiles = [];
|
|
23922
24020
|
try {
|
|
23923
|
-
for (const year of
|
|
23924
|
-
const yearPath =
|
|
24021
|
+
for (const year of fs46.readdirSync(sessionsBase)) {
|
|
24022
|
+
const yearPath = path47.join(sessionsBase, year);
|
|
23925
24023
|
try {
|
|
23926
|
-
if (!
|
|
24024
|
+
if (!fs46.statSync(yearPath).isDirectory()) continue;
|
|
23927
24025
|
} catch {
|
|
23928
24026
|
continue;
|
|
23929
24027
|
}
|
|
23930
|
-
for (const month of
|
|
23931
|
-
const monthPath =
|
|
24028
|
+
for (const month of fs46.readdirSync(yearPath)) {
|
|
24029
|
+
const monthPath = path47.join(yearPath, month);
|
|
23932
24030
|
try {
|
|
23933
|
-
if (!
|
|
24031
|
+
if (!fs46.statSync(monthPath).isDirectory()) continue;
|
|
23934
24032
|
} catch {
|
|
23935
24033
|
continue;
|
|
23936
24034
|
}
|
|
23937
|
-
for (const day of
|
|
23938
|
-
const dayPath =
|
|
24035
|
+
for (const day of fs46.readdirSync(monthPath)) {
|
|
24036
|
+
const dayPath = path47.join(monthPath, day);
|
|
23939
24037
|
try {
|
|
23940
|
-
if (!
|
|
24038
|
+
if (!fs46.statSync(dayPath).isDirectory()) continue;
|
|
23941
24039
|
} catch {
|
|
23942
24040
|
continue;
|
|
23943
24041
|
}
|
|
23944
|
-
for (const file of
|
|
23945
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
24042
|
+
for (const file of fs46.readdirSync(dayPath)) {
|
|
24043
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(path47.join(dayPath, file));
|
|
23946
24044
|
}
|
|
23947
24045
|
}
|
|
23948
24046
|
}
|
|
@@ -23954,7 +24052,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
23954
24052
|
for (const filePath of jsonlFiles) {
|
|
23955
24053
|
let lines;
|
|
23956
24054
|
try {
|
|
23957
|
-
lines =
|
|
24055
|
+
lines = fs46.readFileSync(filePath, "utf-8").split("\n");
|
|
23958
24056
|
} catch {
|
|
23959
24057
|
continue;
|
|
23960
24058
|
}
|
|
@@ -24040,10 +24138,10 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
24040
24138
|
return summaries;
|
|
24041
24139
|
}
|
|
24042
24140
|
function buildSessions(days, historyPath) {
|
|
24043
|
-
const hPath = historyPath ??
|
|
24141
|
+
const hPath = historyPath ?? path47.join(os41.homedir(), ".claude", "history.jsonl");
|
|
24044
24142
|
let historyRaw = "";
|
|
24045
24143
|
try {
|
|
24046
|
-
historyRaw =
|
|
24144
|
+
historyRaw = fs46.readFileSync(hPath, "utf-8");
|
|
24047
24145
|
} catch {
|
|
24048
24146
|
}
|
|
24049
24147
|
const cutoff = days !== null ? (() => {
|
|
@@ -24067,7 +24165,7 @@ function buildSessions(days, historyPath) {
|
|
|
24067
24165
|
const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
|
|
24068
24166
|
let sessionLines = [];
|
|
24069
24167
|
try {
|
|
24070
|
-
sessionLines =
|
|
24168
|
+
sessionLines = fs46.readFileSync(jsonlFile, "utf-8").split("\n");
|
|
24071
24169
|
} catch {
|
|
24072
24170
|
}
|
|
24073
24171
|
const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
|
|
@@ -24367,12 +24465,12 @@ function registerSessionsCommand(program2) {
|
|
|
24367
24465
|
|
|
24368
24466
|
// src/cli/commands/skill-pin.ts
|
|
24369
24467
|
import chalk25 from "chalk";
|
|
24370
|
-
import
|
|
24371
|
-
import
|
|
24372
|
-
import
|
|
24468
|
+
import fs47 from "fs";
|
|
24469
|
+
import os42 from "os";
|
|
24470
|
+
import path48 from "path";
|
|
24373
24471
|
function wipeSkillSessions() {
|
|
24374
24472
|
try {
|
|
24375
|
-
|
|
24473
|
+
fs47.rmSync(path48.join(os42.homedir(), ".node9", "skill-sessions"), {
|
|
24376
24474
|
recursive: true,
|
|
24377
24475
|
force: true
|
|
24378
24476
|
});
|
|
@@ -24454,15 +24552,15 @@ function registerSkillPinCommand(program2) {
|
|
|
24454
24552
|
}
|
|
24455
24553
|
|
|
24456
24554
|
// src/cli/commands/decisions.ts
|
|
24457
|
-
import
|
|
24458
|
-
import
|
|
24459
|
-
import
|
|
24555
|
+
import fs48 from "fs";
|
|
24556
|
+
import os43 from "os";
|
|
24557
|
+
import path49 from "path";
|
|
24460
24558
|
import chalk26 from "chalk";
|
|
24461
|
-
var DECISIONS_FILE2 =
|
|
24559
|
+
var DECISIONS_FILE2 = path49.join(os43.homedir(), ".node9", "decisions.json");
|
|
24462
24560
|
function readDecisions() {
|
|
24463
24561
|
try {
|
|
24464
|
-
if (!
|
|
24465
|
-
const raw =
|
|
24562
|
+
if (!fs48.existsSync(DECISIONS_FILE2)) return {};
|
|
24563
|
+
const raw = fs48.readFileSync(DECISIONS_FILE2, "utf-8");
|
|
24466
24564
|
const parsed = JSON.parse(raw);
|
|
24467
24565
|
const out = {};
|
|
24468
24566
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -24474,11 +24572,11 @@ function readDecisions() {
|
|
|
24474
24572
|
}
|
|
24475
24573
|
}
|
|
24476
24574
|
function writeDecisions(d) {
|
|
24477
|
-
const dir =
|
|
24478
|
-
if (!
|
|
24575
|
+
const dir = path49.dirname(DECISIONS_FILE2);
|
|
24576
|
+
if (!fs48.existsSync(dir)) fs48.mkdirSync(dir, { recursive: true });
|
|
24479
24577
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
24480
|
-
|
|
24481
|
-
|
|
24578
|
+
fs48.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
24579
|
+
fs48.renameSync(tmp, DECISIONS_FILE2);
|
|
24482
24580
|
}
|
|
24483
24581
|
function registerDecisionsCommand(program2) {
|
|
24484
24582
|
const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
|
|
@@ -24535,18 +24633,18 @@ Persistent decisions (${entries.length})
|
|
|
24535
24633
|
|
|
24536
24634
|
// src/cli/commands/dlp.ts
|
|
24537
24635
|
import chalk27 from "chalk";
|
|
24538
|
-
import
|
|
24539
|
-
import
|
|
24540
|
-
import
|
|
24541
|
-
var AUDIT_LOG =
|
|
24542
|
-
var RESOLVED_FILE =
|
|
24636
|
+
import fs49 from "fs";
|
|
24637
|
+
import path50 from "path";
|
|
24638
|
+
import os44 from "os";
|
|
24639
|
+
var AUDIT_LOG = path50.join(os44.homedir(), ".node9", "audit.log");
|
|
24640
|
+
var RESOLVED_FILE = path50.join(os44.homedir(), ".node9", "dlp-resolved.json");
|
|
24543
24641
|
var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
|
|
24544
24642
|
function stripAnsi(s) {
|
|
24545
24643
|
return s.replace(ANSI_RE, "");
|
|
24546
24644
|
}
|
|
24547
24645
|
function loadResolved() {
|
|
24548
24646
|
try {
|
|
24549
|
-
const raw = JSON.parse(
|
|
24647
|
+
const raw = JSON.parse(fs49.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
24550
24648
|
return new Set(raw);
|
|
24551
24649
|
} catch {
|
|
24552
24650
|
return /* @__PURE__ */ new Set();
|
|
@@ -24554,13 +24652,13 @@ function loadResolved() {
|
|
|
24554
24652
|
}
|
|
24555
24653
|
function saveResolved(resolved) {
|
|
24556
24654
|
try {
|
|
24557
|
-
|
|
24655
|
+
fs49.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
24558
24656
|
} catch {
|
|
24559
24657
|
}
|
|
24560
24658
|
}
|
|
24561
24659
|
function loadDlpFindings() {
|
|
24562
|
-
if (!
|
|
24563
|
-
return
|
|
24660
|
+
if (!fs49.existsSync(AUDIT_LOG)) return [];
|
|
24661
|
+
return fs49.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
24564
24662
|
if (!line.trim()) return [];
|
|
24565
24663
|
try {
|
|
24566
24664
|
const e = JSON.parse(line);
|
|
@@ -24659,14 +24757,14 @@ function registerDlpCommand(program2) {
|
|
|
24659
24757
|
// src/cli/commands/mask.ts
|
|
24660
24758
|
init_dlp();
|
|
24661
24759
|
import chalk28 from "chalk";
|
|
24662
|
-
import
|
|
24663
|
-
import
|
|
24664
|
-
import
|
|
24760
|
+
import fs50 from "fs";
|
|
24761
|
+
import path51 from "path";
|
|
24762
|
+
import os45 from "os";
|
|
24665
24763
|
function findJsonlFiles(dir) {
|
|
24666
24764
|
const results = [];
|
|
24667
|
-
if (!
|
|
24668
|
-
for (const entry of
|
|
24669
|
-
const full =
|
|
24765
|
+
if (!fs50.existsSync(dir)) return results;
|
|
24766
|
+
for (const entry of fs50.readdirSync(dir, { withFileTypes: true })) {
|
|
24767
|
+
const full = path51.join(dir, entry.name);
|
|
24670
24768
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
24671
24769
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
24672
24770
|
}
|
|
@@ -24709,7 +24807,7 @@ function redactJson(obj) {
|
|
|
24709
24807
|
function processFile(filePath, dryRun) {
|
|
24710
24808
|
let raw;
|
|
24711
24809
|
try {
|
|
24712
|
-
raw =
|
|
24810
|
+
raw = fs50.readFileSync(filePath, "utf-8");
|
|
24713
24811
|
} catch {
|
|
24714
24812
|
return { redactedLines: 0, patterns: [] };
|
|
24715
24813
|
}
|
|
@@ -24741,14 +24839,14 @@ function processFile(filePath, dryRun) {
|
|
|
24741
24839
|
}
|
|
24742
24840
|
}
|
|
24743
24841
|
if (!dryRun && redactedLines > 0) {
|
|
24744
|
-
|
|
24842
|
+
fs50.writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
24745
24843
|
}
|
|
24746
24844
|
return { redactedLines, patterns };
|
|
24747
24845
|
}
|
|
24748
24846
|
function processJsonFile(filePath, dryRun) {
|
|
24749
24847
|
let raw;
|
|
24750
24848
|
try {
|
|
24751
|
-
raw =
|
|
24849
|
+
raw = fs50.readFileSync(filePath, "utf-8");
|
|
24752
24850
|
} catch {
|
|
24753
24851
|
return { redactedLines: 0, patterns: [] };
|
|
24754
24852
|
}
|
|
@@ -24761,15 +24859,15 @@ function processJsonFile(filePath, dryRun) {
|
|
|
24761
24859
|
const { value, modified, found } = redactJson(parsed);
|
|
24762
24860
|
if (!modified) return { redactedLines: 0, patterns: [] };
|
|
24763
24861
|
if (!dryRun) {
|
|
24764
|
-
|
|
24862
|
+
fs50.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
|
|
24765
24863
|
}
|
|
24766
24864
|
return { redactedLines: 1, patterns: found };
|
|
24767
24865
|
}
|
|
24768
24866
|
function findJsonFiles(dir) {
|
|
24769
24867
|
const results = [];
|
|
24770
|
-
if (!
|
|
24771
|
-
for (const entry of
|
|
24772
|
-
const full =
|
|
24868
|
+
if (!fs50.existsSync(dir)) return results;
|
|
24869
|
+
for (const entry of fs50.readdirSync(dir, { withFileTypes: true })) {
|
|
24870
|
+
const full = path51.join(dir, entry.name);
|
|
24773
24871
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
24774
24872
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
24775
24873
|
}
|
|
@@ -24778,9 +24876,9 @@ function findJsonFiles(dir) {
|
|
|
24778
24876
|
function registerMaskCommand(program2) {
|
|
24779
24877
|
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
24878
|
const dryRun = !!options.dryRun;
|
|
24781
|
-
const home =
|
|
24782
|
-
const claudeDir =
|
|
24783
|
-
const geminiDir =
|
|
24879
|
+
const home = os45.homedir();
|
|
24880
|
+
const claudeDir = path51.join(home, ".claude", "projects");
|
|
24881
|
+
const geminiDir = path51.join(home, ".gemini", "tmp");
|
|
24784
24882
|
const allFiles = [
|
|
24785
24883
|
...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
|
|
24786
24884
|
...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
|
|
@@ -24788,7 +24886,7 @@ function registerMaskCommand(program2) {
|
|
|
24788
24886
|
const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
24789
24887
|
const filtered = cutoff ? allFiles.filter((f) => {
|
|
24790
24888
|
try {
|
|
24791
|
-
return
|
|
24889
|
+
return fs50.statSync(f.path).mtime >= cutoff;
|
|
24792
24890
|
} catch {
|
|
24793
24891
|
return false;
|
|
24794
24892
|
}
|
|
@@ -24844,20 +24942,20 @@ function registerMaskCommand(program2) {
|
|
|
24844
24942
|
// src/cli.ts
|
|
24845
24943
|
init_blast();
|
|
24846
24944
|
var { version } = JSON.parse(
|
|
24847
|
-
|
|
24945
|
+
fs53.readFileSync(path54.join(__dirname, "../package.json"), "utf-8")
|
|
24848
24946
|
);
|
|
24849
24947
|
var program = new Command();
|
|
24850
24948
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
24851
24949
|
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
24950
|
const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
|
|
24853
|
-
const credPath =
|
|
24854
|
-
if (!
|
|
24855
|
-
|
|
24951
|
+
const credPath = path54.join(os48.homedir(), ".node9", "credentials.json");
|
|
24952
|
+
if (!fs53.existsSync(path54.dirname(credPath)))
|
|
24953
|
+
fs53.mkdirSync(path54.dirname(credPath), { recursive: true });
|
|
24856
24954
|
const profileName = options.profile || "default";
|
|
24857
24955
|
let existingCreds = {};
|
|
24858
24956
|
try {
|
|
24859
|
-
if (
|
|
24860
|
-
const raw = JSON.parse(
|
|
24957
|
+
if (fs53.existsSync(credPath)) {
|
|
24958
|
+
const raw = JSON.parse(fs53.readFileSync(credPath, "utf-8"));
|
|
24861
24959
|
if (raw.apiKey) {
|
|
24862
24960
|
existingCreds = {
|
|
24863
24961
|
default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
|
|
@@ -24869,14 +24967,14 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
24869
24967
|
} catch {
|
|
24870
24968
|
}
|
|
24871
24969
|
existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
|
|
24872
|
-
|
|
24970
|
+
fs53.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
|
|
24873
24971
|
let effectiveCloud = null;
|
|
24874
24972
|
if (profileName === "default") {
|
|
24875
|
-
const configPath =
|
|
24973
|
+
const configPath = path54.join(os48.homedir(), ".node9", "config.json");
|
|
24876
24974
|
let config = {};
|
|
24877
24975
|
try {
|
|
24878
|
-
if (
|
|
24879
|
-
config = JSON.parse(
|
|
24976
|
+
if (fs53.existsSync(configPath))
|
|
24977
|
+
config = JSON.parse(fs53.readFileSync(configPath, "utf-8"));
|
|
24880
24978
|
} catch {
|
|
24881
24979
|
}
|
|
24882
24980
|
if (!config.settings || typeof config.settings !== "object") config.settings = {};
|
|
@@ -24891,9 +24989,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
24891
24989
|
approvers.cloud = false;
|
|
24892
24990
|
}
|
|
24893
24991
|
s.approvers = approvers;
|
|
24894
|
-
if (!
|
|
24895
|
-
|
|
24896
|
-
|
|
24992
|
+
if (!fs53.existsSync(path54.dirname(configPath)))
|
|
24993
|
+
fs53.mkdirSync(path54.dirname(configPath), { recursive: true });
|
|
24994
|
+
fs53.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
24897
24995
|
effectiveCloud = approvers.cloud === true;
|
|
24898
24996
|
}
|
|
24899
24997
|
if (options.profile && profileName !== "default") {
|
|
@@ -25052,15 +25150,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
25052
25150
|
}
|
|
25053
25151
|
}
|
|
25054
25152
|
if (options.purge) {
|
|
25055
|
-
const node9Dir =
|
|
25056
|
-
if (
|
|
25153
|
+
const node9Dir = path54.join(os48.homedir(), ".node9");
|
|
25154
|
+
if (fs53.existsSync(node9Dir)) {
|
|
25057
25155
|
const confirmed = await confirm2({
|
|
25058
25156
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
25059
25157
|
default: false
|
|
25060
25158
|
});
|
|
25061
25159
|
if (confirmed) {
|
|
25062
|
-
|
|
25063
|
-
if (
|
|
25160
|
+
fs53.rmSync(node9Dir, { recursive: true });
|
|
25161
|
+
if (fs53.existsSync(node9Dir)) {
|
|
25064
25162
|
console.error(
|
|
25065
25163
|
chalk30.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
25066
25164
|
);
|
|
@@ -25175,7 +25273,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
|
|
|
25175
25273
|
});
|
|
25176
25274
|
program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
|
|
25177
25275
|
try {
|
|
25178
|
-
const dashboardPath =
|
|
25276
|
+
const dashboardPath = path54.join(__dirname, "dashboard.mjs");
|
|
25179
25277
|
const dynamicImport = new Function("id", "return import(id)");
|
|
25180
25278
|
const mod = await dynamicImport(`file://${dashboardPath}`);
|
|
25181
25279
|
await mod.startMonitor();
|
|
@@ -25213,14 +25311,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
|
|
|
25213
25311
|
Run "node9 addto claude" to register it as the statusLine.`
|
|
25214
25312
|
).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
25313
|
if (subcommand === "debug") {
|
|
25216
|
-
const flagFile =
|
|
25314
|
+
const flagFile = path54.join(os48.homedir(), ".node9", "hud-debug");
|
|
25217
25315
|
if (state === "on") {
|
|
25218
|
-
|
|
25219
|
-
|
|
25316
|
+
fs53.mkdirSync(path54.dirname(flagFile), { recursive: true });
|
|
25317
|
+
fs53.writeFileSync(flagFile, "");
|
|
25220
25318
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
25221
25319
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
25222
25320
|
} else if (state === "off") {
|
|
25223
|
-
if (
|
|
25321
|
+
if (fs53.existsSync(flagFile)) fs53.unlinkSync(flagFile);
|
|
25224
25322
|
console.log("HUD debug logging disabled.");
|
|
25225
25323
|
} else {
|
|
25226
25324
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -25337,9 +25435,9 @@ if (process.argv[2] !== "daemon") {
|
|
|
25337
25435
|
const isCheckHook = process.argv[2] === "check";
|
|
25338
25436
|
if (isCheckHook) {
|
|
25339
25437
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
25340
|
-
const logPath =
|
|
25438
|
+
const logPath = path54.join(os48.homedir(), ".node9", "hook-debug.log");
|
|
25341
25439
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
25342
|
-
|
|
25440
|
+
fs53.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
25343
25441
|
`);
|
|
25344
25442
|
}
|
|
25345
25443
|
process.exit(0);
|