@node9/proxy 1.34.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 +596 -355
- package/dist/cli.mjs +592 -350
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -206,8 +206,8 @@ function sanitizeConfig(raw) {
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
const lines = result.error.issues.map((issue) => {
|
|
209
|
-
const
|
|
210
|
-
return ` \u2022 ${
|
|
209
|
+
const path55 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
210
|
+
return ` \u2022 ${path55}: ${issue.message}`;
|
|
211
211
|
});
|
|
212
212
|
return {
|
|
213
213
|
sanitized,
|
|
@@ -1256,9 +1256,9 @@ function matchesPattern(text, patterns) {
|
|
|
1256
1256
|
const withoutDotSlash = text.replace(/^\.\//, "");
|
|
1257
1257
|
return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
|
|
1258
1258
|
}
|
|
1259
|
-
function getNestedValue(obj,
|
|
1259
|
+
function getNestedValue(obj, path55) {
|
|
1260
1260
|
if (!obj || typeof obj !== "object") return null;
|
|
1261
|
-
const segments =
|
|
1261
|
+
const segments = path55.split(".");
|
|
1262
1262
|
for (const seg of segments) {
|
|
1263
1263
|
if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
|
|
1264
1264
|
}
|
|
@@ -5889,6 +5889,57 @@ function validateApiUrl(raw) {
|
|
|
5889
5889
|
}
|
|
5890
5890
|
return null;
|
|
5891
5891
|
}
|
|
5892
|
+
function auditLocalAllow(toolName, args, checkedBy, creds, meta, dlpInfo, containsSensitiveArgs = false, riskMetadata) {
|
|
5893
|
+
const validated = validateApiUrl(creds.apiUrl);
|
|
5894
|
+
if (!validated) {
|
|
5895
|
+
try {
|
|
5896
|
+
import_fs10.default.appendFileSync(
|
|
5897
|
+
HOOK_DEBUG_LOG,
|
|
5898
|
+
`[audit] refused to send: invalid apiUrl scheme/host (got "${String(creds.apiUrl).slice(0, 200)}")
|
|
5899
|
+
`
|
|
5900
|
+
);
|
|
5901
|
+
} catch {
|
|
5902
|
+
}
|
|
5903
|
+
return Promise.resolve();
|
|
5904
|
+
}
|
|
5905
|
+
const safeArgs = containsSensitiveArgs ? { tool: toolName, redacted: true } : args;
|
|
5906
|
+
const dlpSample = dlpInfo && typeof dlpInfo.redactedSample === "string" ? dlpInfo.redactedSample.slice(0, DLP_SAMPLE_MAX_LEN) : void 0;
|
|
5907
|
+
const dlpPattern = dlpInfo && typeof dlpInfo.pattern === "string" ? dlpInfo.pattern.slice(0, DLP_PATTERN_MAX_LEN) : void 0;
|
|
5908
|
+
const safeCheckedBy = KNOWN_CHECKED_BY.has(checkedBy) ? checkedBy : "unknown";
|
|
5909
|
+
const cleanedRiskMetadata = riskMetadata ? Object.fromEntries(
|
|
5910
|
+
Object.entries(riskMetadata).filter(
|
|
5911
|
+
([, v]) => typeof v === "string" && v.length > 0 || typeof v === "number" && Number.isFinite(v)
|
|
5912
|
+
)
|
|
5913
|
+
) : void 0;
|
|
5914
|
+
const hasRiskMetadata = cleanedRiskMetadata && Object.keys(cleanedRiskMetadata).length > 0;
|
|
5915
|
+
return fetch(`${validated.toString().replace(/\/$/, "")}/audit`, {
|
|
5916
|
+
method: "POST",
|
|
5917
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${creds.apiKey}` },
|
|
5918
|
+
body: JSON.stringify({
|
|
5919
|
+
toolName,
|
|
5920
|
+
args: safeArgs,
|
|
5921
|
+
checkedBy: safeCheckedBy,
|
|
5922
|
+
...dlpInfo && { dlpPattern, dlpSample },
|
|
5923
|
+
...hasRiskMetadata && { riskMetadata: cleanedRiskMetadata },
|
|
5924
|
+
// session_id (Claude Code + Gemini CLI) groups all audit rows from one
|
|
5925
|
+
// agent run; transcript_path is the authoritative pointer to the
|
|
5926
|
+
// session log (survives Gemini resume drift). Both optional —
|
|
5927
|
+
// unsupported agents (MCP-mediated) leave them undefined.
|
|
5928
|
+
...meta?.sessionId && { runId: meta.sessionId },
|
|
5929
|
+
...meta?.transcriptPath && { transcriptPath: meta.transcriptPath },
|
|
5930
|
+
context: {
|
|
5931
|
+
agent: meta?.agent,
|
|
5932
|
+
mcpServer: meta?.mcpServer,
|
|
5933
|
+
hostname: import_os9.default.hostname(),
|
|
5934
|
+
cwd: process.cwd(),
|
|
5935
|
+
platform: import_os9.default.platform()
|
|
5936
|
+
}
|
|
5937
|
+
}),
|
|
5938
|
+
signal: AbortSignal.timeout(5e3)
|
|
5939
|
+
}).then(() => {
|
|
5940
|
+
}).catch(() => {
|
|
5941
|
+
});
|
|
5942
|
+
}
|
|
5892
5943
|
async function initNode9SaaS(toolName, args, creds, meta, riskMetadata, agentPolicy, forceReview) {
|
|
5893
5944
|
const controller = new AbortController();
|
|
5894
5945
|
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
@@ -6012,7 +6063,7 @@ async function resolveNode9SaaS(requestId, creds, approved, decidedBy) {
|
|
|
6012
6063
|
);
|
|
6013
6064
|
}
|
|
6014
6065
|
}
|
|
6015
|
-
var import_fs10, import_os9, import_path12;
|
|
6066
|
+
var import_fs10, import_os9, import_path12, DLP_SAMPLE_MAX_LEN, DLP_PATTERN_MAX_LEN, KNOWN_CHECKED_BY;
|
|
6016
6067
|
var init_cloud = __esm({
|
|
6017
6068
|
"src/auth/cloud.ts"() {
|
|
6018
6069
|
"use strict";
|
|
@@ -6020,6 +6071,39 @@ var init_cloud = __esm({
|
|
|
6020
6071
|
import_os9 = __toESM(require("os"));
|
|
6021
6072
|
import_path12 = __toESM(require("path"));
|
|
6022
6073
|
init_audit();
|
|
6074
|
+
DLP_SAMPLE_MAX_LEN = 200;
|
|
6075
|
+
DLP_PATTERN_MAX_LEN = 100;
|
|
6076
|
+
KNOWN_CHECKED_BY = /* @__PURE__ */ new Set([
|
|
6077
|
+
"dlp-block",
|
|
6078
|
+
"observe-mode-dlp-would-block",
|
|
6079
|
+
"dlp-review-flagged",
|
|
6080
|
+
"loop-detected",
|
|
6081
|
+
"audit-mode",
|
|
6082
|
+
"local-policy",
|
|
6083
|
+
"smart-rule-block",
|
|
6084
|
+
// Smart-rule block was downgraded to review because the daemon was
|
|
6085
|
+
// running and we're not in CI. The block attempt is still recorded;
|
|
6086
|
+
// the user got a popup. Distinct from 'smart-rule-block' so the
|
|
6087
|
+
// dashboard can show "block rule overridden" separately from a hard
|
|
6088
|
+
// block that fired with no human in the loop.
|
|
6089
|
+
"smart-rule-block-override",
|
|
6090
|
+
"persistent",
|
|
6091
|
+
"trust",
|
|
6092
|
+
"observe-mode",
|
|
6093
|
+
"observe-mode-would-block",
|
|
6094
|
+
// MCP supply-chain: the gateway pinned a server's tool definitions and they
|
|
6095
|
+
// changed since (possible tool poisoning / rug pull). Emitted as a synthetic
|
|
6096
|
+
// audit row so the SaaS surfaces it as a blocked event. The firewall maps
|
|
6097
|
+
// this checkedBy to AUTO_BLOCKED. See doc/roadmap/active/saas-value-first.md
|
|
6098
|
+
// (workstream B-Tier2).
|
|
6099
|
+
"mcp-pin-mismatch",
|
|
6100
|
+
// MCP visibility (B-Tier2, informational — NOT blocks): the gateway
|
|
6101
|
+
// discovered a server's tool inventory (mcp-discovered) or saw an oversized
|
|
6102
|
+
// tool response that bloats the context window (mcp-large-response). Stored
|
|
6103
|
+
// AUTO_ALLOWED; carries mcpToolCount / mcpResponseBytes in riskMetadata.
|
|
6104
|
+
"mcp-discovered",
|
|
6105
|
+
"mcp-large-response"
|
|
6106
|
+
]);
|
|
6023
6107
|
}
|
|
6024
6108
|
});
|
|
6025
6109
|
|
|
@@ -16867,20 +16951,20 @@ function getModelContextLimit(model) {
|
|
|
16867
16951
|
return 2e5;
|
|
16868
16952
|
}
|
|
16869
16953
|
function readSessionUsage() {
|
|
16870
|
-
const projectsDir =
|
|
16871
|
-
if (!
|
|
16954
|
+
const projectsDir = import_path52.default.join(import_os46.default.homedir(), ".claude", "projects");
|
|
16955
|
+
if (!import_fs51.default.existsSync(projectsDir)) return null;
|
|
16872
16956
|
let latestFile = null;
|
|
16873
16957
|
let latestMtime = 0;
|
|
16874
16958
|
try {
|
|
16875
|
-
for (const dir of
|
|
16876
|
-
const dirPath =
|
|
16959
|
+
for (const dir of import_fs51.default.readdirSync(projectsDir)) {
|
|
16960
|
+
const dirPath = import_path52.default.join(projectsDir, dir);
|
|
16877
16961
|
try {
|
|
16878
|
-
if (!
|
|
16879
|
-
for (const file of
|
|
16962
|
+
if (!import_fs51.default.statSync(dirPath).isDirectory()) continue;
|
|
16963
|
+
for (const file of import_fs51.default.readdirSync(dirPath)) {
|
|
16880
16964
|
if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
|
|
16881
|
-
const filePath =
|
|
16965
|
+
const filePath = import_path52.default.join(dirPath, file);
|
|
16882
16966
|
try {
|
|
16883
|
-
const mtime =
|
|
16967
|
+
const mtime = import_fs51.default.statSync(filePath).mtimeMs;
|
|
16884
16968
|
if (mtime > latestMtime) {
|
|
16885
16969
|
latestMtime = mtime;
|
|
16886
16970
|
latestFile = filePath;
|
|
@@ -16895,7 +16979,7 @@ function readSessionUsage() {
|
|
|
16895
16979
|
}
|
|
16896
16980
|
if (!latestFile) return null;
|
|
16897
16981
|
try {
|
|
16898
|
-
const lines =
|
|
16982
|
+
const lines = import_fs51.default.readFileSync(latestFile, "utf-8").split("\n");
|
|
16899
16983
|
let lastModel = "";
|
|
16900
16984
|
let lastInput = 0;
|
|
16901
16985
|
let lastOutput = 0;
|
|
@@ -16956,7 +17040,7 @@ function formatBase(activity) {
|
|
|
16956
17040
|
const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
|
|
16957
17041
|
const icon = getIcon(activity.tool);
|
|
16958
17042
|
const toolName = activity.tool.slice(0, 16).padEnd(16);
|
|
16959
|
-
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(
|
|
17043
|
+
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os46.default.homedir(), "~");
|
|
16960
17044
|
const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
|
|
16961
17045
|
return `${import_chalk29.default.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${import_chalk29.default.white.bold(toolName)} ${import_chalk29.default.dim(argsPreview)}`;
|
|
16962
17046
|
}
|
|
@@ -16995,9 +17079,9 @@ function renderPending(activity) {
|
|
|
16995
17079
|
}
|
|
16996
17080
|
async function ensureDaemon() {
|
|
16997
17081
|
let pidPort = null;
|
|
16998
|
-
if (
|
|
17082
|
+
if (import_fs51.default.existsSync(PID_FILE)) {
|
|
16999
17083
|
try {
|
|
17000
|
-
const { port } = JSON.parse(
|
|
17084
|
+
const { port } = JSON.parse(import_fs51.default.readFileSync(PID_FILE, "utf-8"));
|
|
17001
17085
|
pidPort = port;
|
|
17002
17086
|
} catch {
|
|
17003
17087
|
console.error(import_chalk29.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
@@ -17153,9 +17237,9 @@ function buildRecoveryCardLines(req) {
|
|
|
17153
17237
|
];
|
|
17154
17238
|
}
|
|
17155
17239
|
function readApproversFromDisk() {
|
|
17156
|
-
const configPath =
|
|
17240
|
+
const configPath = import_path52.default.join(import_os46.default.homedir(), ".node9", "config.json");
|
|
17157
17241
|
try {
|
|
17158
|
-
const raw = JSON.parse(
|
|
17242
|
+
const raw = JSON.parse(import_fs51.default.readFileSync(configPath, "utf-8"));
|
|
17159
17243
|
const settings = raw.settings ?? {};
|
|
17160
17244
|
return settings.approvers ?? {};
|
|
17161
17245
|
} catch {
|
|
@@ -17171,15 +17255,15 @@ function approverStatusLine() {
|
|
|
17171
17255
|
return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
|
|
17172
17256
|
}
|
|
17173
17257
|
function toggleApprover(channel) {
|
|
17174
|
-
const configPath =
|
|
17258
|
+
const configPath = import_path52.default.join(import_os46.default.homedir(), ".node9", "config.json");
|
|
17175
17259
|
try {
|
|
17176
|
-
const raw = JSON.parse(
|
|
17260
|
+
const raw = JSON.parse(import_fs51.default.readFileSync(configPath, "utf-8"));
|
|
17177
17261
|
const settings = raw.settings ?? {};
|
|
17178
17262
|
const approvers = settings.approvers ?? {};
|
|
17179
17263
|
approvers[channel] = approvers[channel] === false;
|
|
17180
17264
|
settings.approvers = approvers;
|
|
17181
17265
|
raw.settings = settings;
|
|
17182
|
-
|
|
17266
|
+
import_fs51.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
|
|
17183
17267
|
} catch (err2) {
|
|
17184
17268
|
process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
|
|
17185
17269
|
`);
|
|
@@ -17351,8 +17435,8 @@ async function startTail(options = {}) {
|
|
|
17351
17435
|
}
|
|
17352
17436
|
postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
|
|
17353
17437
|
try {
|
|
17354
|
-
|
|
17355
|
-
|
|
17438
|
+
import_fs51.default.appendFileSync(
|
|
17439
|
+
import_path52.default.join(import_os46.default.homedir(), ".node9", "hook-debug.log"),
|
|
17356
17440
|
`[tail] POST /decision failed: ${String(err2)}
|
|
17357
17441
|
`
|
|
17358
17442
|
);
|
|
@@ -17416,9 +17500,9 @@ async function startTail(options = {}) {
|
|
|
17416
17500
|
};
|
|
17417
17501
|
process.stdin.on("keypress", onKeypress);
|
|
17418
17502
|
}
|
|
17419
|
-
const auditLog =
|
|
17503
|
+
const auditLog = import_path52.default.join(import_os46.default.homedir(), ".node9", "audit.log");
|
|
17420
17504
|
try {
|
|
17421
|
-
const unackedDlp =
|
|
17505
|
+
const unackedDlp = import_fs51.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
17422
17506
|
if (unackedDlp > 0) {
|
|
17423
17507
|
console.log("");
|
|
17424
17508
|
console.log(
|
|
@@ -17458,7 +17542,7 @@ async function startTail(options = {}) {
|
|
|
17458
17542
|
if (stallWarned) return;
|
|
17459
17543
|
if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
|
|
17460
17544
|
try {
|
|
17461
|
-
const auditMtime =
|
|
17545
|
+
const auditMtime = import_fs51.default.statSync(auditLog).mtimeMs;
|
|
17462
17546
|
if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
|
|
17463
17547
|
console.log("");
|
|
17464
17548
|
console.log(
|
|
@@ -17643,20 +17727,20 @@ async function startTail(options = {}) {
|
|
|
17643
17727
|
process.exit(1);
|
|
17644
17728
|
});
|
|
17645
17729
|
}
|
|
17646
|
-
var import_http2, import_chalk29,
|
|
17730
|
+
var import_http2, import_chalk29, import_fs51, import_os46, import_path52, import_readline6, import_child_process12, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
|
|
17647
17731
|
var init_tail = __esm({
|
|
17648
17732
|
"src/tui/tail.ts"() {
|
|
17649
17733
|
"use strict";
|
|
17650
17734
|
import_http2 = __toESM(require("http"));
|
|
17651
17735
|
import_chalk29 = __toESM(require("chalk"));
|
|
17652
|
-
|
|
17653
|
-
|
|
17654
|
-
|
|
17736
|
+
import_fs51 = __toESM(require("fs"));
|
|
17737
|
+
import_os46 = __toESM(require("os"));
|
|
17738
|
+
import_path52 = __toESM(require("path"));
|
|
17655
17739
|
import_readline6 = __toESM(require("readline"));
|
|
17656
17740
|
import_child_process12 = require("child_process");
|
|
17657
17741
|
init_daemon2();
|
|
17658
17742
|
init_daemon();
|
|
17659
|
-
PID_FILE =
|
|
17743
|
+
PID_FILE = import_path52.default.join(import_os46.default.homedir(), ".node9", "daemon.pid");
|
|
17660
17744
|
ICONS = {
|
|
17661
17745
|
bash: "\u{1F4BB}",
|
|
17662
17746
|
shell: "\u{1F4BB}",
|
|
@@ -17778,9 +17862,9 @@ function formatTimeLeft(resetsAt) {
|
|
|
17778
17862
|
return ` (${m}m left)`;
|
|
17779
17863
|
}
|
|
17780
17864
|
function safeReadJson(filePath) {
|
|
17781
|
-
if (!
|
|
17865
|
+
if (!import_fs52.default.existsSync(filePath)) return null;
|
|
17782
17866
|
try {
|
|
17783
|
-
return JSON.parse(
|
|
17867
|
+
return JSON.parse(import_fs52.default.readFileSync(filePath, "utf-8"));
|
|
17784
17868
|
} catch {
|
|
17785
17869
|
return null;
|
|
17786
17870
|
}
|
|
@@ -17801,12 +17885,12 @@ function countHooksInFile(filePath) {
|
|
|
17801
17885
|
return Object.keys(cfg.hooks).length;
|
|
17802
17886
|
}
|
|
17803
17887
|
function countRulesInDir(rulesDir) {
|
|
17804
|
-
if (!
|
|
17888
|
+
if (!import_fs52.default.existsSync(rulesDir)) return 0;
|
|
17805
17889
|
let count = 0;
|
|
17806
17890
|
try {
|
|
17807
|
-
for (const entry of
|
|
17891
|
+
for (const entry of import_fs52.default.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
17808
17892
|
if (entry.isDirectory()) {
|
|
17809
|
-
count += countRulesInDir(
|
|
17893
|
+
count += countRulesInDir(import_path53.default.join(rulesDir, entry.name));
|
|
17810
17894
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
17811
17895
|
count++;
|
|
17812
17896
|
}
|
|
@@ -17817,46 +17901,46 @@ function countRulesInDir(rulesDir) {
|
|
|
17817
17901
|
}
|
|
17818
17902
|
function isSamePath(a, b) {
|
|
17819
17903
|
try {
|
|
17820
|
-
return
|
|
17904
|
+
return import_path53.default.resolve(a) === import_path53.default.resolve(b);
|
|
17821
17905
|
} catch {
|
|
17822
17906
|
return false;
|
|
17823
17907
|
}
|
|
17824
17908
|
}
|
|
17825
17909
|
function countConfigs(cwd) {
|
|
17826
|
-
const homeDir2 =
|
|
17827
|
-
const claudeDir =
|
|
17910
|
+
const homeDir2 = import_os47.default.homedir();
|
|
17911
|
+
const claudeDir = import_path53.default.join(homeDir2, ".claude");
|
|
17828
17912
|
let claudeMdCount = 0;
|
|
17829
17913
|
let rulesCount = 0;
|
|
17830
17914
|
let hooksCount = 0;
|
|
17831
17915
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
17832
17916
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
17833
|
-
if (
|
|
17834
|
-
rulesCount += countRulesInDir(
|
|
17835
|
-
const userSettings =
|
|
17917
|
+
if (import_fs52.default.existsSync(import_path53.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
17918
|
+
rulesCount += countRulesInDir(import_path53.default.join(claudeDir, "rules"));
|
|
17919
|
+
const userSettings = import_path53.default.join(claudeDir, "settings.json");
|
|
17836
17920
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
17837
17921
|
hooksCount += countHooksInFile(userSettings);
|
|
17838
|
-
const userClaudeJson =
|
|
17922
|
+
const userClaudeJson = import_path53.default.join(homeDir2, ".claude.json");
|
|
17839
17923
|
for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
|
|
17840
17924
|
for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
|
|
17841
17925
|
userMcpServers.delete(name);
|
|
17842
17926
|
}
|
|
17843
17927
|
if (cwd) {
|
|
17844
|
-
if (
|
|
17845
|
-
if (
|
|
17846
|
-
const projectClaudeDir =
|
|
17928
|
+
if (import_fs52.default.existsSync(import_path53.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
17929
|
+
if (import_fs52.default.existsSync(import_path53.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
17930
|
+
const projectClaudeDir = import_path53.default.join(cwd, ".claude");
|
|
17847
17931
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
17848
17932
|
if (!overlapsUserScope) {
|
|
17849
|
-
if (
|
|
17850
|
-
rulesCount += countRulesInDir(
|
|
17851
|
-
const projSettings =
|
|
17933
|
+
if (import_fs52.default.existsSync(import_path53.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
17934
|
+
rulesCount += countRulesInDir(import_path53.default.join(projectClaudeDir, "rules"));
|
|
17935
|
+
const projSettings = import_path53.default.join(projectClaudeDir, "settings.json");
|
|
17852
17936
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
17853
17937
|
hooksCount += countHooksInFile(projSettings);
|
|
17854
17938
|
}
|
|
17855
|
-
if (
|
|
17856
|
-
const localSettings =
|
|
17939
|
+
if (import_fs52.default.existsSync(import_path53.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
17940
|
+
const localSettings = import_path53.default.join(projectClaudeDir, "settings.local.json");
|
|
17857
17941
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
17858
17942
|
hooksCount += countHooksInFile(localSettings);
|
|
17859
|
-
const mcpJsonServers = getMcpServerNames(
|
|
17943
|
+
const mcpJsonServers = getMcpServerNames(import_path53.default.join(cwd, ".mcp.json"));
|
|
17860
17944
|
const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
|
|
17861
17945
|
for (const name of disabledMcpJson) mcpJsonServers.delete(name);
|
|
17862
17946
|
for (const name of mcpJsonServers) projectMcpServers.add(name);
|
|
@@ -17889,12 +17973,12 @@ function readActiveShieldsHud() {
|
|
|
17889
17973
|
return shieldsCache.value;
|
|
17890
17974
|
}
|
|
17891
17975
|
try {
|
|
17892
|
-
const shieldsPath =
|
|
17893
|
-
if (!
|
|
17976
|
+
const shieldsPath = import_path53.default.join(import_os47.default.homedir(), ".node9", "shields.json");
|
|
17977
|
+
if (!import_fs52.default.existsSync(shieldsPath)) {
|
|
17894
17978
|
shieldsCache = { value: [], ts: now };
|
|
17895
17979
|
return [];
|
|
17896
17980
|
}
|
|
17897
|
-
const parsed = JSON.parse(
|
|
17981
|
+
const parsed = JSON.parse(import_fs52.default.readFileSync(shieldsPath, "utf-8"));
|
|
17898
17982
|
if (!Array.isArray(parsed.active)) {
|
|
17899
17983
|
shieldsCache = { value: [], ts: now };
|
|
17900
17984
|
return [];
|
|
@@ -17996,17 +18080,17 @@ function renderContextLine(stdin) {
|
|
|
17996
18080
|
async function main() {
|
|
17997
18081
|
try {
|
|
17998
18082
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
17999
|
-
if (
|
|
18083
|
+
if (import_fs52.default.existsSync(import_path53.default.join(import_os47.default.homedir(), ".node9", "hud-debug"))) {
|
|
18000
18084
|
try {
|
|
18001
|
-
const logPath =
|
|
18085
|
+
const logPath = import_path53.default.join(import_os47.default.homedir(), ".node9", "hud-debug.log");
|
|
18002
18086
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
18003
18087
|
let size = 0;
|
|
18004
18088
|
try {
|
|
18005
|
-
size =
|
|
18089
|
+
size = import_fs52.default.statSync(logPath).size;
|
|
18006
18090
|
} catch {
|
|
18007
18091
|
}
|
|
18008
18092
|
if (size < MAX_LOG_SIZE) {
|
|
18009
|
-
|
|
18093
|
+
import_fs52.default.appendFileSync(
|
|
18010
18094
|
logPath,
|
|
18011
18095
|
JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
|
|
18012
18096
|
);
|
|
@@ -18027,11 +18111,11 @@ async function main() {
|
|
|
18027
18111
|
try {
|
|
18028
18112
|
const cwd = stdin.cwd ?? process.cwd();
|
|
18029
18113
|
for (const configPath of [
|
|
18030
|
-
|
|
18031
|
-
|
|
18114
|
+
import_path53.default.join(cwd, "node9.config.json"),
|
|
18115
|
+
import_path53.default.join(import_os47.default.homedir(), ".node9", "config.json")
|
|
18032
18116
|
]) {
|
|
18033
|
-
if (!
|
|
18034
|
-
const cfg = JSON.parse(
|
|
18117
|
+
if (!import_fs52.default.existsSync(configPath)) continue;
|
|
18118
|
+
const cfg = JSON.parse(import_fs52.default.readFileSync(configPath, "utf-8"));
|
|
18035
18119
|
const hud = cfg.settings?.hud;
|
|
18036
18120
|
if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
|
|
18037
18121
|
}
|
|
@@ -18049,13 +18133,13 @@ async function main() {
|
|
|
18049
18133
|
renderOffline();
|
|
18050
18134
|
}
|
|
18051
18135
|
}
|
|
18052
|
-
var
|
|
18136
|
+
var import_fs52, import_path53, import_os47, import_http3, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
|
|
18053
18137
|
var init_hud = __esm({
|
|
18054
18138
|
"src/cli/hud.ts"() {
|
|
18055
18139
|
"use strict";
|
|
18056
|
-
|
|
18057
|
-
|
|
18058
|
-
|
|
18140
|
+
import_fs52 = __toESM(require("fs"));
|
|
18141
|
+
import_path53 = __toESM(require("path"));
|
|
18142
|
+
import_os47 = __toESM(require("os"));
|
|
18059
18143
|
import_http3 = __toESM(require("http"));
|
|
18060
18144
|
init_daemon();
|
|
18061
18145
|
RESET3 = "\x1B[0m";
|
|
@@ -18082,9 +18166,9 @@ init_core();
|
|
|
18082
18166
|
init_setup();
|
|
18083
18167
|
init_daemon2();
|
|
18084
18168
|
var import_chalk30 = __toESM(require("chalk"));
|
|
18085
|
-
var
|
|
18086
|
-
var
|
|
18087
|
-
var
|
|
18169
|
+
var import_fs53 = __toESM(require("fs"));
|
|
18170
|
+
var import_path54 = __toESM(require("path"));
|
|
18171
|
+
var import_os48 = __toESM(require("os"));
|
|
18088
18172
|
var import_prompts2 = require("@inquirer/prompts");
|
|
18089
18173
|
|
|
18090
18174
|
// src/utils/duration.ts
|
|
@@ -19872,15 +19956,151 @@ function registerConfigShowCommand(program2) {
|
|
|
19872
19956
|
|
|
19873
19957
|
// src/cli/commands/doctor.ts
|
|
19874
19958
|
var import_chalk11 = __toESM(require("chalk"));
|
|
19875
|
-
var
|
|
19876
|
-
var
|
|
19877
|
-
var
|
|
19959
|
+
var import_fs39 = __toESM(require("fs"));
|
|
19960
|
+
var import_path40 = __toESM(require("path"));
|
|
19961
|
+
var import_os35 = __toESM(require("os"));
|
|
19878
19962
|
var import_child_process8 = require("child_process");
|
|
19879
19963
|
init_daemon();
|
|
19880
19964
|
init_config();
|
|
19965
|
+
|
|
19966
|
+
// src/agent-wiring.ts
|
|
19967
|
+
var import_fs38 = __toESM(require("fs"));
|
|
19968
|
+
var import_path39 = __toESM(require("path"));
|
|
19969
|
+
var import_os34 = __toESM(require("os"));
|
|
19970
|
+
var yaml2 = __toESM(require("yaml"));
|
|
19971
|
+
init_setup();
|
|
19972
|
+
function readJson2(filePath) {
|
|
19973
|
+
if (!import_fs38.default.existsSync(filePath)) return null;
|
|
19974
|
+
try {
|
|
19975
|
+
return JSON.parse(import_fs38.default.readFileSync(filePath, "utf-8"));
|
|
19976
|
+
} catch {
|
|
19977
|
+
return "invalid";
|
|
19978
|
+
}
|
|
19979
|
+
}
|
|
19980
|
+
function matchersHaveNode9Hook(matchers) {
|
|
19981
|
+
return (matchers ?? []).some((m) => (m.hooks ?? []).some((h) => isNode9Hook(h.command)));
|
|
19982
|
+
}
|
|
19983
|
+
function flatHaveNode9Hook(entries) {
|
|
19984
|
+
return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
|
|
19985
|
+
}
|
|
19986
|
+
function jsonWire(filePath, read) {
|
|
19987
|
+
const parsed = readJson2(filePath);
|
|
19988
|
+
if (parsed === null) return "absent";
|
|
19989
|
+
if (parsed === "invalid") return "invalid";
|
|
19990
|
+
return read(parsed) ? "wired" : "unwired";
|
|
19991
|
+
}
|
|
19992
|
+
function hermesWire(home) {
|
|
19993
|
+
const configPath = hermesConfigPath(home);
|
|
19994
|
+
if (!import_fs38.default.existsSync(configPath)) return "absent";
|
|
19995
|
+
let raw;
|
|
19996
|
+
try {
|
|
19997
|
+
raw = import_fs38.default.readFileSync(configPath, "utf-8");
|
|
19998
|
+
} catch {
|
|
19999
|
+
return "absent";
|
|
20000
|
+
}
|
|
20001
|
+
try {
|
|
20002
|
+
const cfg = yaml2.parse(raw);
|
|
20003
|
+
const pre = (cfg?.hooks?.pre_tool_call ?? []).some(
|
|
20004
|
+
(e) => typeof e?.command === "string" && isNode9Hook(e.command)
|
|
20005
|
+
);
|
|
20006
|
+
return pre ? "wired" : "unwired";
|
|
20007
|
+
} catch {
|
|
20008
|
+
return "invalid";
|
|
20009
|
+
}
|
|
20010
|
+
}
|
|
20011
|
+
var AGENT_SPECS = [
|
|
20012
|
+
{
|
|
20013
|
+
id: "claude",
|
|
20014
|
+
label: "Claude Code",
|
|
20015
|
+
hookLabel: "PreToolUse hook",
|
|
20016
|
+
setupCommand: "node9 setup claude",
|
|
20017
|
+
settingsPath: (h) => import_path39.default.join(h, ".claude", "settings.json"),
|
|
20018
|
+
wireState: (h) => jsonWire(
|
|
20019
|
+
import_path39.default.join(h, ".claude", "settings.json"),
|
|
20020
|
+
(p) => matchersHaveNode9Hook(p.hooks?.PreToolUse)
|
|
20021
|
+
)
|
|
20022
|
+
},
|
|
20023
|
+
{
|
|
20024
|
+
id: "gemini",
|
|
20025
|
+
label: "Gemini CLI",
|
|
20026
|
+
hookLabel: "BeforeTool hook",
|
|
20027
|
+
setupCommand: "node9 setup gemini",
|
|
20028
|
+
settingsPath: (h) => import_path39.default.join(h, ".gemini", "settings.json"),
|
|
20029
|
+
wireState: (h) => jsonWire(
|
|
20030
|
+
import_path39.default.join(h, ".gemini", "settings.json"),
|
|
20031
|
+
(p) => matchersHaveNode9Hook(p.hooks?.BeforeTool)
|
|
20032
|
+
)
|
|
20033
|
+
},
|
|
20034
|
+
{
|
|
20035
|
+
id: "codex",
|
|
20036
|
+
label: "Codex",
|
|
20037
|
+
hookLabel: "PreToolUse hook",
|
|
20038
|
+
setupCommand: "node9 setup codex",
|
|
20039
|
+
settingsPath: (h) => import_path39.default.join(h, ".codex", "hooks.json"),
|
|
20040
|
+
wireState: (h) => jsonWire(
|
|
20041
|
+
import_path39.default.join(h, ".codex", "hooks.json"),
|
|
20042
|
+
(p) => matchersHaveNode9Hook(p.hooks?.PreToolUse)
|
|
20043
|
+
)
|
|
20044
|
+
},
|
|
20045
|
+
{
|
|
20046
|
+
id: "antigravity",
|
|
20047
|
+
label: "Antigravity",
|
|
20048
|
+
hookLabel: "PreToolUse hook",
|
|
20049
|
+
setupCommand: "node9 setup antigravity",
|
|
20050
|
+
settingsPath: (h) => import_path39.default.join(h, ".gemini", "config", "hooks.json"),
|
|
20051
|
+
wireState: (h) => jsonWire(
|
|
20052
|
+
import_path39.default.join(h, ".gemini", "config", "hooks.json"),
|
|
20053
|
+
(p) => matchersHaveNode9Hook(p.hooks?.PreToolUse)
|
|
20054
|
+
)
|
|
20055
|
+
},
|
|
20056
|
+
{
|
|
20057
|
+
id: "copilot",
|
|
20058
|
+
label: "GitHub Copilot",
|
|
20059
|
+
hookLabel: "PreToolUse hook",
|
|
20060
|
+
setupCommand: "node9 setup copilot",
|
|
20061
|
+
settingsPath: (h) => import_path39.default.join(h, ".copilot", "hooks", "node9.json"),
|
|
20062
|
+
wireState: (h) => jsonWire(
|
|
20063
|
+
import_path39.default.join(h, ".copilot", "hooks", "node9.json"),
|
|
20064
|
+
(p) => flatHaveNode9Hook(p.hooks?.PreToolUse)
|
|
20065
|
+
)
|
|
20066
|
+
},
|
|
20067
|
+
{
|
|
20068
|
+
id: "cursor",
|
|
20069
|
+
label: "Cursor",
|
|
20070
|
+
hookLabel: "preToolUse hook",
|
|
20071
|
+
setupCommand: "node9 setup cursor",
|
|
20072
|
+
settingsPath: (h) => import_path39.default.join(h, ".cursor", "hooks.json"),
|
|
20073
|
+
wireState: (h) => jsonWire(
|
|
20074
|
+
import_path39.default.join(h, ".cursor", "hooks.json"),
|
|
20075
|
+
(p) => flatHaveNode9Hook(p.hooks?.preToolUse)
|
|
20076
|
+
)
|
|
20077
|
+
},
|
|
20078
|
+
{
|
|
20079
|
+
id: "hermes",
|
|
20080
|
+
label: "Hermes Agent",
|
|
20081
|
+
hookLabel: "pre_tool_call hook",
|
|
20082
|
+
setupCommand: "node9 setup hermes",
|
|
20083
|
+
settingsPath: (h) => hermesConfigPath(h),
|
|
20084
|
+
wireState: (h) => hermesWire(h)
|
|
20085
|
+
}
|
|
20086
|
+
];
|
|
20087
|
+
function getAgentWiring(home = import_os34.default.homedir()) {
|
|
20088
|
+
const detected = detectAgents(home);
|
|
20089
|
+
return AGENT_SPECS.map((spec) => ({
|
|
20090
|
+
id: spec.id,
|
|
20091
|
+
label: spec.label,
|
|
20092
|
+
hookLabel: spec.hookLabel,
|
|
20093
|
+
setupCommand: spec.setupCommand,
|
|
20094
|
+
settingsPath: spec.settingsPath(home),
|
|
20095
|
+
installed: detected[spec.id],
|
|
20096
|
+
wireState: spec.wireState(home)
|
|
20097
|
+
}));
|
|
20098
|
+
}
|
|
20099
|
+
|
|
20100
|
+
// src/cli/commands/doctor.ts
|
|
19881
20101
|
function registerDoctorCommand(program2, version2) {
|
|
19882
20102
|
program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
|
|
19883
|
-
const homeDir2 =
|
|
20103
|
+
const homeDir2 = import_os35.default.homedir();
|
|
19884
20104
|
let failures = 0;
|
|
19885
20105
|
function pass(msg) {
|
|
19886
20106
|
console.log(import_chalk11.default.green(" \u2705 ") + msg);
|
|
@@ -19929,10 +20149,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19929
20149
|
);
|
|
19930
20150
|
}
|
|
19931
20151
|
section("Configuration");
|
|
19932
|
-
const globalConfigPath =
|
|
19933
|
-
if (
|
|
20152
|
+
const globalConfigPath = import_path40.default.join(homeDir2, ".node9", "config.json");
|
|
20153
|
+
if (import_fs39.default.existsSync(globalConfigPath)) {
|
|
19934
20154
|
try {
|
|
19935
|
-
JSON.parse(
|
|
20155
|
+
JSON.parse(import_fs39.default.readFileSync(globalConfigPath, "utf-8"));
|
|
19936
20156
|
pass("~/.node9/config.json found and valid");
|
|
19937
20157
|
} catch {
|
|
19938
20158
|
fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
|
|
@@ -19940,10 +20160,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19940
20160
|
} else {
|
|
19941
20161
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
19942
20162
|
}
|
|
19943
|
-
const projectConfigPath =
|
|
19944
|
-
if (
|
|
20163
|
+
const projectConfigPath = import_path40.default.join(process.cwd(), "node9.config.json");
|
|
20164
|
+
if (import_fs39.default.existsSync(projectConfigPath)) {
|
|
19945
20165
|
try {
|
|
19946
|
-
JSON.parse(
|
|
20166
|
+
JSON.parse(import_fs39.default.readFileSync(projectConfigPath, "utf-8"));
|
|
19947
20167
|
pass("node9.config.json found and valid (project)");
|
|
19948
20168
|
} catch {
|
|
19949
20169
|
fail(
|
|
@@ -19952,8 +20172,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19952
20172
|
);
|
|
19953
20173
|
}
|
|
19954
20174
|
}
|
|
19955
|
-
const credsPath =
|
|
19956
|
-
if (
|
|
20175
|
+
const credsPath = import_path40.default.join(homeDir2, ".node9", "credentials.json");
|
|
20176
|
+
if (import_fs39.default.existsSync(credsPath)) {
|
|
19957
20177
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
19958
20178
|
} else {
|
|
19959
20179
|
warn(
|
|
@@ -19962,62 +20182,24 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19962
20182
|
);
|
|
19963
20183
|
}
|
|
19964
20184
|
section("Agent Hooks");
|
|
19965
|
-
const
|
|
19966
|
-
|
|
19967
|
-
|
|
19968
|
-
|
|
19969
|
-
|
|
19970
|
-
|
|
19971
|
-
|
|
19972
|
-
|
|
19973
|
-
|
|
19974
|
-
|
|
19975
|
-
"Claude Code \u2014 hooks file found but node9 hook missing",
|
|
19976
|
-
"Run: node9 setup claude"
|
|
19977
|
-
);
|
|
19978
|
-
} catch {
|
|
19979
|
-
fail("Claude Code \u2014 ~/.claude/settings.json is invalid JSON");
|
|
19980
|
-
}
|
|
19981
|
-
} else {
|
|
19982
|
-
warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
|
|
19983
|
-
}
|
|
19984
|
-
const geminiSettingsPath = import_path39.default.join(homeDir2, ".gemini", "settings.json");
|
|
19985
|
-
if (import_fs38.default.existsSync(geminiSettingsPath)) {
|
|
19986
|
-
try {
|
|
19987
|
-
const gs = JSON.parse(import_fs38.default.readFileSync(geminiSettingsPath, "utf-8"));
|
|
19988
|
-
const hasHook = gs.hooks?.BeforeTool?.some(
|
|
19989
|
-
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
19990
|
-
);
|
|
19991
|
-
if (hasHook) pass("Gemini CLI \u2014 BeforeTool hook active");
|
|
19992
|
-
else
|
|
19993
|
-
fail(
|
|
19994
|
-
"Gemini CLI \u2014 hooks file found but node9 hook missing",
|
|
19995
|
-
"Run: node9 setup gemini"
|
|
19996
|
-
);
|
|
19997
|
-
} catch {
|
|
19998
|
-
fail("Gemini CLI \u2014 ~/.gemini/settings.json is invalid JSON");
|
|
20185
|
+
const notConfigured = [];
|
|
20186
|
+
for (const a of getAgentWiring(homeDir2)) {
|
|
20187
|
+
if (a.wireState === "wired") {
|
|
20188
|
+
pass(`${a.label} \u2014 ${a.hookLabel} active`);
|
|
20189
|
+
} else if (a.wireState === "unwired") {
|
|
20190
|
+
fail(`${a.label} \u2014 settings found but node9 hook missing`, `Run: ${a.setupCommand}`);
|
|
20191
|
+
} else if (a.wireState === "invalid") {
|
|
20192
|
+
fail(`${a.label} \u2014 settings file is invalid JSON`, a.settingsPath);
|
|
20193
|
+
} else {
|
|
20194
|
+
notConfigured.push(a.label);
|
|
19999
20195
|
}
|
|
20000
|
-
} else {
|
|
20001
|
-
warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
|
|
20002
20196
|
}
|
|
20003
|
-
|
|
20004
|
-
|
|
20005
|
-
|
|
20006
|
-
|
|
20007
|
-
|
|
20008
|
-
|
|
20009
|
-
);
|
|
20010
|
-
if (hasHook) pass("Cursor \u2014 preToolUse hook active");
|
|
20011
|
-
else
|
|
20012
|
-
fail(
|
|
20013
|
-
"Cursor \u2014 hooks file found but node9 hook missing",
|
|
20014
|
-
"Run: node9 setup cursor"
|
|
20015
|
-
);
|
|
20016
|
-
} catch {
|
|
20017
|
-
fail("Cursor \u2014 ~/.cursor/hooks.json is invalid JSON");
|
|
20018
|
-
}
|
|
20019
|
-
} else {
|
|
20020
|
-
warn("Cursor \u2014 not configured", "Run: node9 setup cursor (skip if not using Cursor)");
|
|
20197
|
+
if (notConfigured.length > 0) {
|
|
20198
|
+
console.log(
|
|
20199
|
+
import_chalk11.default.gray(
|
|
20200
|
+
` \xB7 Not configured: ${notConfigured.join(", ")} \u2014 run \`node9 setup <agent>\` if you use one`
|
|
20201
|
+
)
|
|
20202
|
+
);
|
|
20021
20203
|
}
|
|
20022
20204
|
section("Daemon (optional)");
|
|
20023
20205
|
if (isDaemonRunning()) {
|
|
@@ -20034,7 +20216,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
20034
20216
|
try {
|
|
20035
20217
|
const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
|
|
20036
20218
|
const cfg = getConfig();
|
|
20037
|
-
const creds =
|
|
20219
|
+
const creds = import_fs39.default.existsSync(import_path40.default.join(import_os35.default.homedir(), ".node9", "credentials.json"));
|
|
20038
20220
|
if (!creds) {
|
|
20039
20221
|
warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
|
|
20040
20222
|
} else if (!cfg.settings.approvers.cloud) {
|
|
@@ -20084,9 +20266,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
20084
20266
|
|
|
20085
20267
|
// src/cli/commands/audit.ts
|
|
20086
20268
|
var import_chalk12 = __toESM(require("chalk"));
|
|
20087
|
-
var
|
|
20088
|
-
var
|
|
20089
|
-
var
|
|
20269
|
+
var import_fs40 = __toESM(require("fs"));
|
|
20270
|
+
var import_path41 = __toESM(require("path"));
|
|
20271
|
+
var import_os36 = __toESM(require("os"));
|
|
20090
20272
|
function formatRelativeTime(timestamp) {
|
|
20091
20273
|
const diff = Date.now() - new Date(timestamp).getTime();
|
|
20092
20274
|
const sec = Math.floor(diff / 1e3);
|
|
@@ -20099,14 +20281,14 @@ function formatRelativeTime(timestamp) {
|
|
|
20099
20281
|
}
|
|
20100
20282
|
function registerAuditCommand(program2) {
|
|
20101
20283
|
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) => {
|
|
20102
|
-
const logPath =
|
|
20103
|
-
if (!
|
|
20284
|
+
const logPath = import_path41.default.join(import_os36.default.homedir(), ".node9", "audit.log");
|
|
20285
|
+
if (!import_fs40.default.existsSync(logPath)) {
|
|
20104
20286
|
console.log(
|
|
20105
20287
|
import_chalk12.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
20106
20288
|
);
|
|
20107
20289
|
return;
|
|
20108
20290
|
}
|
|
20109
|
-
const raw =
|
|
20291
|
+
const raw = import_fs40.default.readFileSync(logPath, "utf-8");
|
|
20110
20292
|
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
20111
20293
|
let entries = lines.flatMap((line) => {
|
|
20112
20294
|
try {
|
|
@@ -20162,9 +20344,9 @@ function registerAuditCommand(program2) {
|
|
|
20162
20344
|
var import_chalk13 = __toESM(require("chalk"));
|
|
20163
20345
|
|
|
20164
20346
|
// src/cli/aggregate/report-audit.ts
|
|
20165
|
-
var
|
|
20166
|
-
var
|
|
20167
|
-
var
|
|
20347
|
+
var import_fs41 = __toESM(require("fs"));
|
|
20348
|
+
var import_os37 = __toESM(require("os"));
|
|
20349
|
+
var import_path42 = __toESM(require("path"));
|
|
20168
20350
|
init_costSync();
|
|
20169
20351
|
init_litellm();
|
|
20170
20352
|
init_cost_codex();
|
|
@@ -20247,8 +20429,8 @@ function getDateRange(period, now) {
|
|
|
20247
20429
|
}
|
|
20248
20430
|
}
|
|
20249
20431
|
function parseAuditLog(logPath) {
|
|
20250
|
-
if (!
|
|
20251
|
-
const raw =
|
|
20432
|
+
if (!import_fs41.default.existsSync(logPath)) return [];
|
|
20433
|
+
const raw = import_fs41.default.readFileSync(logPath, "utf-8");
|
|
20252
20434
|
return raw.split("\n").flatMap((line) => {
|
|
20253
20435
|
if (!line.trim()) return [];
|
|
20254
20436
|
try {
|
|
@@ -20295,25 +20477,25 @@ function freezeClaudeCost(acc) {
|
|
|
20295
20477
|
};
|
|
20296
20478
|
}
|
|
20297
20479
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
20298
|
-
const projPath =
|
|
20480
|
+
const projPath = import_path42.default.join(projectsDir, proj);
|
|
20299
20481
|
let files;
|
|
20300
20482
|
try {
|
|
20301
|
-
const stat =
|
|
20483
|
+
const stat = import_fs41.default.statSync(projPath);
|
|
20302
20484
|
if (!stat.isDirectory()) return;
|
|
20303
|
-
files =
|
|
20485
|
+
files = import_fs41.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
20304
20486
|
} catch {
|
|
20305
20487
|
return;
|
|
20306
20488
|
}
|
|
20307
20489
|
const startMs = start.getTime();
|
|
20308
20490
|
for (const file of files) {
|
|
20309
|
-
const filePath =
|
|
20491
|
+
const filePath = import_path42.default.join(projPath, file);
|
|
20310
20492
|
try {
|
|
20311
|
-
if (
|
|
20493
|
+
if (import_fs41.default.statSync(filePath).mtimeMs < startMs) continue;
|
|
20312
20494
|
} catch {
|
|
20313
20495
|
continue;
|
|
20314
20496
|
}
|
|
20315
20497
|
try {
|
|
20316
|
-
const raw =
|
|
20498
|
+
const raw = import_fs41.default.readFileSync(filePath, "utf-8");
|
|
20317
20499
|
for (const line of raw.split("\n")) {
|
|
20318
20500
|
if (!line.trim()) continue;
|
|
20319
20501
|
let entry;
|
|
@@ -20363,10 +20545,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
20363
20545
|
}
|
|
20364
20546
|
function loadClaudeCost(start, end, projectsDir) {
|
|
20365
20547
|
const acc = emptyClaudeCostAccumulator();
|
|
20366
|
-
if (!
|
|
20548
|
+
if (!import_fs41.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
|
|
20367
20549
|
let dirs;
|
|
20368
20550
|
try {
|
|
20369
|
-
dirs =
|
|
20551
|
+
dirs = import_fs41.default.readdirSync(projectsDir);
|
|
20370
20552
|
} catch {
|
|
20371
20553
|
return freezeClaudeCost(acc);
|
|
20372
20554
|
}
|
|
@@ -20378,7 +20560,7 @@ function loadClaudeCost(start, end, projectsDir) {
|
|
|
20378
20560
|
function processCodexCostFile(filePath, start, end, acc) {
|
|
20379
20561
|
let lines;
|
|
20380
20562
|
try {
|
|
20381
|
-
lines =
|
|
20563
|
+
lines = import_fs41.default.readFileSync(filePath, "utf-8").split("\n");
|
|
20382
20564
|
} catch {
|
|
20383
20565
|
return;
|
|
20384
20566
|
}
|
|
@@ -20433,31 +20615,31 @@ function processCodexCostFile(filePath, start, end, acc) {
|
|
|
20433
20615
|
}
|
|
20434
20616
|
function listCodexSessionFiles2(sessionsBase) {
|
|
20435
20617
|
const jsonlFiles = [];
|
|
20436
|
-
if (!
|
|
20618
|
+
if (!import_fs41.default.existsSync(sessionsBase)) return jsonlFiles;
|
|
20437
20619
|
try {
|
|
20438
|
-
for (const year of
|
|
20439
|
-
const yearPath =
|
|
20620
|
+
for (const year of import_fs41.default.readdirSync(sessionsBase)) {
|
|
20621
|
+
const yearPath = import_path42.default.join(sessionsBase, year);
|
|
20440
20622
|
try {
|
|
20441
|
-
if (!
|
|
20623
|
+
if (!import_fs41.default.statSync(yearPath).isDirectory()) continue;
|
|
20442
20624
|
} catch {
|
|
20443
20625
|
continue;
|
|
20444
20626
|
}
|
|
20445
|
-
for (const month of
|
|
20446
|
-
const monthPath =
|
|
20627
|
+
for (const month of import_fs41.default.readdirSync(yearPath)) {
|
|
20628
|
+
const monthPath = import_path42.default.join(yearPath, month);
|
|
20447
20629
|
try {
|
|
20448
|
-
if (!
|
|
20630
|
+
if (!import_fs41.default.statSync(monthPath).isDirectory()) continue;
|
|
20449
20631
|
} catch {
|
|
20450
20632
|
continue;
|
|
20451
20633
|
}
|
|
20452
|
-
for (const day of
|
|
20453
|
-
const dayPath =
|
|
20634
|
+
for (const day of import_fs41.default.readdirSync(monthPath)) {
|
|
20635
|
+
const dayPath = import_path42.default.join(monthPath, day);
|
|
20454
20636
|
try {
|
|
20455
|
-
if (!
|
|
20637
|
+
if (!import_fs41.default.statSync(dayPath).isDirectory()) continue;
|
|
20456
20638
|
} catch {
|
|
20457
20639
|
continue;
|
|
20458
20640
|
}
|
|
20459
|
-
for (const file of
|
|
20460
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
20641
|
+
for (const file of import_fs41.default.readdirSync(dayPath)) {
|
|
20642
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path42.default.join(dayPath, file));
|
|
20461
20643
|
}
|
|
20462
20644
|
}
|
|
20463
20645
|
}
|
|
@@ -20522,13 +20704,13 @@ function freezeGeminiCost(acc) {
|
|
|
20522
20704
|
function processGeminiCostFile(filePath, projectKey, start, end, acc) {
|
|
20523
20705
|
const startMs = start.getTime();
|
|
20524
20706
|
try {
|
|
20525
|
-
if (
|
|
20707
|
+
if (import_fs41.default.statSync(filePath).mtimeMs < startMs) return;
|
|
20526
20708
|
} catch {
|
|
20527
20709
|
return;
|
|
20528
20710
|
}
|
|
20529
20711
|
let raw;
|
|
20530
20712
|
try {
|
|
20531
|
-
raw =
|
|
20713
|
+
raw = import_fs41.default.readFileSync(filePath, "utf-8");
|
|
20532
20714
|
} catch {
|
|
20533
20715
|
return;
|
|
20534
20716
|
}
|
|
@@ -20577,30 +20759,30 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
|
|
|
20577
20759
|
const out = [];
|
|
20578
20760
|
let dirs;
|
|
20579
20761
|
try {
|
|
20580
|
-
if (!
|
|
20581
|
-
dirs =
|
|
20762
|
+
if (!import_fs41.default.statSync(geminiTmpDir2).isDirectory()) return out;
|
|
20763
|
+
dirs = import_fs41.default.readdirSync(geminiTmpDir2);
|
|
20582
20764
|
} catch {
|
|
20583
20765
|
return out;
|
|
20584
20766
|
}
|
|
20585
20767
|
for (const proj of dirs) {
|
|
20586
|
-
const chatsDir =
|
|
20768
|
+
const chatsDir = import_path42.default.join(geminiTmpDir2, proj, "chats");
|
|
20587
20769
|
let files;
|
|
20588
20770
|
try {
|
|
20589
|
-
if (!
|
|
20590
|
-
files =
|
|
20771
|
+
if (!import_fs41.default.statSync(chatsDir).isDirectory()) continue;
|
|
20772
|
+
files = import_fs41.default.readdirSync(chatsDir);
|
|
20591
20773
|
} catch {
|
|
20592
20774
|
continue;
|
|
20593
20775
|
}
|
|
20594
20776
|
for (const f of files) {
|
|
20595
20777
|
if (!f.endsWith(".jsonl")) continue;
|
|
20596
|
-
out.push({ projectKey: proj, file:
|
|
20778
|
+
out.push({ projectKey: proj, file: import_path42.default.join(chatsDir, f) });
|
|
20597
20779
|
}
|
|
20598
20780
|
}
|
|
20599
20781
|
return out;
|
|
20600
20782
|
}
|
|
20601
20783
|
function loadGeminiCost(start, end, geminiTmpDir2) {
|
|
20602
20784
|
const acc = emptyGeminiAccumulator();
|
|
20603
|
-
if (!
|
|
20785
|
+
if (!import_fs41.default.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
|
|
20604
20786
|
for (const { projectKey, file } of listGeminiSessionFiles2(geminiTmpDir2)) {
|
|
20605
20787
|
processGeminiCostFile(file, projectKey, start, end, acc);
|
|
20606
20788
|
}
|
|
@@ -20608,11 +20790,11 @@ function loadGeminiCost(start, end, geminiTmpDir2) {
|
|
|
20608
20790
|
}
|
|
20609
20791
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
20610
20792
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
20611
|
-
const auditLogPath = opts.auditLogPath ??
|
|
20612
|
-
const claudeProjectsDir = opts.claudeProjectsDir ??
|
|
20613
|
-
const codexSessionsDir2 = opts.codexSessionsDir ??
|
|
20614
|
-
const geminiTmpDir2 = opts.geminiTmpDir ??
|
|
20615
|
-
const hasAuditFile =
|
|
20793
|
+
const auditLogPath = opts.auditLogPath ?? import_path42.default.join(import_os37.default.homedir(), ".node9", "audit.log");
|
|
20794
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? import_path42.default.join(import_os37.default.homedir(), ".claude", "projects");
|
|
20795
|
+
const codexSessionsDir2 = opts.codexSessionsDir ?? import_path42.default.join(import_os37.default.homedir(), ".codex", "sessions");
|
|
20796
|
+
const geminiTmpDir2 = opts.geminiTmpDir ?? import_path42.default.join(import_os37.default.homedir(), ".gemini", "tmp");
|
|
20797
|
+
const hasAuditFile = import_fs41.default.existsSync(auditLogPath);
|
|
20616
20798
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
|
|
20617
20799
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
20618
20800
|
const { start, end } = getDateRange(period, now);
|
|
@@ -21308,23 +21490,23 @@ function registerDaemonCommand(program2) {
|
|
|
21308
21490
|
|
|
21309
21491
|
// src/cli/commands/status.ts
|
|
21310
21492
|
var import_chalk15 = __toESM(require("chalk"));
|
|
21311
|
-
var
|
|
21312
|
-
var
|
|
21313
|
-
var
|
|
21314
|
-
var
|
|
21493
|
+
var import_fs42 = __toESM(require("fs"));
|
|
21494
|
+
var import_path43 = __toESM(require("path"));
|
|
21495
|
+
var import_os38 = __toESM(require("os"));
|
|
21496
|
+
var yaml3 = __toESM(require("yaml"));
|
|
21315
21497
|
init_core();
|
|
21316
21498
|
init_daemon();
|
|
21317
21499
|
init_setup();
|
|
21318
21500
|
function readHermesHooks(configPath) {
|
|
21319
|
-
if (!
|
|
21501
|
+
if (!import_fs42.default.existsSync(configPath)) return null;
|
|
21320
21502
|
let raw;
|
|
21321
21503
|
try {
|
|
21322
|
-
raw =
|
|
21504
|
+
raw = import_fs42.default.readFileSync(configPath, "utf-8");
|
|
21323
21505
|
} catch {
|
|
21324
21506
|
return null;
|
|
21325
21507
|
}
|
|
21326
21508
|
try {
|
|
21327
|
-
const cfg =
|
|
21509
|
+
const cfg = yaml3.parse(raw);
|
|
21328
21510
|
const has = (event) => (cfg?.hooks?.[event] ?? []).some(
|
|
21329
21511
|
(e) => typeof e?.command === "string" && isNode9Hook(e.command)
|
|
21330
21512
|
);
|
|
@@ -21338,17 +21520,17 @@ function readHermesHooks(configPath) {
|
|
|
21338
21520
|
return { pre: false, post: false };
|
|
21339
21521
|
}
|
|
21340
21522
|
}
|
|
21341
|
-
function
|
|
21523
|
+
function readJson3(filePath) {
|
|
21342
21524
|
try {
|
|
21343
|
-
if (
|
|
21525
|
+
if (import_fs42.default.existsSync(filePath)) return JSON.parse(import_fs42.default.readFileSync(filePath, "utf-8"));
|
|
21344
21526
|
} catch {
|
|
21345
21527
|
}
|
|
21346
21528
|
return null;
|
|
21347
21529
|
}
|
|
21348
|
-
function
|
|
21530
|
+
function matchersHaveNode9Hook2(matchers) {
|
|
21349
21531
|
return (matchers ?? []).some((m) => (m.hooks ?? []).some((h) => isNode9Hook(h.command)));
|
|
21350
21532
|
}
|
|
21351
|
-
function
|
|
21533
|
+
function flatHaveNode9Hook2(entries) {
|
|
21352
21534
|
return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
|
|
21353
21535
|
}
|
|
21354
21536
|
function wrappedMcpServers(servers) {
|
|
@@ -21408,42 +21590,42 @@ function registerStatusCommand(program2) {
|
|
|
21408
21590
|
console.log("");
|
|
21409
21591
|
const modeLabel = settings.mode === "audit" ? import_chalk15.default.blue("audit") : settings.mode === "strict" ? import_chalk15.default.red("strict") : import_chalk15.default.white("standard");
|
|
21410
21592
|
console.log(` Mode: ${modeLabel}`);
|
|
21411
|
-
const projectConfig =
|
|
21412
|
-
const globalConfig =
|
|
21593
|
+
const projectConfig = import_path43.default.join(process.cwd(), "node9.config.json");
|
|
21594
|
+
const globalConfig = import_path43.default.join(import_os38.default.homedir(), ".node9", "config.json");
|
|
21413
21595
|
console.log(
|
|
21414
|
-
` Local: ${
|
|
21596
|
+
` Local: ${import_fs42.default.existsSync(projectConfig) ? import_chalk15.default.green("Active (node9.config.json)") : import_chalk15.default.gray("Not present")}`
|
|
21415
21597
|
);
|
|
21416
21598
|
console.log(
|
|
21417
|
-
` Global: ${
|
|
21599
|
+
` Global: ${import_fs42.default.existsSync(globalConfig) ? import_chalk15.default.green("Active (~/.node9/config.json)") : import_chalk15.default.gray("Not present")}`
|
|
21418
21600
|
);
|
|
21419
21601
|
if (mergedConfig.policy.sandboxPaths.length > 0) {
|
|
21420
21602
|
console.log(
|
|
21421
21603
|
` Sandbox: ${import_chalk15.default.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
|
|
21422
21604
|
);
|
|
21423
21605
|
}
|
|
21424
|
-
const homeDir2 =
|
|
21425
|
-
const claudeSettings =
|
|
21426
|
-
|
|
21606
|
+
const homeDir2 = import_os38.default.homedir();
|
|
21607
|
+
const claudeSettings = readJson3(
|
|
21608
|
+
import_path43.default.join(homeDir2, ".claude", "settings.json")
|
|
21427
21609
|
);
|
|
21428
|
-
const claudeConfig =
|
|
21429
|
-
const geminiSettings =
|
|
21430
|
-
|
|
21610
|
+
const claudeConfig = readJson3(import_path43.default.join(homeDir2, ".claude.json"));
|
|
21611
|
+
const geminiSettings = readJson3(
|
|
21612
|
+
import_path43.default.join(homeDir2, ".gemini", "settings.json")
|
|
21431
21613
|
);
|
|
21432
|
-
const cursorConfig =
|
|
21433
|
-
const antigravityHooks =
|
|
21434
|
-
|
|
21614
|
+
const cursorConfig = readJson3(import_path43.default.join(homeDir2, ".cursor", "mcp.json"));
|
|
21615
|
+
const antigravityHooks = readJson3(
|
|
21616
|
+
import_path43.default.join(homeDir2, ".gemini", "config", "hooks.json")
|
|
21435
21617
|
);
|
|
21436
|
-
const antigravityMcp =
|
|
21437
|
-
|
|
21618
|
+
const antigravityMcp = readJson3(
|
|
21619
|
+
import_path43.default.join(homeDir2, ".gemini", "config", "mcp_config.json")
|
|
21438
21620
|
);
|
|
21439
|
-
const antigravityPresent = antigravityHooks !== null ||
|
|
21440
|
-
const copilotHooks =
|
|
21441
|
-
|
|
21621
|
+
const antigravityPresent = antigravityHooks !== null || import_fs42.default.existsSync(import_path43.default.join(homeDir2, ".gemini", "antigravity-cli")) || import_fs42.default.existsSync(import_path43.default.join(homeDir2, ".gemini", "antigravity-ide"));
|
|
21622
|
+
const copilotHooks = readJson3(
|
|
21623
|
+
import_path43.default.join(homeDir2, ".copilot", "hooks", "node9.json")
|
|
21442
21624
|
);
|
|
21443
|
-
const copilotMcp =
|
|
21444
|
-
|
|
21625
|
+
const copilotMcp = readJson3(
|
|
21626
|
+
import_path43.default.join(homeDir2, ".copilot", "mcp-config.json")
|
|
21445
21627
|
);
|
|
21446
|
-
const copilotPresent =
|
|
21628
|
+
const copilotPresent = import_fs42.default.existsSync(import_path43.default.join(homeDir2, ".copilot"));
|
|
21447
21629
|
const hermesHooks = readHermesHooks(hermesConfigPath(homeDir2));
|
|
21448
21630
|
const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig || antigravityPresent || copilotPresent || hermesHooks;
|
|
21449
21631
|
if (agentFound) {
|
|
@@ -21451,8 +21633,8 @@ function registerStatusCommand(program2) {
|
|
|
21451
21633
|
console.log(import_chalk15.default.bold(" Agent Wiring:"));
|
|
21452
21634
|
console.log("");
|
|
21453
21635
|
if (claudeSettings || claudeConfig) {
|
|
21454
|
-
const preHook =
|
|
21455
|
-
const postHook =
|
|
21636
|
+
const preHook = matchersHaveNode9Hook2(claudeSettings?.hooks?.PreToolUse);
|
|
21637
|
+
const postHook = matchersHaveNode9Hook2(claudeSettings?.hooks?.PostToolUse);
|
|
21456
21638
|
printAgentSection(
|
|
21457
21639
|
"Claude Code",
|
|
21458
21640
|
[
|
|
@@ -21464,8 +21646,8 @@ function registerStatusCommand(program2) {
|
|
|
21464
21646
|
console.log("");
|
|
21465
21647
|
}
|
|
21466
21648
|
if (geminiSettings) {
|
|
21467
|
-
const beforeHook =
|
|
21468
|
-
const afterHook =
|
|
21649
|
+
const beforeHook = matchersHaveNode9Hook2(geminiSettings.hooks?.BeforeTool);
|
|
21650
|
+
const afterHook = matchersHaveNode9Hook2(geminiSettings.hooks?.AfterTool);
|
|
21469
21651
|
printAgentSection(
|
|
21470
21652
|
"Gemini CLI",
|
|
21471
21653
|
[
|
|
@@ -21477,8 +21659,8 @@ function registerStatusCommand(program2) {
|
|
|
21477
21659
|
console.log("");
|
|
21478
21660
|
}
|
|
21479
21661
|
if (antigravityPresent) {
|
|
21480
|
-
const preHook =
|
|
21481
|
-
const postHook =
|
|
21662
|
+
const preHook = matchersHaveNode9Hook2(antigravityHooks?.hooks?.PreToolUse);
|
|
21663
|
+
const postHook = matchersHaveNode9Hook2(antigravityHooks?.hooks?.PostToolUse);
|
|
21482
21664
|
printAgentSection(
|
|
21483
21665
|
"Antigravity",
|
|
21484
21666
|
[
|
|
@@ -21490,9 +21672,9 @@ function registerStatusCommand(program2) {
|
|
|
21490
21672
|
console.log("");
|
|
21491
21673
|
}
|
|
21492
21674
|
if (copilotPresent) {
|
|
21493
|
-
const preHook =
|
|
21494
|
-
const postHook =
|
|
21495
|
-
const promptHook =
|
|
21675
|
+
const preHook = flatHaveNode9Hook2(copilotHooks?.hooks?.PreToolUse);
|
|
21676
|
+
const postHook = flatHaveNode9Hook2(copilotHooks?.hooks?.PostToolUse);
|
|
21677
|
+
const promptHook = flatHaveNode9Hook2(copilotHooks?.hooks?.UserPromptSubmit);
|
|
21496
21678
|
printAgentSection(
|
|
21497
21679
|
"GitHub Copilot",
|
|
21498
21680
|
[
|
|
@@ -21535,9 +21717,9 @@ function registerStatusCommand(program2) {
|
|
|
21535
21717
|
|
|
21536
21718
|
// src/cli/commands/init.ts
|
|
21537
21719
|
var import_chalk16 = __toESM(require("chalk"));
|
|
21538
|
-
var
|
|
21539
|
-
var
|
|
21540
|
-
var
|
|
21720
|
+
var import_fs43 = __toESM(require("fs"));
|
|
21721
|
+
var import_path44 = __toESM(require("path"));
|
|
21722
|
+
var import_os39 = __toESM(require("os"));
|
|
21541
21723
|
var import_https4 = __toESM(require("https"));
|
|
21542
21724
|
init_core();
|
|
21543
21725
|
init_setup();
|
|
@@ -21627,16 +21809,16 @@ function registerInitCommand(program2) {
|
|
|
21627
21809
|
}
|
|
21628
21810
|
console.log("");
|
|
21629
21811
|
}
|
|
21630
|
-
const configPath =
|
|
21631
|
-
const isFirstInstall = !
|
|
21632
|
-
if (
|
|
21812
|
+
const configPath = import_path44.default.join(import_os39.default.homedir(), ".node9", "config.json");
|
|
21813
|
+
const isFirstInstall = !import_fs43.default.existsSync(configPath);
|
|
21814
|
+
if (import_fs43.default.existsSync(configPath) && !options.force) {
|
|
21633
21815
|
try {
|
|
21634
|
-
const existing = JSON.parse(
|
|
21816
|
+
const existing = JSON.parse(import_fs43.default.readFileSync(configPath, "utf-8"));
|
|
21635
21817
|
const settings = existing.settings ?? {};
|
|
21636
21818
|
if (settings.mode !== chosenMode) {
|
|
21637
21819
|
settings.mode = chosenMode;
|
|
21638
21820
|
existing.settings = settings;
|
|
21639
|
-
|
|
21821
|
+
import_fs43.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
|
|
21640
21822
|
console.log(import_chalk16.default.green(`\u2705 Mode updated: ${chosenMode}`));
|
|
21641
21823
|
} else {
|
|
21642
21824
|
console.log(import_chalk16.default.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
|
|
@@ -21649,9 +21831,9 @@ function registerInitCommand(program2) {
|
|
|
21649
21831
|
...DEFAULT_CONFIG,
|
|
21650
21832
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
21651
21833
|
};
|
|
21652
|
-
const dir =
|
|
21653
|
-
if (!
|
|
21654
|
-
|
|
21834
|
+
const dir = import_path44.default.dirname(configPath);
|
|
21835
|
+
if (!import_fs43.default.existsSync(dir)) import_fs43.default.mkdirSync(dir, { recursive: true });
|
|
21836
|
+
import_fs43.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
|
|
21655
21837
|
console.log(import_chalk16.default.green(`\u2705 Config created: ${configPath}`));
|
|
21656
21838
|
console.log(import_chalk16.default.gray(` Mode: ${chosenMode}`));
|
|
21657
21839
|
}
|
|
@@ -21756,7 +21938,7 @@ function registerInitCommand(program2) {
|
|
|
21756
21938
|
}
|
|
21757
21939
|
|
|
21758
21940
|
// src/cli/commands/undo.ts
|
|
21759
|
-
var
|
|
21941
|
+
var import_path45 = __toESM(require("path"));
|
|
21760
21942
|
var import_chalk18 = __toESM(require("chalk"));
|
|
21761
21943
|
|
|
21762
21944
|
// src/tui/undo-navigator.ts
|
|
@@ -21915,7 +22097,7 @@ function findMatchingCwd(startDir, history) {
|
|
|
21915
22097
|
let dir = startDir;
|
|
21916
22098
|
while (true) {
|
|
21917
22099
|
if (cwds.has(dir)) return dir;
|
|
21918
|
-
const parent =
|
|
22100
|
+
const parent = import_path45.default.dirname(dir);
|
|
21919
22101
|
if (parent === dir) return null;
|
|
21920
22102
|
dir = parent;
|
|
21921
22103
|
}
|
|
@@ -22047,6 +22229,8 @@ var import_chalk19 = __toESM(require("chalk"));
|
|
|
22047
22229
|
var import_child_process10 = require("child_process");
|
|
22048
22230
|
var import_execa3 = require("execa");
|
|
22049
22231
|
init_orchestrator();
|
|
22232
|
+
init_cloud();
|
|
22233
|
+
init_config();
|
|
22050
22234
|
init_provenance();
|
|
22051
22235
|
init_mcp_pin();
|
|
22052
22236
|
init_mcp_tools();
|
|
@@ -22075,6 +22259,60 @@ function normalizeClientName(name) {
|
|
|
22075
22259
|
const sanitized = sanitize4(name).slice(0, 40);
|
|
22076
22260
|
return sanitized.length > 0 ? sanitized : void 0;
|
|
22077
22261
|
}
|
|
22262
|
+
function reportPinMismatchToCloud(serverKey, agent) {
|
|
22263
|
+
try {
|
|
22264
|
+
const creds = getCredentials();
|
|
22265
|
+
if (!creds) return;
|
|
22266
|
+
void auditLocalAllow(
|
|
22267
|
+
`mcp-server:${serverKey}`,
|
|
22268
|
+
{ serverKey, reason: "tool-pin-mismatch" },
|
|
22269
|
+
"mcp-pin-mismatch",
|
|
22270
|
+
creds,
|
|
22271
|
+
{ mcpServer: serverKey, agent },
|
|
22272
|
+
void 0,
|
|
22273
|
+
false,
|
|
22274
|
+
{
|
|
22275
|
+
ruleName: "MCP tool definitions changed (possible rug pull)",
|
|
22276
|
+
ruleDescription: `The MCP server "${serverKey}" changed its tool definitions since they were pinned. This can indicate a supply-chain attack (tool poisoning). The session was quarantined. Review with: node9 mcp pin update ${serverKey}`
|
|
22277
|
+
}
|
|
22278
|
+
);
|
|
22279
|
+
} catch {
|
|
22280
|
+
}
|
|
22281
|
+
}
|
|
22282
|
+
function reportInventoryToCloud(serverKey, toolCount, agent) {
|
|
22283
|
+
try {
|
|
22284
|
+
const creds = getCredentials();
|
|
22285
|
+
if (!creds) return;
|
|
22286
|
+
void auditLocalAllow(
|
|
22287
|
+
`mcp-server:${serverKey}`,
|
|
22288
|
+
{ serverKey, toolCount },
|
|
22289
|
+
"mcp-discovered",
|
|
22290
|
+
creds,
|
|
22291
|
+
{ mcpServer: serverKey, agent },
|
|
22292
|
+
void 0,
|
|
22293
|
+
false,
|
|
22294
|
+
{ mcpToolCount: toolCount }
|
|
22295
|
+
);
|
|
22296
|
+
} catch {
|
|
22297
|
+
}
|
|
22298
|
+
}
|
|
22299
|
+
function reportLargeResponseToCloud(serverKey, responseBytes, agent) {
|
|
22300
|
+
try {
|
|
22301
|
+
const creds = getCredentials();
|
|
22302
|
+
if (!creds) return;
|
|
22303
|
+
void auditLocalAllow(
|
|
22304
|
+
`mcp-server:${serverKey}`,
|
|
22305
|
+
{ serverKey, responseBytes },
|
|
22306
|
+
"mcp-large-response",
|
|
22307
|
+
creds,
|
|
22308
|
+
{ mcpServer: serverKey, agent },
|
|
22309
|
+
void 0,
|
|
22310
|
+
false,
|
|
22311
|
+
{ mcpResponseBytes: responseBytes }
|
|
22312
|
+
);
|
|
22313
|
+
} catch {
|
|
22314
|
+
}
|
|
22315
|
+
}
|
|
22078
22316
|
function tokenize4(cmd) {
|
|
22079
22317
|
const tokens = [];
|
|
22080
22318
|
let current = "";
|
|
@@ -22335,6 +22573,7 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
22335
22573
|
const currentHash = hashToolDefinitions(tools);
|
|
22336
22574
|
const pinStatus = checkPin(serverKey, currentHash, gatewayCwd);
|
|
22337
22575
|
const token = getInternalToken();
|
|
22576
|
+
reportInventoryToCloud(serverKey, tools.length, clientName);
|
|
22338
22577
|
if (isDaemonRunning() && process.env.NODE9_TESTING !== "1") {
|
|
22339
22578
|
const toolSummary = tools.map((t) => ({ name: t.name, description: t.description }));
|
|
22340
22579
|
fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/mcp/discovered`, {
|
|
@@ -22399,6 +22638,7 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
22399
22638
|
console.error(import_chalk19.default.red(" Session quarantined \u2014 all tool calls blocked."));
|
|
22400
22639
|
console.error(import_chalk19.default.yellow(` Run: node9 mcp pin update ${serverKey}
|
|
22401
22640
|
`));
|
|
22641
|
+
reportPinMismatchToCloud(serverKey, clientName);
|
|
22402
22642
|
const errorResponse = {
|
|
22403
22643
|
jsonrpc: "2.0",
|
|
22404
22644
|
id: parsed.id,
|
|
@@ -22444,6 +22684,7 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
22444
22684
|
`\u26A1 Node9: Large MCP response from '${toolName}' (${(line.length / 1024).toFixed(0)}KB) \u2014 context window enlarged`
|
|
22445
22685
|
)
|
|
22446
22686
|
);
|
|
22687
|
+
reportLargeResponseToCloud(serverKey, line.length, clientName);
|
|
22447
22688
|
if (isDaemonRunning() && process.env.NODE9_TESTING !== "1") {
|
|
22448
22689
|
const token = getInternalToken();
|
|
22449
22690
|
fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/mcp/large-response`, {
|
|
@@ -22491,9 +22732,9 @@ function registerMcpGatewayCommand(program2) {
|
|
|
22491
22732
|
|
|
22492
22733
|
// src/mcp-server/index.ts
|
|
22493
22734
|
var import_readline5 = __toESM(require("readline"));
|
|
22494
|
-
var
|
|
22495
|
-
var
|
|
22496
|
-
var
|
|
22735
|
+
var import_fs44 = __toESM(require("fs"));
|
|
22736
|
+
var import_os40 = __toESM(require("os"));
|
|
22737
|
+
var import_path46 = __toESM(require("path"));
|
|
22497
22738
|
var import_child_process11 = require("child_process");
|
|
22498
22739
|
init_core();
|
|
22499
22740
|
init_daemon();
|
|
@@ -22744,13 +22985,13 @@ function handleStatus() {
|
|
|
22744
22985
|
lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
|
|
22745
22986
|
lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
|
|
22746
22987
|
lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
|
|
22747
|
-
const projectConfig =
|
|
22748
|
-
const globalConfig =
|
|
22988
|
+
const projectConfig = import_path46.default.join(process.cwd(), "node9.config.json");
|
|
22989
|
+
const globalConfig = import_path46.default.join(import_os40.default.homedir(), ".node9", "config.json");
|
|
22749
22990
|
lines.push(
|
|
22750
|
-
`Project config (node9.config.json): ${
|
|
22991
|
+
`Project config (node9.config.json): ${import_fs44.default.existsSync(projectConfig) ? "present" : "not found"}`
|
|
22751
22992
|
);
|
|
22752
22993
|
lines.push(
|
|
22753
|
-
`Global config (~/.node9/config.json): ${
|
|
22994
|
+
`Global config (~/.node9/config.json): ${import_fs44.default.existsSync(globalConfig) ? "present" : "not found"}`
|
|
22754
22995
|
);
|
|
22755
22996
|
return lines.join("\n");
|
|
22756
22997
|
}
|
|
@@ -22824,21 +23065,21 @@ function handleShieldDisable(args) {
|
|
|
22824
23065
|
writeActiveShields(active.filter((s) => s !== name));
|
|
22825
23066
|
return `Shield "${name}" disabled.`;
|
|
22826
23067
|
}
|
|
22827
|
-
var GLOBAL_CONFIG_PATH =
|
|
23068
|
+
var GLOBAL_CONFIG_PATH = import_path46.default.join(import_os40.default.homedir(), ".node9", "config.json");
|
|
22828
23069
|
var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
|
|
22829
23070
|
function readGlobalConfigRaw() {
|
|
22830
23071
|
try {
|
|
22831
|
-
if (
|
|
22832
|
-
return JSON.parse(
|
|
23072
|
+
if (import_fs44.default.existsSync(GLOBAL_CONFIG_PATH)) {
|
|
23073
|
+
return JSON.parse(import_fs44.default.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
|
|
22833
23074
|
}
|
|
22834
23075
|
} catch {
|
|
22835
23076
|
}
|
|
22836
23077
|
return {};
|
|
22837
23078
|
}
|
|
22838
23079
|
function writeGlobalConfigRaw(data) {
|
|
22839
|
-
const dir =
|
|
22840
|
-
if (!
|
|
22841
|
-
|
|
23080
|
+
const dir = import_path46.default.dirname(GLOBAL_CONFIG_PATH);
|
|
23081
|
+
if (!import_fs44.default.existsSync(dir)) import_fs44.default.mkdirSync(dir, { recursive: true });
|
|
23082
|
+
import_fs44.default.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
|
|
22842
23083
|
}
|
|
22843
23084
|
function handleApproverList() {
|
|
22844
23085
|
const config = getConfig();
|
|
@@ -22882,9 +23123,9 @@ function handleApproverSet(args) {
|
|
|
22882
23123
|
function handleAuditGet(args) {
|
|
22883
23124
|
const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
|
|
22884
23125
|
const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
|
|
22885
|
-
const auditPath =
|
|
22886
|
-
if (!
|
|
22887
|
-
const rawLines =
|
|
23126
|
+
const auditPath = import_path46.default.join(import_os40.default.homedir(), ".node9", "audit.log");
|
|
23127
|
+
if (!import_fs44.default.existsSync(auditPath)) return "No audit log found.";
|
|
23128
|
+
const rawLines = import_fs44.default.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
|
|
22888
23129
|
const parsed = [];
|
|
22889
23130
|
for (const line of rawLines) {
|
|
22890
23131
|
try {
|
|
@@ -23219,7 +23460,7 @@ function registerTrustCommand(program2) {
|
|
|
23219
23460
|
// src/cli/commands/mcp-pin.ts
|
|
23220
23461
|
var import_chalk21 = __toESM(require("chalk"));
|
|
23221
23462
|
init_mcp_pin();
|
|
23222
|
-
var
|
|
23463
|
+
var import_fs45 = __toESM(require("fs"));
|
|
23223
23464
|
function registerMcpPinCommand(program2) {
|
|
23224
23465
|
const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
|
|
23225
23466
|
const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
|
|
@@ -23230,7 +23471,7 @@ function registerMcpPinCommand(program2) {
|
|
|
23230
23471
|
let repoCorrupt = false;
|
|
23231
23472
|
if (found.source === "repo") {
|
|
23232
23473
|
try {
|
|
23233
|
-
const raw =
|
|
23474
|
+
const raw = import_fs45.default.readFileSync(found.path, "utf-8");
|
|
23234
23475
|
const parsed = JSON.parse(raw);
|
|
23235
23476
|
repoEntries = parsed.servers ?? {};
|
|
23236
23477
|
} catch {
|
|
@@ -23543,9 +23784,9 @@ init_scan();
|
|
|
23543
23784
|
|
|
23544
23785
|
// src/cli/commands/sessions.ts
|
|
23545
23786
|
var import_chalk24 = __toESM(require("chalk"));
|
|
23546
|
-
var
|
|
23547
|
-
var
|
|
23548
|
-
var
|
|
23787
|
+
var import_fs46 = __toESM(require("fs"));
|
|
23788
|
+
var import_path47 = __toESM(require("path"));
|
|
23789
|
+
var import_os41 = __toESM(require("os"));
|
|
23549
23790
|
init_scan_summary();
|
|
23550
23791
|
init_litellm();
|
|
23551
23792
|
init_cost_gemini();
|
|
@@ -23566,10 +23807,10 @@ function encodeProjectPath(projectPath) {
|
|
|
23566
23807
|
}
|
|
23567
23808
|
function sessionJsonlPath(projectPath, sessionId) {
|
|
23568
23809
|
const encoded = encodeProjectPath(projectPath);
|
|
23569
|
-
return
|
|
23810
|
+
return import_path47.default.join(import_os41.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
|
|
23570
23811
|
}
|
|
23571
23812
|
function projectLabel(projectPath) {
|
|
23572
|
-
return projectPath.replace(
|
|
23813
|
+
return projectPath.replace(import_os41.default.homedir(), "~");
|
|
23573
23814
|
}
|
|
23574
23815
|
function parseHistoryLines(lines) {
|
|
23575
23816
|
const entries = [];
|
|
@@ -23638,10 +23879,10 @@ function parseSessionLines(lines) {
|
|
|
23638
23879
|
return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
|
|
23639
23880
|
}
|
|
23640
23881
|
function loadAuditEntries(auditPath) {
|
|
23641
|
-
const aPath = auditPath ??
|
|
23882
|
+
const aPath = auditPath ?? import_path47.default.join(import_os41.default.homedir(), ".node9", "audit.log");
|
|
23642
23883
|
let raw;
|
|
23643
23884
|
try {
|
|
23644
|
-
raw =
|
|
23885
|
+
raw = import_fs46.default.readFileSync(aPath, "utf-8");
|
|
23645
23886
|
} catch {
|
|
23646
23887
|
return [];
|
|
23647
23888
|
}
|
|
@@ -23677,8 +23918,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
23677
23918
|
return result;
|
|
23678
23919
|
}
|
|
23679
23920
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
23680
|
-
const tmpDir =
|
|
23681
|
-
if (!
|
|
23921
|
+
const tmpDir = import_path47.default.join(import_os41.default.homedir(), ".gemini", "tmp");
|
|
23922
|
+
if (!import_fs46.default.existsSync(tmpDir)) return [];
|
|
23682
23923
|
const cutoff = days !== null ? (() => {
|
|
23683
23924
|
const d = /* @__PURE__ */ new Date();
|
|
23684
23925
|
d.setDate(d.getDate() - days);
|
|
@@ -23687,35 +23928,35 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
23687
23928
|
})() : null;
|
|
23688
23929
|
let slugDirs;
|
|
23689
23930
|
try {
|
|
23690
|
-
slugDirs =
|
|
23931
|
+
slugDirs = import_fs46.default.readdirSync(tmpDir);
|
|
23691
23932
|
} catch {
|
|
23692
23933
|
return [];
|
|
23693
23934
|
}
|
|
23694
23935
|
const summaries = [];
|
|
23695
23936
|
for (const slug of slugDirs) {
|
|
23696
|
-
const slugPath =
|
|
23937
|
+
const slugPath = import_path47.default.join(tmpDir, slug);
|
|
23697
23938
|
try {
|
|
23698
|
-
if (!
|
|
23939
|
+
if (!import_fs46.default.statSync(slugPath).isDirectory()) continue;
|
|
23699
23940
|
} catch {
|
|
23700
23941
|
continue;
|
|
23701
23942
|
}
|
|
23702
|
-
let projectRoot =
|
|
23943
|
+
let projectRoot = import_path47.default.join(import_os41.default.homedir(), slug);
|
|
23703
23944
|
try {
|
|
23704
|
-
projectRoot =
|
|
23945
|
+
projectRoot = import_fs46.default.readFileSync(import_path47.default.join(slugPath, ".project_root"), "utf-8").trim();
|
|
23705
23946
|
} catch {
|
|
23706
23947
|
}
|
|
23707
|
-
const chatsDir =
|
|
23708
|
-
if (!
|
|
23948
|
+
const chatsDir = import_path47.default.join(slugPath, "chats");
|
|
23949
|
+
if (!import_fs46.default.existsSync(chatsDir)) continue;
|
|
23709
23950
|
let chatFiles;
|
|
23710
23951
|
try {
|
|
23711
|
-
chatFiles =
|
|
23952
|
+
chatFiles = import_fs46.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
23712
23953
|
} catch {
|
|
23713
23954
|
continue;
|
|
23714
23955
|
}
|
|
23715
23956
|
for (const chatFile of chatFiles) {
|
|
23716
23957
|
let raw;
|
|
23717
23958
|
try {
|
|
23718
|
-
raw =
|
|
23959
|
+
raw = import_fs46.default.readFileSync(import_path47.default.join(chatsDir, chatFile), "utf-8");
|
|
23719
23960
|
} catch {
|
|
23720
23961
|
continue;
|
|
23721
23962
|
}
|
|
@@ -23795,8 +24036,8 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
23795
24036
|
return summaries;
|
|
23796
24037
|
}
|
|
23797
24038
|
function buildCodexSessions(days, allAuditEntries) {
|
|
23798
|
-
const sessionsBase =
|
|
23799
|
-
if (!
|
|
24039
|
+
const sessionsBase = import_path47.default.join(import_os41.default.homedir(), ".codex", "sessions");
|
|
24040
|
+
if (!import_fs46.default.existsSync(sessionsBase)) return [];
|
|
23800
24041
|
const cutoff = days !== null ? (() => {
|
|
23801
24042
|
const d = /* @__PURE__ */ new Date();
|
|
23802
24043
|
d.setDate(d.getDate() - days);
|
|
@@ -23805,29 +24046,29 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
23805
24046
|
})() : null;
|
|
23806
24047
|
const jsonlFiles = [];
|
|
23807
24048
|
try {
|
|
23808
|
-
for (const year of
|
|
23809
|
-
const yearPath =
|
|
24049
|
+
for (const year of import_fs46.default.readdirSync(sessionsBase)) {
|
|
24050
|
+
const yearPath = import_path47.default.join(sessionsBase, year);
|
|
23810
24051
|
try {
|
|
23811
|
-
if (!
|
|
24052
|
+
if (!import_fs46.default.statSync(yearPath).isDirectory()) continue;
|
|
23812
24053
|
} catch {
|
|
23813
24054
|
continue;
|
|
23814
24055
|
}
|
|
23815
|
-
for (const month of
|
|
23816
|
-
const monthPath =
|
|
24056
|
+
for (const month of import_fs46.default.readdirSync(yearPath)) {
|
|
24057
|
+
const monthPath = import_path47.default.join(yearPath, month);
|
|
23817
24058
|
try {
|
|
23818
|
-
if (!
|
|
24059
|
+
if (!import_fs46.default.statSync(monthPath).isDirectory()) continue;
|
|
23819
24060
|
} catch {
|
|
23820
24061
|
continue;
|
|
23821
24062
|
}
|
|
23822
|
-
for (const day of
|
|
23823
|
-
const dayPath =
|
|
24063
|
+
for (const day of import_fs46.default.readdirSync(monthPath)) {
|
|
24064
|
+
const dayPath = import_path47.default.join(monthPath, day);
|
|
23824
24065
|
try {
|
|
23825
|
-
if (!
|
|
24066
|
+
if (!import_fs46.default.statSync(dayPath).isDirectory()) continue;
|
|
23826
24067
|
} catch {
|
|
23827
24068
|
continue;
|
|
23828
24069
|
}
|
|
23829
|
-
for (const file of
|
|
23830
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
24070
|
+
for (const file of import_fs46.default.readdirSync(dayPath)) {
|
|
24071
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path47.default.join(dayPath, file));
|
|
23831
24072
|
}
|
|
23832
24073
|
}
|
|
23833
24074
|
}
|
|
@@ -23839,7 +24080,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
23839
24080
|
for (const filePath of jsonlFiles) {
|
|
23840
24081
|
let lines;
|
|
23841
24082
|
try {
|
|
23842
|
-
lines =
|
|
24083
|
+
lines = import_fs46.default.readFileSync(filePath, "utf-8").split("\n");
|
|
23843
24084
|
} catch {
|
|
23844
24085
|
continue;
|
|
23845
24086
|
}
|
|
@@ -23925,10 +24166,10 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
23925
24166
|
return summaries;
|
|
23926
24167
|
}
|
|
23927
24168
|
function buildSessions(days, historyPath) {
|
|
23928
|
-
const hPath = historyPath ??
|
|
24169
|
+
const hPath = historyPath ?? import_path47.default.join(import_os41.default.homedir(), ".claude", "history.jsonl");
|
|
23929
24170
|
let historyRaw = "";
|
|
23930
24171
|
try {
|
|
23931
|
-
historyRaw =
|
|
24172
|
+
historyRaw = import_fs46.default.readFileSync(hPath, "utf-8");
|
|
23932
24173
|
} catch {
|
|
23933
24174
|
}
|
|
23934
24175
|
const cutoff = days !== null ? (() => {
|
|
@@ -23952,7 +24193,7 @@ function buildSessions(days, historyPath) {
|
|
|
23952
24193
|
const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
|
|
23953
24194
|
let sessionLines = [];
|
|
23954
24195
|
try {
|
|
23955
|
-
sessionLines =
|
|
24196
|
+
sessionLines = import_fs46.default.readFileSync(jsonlFile, "utf-8").split("\n");
|
|
23956
24197
|
} catch {
|
|
23957
24198
|
}
|
|
23958
24199
|
const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
|
|
@@ -24252,12 +24493,12 @@ function registerSessionsCommand(program2) {
|
|
|
24252
24493
|
|
|
24253
24494
|
// src/cli/commands/skill-pin.ts
|
|
24254
24495
|
var import_chalk25 = __toESM(require("chalk"));
|
|
24255
|
-
var
|
|
24256
|
-
var
|
|
24257
|
-
var
|
|
24496
|
+
var import_fs47 = __toESM(require("fs"));
|
|
24497
|
+
var import_os42 = __toESM(require("os"));
|
|
24498
|
+
var import_path48 = __toESM(require("path"));
|
|
24258
24499
|
function wipeSkillSessions() {
|
|
24259
24500
|
try {
|
|
24260
|
-
|
|
24501
|
+
import_fs47.default.rmSync(import_path48.default.join(import_os42.default.homedir(), ".node9", "skill-sessions"), {
|
|
24261
24502
|
recursive: true,
|
|
24262
24503
|
force: true
|
|
24263
24504
|
});
|
|
@@ -24339,15 +24580,15 @@ function registerSkillPinCommand(program2) {
|
|
|
24339
24580
|
}
|
|
24340
24581
|
|
|
24341
24582
|
// src/cli/commands/decisions.ts
|
|
24342
|
-
var
|
|
24343
|
-
var
|
|
24344
|
-
var
|
|
24583
|
+
var import_fs48 = __toESM(require("fs"));
|
|
24584
|
+
var import_os43 = __toESM(require("os"));
|
|
24585
|
+
var import_path49 = __toESM(require("path"));
|
|
24345
24586
|
var import_chalk26 = __toESM(require("chalk"));
|
|
24346
|
-
var DECISIONS_FILE2 =
|
|
24587
|
+
var DECISIONS_FILE2 = import_path49.default.join(import_os43.default.homedir(), ".node9", "decisions.json");
|
|
24347
24588
|
function readDecisions() {
|
|
24348
24589
|
try {
|
|
24349
|
-
if (!
|
|
24350
|
-
const raw =
|
|
24590
|
+
if (!import_fs48.default.existsSync(DECISIONS_FILE2)) return {};
|
|
24591
|
+
const raw = import_fs48.default.readFileSync(DECISIONS_FILE2, "utf-8");
|
|
24351
24592
|
const parsed = JSON.parse(raw);
|
|
24352
24593
|
const out = {};
|
|
24353
24594
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -24359,11 +24600,11 @@ function readDecisions() {
|
|
|
24359
24600
|
}
|
|
24360
24601
|
}
|
|
24361
24602
|
function writeDecisions(d) {
|
|
24362
|
-
const dir =
|
|
24363
|
-
if (!
|
|
24603
|
+
const dir = import_path49.default.dirname(DECISIONS_FILE2);
|
|
24604
|
+
if (!import_fs48.default.existsSync(dir)) import_fs48.default.mkdirSync(dir, { recursive: true });
|
|
24364
24605
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
24365
|
-
|
|
24366
|
-
|
|
24606
|
+
import_fs48.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
24607
|
+
import_fs48.default.renameSync(tmp, DECISIONS_FILE2);
|
|
24367
24608
|
}
|
|
24368
24609
|
function registerDecisionsCommand(program2) {
|
|
24369
24610
|
const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
|
|
@@ -24420,18 +24661,18 @@ Persistent decisions (${entries.length})
|
|
|
24420
24661
|
|
|
24421
24662
|
// src/cli/commands/dlp.ts
|
|
24422
24663
|
var import_chalk27 = __toESM(require("chalk"));
|
|
24423
|
-
var
|
|
24424
|
-
var
|
|
24425
|
-
var
|
|
24426
|
-
var AUDIT_LOG =
|
|
24427
|
-
var RESOLVED_FILE =
|
|
24664
|
+
var import_fs49 = __toESM(require("fs"));
|
|
24665
|
+
var import_path50 = __toESM(require("path"));
|
|
24666
|
+
var import_os44 = __toESM(require("os"));
|
|
24667
|
+
var AUDIT_LOG = import_path50.default.join(import_os44.default.homedir(), ".node9", "audit.log");
|
|
24668
|
+
var RESOLVED_FILE = import_path50.default.join(import_os44.default.homedir(), ".node9", "dlp-resolved.json");
|
|
24428
24669
|
var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
|
|
24429
24670
|
function stripAnsi(s) {
|
|
24430
24671
|
return s.replace(ANSI_RE, "");
|
|
24431
24672
|
}
|
|
24432
24673
|
function loadResolved() {
|
|
24433
24674
|
try {
|
|
24434
|
-
const raw = JSON.parse(
|
|
24675
|
+
const raw = JSON.parse(import_fs49.default.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
24435
24676
|
return new Set(raw);
|
|
24436
24677
|
} catch {
|
|
24437
24678
|
return /* @__PURE__ */ new Set();
|
|
@@ -24439,13 +24680,13 @@ function loadResolved() {
|
|
|
24439
24680
|
}
|
|
24440
24681
|
function saveResolved(resolved) {
|
|
24441
24682
|
try {
|
|
24442
|
-
|
|
24683
|
+
import_fs49.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
24443
24684
|
} catch {
|
|
24444
24685
|
}
|
|
24445
24686
|
}
|
|
24446
24687
|
function loadDlpFindings() {
|
|
24447
|
-
if (!
|
|
24448
|
-
return
|
|
24688
|
+
if (!import_fs49.default.existsSync(AUDIT_LOG)) return [];
|
|
24689
|
+
return import_fs49.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
24449
24690
|
if (!line.trim()) return [];
|
|
24450
24691
|
try {
|
|
24451
24692
|
const e = JSON.parse(line);
|
|
@@ -24543,15 +24784,15 @@ function registerDlpCommand(program2) {
|
|
|
24543
24784
|
|
|
24544
24785
|
// src/cli/commands/mask.ts
|
|
24545
24786
|
var import_chalk28 = __toESM(require("chalk"));
|
|
24546
|
-
var
|
|
24547
|
-
var
|
|
24548
|
-
var
|
|
24787
|
+
var import_fs50 = __toESM(require("fs"));
|
|
24788
|
+
var import_path51 = __toESM(require("path"));
|
|
24789
|
+
var import_os45 = __toESM(require("os"));
|
|
24549
24790
|
init_dlp();
|
|
24550
24791
|
function findJsonlFiles(dir) {
|
|
24551
24792
|
const results = [];
|
|
24552
|
-
if (!
|
|
24553
|
-
for (const entry of
|
|
24554
|
-
const full =
|
|
24793
|
+
if (!import_fs50.default.existsSync(dir)) return results;
|
|
24794
|
+
for (const entry of import_fs50.default.readdirSync(dir, { withFileTypes: true })) {
|
|
24795
|
+
const full = import_path51.default.join(dir, entry.name);
|
|
24555
24796
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
24556
24797
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
24557
24798
|
}
|
|
@@ -24594,7 +24835,7 @@ function redactJson(obj) {
|
|
|
24594
24835
|
function processFile(filePath, dryRun) {
|
|
24595
24836
|
let raw;
|
|
24596
24837
|
try {
|
|
24597
|
-
raw =
|
|
24838
|
+
raw = import_fs50.default.readFileSync(filePath, "utf-8");
|
|
24598
24839
|
} catch {
|
|
24599
24840
|
return { redactedLines: 0, patterns: [] };
|
|
24600
24841
|
}
|
|
@@ -24626,14 +24867,14 @@ function processFile(filePath, dryRun) {
|
|
|
24626
24867
|
}
|
|
24627
24868
|
}
|
|
24628
24869
|
if (!dryRun && redactedLines > 0) {
|
|
24629
|
-
|
|
24870
|
+
import_fs50.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
24630
24871
|
}
|
|
24631
24872
|
return { redactedLines, patterns };
|
|
24632
24873
|
}
|
|
24633
24874
|
function processJsonFile(filePath, dryRun) {
|
|
24634
24875
|
let raw;
|
|
24635
24876
|
try {
|
|
24636
|
-
raw =
|
|
24877
|
+
raw = import_fs50.default.readFileSync(filePath, "utf-8");
|
|
24637
24878
|
} catch {
|
|
24638
24879
|
return { redactedLines: 0, patterns: [] };
|
|
24639
24880
|
}
|
|
@@ -24646,15 +24887,15 @@ function processJsonFile(filePath, dryRun) {
|
|
|
24646
24887
|
const { value, modified, found } = redactJson(parsed);
|
|
24647
24888
|
if (!modified) return { redactedLines: 0, patterns: [] };
|
|
24648
24889
|
if (!dryRun) {
|
|
24649
|
-
|
|
24890
|
+
import_fs50.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
|
|
24650
24891
|
}
|
|
24651
24892
|
return { redactedLines: 1, patterns: found };
|
|
24652
24893
|
}
|
|
24653
24894
|
function findJsonFiles(dir) {
|
|
24654
24895
|
const results = [];
|
|
24655
|
-
if (!
|
|
24656
|
-
for (const entry of
|
|
24657
|
-
const full =
|
|
24896
|
+
if (!import_fs50.default.existsSync(dir)) return results;
|
|
24897
|
+
for (const entry of import_fs50.default.readdirSync(dir, { withFileTypes: true })) {
|
|
24898
|
+
const full = import_path51.default.join(dir, entry.name);
|
|
24658
24899
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
24659
24900
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
24660
24901
|
}
|
|
@@ -24663,9 +24904,9 @@ function findJsonFiles(dir) {
|
|
|
24663
24904
|
function registerMaskCommand(program2) {
|
|
24664
24905
|
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) => {
|
|
24665
24906
|
const dryRun = !!options.dryRun;
|
|
24666
|
-
const home =
|
|
24667
|
-
const claudeDir =
|
|
24668
|
-
const geminiDir =
|
|
24907
|
+
const home = import_os45.default.homedir();
|
|
24908
|
+
const claudeDir = import_path51.default.join(home, ".claude", "projects");
|
|
24909
|
+
const geminiDir = import_path51.default.join(home, ".gemini", "tmp");
|
|
24669
24910
|
const allFiles = [
|
|
24670
24911
|
...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
|
|
24671
24912
|
...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
|
|
@@ -24673,7 +24914,7 @@ function registerMaskCommand(program2) {
|
|
|
24673
24914
|
const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
24674
24915
|
const filtered = cutoff ? allFiles.filter((f) => {
|
|
24675
24916
|
try {
|
|
24676
|
-
return
|
|
24917
|
+
return import_fs50.default.statSync(f.path).mtime >= cutoff;
|
|
24677
24918
|
} catch {
|
|
24678
24919
|
return false;
|
|
24679
24920
|
}
|
|
@@ -24729,20 +24970,20 @@ function registerMaskCommand(program2) {
|
|
|
24729
24970
|
// src/cli.ts
|
|
24730
24971
|
init_blast();
|
|
24731
24972
|
var { version } = JSON.parse(
|
|
24732
|
-
|
|
24973
|
+
import_fs53.default.readFileSync(import_path54.default.join(__dirname, "../package.json"), "utf-8")
|
|
24733
24974
|
);
|
|
24734
24975
|
var program = new import_commander.Command();
|
|
24735
24976
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
24736
24977
|
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) => {
|
|
24737
24978
|
const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
|
|
24738
|
-
const credPath =
|
|
24739
|
-
if (!
|
|
24740
|
-
|
|
24979
|
+
const credPath = import_path54.default.join(import_os48.default.homedir(), ".node9", "credentials.json");
|
|
24980
|
+
if (!import_fs53.default.existsSync(import_path54.default.dirname(credPath)))
|
|
24981
|
+
import_fs53.default.mkdirSync(import_path54.default.dirname(credPath), { recursive: true });
|
|
24741
24982
|
const profileName = options.profile || "default";
|
|
24742
24983
|
let existingCreds = {};
|
|
24743
24984
|
try {
|
|
24744
|
-
if (
|
|
24745
|
-
const raw = JSON.parse(
|
|
24985
|
+
if (import_fs53.default.existsSync(credPath)) {
|
|
24986
|
+
const raw = JSON.parse(import_fs53.default.readFileSync(credPath, "utf-8"));
|
|
24746
24987
|
if (raw.apiKey) {
|
|
24747
24988
|
existingCreds = {
|
|
24748
24989
|
default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
|
|
@@ -24754,14 +24995,14 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
24754
24995
|
} catch {
|
|
24755
24996
|
}
|
|
24756
24997
|
existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
|
|
24757
|
-
|
|
24998
|
+
import_fs53.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
|
|
24758
24999
|
let effectiveCloud = null;
|
|
24759
25000
|
if (profileName === "default") {
|
|
24760
|
-
const configPath =
|
|
25001
|
+
const configPath = import_path54.default.join(import_os48.default.homedir(), ".node9", "config.json");
|
|
24761
25002
|
let config = {};
|
|
24762
25003
|
try {
|
|
24763
|
-
if (
|
|
24764
|
-
config = JSON.parse(
|
|
25004
|
+
if (import_fs53.default.existsSync(configPath))
|
|
25005
|
+
config = JSON.parse(import_fs53.default.readFileSync(configPath, "utf-8"));
|
|
24765
25006
|
} catch {
|
|
24766
25007
|
}
|
|
24767
25008
|
if (!config.settings || typeof config.settings !== "object") config.settings = {};
|
|
@@ -24776,9 +25017,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
24776
25017
|
approvers.cloud = false;
|
|
24777
25018
|
}
|
|
24778
25019
|
s.approvers = approvers;
|
|
24779
|
-
if (!
|
|
24780
|
-
|
|
24781
|
-
|
|
25020
|
+
if (!import_fs53.default.existsSync(import_path54.default.dirname(configPath)))
|
|
25021
|
+
import_fs53.default.mkdirSync(import_path54.default.dirname(configPath), { recursive: true });
|
|
25022
|
+
import_fs53.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
24782
25023
|
effectiveCloud = approvers.cloud === true;
|
|
24783
25024
|
}
|
|
24784
25025
|
if (options.profile && profileName !== "default") {
|
|
@@ -24937,15 +25178,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
24937
25178
|
}
|
|
24938
25179
|
}
|
|
24939
25180
|
if (options.purge) {
|
|
24940
|
-
const node9Dir =
|
|
24941
|
-
if (
|
|
25181
|
+
const node9Dir = import_path54.default.join(import_os48.default.homedir(), ".node9");
|
|
25182
|
+
if (import_fs53.default.existsSync(node9Dir)) {
|
|
24942
25183
|
const confirmed = await (0, import_prompts2.confirm)({
|
|
24943
25184
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
24944
25185
|
default: false
|
|
24945
25186
|
});
|
|
24946
25187
|
if (confirmed) {
|
|
24947
|
-
|
|
24948
|
-
if (
|
|
25188
|
+
import_fs53.default.rmSync(node9Dir, { recursive: true });
|
|
25189
|
+
if (import_fs53.default.existsSync(node9Dir)) {
|
|
24949
25190
|
console.error(
|
|
24950
25191
|
import_chalk30.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
24951
25192
|
);
|
|
@@ -25060,7 +25301,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
|
|
|
25060
25301
|
});
|
|
25061
25302
|
program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
|
|
25062
25303
|
try {
|
|
25063
|
-
const dashboardPath =
|
|
25304
|
+
const dashboardPath = import_path54.default.join(__dirname, "dashboard.mjs");
|
|
25064
25305
|
const dynamicImport = new Function("id", "return import(id)");
|
|
25065
25306
|
const mod = await dynamicImport(`file://${dashboardPath}`);
|
|
25066
25307
|
await mod.startMonitor();
|
|
@@ -25098,14 +25339,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
|
|
|
25098
25339
|
Run "node9 addto claude" to register it as the statusLine.`
|
|
25099
25340
|
).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
|
|
25100
25341
|
if (subcommand === "debug") {
|
|
25101
|
-
const flagFile =
|
|
25342
|
+
const flagFile = import_path54.default.join(import_os48.default.homedir(), ".node9", "hud-debug");
|
|
25102
25343
|
if (state === "on") {
|
|
25103
|
-
|
|
25104
|
-
|
|
25344
|
+
import_fs53.default.mkdirSync(import_path54.default.dirname(flagFile), { recursive: true });
|
|
25345
|
+
import_fs53.default.writeFileSync(flagFile, "");
|
|
25105
25346
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
25106
25347
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
25107
25348
|
} else if (state === "off") {
|
|
25108
|
-
if (
|
|
25349
|
+
if (import_fs53.default.existsSync(flagFile)) import_fs53.default.unlinkSync(flagFile);
|
|
25109
25350
|
console.log("HUD debug logging disabled.");
|
|
25110
25351
|
} else {
|
|
25111
25352
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -25222,9 +25463,9 @@ if (process.argv[2] !== "daemon") {
|
|
|
25222
25463
|
const isCheckHook = process.argv[2] === "check";
|
|
25223
25464
|
if (isCheckHook) {
|
|
25224
25465
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
25225
|
-
const logPath =
|
|
25466
|
+
const logPath = import_path54.default.join(import_os48.default.homedir(), ".node9", "hook-debug.log");
|
|
25226
25467
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
25227
|
-
|
|
25468
|
+
import_fs53.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
25228
25469
|
`);
|
|
25229
25470
|
}
|
|
25230
25471
|
process.exit(0);
|