@node9/proxy 1.40.0 → 1.41.0
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 +631 -451
- package/dist/cli.mjs +629 -449
- package/dist/dashboard.mjs +5 -0
- package/dist/index.js +17 -1
- package/dist/index.mjs +17 -1
- 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 path62 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
210
|
+
return ` \u2022 ${path62}: ${issue.message}`;
|
|
211
211
|
});
|
|
212
212
|
return {
|
|
213
213
|
sanitized,
|
|
@@ -293,6 +293,11 @@ var init_config_schema = __esm({
|
|
|
293
293
|
allowGlobalPause: import_zod.z.boolean().optional(),
|
|
294
294
|
auditHashArgs: import_zod.z.boolean().optional(),
|
|
295
295
|
agentPolicy: import_zod.z.enum(["require_approval", "block_on_rules"]).optional(),
|
|
296
|
+
// Where a `review` verdict's prompt is rendered: 'ask' = the agent's own
|
|
297
|
+
// inline approve/deny prompt (Claude Code / GitHub Copilot); 'approver' =
|
|
298
|
+
// node9's own approver (terminal/native/cloud). Unset → smart default
|
|
299
|
+
// (ask for ask-capable agents unless a cloud approver is configured).
|
|
300
|
+
reviewChannel: import_zod.z.enum(["ask", "approver"]).optional(),
|
|
296
301
|
cloudSyncIntervalHours: import_zod.z.number().positive().optional(),
|
|
297
302
|
// Outbox shipper (audit.log → SaaS batch ingest). enabled defaults
|
|
298
303
|
// to true; set false to fall back to local-only auditing.
|
|
@@ -1274,9 +1279,9 @@ function matchesPattern(text, patterns) {
|
|
|
1274
1279
|
const withoutDotSlash = text.replace(/^\.\//, "");
|
|
1275
1280
|
return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
|
|
1276
1281
|
}
|
|
1277
|
-
function getNestedValue(obj,
|
|
1282
|
+
function getNestedValue(obj, path62) {
|
|
1278
1283
|
if (!obj || typeof obj !== "object") return null;
|
|
1279
|
-
const segments =
|
|
1284
|
+
const segments = path62.split(".");
|
|
1280
1285
|
for (const seg of segments) {
|
|
1281
1286
|
if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
|
|
1282
1287
|
}
|
|
@@ -4197,6 +4202,7 @@ function getConfig(cwd) {
|
|
|
4197
4202
|
if (s.approvalTimeoutSeconds !== void 0 && s.approvalTimeoutMs === void 0)
|
|
4198
4203
|
mergedSettings.approvalTimeoutMs = s.approvalTimeoutSeconds * 1e3;
|
|
4199
4204
|
if (s.environment !== void 0) mergedSettings.environment = s.environment;
|
|
4205
|
+
if (s.reviewChannel !== void 0) mergedSettings.reviewChannel = s.reviewChannel;
|
|
4200
4206
|
if (s.cloudSyncIntervalHours !== void 0)
|
|
4201
4207
|
mergedSettings.cloudSyncIntervalHours = s.cloudSyncIntervalHours;
|
|
4202
4208
|
if (s.hud !== void 0) mergedSettings.hud = { ...mergedSettings.hud, ...s.hud };
|
|
@@ -6353,7 +6359,7 @@ async function authorizeHeadless(toolName, args, meta, options) {
|
|
|
6353
6359
|
tool: toolName,
|
|
6354
6360
|
args,
|
|
6355
6361
|
ts: actTs,
|
|
6356
|
-
status: result.approved ? "allow" : result.blockedByLabel?.includes("DLP") ? "dlp" : result.blockedByLabel?.includes("Taint") ? "taint" : "block",
|
|
6362
|
+
status: result.review ? "review" : result.approved ? "allow" : result.blockedByLabel?.includes("DLP") ? "dlp" : result.blockedByLabel?.includes("Taint") ? "taint" : "block",
|
|
6357
6363
|
label: result.blockedByLabel,
|
|
6358
6364
|
ruleHit: result.ruleHit,
|
|
6359
6365
|
observeWouldBlock: result.observeWouldBlock,
|
|
@@ -6716,6 +6722,16 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
|
|
|
6716
6722
|
taintWarning
|
|
6717
6723
|
);
|
|
6718
6724
|
}
|
|
6725
|
+
const cloudEnforcedForDefer = approvers.cloud && !!creds?.apiKey;
|
|
6726
|
+
if (options?.deferReview && !taintWarning && !cloudEnforcedForDefer) {
|
|
6727
|
+
return {
|
|
6728
|
+
approved: false,
|
|
6729
|
+
review: true,
|
|
6730
|
+
reason: explainableLabel || "Node9 flagged this action for review.",
|
|
6731
|
+
ruleDescription: policyRuleDescription,
|
|
6732
|
+
blockedByLabel: explainableLabel
|
|
6733
|
+
};
|
|
6734
|
+
}
|
|
6719
6735
|
let cloudRequestId = null;
|
|
6720
6736
|
const cloudEnforced = approvers.cloud && !!creds?.apiKey;
|
|
6721
6737
|
const forceReview = localSmartRuleMatched === true || options?.localSmartRuleMatched === true || void 0;
|
|
@@ -7522,6 +7538,18 @@ function removeNode9McpServer(servers) {
|
|
|
7522
7538
|
function printDaemonTip() {
|
|
7523
7539
|
console.log(import_chalk.default.cyan("\n \u{1F4A1} Node9 will protect you automatically using Native OS popups."));
|
|
7524
7540
|
}
|
|
7541
|
+
function printInlineAskNotice() {
|
|
7542
|
+
console.log(
|
|
7543
|
+
import_chalk.default.cyan(
|
|
7544
|
+
" \u{1F4AC} Review prompts appear inline in your agent (approve/deny in the chat) by default."
|
|
7545
|
+
)
|
|
7546
|
+
);
|
|
7547
|
+
console.log(
|
|
7548
|
+
import_chalk.default.gray(
|
|
7549
|
+
' Prefer node9\u2019s own approver? Set "reviewChannel": "approver" in config, or add --no-ask to the hook.\n (Inline prompts are auto-disabled when a cloud approver is configured.)'
|
|
7550
|
+
)
|
|
7551
|
+
);
|
|
7552
|
+
}
|
|
7525
7553
|
function fullPathCommand(subcommand) {
|
|
7526
7554
|
if (process.env.NODE9_TESTING === "1") return `node9 ${subcommand}`;
|
|
7527
7555
|
const nodeExec = toForwardSlashes(process.execPath);
|
|
@@ -7846,6 +7874,7 @@ async function setupClaude() {
|
|
|
7846
7874
|
console.log(import_chalk.default.green.bold("\u{1F6E1}\uFE0F Node9 is now protecting Claude Code!"));
|
|
7847
7875
|
console.log(import_chalk.default.gray(" Restart Claude Code for changes to take effect."));
|
|
7848
7876
|
printDaemonTip();
|
|
7877
|
+
printInlineAskNotice();
|
|
7849
7878
|
}
|
|
7850
7879
|
}
|
|
7851
7880
|
async function setupGemini() {
|
|
@@ -8242,6 +8271,7 @@ async function setupCopilot() {
|
|
|
8242
8271
|
console.log(import_chalk.default.green.bold("\u{1F6E1}\uFE0F Node9 is now protecting GitHub Copilot CLI!"));
|
|
8243
8272
|
console.log(import_chalk.default.gray(" Restart Copilot CLI for changes to take effect."));
|
|
8244
8273
|
printDaemonTip();
|
|
8274
|
+
printInlineAskNotice();
|
|
8245
8275
|
}
|
|
8246
8276
|
function teardownCopilot() {
|
|
8247
8277
|
const homeDir2 = import_os12.default.homedir();
|
|
@@ -15532,8 +15562,8 @@ function fileSignature(filePath) {
|
|
|
15532
15562
|
const fd = import_fs27.default.openSync(filePath, "r");
|
|
15533
15563
|
try {
|
|
15534
15564
|
const buf = Buffer.alloc(512);
|
|
15535
|
-
const
|
|
15536
|
-
const slice = buf.subarray(0,
|
|
15565
|
+
const read2 = import_fs27.default.readSync(fd, buf, 0, 512, 0);
|
|
15566
|
+
const slice = buf.subarray(0, read2);
|
|
15537
15567
|
const nl = slice.indexOf(10);
|
|
15538
15568
|
const firstLine = nl === -1 ? slice : slice.subarray(0, nl);
|
|
15539
15569
|
return import_crypto9.default.createHash("sha256").update(firstLine).digest("hex").slice(0, 16);
|
|
@@ -15637,13 +15667,13 @@ async function shipOnce(deps = {}) {
|
|
|
15637
15667
|
const toRead = Math.min(size - offset, MAX_CHUNK_BYTES);
|
|
15638
15668
|
const buf = Buffer.alloc(toRead);
|
|
15639
15669
|
const fd = import_fs27.default.openSync(auditLogPath, "r");
|
|
15640
|
-
let
|
|
15670
|
+
let read2;
|
|
15641
15671
|
try {
|
|
15642
|
-
|
|
15672
|
+
read2 = import_fs27.default.readSync(fd, buf, 0, toRead, offset);
|
|
15643
15673
|
} finally {
|
|
15644
15674
|
import_fs27.default.closeSync(fd);
|
|
15645
15675
|
}
|
|
15646
|
-
const { rows, consumed } = buildWireRows(buf.subarray(0,
|
|
15676
|
+
const { rows, consumed } = buildWireRows(buf.subarray(0, read2));
|
|
15647
15677
|
if (consumed === 0) break;
|
|
15648
15678
|
for (let i = 0; i < rows.length; i += MAX_BATCH) {
|
|
15649
15679
|
const batch = rows.slice(i, i + MAX_BATCH);
|
|
@@ -17246,20 +17276,20 @@ function getModelContextLimit(model) {
|
|
|
17246
17276
|
return 2e5;
|
|
17247
17277
|
}
|
|
17248
17278
|
function readSessionUsage() {
|
|
17249
|
-
const projectsDir =
|
|
17250
|
-
if (!
|
|
17279
|
+
const projectsDir = import_path59.default.join(import_os53.default.homedir(), ".claude", "projects");
|
|
17280
|
+
if (!import_fs61.default.existsSync(projectsDir)) return null;
|
|
17251
17281
|
let latestFile = null;
|
|
17252
17282
|
let latestMtime = 0;
|
|
17253
17283
|
try {
|
|
17254
|
-
for (const dir of
|
|
17255
|
-
const dirPath =
|
|
17284
|
+
for (const dir of import_fs61.default.readdirSync(projectsDir)) {
|
|
17285
|
+
const dirPath = import_path59.default.join(projectsDir, dir);
|
|
17256
17286
|
try {
|
|
17257
|
-
if (!
|
|
17258
|
-
for (const file of
|
|
17287
|
+
if (!import_fs61.default.statSync(dirPath).isDirectory()) continue;
|
|
17288
|
+
for (const file of import_fs61.default.readdirSync(dirPath)) {
|
|
17259
17289
|
if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
|
|
17260
|
-
const filePath =
|
|
17290
|
+
const filePath = import_path59.default.join(dirPath, file);
|
|
17261
17291
|
try {
|
|
17262
|
-
const mtime =
|
|
17292
|
+
const mtime = import_fs61.default.statSync(filePath).mtimeMs;
|
|
17263
17293
|
if (mtime > latestMtime) {
|
|
17264
17294
|
latestMtime = mtime;
|
|
17265
17295
|
latestFile = filePath;
|
|
@@ -17274,7 +17304,7 @@ function readSessionUsage() {
|
|
|
17274
17304
|
}
|
|
17275
17305
|
if (!latestFile) return null;
|
|
17276
17306
|
try {
|
|
17277
|
-
const lines =
|
|
17307
|
+
const lines = import_fs61.default.readFileSync(latestFile, "utf-8").split("\n");
|
|
17278
17308
|
let lastModel = "";
|
|
17279
17309
|
let lastInput = 0;
|
|
17280
17310
|
let lastOutput = 0;
|
|
@@ -17335,7 +17365,7 @@ function formatBase(activity) {
|
|
|
17335
17365
|
const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
|
|
17336
17366
|
const icon = getIcon(activity.tool);
|
|
17337
17367
|
const toolName = activity.tool.slice(0, 16).padEnd(16);
|
|
17338
|
-
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(
|
|
17368
|
+
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os53.default.homedir(), "~");
|
|
17339
17369
|
const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
|
|
17340
17370
|
return `${import_chalk34.default.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${import_chalk34.default.white.bold(toolName)} ${import_chalk34.default.dim(argsPreview)}`;
|
|
17341
17371
|
}
|
|
@@ -17374,9 +17404,9 @@ function renderPending(activity) {
|
|
|
17374
17404
|
}
|
|
17375
17405
|
async function ensureDaemon() {
|
|
17376
17406
|
let pidPort = null;
|
|
17377
|
-
if (
|
|
17407
|
+
if (import_fs61.default.existsSync(PID_FILE)) {
|
|
17378
17408
|
try {
|
|
17379
|
-
const { port } = JSON.parse(
|
|
17409
|
+
const { port } = JSON.parse(import_fs61.default.readFileSync(PID_FILE, "utf-8"));
|
|
17380
17410
|
pidPort = port;
|
|
17381
17411
|
} catch {
|
|
17382
17412
|
console.error(import_chalk34.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
@@ -17532,9 +17562,9 @@ function buildRecoveryCardLines(req) {
|
|
|
17532
17562
|
];
|
|
17533
17563
|
}
|
|
17534
17564
|
function readApproversFromDisk() {
|
|
17535
|
-
const configPath2 =
|
|
17565
|
+
const configPath2 = import_path59.default.join(import_os53.default.homedir(), ".node9", "config.json");
|
|
17536
17566
|
try {
|
|
17537
|
-
const raw = JSON.parse(
|
|
17567
|
+
const raw = JSON.parse(import_fs61.default.readFileSync(configPath2, "utf-8"));
|
|
17538
17568
|
const settings = raw.settings ?? {};
|
|
17539
17569
|
return settings.approvers ?? {};
|
|
17540
17570
|
} catch {
|
|
@@ -17550,15 +17580,15 @@ function approverStatusLine() {
|
|
|
17550
17580
|
return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
|
|
17551
17581
|
}
|
|
17552
17582
|
function toggleApprover(channel) {
|
|
17553
|
-
const configPath2 =
|
|
17583
|
+
const configPath2 = import_path59.default.join(import_os53.default.homedir(), ".node9", "config.json");
|
|
17554
17584
|
try {
|
|
17555
|
-
const raw = JSON.parse(
|
|
17585
|
+
const raw = JSON.parse(import_fs61.default.readFileSync(configPath2, "utf-8"));
|
|
17556
17586
|
const settings = raw.settings ?? {};
|
|
17557
17587
|
const approvers = settings.approvers ?? {};
|
|
17558
17588
|
approvers[channel] = approvers[channel] === false;
|
|
17559
17589
|
settings.approvers = approvers;
|
|
17560
17590
|
raw.settings = settings;
|
|
17561
|
-
|
|
17591
|
+
import_fs61.default.writeFileSync(configPath2, JSON.stringify(raw, null, 2) + "\n");
|
|
17562
17592
|
} catch (err2) {
|
|
17563
17593
|
process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
|
|
17564
17594
|
`);
|
|
@@ -17730,8 +17760,8 @@ async function startTail(options = {}) {
|
|
|
17730
17760
|
}
|
|
17731
17761
|
postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
|
|
17732
17762
|
try {
|
|
17733
|
-
|
|
17734
|
-
|
|
17763
|
+
import_fs61.default.appendFileSync(
|
|
17764
|
+
import_path59.default.join(import_os53.default.homedir(), ".node9", "hook-debug.log"),
|
|
17735
17765
|
`[tail] POST /decision failed: ${String(err2)}
|
|
17736
17766
|
`
|
|
17737
17767
|
);
|
|
@@ -17795,9 +17825,9 @@ async function startTail(options = {}) {
|
|
|
17795
17825
|
};
|
|
17796
17826
|
process.stdin.on("keypress", onKeypress);
|
|
17797
17827
|
}
|
|
17798
|
-
const auditLog =
|
|
17828
|
+
const auditLog = import_path59.default.join(import_os53.default.homedir(), ".node9", "audit.log");
|
|
17799
17829
|
try {
|
|
17800
|
-
const unackedDlp =
|
|
17830
|
+
const unackedDlp = import_fs61.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
17801
17831
|
if (unackedDlp > 0) {
|
|
17802
17832
|
console.log("");
|
|
17803
17833
|
console.log(
|
|
@@ -17837,7 +17867,7 @@ async function startTail(options = {}) {
|
|
|
17837
17867
|
if (stallWarned) return;
|
|
17838
17868
|
if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
|
|
17839
17869
|
try {
|
|
17840
|
-
const auditMtime =
|
|
17870
|
+
const auditMtime = import_fs61.default.statSync(auditLog).mtimeMs;
|
|
17841
17871
|
if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
|
|
17842
17872
|
console.log("");
|
|
17843
17873
|
console.log(
|
|
@@ -18022,20 +18052,20 @@ async function startTail(options = {}) {
|
|
|
18022
18052
|
process.exit(1);
|
|
18023
18053
|
});
|
|
18024
18054
|
}
|
|
18025
|
-
var import_http3, import_chalk34,
|
|
18055
|
+
var import_http3, import_chalk34, import_fs61, import_os53, import_path59, import_readline6, import_child_process14, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
|
|
18026
18056
|
var init_tail = __esm({
|
|
18027
18057
|
"src/tui/tail.ts"() {
|
|
18028
18058
|
"use strict";
|
|
18029
18059
|
import_http3 = __toESM(require("http"));
|
|
18030
18060
|
import_chalk34 = __toESM(require("chalk"));
|
|
18031
|
-
|
|
18032
|
-
|
|
18033
|
-
|
|
18061
|
+
import_fs61 = __toESM(require("fs"));
|
|
18062
|
+
import_os53 = __toESM(require("os"));
|
|
18063
|
+
import_path59 = __toESM(require("path"));
|
|
18034
18064
|
import_readline6 = __toESM(require("readline"));
|
|
18035
18065
|
import_child_process14 = require("child_process");
|
|
18036
18066
|
init_daemon2();
|
|
18037
18067
|
init_daemon();
|
|
18038
|
-
PID_FILE =
|
|
18068
|
+
PID_FILE = import_path59.default.join(import_os53.default.homedir(), ".node9", "daemon.pid");
|
|
18039
18069
|
ICONS = {
|
|
18040
18070
|
bash: "\u{1F4BB}",
|
|
18041
18071
|
shell: "\u{1F4BB}",
|
|
@@ -18157,9 +18187,9 @@ function formatTimeLeft(resetsAt) {
|
|
|
18157
18187
|
return ` (${m}m left)`;
|
|
18158
18188
|
}
|
|
18159
18189
|
function safeReadJson(filePath) {
|
|
18160
|
-
if (!
|
|
18190
|
+
if (!import_fs62.default.existsSync(filePath)) return null;
|
|
18161
18191
|
try {
|
|
18162
|
-
return JSON.parse(
|
|
18192
|
+
return JSON.parse(import_fs62.default.readFileSync(filePath, "utf-8"));
|
|
18163
18193
|
} catch {
|
|
18164
18194
|
return null;
|
|
18165
18195
|
}
|
|
@@ -18180,12 +18210,12 @@ function countHooksInFile(filePath) {
|
|
|
18180
18210
|
return Object.keys(cfg.hooks).length;
|
|
18181
18211
|
}
|
|
18182
18212
|
function countRulesInDir(rulesDir) {
|
|
18183
|
-
if (!
|
|
18213
|
+
if (!import_fs62.default.existsSync(rulesDir)) return 0;
|
|
18184
18214
|
let count = 0;
|
|
18185
18215
|
try {
|
|
18186
|
-
for (const entry of
|
|
18216
|
+
for (const entry of import_fs62.default.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
18187
18217
|
if (entry.isDirectory()) {
|
|
18188
|
-
count += countRulesInDir(
|
|
18218
|
+
count += countRulesInDir(import_path60.default.join(rulesDir, entry.name));
|
|
18189
18219
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
18190
18220
|
count++;
|
|
18191
18221
|
}
|
|
@@ -18196,46 +18226,46 @@ function countRulesInDir(rulesDir) {
|
|
|
18196
18226
|
}
|
|
18197
18227
|
function isSamePath(a, b) {
|
|
18198
18228
|
try {
|
|
18199
|
-
return
|
|
18229
|
+
return import_path60.default.resolve(a) === import_path60.default.resolve(b);
|
|
18200
18230
|
} catch {
|
|
18201
18231
|
return false;
|
|
18202
18232
|
}
|
|
18203
18233
|
}
|
|
18204
18234
|
function countConfigs(cwd) {
|
|
18205
|
-
const homeDir2 =
|
|
18206
|
-
const claudeDir =
|
|
18235
|
+
const homeDir2 = import_os54.default.homedir();
|
|
18236
|
+
const claudeDir = import_path60.default.join(homeDir2, ".claude");
|
|
18207
18237
|
let claudeMdCount = 0;
|
|
18208
18238
|
let rulesCount = 0;
|
|
18209
18239
|
let hooksCount = 0;
|
|
18210
18240
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
18211
18241
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
18212
|
-
if (
|
|
18213
|
-
rulesCount += countRulesInDir(
|
|
18214
|
-
const userSettings =
|
|
18242
|
+
if (import_fs62.default.existsSync(import_path60.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
18243
|
+
rulesCount += countRulesInDir(import_path60.default.join(claudeDir, "rules"));
|
|
18244
|
+
const userSettings = import_path60.default.join(claudeDir, "settings.json");
|
|
18215
18245
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
18216
18246
|
hooksCount += countHooksInFile(userSettings);
|
|
18217
|
-
const userClaudeJson =
|
|
18247
|
+
const userClaudeJson = import_path60.default.join(homeDir2, ".claude.json");
|
|
18218
18248
|
for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
|
|
18219
18249
|
for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
|
|
18220
18250
|
userMcpServers.delete(name);
|
|
18221
18251
|
}
|
|
18222
18252
|
if (cwd) {
|
|
18223
|
-
if (
|
|
18224
|
-
if (
|
|
18225
|
-
const projectClaudeDir =
|
|
18253
|
+
if (import_fs62.default.existsSync(import_path60.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
18254
|
+
if (import_fs62.default.existsSync(import_path60.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
18255
|
+
const projectClaudeDir = import_path60.default.join(cwd, ".claude");
|
|
18226
18256
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
18227
18257
|
if (!overlapsUserScope) {
|
|
18228
|
-
if (
|
|
18229
|
-
rulesCount += countRulesInDir(
|
|
18230
|
-
const projSettings =
|
|
18258
|
+
if (import_fs62.default.existsSync(import_path60.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
18259
|
+
rulesCount += countRulesInDir(import_path60.default.join(projectClaudeDir, "rules"));
|
|
18260
|
+
const projSettings = import_path60.default.join(projectClaudeDir, "settings.json");
|
|
18231
18261
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
18232
18262
|
hooksCount += countHooksInFile(projSettings);
|
|
18233
18263
|
}
|
|
18234
|
-
if (
|
|
18235
|
-
const localSettings =
|
|
18264
|
+
if (import_fs62.default.existsSync(import_path60.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
18265
|
+
const localSettings = import_path60.default.join(projectClaudeDir, "settings.local.json");
|
|
18236
18266
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
18237
18267
|
hooksCount += countHooksInFile(localSettings);
|
|
18238
|
-
const mcpJsonServers = getMcpServerNames(
|
|
18268
|
+
const mcpJsonServers = getMcpServerNames(import_path60.default.join(cwd, ".mcp.json"));
|
|
18239
18269
|
const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
|
|
18240
18270
|
for (const name of disabledMcpJson) mcpJsonServers.delete(name);
|
|
18241
18271
|
for (const name of mcpJsonServers) projectMcpServers.add(name);
|
|
@@ -18268,12 +18298,12 @@ function readActiveShieldsHud() {
|
|
|
18268
18298
|
return shieldsCache.value;
|
|
18269
18299
|
}
|
|
18270
18300
|
try {
|
|
18271
|
-
const shieldsPath =
|
|
18272
|
-
if (!
|
|
18301
|
+
const shieldsPath = import_path60.default.join(import_os54.default.homedir(), ".node9", "shields.json");
|
|
18302
|
+
if (!import_fs62.default.existsSync(shieldsPath)) {
|
|
18273
18303
|
shieldsCache = { value: [], ts: now };
|
|
18274
18304
|
return [];
|
|
18275
18305
|
}
|
|
18276
|
-
const parsed = JSON.parse(
|
|
18306
|
+
const parsed = JSON.parse(import_fs62.default.readFileSync(shieldsPath, "utf-8"));
|
|
18277
18307
|
if (!Array.isArray(parsed.active)) {
|
|
18278
18308
|
shieldsCache = { value: [], ts: now };
|
|
18279
18309
|
return [];
|
|
@@ -18375,17 +18405,17 @@ function renderContextLine(stdin) {
|
|
|
18375
18405
|
async function main() {
|
|
18376
18406
|
try {
|
|
18377
18407
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
18378
|
-
if (
|
|
18408
|
+
if (import_fs62.default.existsSync(import_path60.default.join(import_os54.default.homedir(), ".node9", "hud-debug"))) {
|
|
18379
18409
|
try {
|
|
18380
|
-
const logPath =
|
|
18410
|
+
const logPath = import_path60.default.join(import_os54.default.homedir(), ".node9", "hud-debug.log");
|
|
18381
18411
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
18382
18412
|
let size = 0;
|
|
18383
18413
|
try {
|
|
18384
|
-
size =
|
|
18414
|
+
size = import_fs62.default.statSync(logPath).size;
|
|
18385
18415
|
} catch {
|
|
18386
18416
|
}
|
|
18387
18417
|
if (size < MAX_LOG_SIZE) {
|
|
18388
|
-
|
|
18418
|
+
import_fs62.default.appendFileSync(
|
|
18389
18419
|
logPath,
|
|
18390
18420
|
JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
|
|
18391
18421
|
);
|
|
@@ -18406,11 +18436,11 @@ async function main() {
|
|
|
18406
18436
|
try {
|
|
18407
18437
|
const cwd = stdin.cwd ?? process.cwd();
|
|
18408
18438
|
for (const configPath2 of [
|
|
18409
|
-
|
|
18410
|
-
|
|
18439
|
+
import_path60.default.join(cwd, "node9.config.json"),
|
|
18440
|
+
import_path60.default.join(import_os54.default.homedir(), ".node9", "config.json")
|
|
18411
18441
|
]) {
|
|
18412
|
-
if (!
|
|
18413
|
-
const cfg = JSON.parse(
|
|
18442
|
+
if (!import_fs62.default.existsSync(configPath2)) continue;
|
|
18443
|
+
const cfg = JSON.parse(import_fs62.default.readFileSync(configPath2, "utf-8"));
|
|
18414
18444
|
const hud = cfg.settings?.hud;
|
|
18415
18445
|
if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
|
|
18416
18446
|
}
|
|
@@ -18428,13 +18458,13 @@ async function main() {
|
|
|
18428
18458
|
renderOffline();
|
|
18429
18459
|
}
|
|
18430
18460
|
}
|
|
18431
|
-
var
|
|
18461
|
+
var import_fs62, import_path60, import_os54, import_http4, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
|
|
18432
18462
|
var init_hud = __esm({
|
|
18433
18463
|
"src/cli/hud.ts"() {
|
|
18434
18464
|
"use strict";
|
|
18435
|
-
|
|
18436
|
-
|
|
18437
|
-
|
|
18465
|
+
import_fs62 = __toESM(require("fs"));
|
|
18466
|
+
import_path60 = __toESM(require("path"));
|
|
18467
|
+
import_os54 = __toESM(require("os"));
|
|
18438
18468
|
import_http4 = __toESM(require("http"));
|
|
18439
18469
|
init_daemon();
|
|
18440
18470
|
RESET3 = "\x1B[0m";
|
|
@@ -18461,9 +18491,9 @@ init_core();
|
|
|
18461
18491
|
init_setup();
|
|
18462
18492
|
init_daemon2();
|
|
18463
18493
|
var import_chalk35 = __toESM(require("chalk"));
|
|
18464
|
-
var
|
|
18465
|
-
var
|
|
18466
|
-
var
|
|
18494
|
+
var import_fs63 = __toESM(require("fs"));
|
|
18495
|
+
var import_path61 = __toESM(require("path"));
|
|
18496
|
+
var import_os55 = __toESM(require("os"));
|
|
18467
18497
|
var import_child_process15 = require("child_process");
|
|
18468
18498
|
var import_prompts2 = require("@inquirer/prompts");
|
|
18469
18499
|
|
|
@@ -18558,6 +18588,10 @@ INSTRUCTIONS:
|
|
|
18558
18588
|
- Do NOT retry this exact command or attempt to bypass the rule.${recovery}
|
|
18559
18589
|
- Inform the user which security rule was triggered and ask how to proceed.`;
|
|
18560
18590
|
}
|
|
18591
|
+
function buildReviewMessage(blockedByLabel, ruleDescription) {
|
|
18592
|
+
const why = ruleDescription || blockedByLabel || "this action needs your review";
|
|
18593
|
+
return `Node9 flagged this for your review: ${why}. Approve to proceed, or deny to cancel.`;
|
|
18594
|
+
}
|
|
18561
18595
|
|
|
18562
18596
|
// src/proxy/index.ts
|
|
18563
18597
|
function sanitize(value) {
|
|
@@ -18684,10 +18718,10 @@ async function autoStartDaemonAndWait() {
|
|
|
18684
18718
|
|
|
18685
18719
|
// src/cli/commands/check.ts
|
|
18686
18720
|
var import_chalk9 = __toESM(require("chalk"));
|
|
18687
|
-
var
|
|
18721
|
+
var import_fs37 = __toESM(require("fs"));
|
|
18688
18722
|
var import_child_process7 = require("child_process");
|
|
18689
|
-
var
|
|
18690
|
-
var
|
|
18723
|
+
var import_path38 = __toESM(require("path"));
|
|
18724
|
+
var import_os33 = __toESM(require("os"));
|
|
18691
18725
|
init_orchestrator();
|
|
18692
18726
|
init_daemon();
|
|
18693
18727
|
init_config();
|
|
@@ -19229,6 +19263,78 @@ function resolveUserSkillRoot(entry, cwd) {
|
|
|
19229
19263
|
// src/cli/commands/check.ts
|
|
19230
19264
|
init_dlp();
|
|
19231
19265
|
init_audit();
|
|
19266
|
+
|
|
19267
|
+
// src/review-pending.ts
|
|
19268
|
+
var import_fs36 = __toESM(require("fs"));
|
|
19269
|
+
var import_os32 = __toESM(require("os"));
|
|
19270
|
+
var import_path37 = __toESM(require("path"));
|
|
19271
|
+
init_hasher();
|
|
19272
|
+
function storePath() {
|
|
19273
|
+
return process.env.NODE9_PENDING_STORE || import_path37.default.join(import_os32.default.homedir(), ".node9", "pending-reviews.json");
|
|
19274
|
+
}
|
|
19275
|
+
var TTL_MS2 = 6 * 60 * 60 * 1e3;
|
|
19276
|
+
var MAX_ENTRIES = 500;
|
|
19277
|
+
function reviewCorrelationKey(payload) {
|
|
19278
|
+
if (typeof payload.tool_use_id === "string" && payload.tool_use_id) {
|
|
19279
|
+
return `tuid:${payload.tool_use_id}`;
|
|
19280
|
+
}
|
|
19281
|
+
const sid = payload.session_id ?? payload.conversationId;
|
|
19282
|
+
const tool = payload.tool_name;
|
|
19283
|
+
if (typeof sid === "string" && sid && typeof tool === "string" && tool) {
|
|
19284
|
+
return `h:${sid}|${tool}|${hashArgs(payload.tool_input)}`;
|
|
19285
|
+
}
|
|
19286
|
+
return null;
|
|
19287
|
+
}
|
|
19288
|
+
function read() {
|
|
19289
|
+
try {
|
|
19290
|
+
const parsed = JSON.parse(import_fs36.default.readFileSync(storePath(), "utf-8"));
|
|
19291
|
+
if (parsed && Array.isArray(parsed.entries)) return parsed;
|
|
19292
|
+
} catch {
|
|
19293
|
+
}
|
|
19294
|
+
return { entries: [] };
|
|
19295
|
+
}
|
|
19296
|
+
function write(store) {
|
|
19297
|
+
try {
|
|
19298
|
+
const p = storePath();
|
|
19299
|
+
const dir = import_path37.default.dirname(p);
|
|
19300
|
+
if (!import_fs36.default.existsSync(dir)) import_fs36.default.mkdirSync(dir, { recursive: true });
|
|
19301
|
+
const tmp = `${p}.${process.pid}.tmp`;
|
|
19302
|
+
import_fs36.default.writeFileSync(tmp, JSON.stringify(store));
|
|
19303
|
+
import_fs36.default.renameSync(tmp, p);
|
|
19304
|
+
} catch {
|
|
19305
|
+
}
|
|
19306
|
+
}
|
|
19307
|
+
function prune(entries, now) {
|
|
19308
|
+
const fresh = entries.filter((e) => now - e.ts < TTL_MS2);
|
|
19309
|
+
return fresh.length > MAX_ENTRIES ? fresh.slice(fresh.length - MAX_ENTRIES) : fresh;
|
|
19310
|
+
}
|
|
19311
|
+
function recordPendingReview(entry) {
|
|
19312
|
+
try {
|
|
19313
|
+
const store = read();
|
|
19314
|
+
store.entries = prune(store.entries, entry.ts);
|
|
19315
|
+
store.entries.push(entry);
|
|
19316
|
+
write(store);
|
|
19317
|
+
} catch {
|
|
19318
|
+
}
|
|
19319
|
+
}
|
|
19320
|
+
function resolvePendingReview(key, now = Date.now()) {
|
|
19321
|
+
try {
|
|
19322
|
+
const store = read();
|
|
19323
|
+
const idx = store.entries.findIndex((e) => e.key === key);
|
|
19324
|
+
if (idx === -1) {
|
|
19325
|
+
const pruned = prune(store.entries, now);
|
|
19326
|
+
if (pruned.length !== store.entries.length) write({ entries: pruned });
|
|
19327
|
+
return null;
|
|
19328
|
+
}
|
|
19329
|
+
const [match] = store.entries.splice(idx, 1);
|
|
19330
|
+
write({ entries: prune(store.entries, now) });
|
|
19331
|
+
return match;
|
|
19332
|
+
} catch {
|
|
19333
|
+
return null;
|
|
19334
|
+
}
|
|
19335
|
+
}
|
|
19336
|
+
|
|
19337
|
+
// src/cli/commands/check.ts
|
|
19232
19338
|
init_hook_payload();
|
|
19233
19339
|
function sanitize2(value) {
|
|
19234
19340
|
return value.replace(/[\x00-\x1F\x7F]/g, "");
|
|
@@ -19277,11 +19383,26 @@ function detectAiAgent(payload) {
|
|
|
19277
19383
|
}
|
|
19278
19384
|
return "Terminal";
|
|
19279
19385
|
}
|
|
19386
|
+
function agentSupportsAsk(agent) {
|
|
19387
|
+
return agent === "Claude Code" || agent === "GitHub Copilot";
|
|
19388
|
+
}
|
|
19389
|
+
function resolveAskMode(agent, opts, config) {
|
|
19390
|
+
if (!agentSupportsAsk(agent)) return false;
|
|
19391
|
+
if (config.settings.approvers.cloud === true) return false;
|
|
19392
|
+
if (opts.ask === true) return true;
|
|
19393
|
+
if (opts.ask === false) return false;
|
|
19394
|
+
if (config.settings.reviewChannel === "ask") return true;
|
|
19395
|
+
if (config.settings.reviewChannel === "approver") return false;
|
|
19396
|
+
return true;
|
|
19397
|
+
}
|
|
19280
19398
|
function registerCheckCommand(program2) {
|
|
19281
19399
|
program2.command("check", { hidden: true }).description("Hook handler \u2014 evaluates a tool call before execution").argument("[data]", "JSON string of the tool call").option(
|
|
19282
19400
|
"--agent <name>",
|
|
19283
19401
|
"Agent identity override, set by node9-authored hook registrations (e.g. antigravity)"
|
|
19284
|
-
).
|
|
19402
|
+
).option(
|
|
19403
|
+
"--ask",
|
|
19404
|
+
"Route review verdicts to the agent\u2019s native inline approve/deny prompt (Claude Code / GitHub Copilot only)"
|
|
19405
|
+
).option("--no-ask", "Force node9\u2019s own approver for review verdicts (override default-on)").action(async (data, opts) => {
|
|
19285
19406
|
const agentOverride = agentLabelFromFlag(opts?.agent);
|
|
19286
19407
|
const processPayload = async (raw) => {
|
|
19287
19408
|
try {
|
|
@@ -19292,9 +19413,9 @@ function registerCheckCommand(program2) {
|
|
|
19292
19413
|
} catch (err2) {
|
|
19293
19414
|
const tempConfig = getConfig();
|
|
19294
19415
|
if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
|
|
19295
|
-
const logPath =
|
|
19416
|
+
const logPath = import_path38.default.join(import_os33.default.homedir(), ".node9", "hook-debug.log");
|
|
19296
19417
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
19297
|
-
|
|
19418
|
+
import_fs37.default.appendFileSync(
|
|
19298
19419
|
logPath,
|
|
19299
19420
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
|
|
19300
19421
|
RAW: ${raw}
|
|
@@ -19307,14 +19428,14 @@ RAW: ${raw}
|
|
|
19307
19428
|
const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
|
|
19308
19429
|
if (process.env.NODE9_DEBUG === "1") {
|
|
19309
19430
|
try {
|
|
19310
|
-
const logPath =
|
|
19311
|
-
if (!
|
|
19312
|
-
|
|
19431
|
+
const logPath = import_path38.default.join(import_os33.default.homedir(), ".node9", "hook-debug.log");
|
|
19432
|
+
if (!import_fs37.default.existsSync(import_path38.default.dirname(logPath)))
|
|
19433
|
+
import_fs37.default.mkdirSync(import_path38.default.dirname(logPath), { recursive: true });
|
|
19313
19434
|
const sanitized = JSON.stringify({
|
|
19314
19435
|
...payload,
|
|
19315
19436
|
prompt: `<redacted, ${prompt.length} bytes>`
|
|
19316
19437
|
});
|
|
19317
|
-
|
|
19438
|
+
import_fs37.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
|
|
19318
19439
|
`);
|
|
19319
19440
|
} catch {
|
|
19320
19441
|
}
|
|
@@ -19334,8 +19455,8 @@ RAW: ${raw}
|
|
|
19334
19455
|
);
|
|
19335
19456
|
const reason = `\u{1F6A8} Node9 DLP: ${dlpMatch.patternName} detected in prompt (${dlpMatch.redactedSample}). Prompt was not submitted \u2014 remove the credential and try again.`;
|
|
19336
19457
|
try {
|
|
19337
|
-
const ttyFd =
|
|
19338
|
-
|
|
19458
|
+
const ttyFd = import_fs37.default.openSync("/dev/tty", "w");
|
|
19459
|
+
import_fs37.default.writeSync(
|
|
19339
19460
|
ttyFd,
|
|
19340
19461
|
import_chalk9.default.bgRed.white.bold(`
|
|
19341
19462
|
\u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
|
|
@@ -19345,7 +19466,7 @@ RAW: ${raw}
|
|
|
19345
19466
|
|
|
19346
19467
|
`)
|
|
19347
19468
|
);
|
|
19348
|
-
|
|
19469
|
+
import_fs37.default.closeSync(ttyFd);
|
|
19349
19470
|
} catch {
|
|
19350
19471
|
}
|
|
19351
19472
|
const isCodex = agent2 === "Codex";
|
|
@@ -19364,16 +19485,16 @@ RAW: ${raw}
|
|
|
19364
19485
|
process.exit(2);
|
|
19365
19486
|
}
|
|
19366
19487
|
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
19367
|
-
const safeCwdForConfig = typeof payloadCwd === "string" &&
|
|
19488
|
+
const safeCwdForConfig = typeof payloadCwd === "string" && import_path38.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
19368
19489
|
const config = getConfig(safeCwdForConfig);
|
|
19369
19490
|
if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
|
|
19370
19491
|
try {
|
|
19371
19492
|
const scriptPath = process.argv[1];
|
|
19372
|
-
if (typeof scriptPath !== "string" || !
|
|
19493
|
+
if (typeof scriptPath !== "string" || !import_path38.default.isAbsolute(scriptPath))
|
|
19373
19494
|
throw new Error("node9: argv[1] is not an absolute path");
|
|
19374
|
-
const resolvedScript =
|
|
19375
|
-
const packageDist =
|
|
19376
|
-
if (!resolvedScript.startsWith(packageDist +
|
|
19495
|
+
const resolvedScript = import_fs37.default.realpathSync(scriptPath);
|
|
19496
|
+
const packageDist = import_fs37.default.realpathSync(import_path38.default.resolve(__dirname, "../.."));
|
|
19497
|
+
if (!resolvedScript.startsWith(packageDist + import_path38.default.sep) && resolvedScript !== packageDist)
|
|
19377
19498
|
throw new Error(
|
|
19378
19499
|
`node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
|
|
19379
19500
|
);
|
|
@@ -19395,10 +19516,10 @@ RAW: ${raw}
|
|
|
19395
19516
|
});
|
|
19396
19517
|
d.unref();
|
|
19397
19518
|
} catch (spawnErr) {
|
|
19398
|
-
const logPath =
|
|
19519
|
+
const logPath = import_path38.default.join(import_os33.default.homedir(), ".node9", "hook-debug.log");
|
|
19399
19520
|
const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
|
|
19400
19521
|
try {
|
|
19401
|
-
|
|
19522
|
+
import_fs37.default.appendFileSync(
|
|
19402
19523
|
logPath,
|
|
19403
19524
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
|
|
19404
19525
|
`
|
|
@@ -19408,10 +19529,10 @@ RAW: ${raw}
|
|
|
19408
19529
|
}
|
|
19409
19530
|
}
|
|
19410
19531
|
if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
|
|
19411
|
-
const logPath =
|
|
19412
|
-
if (!
|
|
19413
|
-
|
|
19414
|
-
|
|
19532
|
+
const logPath = import_path38.default.join(import_os33.default.homedir(), ".node9", "hook-debug.log");
|
|
19533
|
+
if (!import_fs37.default.existsSync(import_path38.default.dirname(logPath)))
|
|
19534
|
+
import_fs37.default.mkdirSync(import_path38.default.dirname(logPath), { recursive: true });
|
|
19535
|
+
import_fs37.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
|
|
19415
19536
|
`);
|
|
19416
19537
|
}
|
|
19417
19538
|
const rawToolName = sanitize2(extractToolName(payload));
|
|
@@ -19425,8 +19546,8 @@ RAW: ${raw}
|
|
|
19425
19546
|
const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
|
|
19426
19547
|
let ttyFd = null;
|
|
19427
19548
|
try {
|
|
19428
|
-
ttyFd =
|
|
19429
|
-
const writeTty = (line) =>
|
|
19549
|
+
ttyFd = import_fs37.default.openSync("/dev/tty", "w");
|
|
19550
|
+
const writeTty = (line) => import_fs37.default.writeSync(ttyFd, line + "\n");
|
|
19430
19551
|
if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
|
|
19431
19552
|
writeTty(import_chalk9.default.bgRed.white.bold(`
|
|
19432
19553
|
\u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
|
|
@@ -19445,7 +19566,7 @@ RAW: ${raw}
|
|
|
19445
19566
|
} finally {
|
|
19446
19567
|
if (ttyFd !== null)
|
|
19447
19568
|
try {
|
|
19448
|
-
|
|
19569
|
+
import_fs37.default.closeSync(ttyFd);
|
|
19449
19570
|
} catch {
|
|
19450
19571
|
}
|
|
19451
19572
|
}
|
|
@@ -19484,6 +19605,53 @@ RAW: ${raw}
|
|
|
19484
19605
|
);
|
|
19485
19606
|
process.exit(2);
|
|
19486
19607
|
};
|
|
19608
|
+
const sendAsk = (result2) => {
|
|
19609
|
+
const msg = buildReviewMessage(result2.blockedByLabel, result2.ruleDescription);
|
|
19610
|
+
try {
|
|
19611
|
+
const key = reviewCorrelationKey(payload);
|
|
19612
|
+
if (key) {
|
|
19613
|
+
const sid = typeof payload.session_id === "string" ? payload.session_id : typeof payload.conversationId === "string" ? payload.conversationId : void 0;
|
|
19614
|
+
recordPendingReview({
|
|
19615
|
+
key,
|
|
19616
|
+
agent,
|
|
19617
|
+
tool: toolName,
|
|
19618
|
+
sessionId: sid,
|
|
19619
|
+
ts: Date.now(),
|
|
19620
|
+
label: result2.blockedByLabel
|
|
19621
|
+
});
|
|
19622
|
+
}
|
|
19623
|
+
} catch {
|
|
19624
|
+
}
|
|
19625
|
+
try {
|
|
19626
|
+
const ttyFd = import_fs37.default.openSync("/dev/tty", "w");
|
|
19627
|
+
import_fs37.default.writeSync(
|
|
19628
|
+
ttyFd,
|
|
19629
|
+
import_chalk9.default.yellow(
|
|
19630
|
+
`
|
|
19631
|
+
\u26A0\uFE0F Node9: review requested for "${toolName}" \u2014 answer in the prompt.
|
|
19632
|
+
`
|
|
19633
|
+
)
|
|
19634
|
+
);
|
|
19635
|
+
import_fs37.default.closeSync(ttyFd);
|
|
19636
|
+
} catch {
|
|
19637
|
+
}
|
|
19638
|
+
if (agent === "GitHub Copilot") {
|
|
19639
|
+
process.stdout.write(
|
|
19640
|
+
JSON.stringify({ permissionDecision: "ask", permissionDecisionReason: msg }) + "\n"
|
|
19641
|
+
);
|
|
19642
|
+
} else {
|
|
19643
|
+
process.stdout.write(
|
|
19644
|
+
JSON.stringify({
|
|
19645
|
+
hookSpecificOutput: {
|
|
19646
|
+
hookEventName: "PreToolUse",
|
|
19647
|
+
permissionDecision: "ask",
|
|
19648
|
+
permissionDecisionReason: msg
|
|
19649
|
+
}
|
|
19650
|
+
}) + "\n"
|
|
19651
|
+
);
|
|
19652
|
+
}
|
|
19653
|
+
process.exit(0);
|
|
19654
|
+
};
|
|
19487
19655
|
if (!toolName) {
|
|
19488
19656
|
sendBlock("Node9: unrecognised hook payload \u2014 tool name missing.");
|
|
19489
19657
|
return;
|
|
@@ -19496,17 +19664,17 @@ RAW: ${raw}
|
|
|
19496
19664
|
const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
|
|
19497
19665
|
if (skillPinCfg.enabled && safeSessionId) {
|
|
19498
19666
|
try {
|
|
19499
|
-
const sessionsDir =
|
|
19500
|
-
const flagPath =
|
|
19667
|
+
const sessionsDir = import_path38.default.join(import_os33.default.homedir(), ".node9", "skill-sessions");
|
|
19668
|
+
const flagPath = import_path38.default.join(sessionsDir, `${safeSessionId}.json`);
|
|
19501
19669
|
let flag = null;
|
|
19502
19670
|
try {
|
|
19503
|
-
flag = JSON.parse(
|
|
19671
|
+
flag = JSON.parse(import_fs37.default.readFileSync(flagPath, "utf-8"));
|
|
19504
19672
|
} catch {
|
|
19505
19673
|
}
|
|
19506
19674
|
const writeFlag = (data2) => {
|
|
19507
19675
|
try {
|
|
19508
|
-
|
|
19509
|
-
|
|
19676
|
+
import_fs37.default.mkdirSync(sessionsDir, { recursive: true });
|
|
19677
|
+
import_fs37.default.writeFileSync(
|
|
19510
19678
|
flagPath,
|
|
19511
19679
|
JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
|
|
19512
19680
|
{ mode: 384 }
|
|
@@ -19517,8 +19685,8 @@ RAW: ${raw}
|
|
|
19517
19685
|
const sendSkillWarn = (detail, recoveryCmd) => {
|
|
19518
19686
|
let ttyFd = null;
|
|
19519
19687
|
try {
|
|
19520
|
-
ttyFd =
|
|
19521
|
-
const w = (line) =>
|
|
19688
|
+
ttyFd = import_fs37.default.openSync("/dev/tty", "w");
|
|
19689
|
+
const w = (line) => import_fs37.default.writeSync(ttyFd, line + "\n");
|
|
19522
19690
|
w(import_chalk9.default.yellow(`
|
|
19523
19691
|
\u26A0\uFE0F Node9: installed skill drift detected`));
|
|
19524
19692
|
w(import_chalk9.default.gray(` ${detail}`));
|
|
@@ -19533,7 +19701,7 @@ RAW: ${raw}
|
|
|
19533
19701
|
} finally {
|
|
19534
19702
|
if (ttyFd !== null)
|
|
19535
19703
|
try {
|
|
19536
|
-
|
|
19704
|
+
import_fs37.default.closeSync(ttyFd);
|
|
19537
19705
|
} catch {
|
|
19538
19706
|
}
|
|
19539
19707
|
}
|
|
@@ -19549,7 +19717,7 @@ RAW: ${raw}
|
|
|
19549
19717
|
return;
|
|
19550
19718
|
}
|
|
19551
19719
|
if (!flag || flag.state !== "verified" && flag.state !== "warned") {
|
|
19552
|
-
const absoluteCwd = typeof payloadCwd === "string" &&
|
|
19720
|
+
const absoluteCwd = typeof payloadCwd === "string" && import_path38.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
19553
19721
|
const extraRoots = skillPinCfg.roots;
|
|
19554
19722
|
const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
|
|
19555
19723
|
const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
|
|
@@ -19590,10 +19758,10 @@ RAW: ${raw}
|
|
|
19590
19758
|
}
|
|
19591
19759
|
try {
|
|
19592
19760
|
const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
19593
|
-
for (const name of
|
|
19594
|
-
const p =
|
|
19761
|
+
for (const name of import_fs37.default.readdirSync(sessionsDir)) {
|
|
19762
|
+
const p = import_path38.default.join(sessionsDir, name);
|
|
19595
19763
|
try {
|
|
19596
|
-
if (
|
|
19764
|
+
if (import_fs37.default.statSync(p).mtimeMs < cutoff) import_fs37.default.unlinkSync(p);
|
|
19597
19765
|
} catch {
|
|
19598
19766
|
}
|
|
19599
19767
|
}
|
|
@@ -19603,9 +19771,9 @@ RAW: ${raw}
|
|
|
19603
19771
|
} catch (err2) {
|
|
19604
19772
|
if (process.env.NODE9_DEBUG === "1") {
|
|
19605
19773
|
try {
|
|
19606
|
-
const dbg =
|
|
19774
|
+
const dbg = import_path38.default.join(import_os33.default.homedir(), ".node9", "hook-debug.log");
|
|
19607
19775
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
19608
|
-
|
|
19776
|
+
import_fs37.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
|
|
19609
19777
|
`);
|
|
19610
19778
|
} catch {
|
|
19611
19779
|
}
|
|
@@ -19615,9 +19783,11 @@ RAW: ${raw}
|
|
|
19615
19783
|
if (shouldSnapshot(toolName, toolInput, config)) {
|
|
19616
19784
|
await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
|
|
19617
19785
|
}
|
|
19618
|
-
const safeCwdForAuth = typeof payloadCwd === "string" &&
|
|
19786
|
+
const safeCwdForAuth = typeof payloadCwd === "string" && import_path38.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
19787
|
+
const askMode = resolveAskMode(agent, opts, config);
|
|
19619
19788
|
const result = await authorizeHeadless(toolName, toolInput, meta, {
|
|
19620
|
-
cwd: safeCwdForAuth
|
|
19789
|
+
cwd: safeCwdForAuth,
|
|
19790
|
+
deferReview: askMode
|
|
19621
19791
|
});
|
|
19622
19792
|
if (result.approved) {
|
|
19623
19793
|
if (result.checkedBy && process.env.NODE9_DEBUG === "1")
|
|
@@ -19625,14 +19795,18 @@ RAW: ${raw}
|
|
|
19625
19795
|
`);
|
|
19626
19796
|
process.exit(0);
|
|
19627
19797
|
}
|
|
19798
|
+
if (result.review) {
|
|
19799
|
+
sendAsk(result);
|
|
19800
|
+
return;
|
|
19801
|
+
}
|
|
19628
19802
|
if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
|
|
19629
19803
|
try {
|
|
19630
|
-
const tty =
|
|
19631
|
-
|
|
19804
|
+
const tty = import_fs37.default.openSync("/dev/tty", "w");
|
|
19805
|
+
import_fs37.default.writeSync(
|
|
19632
19806
|
tty,
|
|
19633
19807
|
import_chalk9.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
|
|
19634
19808
|
);
|
|
19635
|
-
|
|
19809
|
+
import_fs37.default.closeSync(tty);
|
|
19636
19810
|
} catch {
|
|
19637
19811
|
}
|
|
19638
19812
|
const daemonReady = await autoStartDaemonAndWait();
|
|
@@ -19659,9 +19833,9 @@ RAW: ${raw}
|
|
|
19659
19833
|
});
|
|
19660
19834
|
} catch (err2) {
|
|
19661
19835
|
if (process.env.NODE9_DEBUG === "1") {
|
|
19662
|
-
const logPath =
|
|
19836
|
+
const logPath = import_path38.default.join(import_os33.default.homedir(), ".node9", "hook-debug.log");
|
|
19663
19837
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
19664
|
-
|
|
19838
|
+
import_fs37.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
|
|
19665
19839
|
`);
|
|
19666
19840
|
}
|
|
19667
19841
|
process.exit(0);
|
|
@@ -19695,9 +19869,9 @@ RAW: ${raw}
|
|
|
19695
19869
|
}
|
|
19696
19870
|
|
|
19697
19871
|
// src/cli/commands/log.ts
|
|
19698
|
-
var
|
|
19699
|
-
var
|
|
19700
|
-
var
|
|
19872
|
+
var import_fs38 = __toESM(require("fs"));
|
|
19873
|
+
var import_path39 = __toESM(require("path"));
|
|
19874
|
+
var import_os34 = __toESM(require("os"));
|
|
19701
19875
|
init_audit();
|
|
19702
19876
|
init_config();
|
|
19703
19877
|
init_daemon();
|
|
@@ -19790,21 +19964,27 @@ function registerLogCommand(program2) {
|
|
|
19790
19964
|
return void 0;
|
|
19791
19965
|
})();
|
|
19792
19966
|
const agent = agentOverride !== void 0 ? agentOverride : metaTag !== void 0 ? metaTag : payload.turn_id !== void 0 ? "Codex" : payload.toolCall !== void 0 || payload.conversationId !== void 0 ? "Antigravity" : payload.hook_event_name === "pre_tool_call" || payload.hook_event_name === "post_tool_call" ? "Hermes" : payload.hook_event_name === "PreToolUse" || payload.hook_event_name === "PostToolUse" || payload.tool_use_id !== void 0 || payload.permission_mode !== void 0 ? "Claude Code" : payload.hook_event_name === "BeforeTool" || payload.hook_event_name === "AfterTool" || payload.timestamp !== void 0 ? "Gemini CLI" : process.env.HERMES_SESSION_ID || process.env.HERMES_HOME || process.env.HERMES_INTERACTIVE ? "Hermes" : process.env.ANTIGRAVITY_CONVERSATION_ID ? "Antigravity" : void 0;
|
|
19967
|
+
let reviewApproved = false;
|
|
19968
|
+
try {
|
|
19969
|
+
const key = reviewCorrelationKey(payload);
|
|
19970
|
+
if (key && resolvePendingReview(key)) reviewApproved = true;
|
|
19971
|
+
} catch {
|
|
19972
|
+
}
|
|
19793
19973
|
const entry = {
|
|
19794
19974
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19795
19975
|
tool,
|
|
19796
19976
|
args: JSON.parse(redactSecrets(JSON.stringify(rawInput))),
|
|
19797
19977
|
decision: "allowed",
|
|
19798
|
-
source: "post-hook"
|
|
19978
|
+
source: reviewApproved ? "inline-review-approved" : "post-hook"
|
|
19799
19979
|
};
|
|
19800
19980
|
if (agent) entry.agent = agent;
|
|
19801
19981
|
if (rawToolName !== tool) entry.agentToolName = rawToolName;
|
|
19802
19982
|
const payloadSessionId = payload.session_id ?? payload.conversationId;
|
|
19803
19983
|
if (payloadSessionId) entry.sessionId = payloadSessionId;
|
|
19804
|
-
const logPath =
|
|
19805
|
-
if (!
|
|
19806
|
-
|
|
19807
|
-
|
|
19984
|
+
const logPath = import_path39.default.join(import_os34.default.homedir(), ".node9", "audit.log");
|
|
19985
|
+
if (!import_fs38.default.existsSync(import_path39.default.dirname(logPath)))
|
|
19986
|
+
import_fs38.default.mkdirSync(import_path39.default.dirname(logPath), { recursive: true });
|
|
19987
|
+
import_fs38.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
|
|
19808
19988
|
if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
|
|
19809
19989
|
const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
19810
19990
|
if (command) {
|
|
@@ -19838,7 +20018,7 @@ function registerLogCommand(program2) {
|
|
|
19838
20018
|
}
|
|
19839
20019
|
}
|
|
19840
20020
|
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
19841
|
-
const safeCwd = typeof payloadCwd === "string" &&
|
|
20021
|
+
const safeCwd = typeof payloadCwd === "string" && import_path39.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
19842
20022
|
const config = getConfig(safeCwd);
|
|
19843
20023
|
{
|
|
19844
20024
|
const toolOutput = payload.tool_response?.output;
|
|
@@ -19915,9 +20095,9 @@ function registerLogCommand(program2) {
|
|
|
19915
20095
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
19916
20096
|
process.stderr.write(`[Node9] audit log error: ${msg}
|
|
19917
20097
|
`);
|
|
19918
|
-
const debugPath =
|
|
20098
|
+
const debugPath = import_path39.default.join(import_os34.default.homedir(), ".node9", "hook-debug.log");
|
|
19919
20099
|
try {
|
|
19920
|
-
|
|
20100
|
+
import_fs38.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
|
|
19921
20101
|
`);
|
|
19922
20102
|
} catch {
|
|
19923
20103
|
}
|
|
@@ -20317,24 +20497,24 @@ function registerConfigShowCommand(program2) {
|
|
|
20317
20497
|
|
|
20318
20498
|
// src/cli/commands/doctor.ts
|
|
20319
20499
|
var import_chalk11 = __toESM(require("chalk"));
|
|
20320
|
-
var
|
|
20321
|
-
var
|
|
20322
|
-
var
|
|
20500
|
+
var import_fs40 = __toESM(require("fs"));
|
|
20501
|
+
var import_path41 = __toESM(require("path"));
|
|
20502
|
+
var import_os36 = __toESM(require("os"));
|
|
20323
20503
|
var import_child_process8 = require("child_process");
|
|
20324
20504
|
init_daemon();
|
|
20325
20505
|
init_config();
|
|
20326
20506
|
|
|
20327
20507
|
// src/agent-wiring.ts
|
|
20328
|
-
var
|
|
20329
|
-
var
|
|
20330
|
-
var
|
|
20508
|
+
var import_fs39 = __toESM(require("fs"));
|
|
20509
|
+
var import_path40 = __toESM(require("path"));
|
|
20510
|
+
var import_os35 = __toESM(require("os"));
|
|
20331
20511
|
var yaml2 = __toESM(require("yaml"));
|
|
20332
20512
|
var import_smol_toml2 = require("smol-toml");
|
|
20333
20513
|
init_setup();
|
|
20334
20514
|
function readJson2(filePath) {
|
|
20335
|
-
if (!
|
|
20515
|
+
if (!import_fs39.default.existsSync(filePath)) return null;
|
|
20336
20516
|
try {
|
|
20337
|
-
return JSON.parse(
|
|
20517
|
+
return JSON.parse(import_fs39.default.readFileSync(filePath, "utf-8"));
|
|
20338
20518
|
} catch {
|
|
20339
20519
|
return "invalid";
|
|
20340
20520
|
}
|
|
@@ -20346,10 +20526,10 @@ function flatHaveNode9Hook(entries) {
|
|
|
20346
20526
|
return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
|
|
20347
20527
|
}
|
|
20348
20528
|
function readHookRoot(filePath, format) {
|
|
20349
|
-
if (!
|
|
20529
|
+
if (!import_fs39.default.existsSync(filePath)) return "absent";
|
|
20350
20530
|
let raw;
|
|
20351
20531
|
try {
|
|
20352
|
-
raw =
|
|
20532
|
+
raw = import_fs39.default.readFileSync(filePath, "utf-8");
|
|
20353
20533
|
} catch {
|
|
20354
20534
|
return "absent";
|
|
20355
20535
|
}
|
|
@@ -20372,10 +20552,10 @@ function detectMcp(servers) {
|
|
|
20372
20552
|
return { wrapped, present };
|
|
20373
20553
|
}
|
|
20374
20554
|
function readMcp(filePath, format) {
|
|
20375
|
-
if (!
|
|
20555
|
+
if (!import_fs39.default.existsSync(filePath)) return { wrapped: [], present: false };
|
|
20376
20556
|
try {
|
|
20377
20557
|
if (format === "toml") {
|
|
20378
|
-
const parsed2 = (0, import_smol_toml2.parse)(
|
|
20558
|
+
const parsed2 = (0, import_smol_toml2.parse)(import_fs39.default.readFileSync(filePath, "utf-8"));
|
|
20379
20559
|
return detectMcp(parsed2?.mcp_servers);
|
|
20380
20560
|
}
|
|
20381
20561
|
const parsed = readJson2(filePath);
|
|
@@ -20387,7 +20567,7 @@ function readMcp(filePath, format) {
|
|
|
20387
20567
|
}
|
|
20388
20568
|
var exists = (p) => {
|
|
20389
20569
|
try {
|
|
20390
|
-
return
|
|
20570
|
+
return import_fs39.default.existsSync(p);
|
|
20391
20571
|
} catch {
|
|
20392
20572
|
return false;
|
|
20393
20573
|
}
|
|
@@ -20401,52 +20581,52 @@ var AGENT_SPECS = [
|
|
|
20401
20581
|
id: "claude",
|
|
20402
20582
|
label: "Claude Code",
|
|
20403
20583
|
setupCommand: "node9 agents add claude",
|
|
20404
|
-
hookFile: (h) =>
|
|
20584
|
+
hookFile: (h) => import_path40.default.join(h, ".claude", "settings.json"),
|
|
20405
20585
|
hookFormat: "matcher",
|
|
20406
20586
|
hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
|
|
20407
|
-
mcpFile: (h) =>
|
|
20408
|
-
present: (h) => exists(
|
|
20587
|
+
mcpFile: (h) => import_path40.default.join(h, ".claude.json"),
|
|
20588
|
+
present: (h) => exists(import_path40.default.join(h, ".claude", "settings.json")) || exists(import_path40.default.join(h, ".claude.json"))
|
|
20409
20589
|
},
|
|
20410
20590
|
{
|
|
20411
20591
|
id: "gemini",
|
|
20412
20592
|
label: "Gemini CLI",
|
|
20413
20593
|
setupCommand: "node9 agents add gemini",
|
|
20414
|
-
hookFile: (h) =>
|
|
20594
|
+
hookFile: (h) => import_path40.default.join(h, ".gemini", "settings.json"),
|
|
20415
20595
|
hookFormat: "matcher",
|
|
20416
20596
|
hookEvents: [ck("BeforeTool"), lg("AfterTool")],
|
|
20417
|
-
mcpFile: (h) =>
|
|
20418
|
-
present: (h) => exists(
|
|
20597
|
+
mcpFile: (h) => import_path40.default.join(h, ".gemini", "settings.json"),
|
|
20598
|
+
present: (h) => exists(import_path40.default.join(h, ".gemini", "settings.json"))
|
|
20419
20599
|
},
|
|
20420
20600
|
{
|
|
20421
20601
|
id: "codex",
|
|
20422
20602
|
label: "Codex",
|
|
20423
20603
|
setupCommand: "node9 agents add codex",
|
|
20424
|
-
hookFile: (h) =>
|
|
20604
|
+
hookFile: (h) => import_path40.default.join(h, ".codex", "hooks.json"),
|
|
20425
20605
|
hookFormat: "matcher",
|
|
20426
20606
|
hookEvents: [ck("PreToolUse"), ck("UserPromptSubmit")],
|
|
20427
|
-
mcpFile: (h) =>
|
|
20607
|
+
mcpFile: (h) => import_path40.default.join(h, ".codex", "config.toml"),
|
|
20428
20608
|
mcpFormat: "toml",
|
|
20429
|
-
present: (h) => exists(
|
|
20609
|
+
present: (h) => exists(import_path40.default.join(h, ".codex"))
|
|
20430
20610
|
},
|
|
20431
20611
|
{
|
|
20432
20612
|
id: "antigravity",
|
|
20433
20613
|
label: "Antigravity",
|
|
20434
20614
|
setupCommand: "node9 agents add antigravity",
|
|
20435
|
-
hookFile: (h) =>
|
|
20615
|
+
hookFile: (h) => import_path40.default.join(h, ".gemini", "config", "hooks.json"),
|
|
20436
20616
|
hookFormat: "matcher",
|
|
20437
20617
|
hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
|
|
20438
|
-
mcpFile: (h) =>
|
|
20439
|
-
present: (h) => exists(
|
|
20618
|
+
mcpFile: (h) => import_path40.default.join(h, ".gemini", "config", "mcp_config.json"),
|
|
20619
|
+
present: (h) => exists(import_path40.default.join(h, ".gemini", "config", "hooks.json")) || exists(import_path40.default.join(h, ".gemini", "antigravity-cli")) || exists(import_path40.default.join(h, ".gemini", "antigravity-ide"))
|
|
20440
20620
|
},
|
|
20441
20621
|
{
|
|
20442
20622
|
id: "copilot",
|
|
20443
20623
|
label: "GitHub Copilot",
|
|
20444
20624
|
setupCommand: "node9 agents add copilot",
|
|
20445
|
-
hookFile: (h) =>
|
|
20625
|
+
hookFile: (h) => import_path40.default.join(h, ".copilot", "hooks", "node9.json"),
|
|
20446
20626
|
hookFormat: "flat",
|
|
20447
20627
|
hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
|
|
20448
|
-
mcpFile: (h) =>
|
|
20449
|
-
present: (h) => exists(
|
|
20628
|
+
mcpFile: (h) => import_path40.default.join(h, ".copilot", "mcp-config.json"),
|
|
20629
|
+
present: (h) => exists(import_path40.default.join(h, ".copilot"))
|
|
20450
20630
|
},
|
|
20451
20631
|
{
|
|
20452
20632
|
id: "cursor",
|
|
@@ -20455,8 +20635,8 @@ var AGENT_SPECS = [
|
|
|
20455
20635
|
// MCP-only — no hook file (see note above).
|
|
20456
20636
|
hookFormat: "flat",
|
|
20457
20637
|
hookEvents: [],
|
|
20458
|
-
mcpFile: (h) =>
|
|
20459
|
-
present: (h) => exists(
|
|
20638
|
+
mcpFile: (h) => import_path40.default.join(h, ".cursor", "mcp.json"),
|
|
20639
|
+
present: (h) => exists(import_path40.default.join(h, ".cursor", "mcp.json"))
|
|
20460
20640
|
},
|
|
20461
20641
|
{
|
|
20462
20642
|
id: "hermes",
|
|
@@ -20477,8 +20657,8 @@ var AGENT_SPECS = [
|
|
|
20477
20657
|
setupCommand: "node9 agents add opencode",
|
|
20478
20658
|
hookFormat: "flat",
|
|
20479
20659
|
hookEvents: [],
|
|
20480
|
-
shimFile: (h) =>
|
|
20481
|
-
present: (h) => exists(
|
|
20660
|
+
shimFile: (h) => import_path40.default.join(h, ".config", "opencode", "plugins", "node9.js"),
|
|
20661
|
+
present: (h) => exists(import_path40.default.join(h, ".config", "opencode")) || exists(import_path40.default.join(h, ".config", "opencode", "plugins", "node9.js"))
|
|
20482
20662
|
},
|
|
20483
20663
|
{
|
|
20484
20664
|
id: "pi",
|
|
@@ -20486,11 +20666,11 @@ var AGENT_SPECS = [
|
|
|
20486
20666
|
setupCommand: "node9 agents add pi",
|
|
20487
20667
|
hookFormat: "flat",
|
|
20488
20668
|
hookEvents: [],
|
|
20489
|
-
shimFile: (h) =>
|
|
20490
|
-
present: (h) => exists(
|
|
20669
|
+
shimFile: (h) => import_path40.default.join(h, ".pi", "agent", "extensions", "node9.js"),
|
|
20670
|
+
present: (h) => exists(import_path40.default.join(h, ".pi", "agent")) || exists(import_path40.default.join(h, ".pi", "agent", "extensions", "node9.js"))
|
|
20491
20671
|
}
|
|
20492
20672
|
];
|
|
20493
|
-
function getAgentWiring(home =
|
|
20673
|
+
function getAgentWiring(home = import_os35.default.homedir()) {
|
|
20494
20674
|
const detected = detectAgents(home);
|
|
20495
20675
|
return AGENT_SPECS.map((spec) => {
|
|
20496
20676
|
const present = spec.present(home);
|
|
@@ -20542,7 +20722,7 @@ function getAgentWiring(home = import_os34.default.homedir()) {
|
|
|
20542
20722
|
// src/cli/commands/doctor.ts
|
|
20543
20723
|
function registerDoctorCommand(program2, version2) {
|
|
20544
20724
|
program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
|
|
20545
|
-
const homeDir2 =
|
|
20725
|
+
const homeDir2 = import_os36.default.homedir();
|
|
20546
20726
|
let failures = 0;
|
|
20547
20727
|
function pass(msg) {
|
|
20548
20728
|
console.log(import_chalk11.default.green(" \u2705 ") + msg);
|
|
@@ -20588,10 +20768,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
20588
20768
|
);
|
|
20589
20769
|
}
|
|
20590
20770
|
section("Configuration");
|
|
20591
|
-
const globalConfigPath =
|
|
20592
|
-
if (
|
|
20771
|
+
const globalConfigPath = import_path41.default.join(homeDir2, ".node9", "config.json");
|
|
20772
|
+
if (import_fs40.default.existsSync(globalConfigPath)) {
|
|
20593
20773
|
try {
|
|
20594
|
-
JSON.parse(
|
|
20774
|
+
JSON.parse(import_fs40.default.readFileSync(globalConfigPath, "utf-8"));
|
|
20595
20775
|
pass("~/.node9/config.json found and valid");
|
|
20596
20776
|
} catch {
|
|
20597
20777
|
fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
|
|
@@ -20599,10 +20779,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
20599
20779
|
} else {
|
|
20600
20780
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
20601
20781
|
}
|
|
20602
|
-
const projectConfigPath =
|
|
20603
|
-
if (
|
|
20782
|
+
const projectConfigPath = import_path41.default.join(process.cwd(), "node9.config.json");
|
|
20783
|
+
if (import_fs40.default.existsSync(projectConfigPath)) {
|
|
20604
20784
|
try {
|
|
20605
|
-
JSON.parse(
|
|
20785
|
+
JSON.parse(import_fs40.default.readFileSync(projectConfigPath, "utf-8"));
|
|
20606
20786
|
pass("node9.config.json found and valid (project)");
|
|
20607
20787
|
} catch {
|
|
20608
20788
|
fail(
|
|
@@ -20611,8 +20791,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
20611
20791
|
);
|
|
20612
20792
|
}
|
|
20613
20793
|
}
|
|
20614
|
-
const credsPath =
|
|
20615
|
-
if (
|
|
20794
|
+
const credsPath = import_path41.default.join(homeDir2, ".node9", "credentials.json");
|
|
20795
|
+
if (import_fs40.default.existsSync(credsPath)) {
|
|
20616
20796
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
20617
20797
|
} else {
|
|
20618
20798
|
warn(
|
|
@@ -20656,7 +20836,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
20656
20836
|
try {
|
|
20657
20837
|
const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
|
|
20658
20838
|
const cfg = getConfig();
|
|
20659
|
-
const creds =
|
|
20839
|
+
const creds = import_fs40.default.existsSync(import_path41.default.join(import_os36.default.homedir(), ".node9", "credentials.json"));
|
|
20660
20840
|
if (!creds) {
|
|
20661
20841
|
warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
|
|
20662
20842
|
} else if (!cfg.settings.approvers.cloud) {
|
|
@@ -20706,9 +20886,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
20706
20886
|
|
|
20707
20887
|
// src/cli/commands/audit.ts
|
|
20708
20888
|
var import_chalk12 = __toESM(require("chalk"));
|
|
20709
|
-
var
|
|
20710
|
-
var
|
|
20711
|
-
var
|
|
20889
|
+
var import_fs41 = __toESM(require("fs"));
|
|
20890
|
+
var import_path42 = __toESM(require("path"));
|
|
20891
|
+
var import_os37 = __toESM(require("os"));
|
|
20712
20892
|
function formatRelativeTime(timestamp) {
|
|
20713
20893
|
const diff = Date.now() - new Date(timestamp).getTime();
|
|
20714
20894
|
const sec = Math.floor(diff / 1e3);
|
|
@@ -20721,14 +20901,14 @@ function formatRelativeTime(timestamp) {
|
|
|
20721
20901
|
}
|
|
20722
20902
|
function registerAuditCommand(program2) {
|
|
20723
20903
|
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) => {
|
|
20724
|
-
const logPath =
|
|
20725
|
-
if (!
|
|
20904
|
+
const logPath = import_path42.default.join(import_os37.default.homedir(), ".node9", "audit.log");
|
|
20905
|
+
if (!import_fs41.default.existsSync(logPath)) {
|
|
20726
20906
|
console.log(
|
|
20727
20907
|
import_chalk12.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
20728
20908
|
);
|
|
20729
20909
|
return;
|
|
20730
20910
|
}
|
|
20731
|
-
const raw =
|
|
20911
|
+
const raw = import_fs41.default.readFileSync(logPath, "utf-8");
|
|
20732
20912
|
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
20733
20913
|
let entries = lines.flatMap((line) => {
|
|
20734
20914
|
try {
|
|
@@ -20784,9 +20964,9 @@ function registerAuditCommand(program2) {
|
|
|
20784
20964
|
var import_chalk13 = __toESM(require("chalk"));
|
|
20785
20965
|
|
|
20786
20966
|
// src/cli/aggregate/report-audit.ts
|
|
20787
|
-
var
|
|
20788
|
-
var
|
|
20789
|
-
var
|
|
20967
|
+
var import_fs42 = __toESM(require("fs"));
|
|
20968
|
+
var import_os38 = __toESM(require("os"));
|
|
20969
|
+
var import_path43 = __toESM(require("path"));
|
|
20790
20970
|
init_costSync();
|
|
20791
20971
|
init_litellm();
|
|
20792
20972
|
init_cost_codex();
|
|
@@ -20869,8 +21049,8 @@ function getDateRange(period, now) {
|
|
|
20869
21049
|
}
|
|
20870
21050
|
}
|
|
20871
21051
|
function parseAuditLog(logPath) {
|
|
20872
|
-
if (!
|
|
20873
|
-
const raw =
|
|
21052
|
+
if (!import_fs42.default.existsSync(logPath)) return [];
|
|
21053
|
+
const raw = import_fs42.default.readFileSync(logPath, "utf-8");
|
|
20874
21054
|
return raw.split("\n").flatMap((line) => {
|
|
20875
21055
|
if (!line.trim()) return [];
|
|
20876
21056
|
try {
|
|
@@ -20917,25 +21097,25 @@ function freezeClaudeCost(acc) {
|
|
|
20917
21097
|
};
|
|
20918
21098
|
}
|
|
20919
21099
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
20920
|
-
const projPath =
|
|
21100
|
+
const projPath = import_path43.default.join(projectsDir, proj);
|
|
20921
21101
|
let files;
|
|
20922
21102
|
try {
|
|
20923
|
-
const stat =
|
|
21103
|
+
const stat = import_fs42.default.statSync(projPath);
|
|
20924
21104
|
if (!stat.isDirectory()) return;
|
|
20925
|
-
files =
|
|
21105
|
+
files = import_fs42.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
20926
21106
|
} catch {
|
|
20927
21107
|
return;
|
|
20928
21108
|
}
|
|
20929
21109
|
const startMs = start.getTime();
|
|
20930
21110
|
for (const file of files) {
|
|
20931
|
-
const filePath =
|
|
21111
|
+
const filePath = import_path43.default.join(projPath, file);
|
|
20932
21112
|
try {
|
|
20933
|
-
if (
|
|
21113
|
+
if (import_fs42.default.statSync(filePath).mtimeMs < startMs) continue;
|
|
20934
21114
|
} catch {
|
|
20935
21115
|
continue;
|
|
20936
21116
|
}
|
|
20937
21117
|
try {
|
|
20938
|
-
const raw =
|
|
21118
|
+
const raw = import_fs42.default.readFileSync(filePath, "utf-8");
|
|
20939
21119
|
for (const line of raw.split("\n")) {
|
|
20940
21120
|
if (!line.trim()) continue;
|
|
20941
21121
|
let entry;
|
|
@@ -20985,10 +21165,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
20985
21165
|
}
|
|
20986
21166
|
function loadClaudeCost(start, end, projectsDir) {
|
|
20987
21167
|
const acc = emptyClaudeCostAccumulator();
|
|
20988
|
-
if (!
|
|
21168
|
+
if (!import_fs42.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
|
|
20989
21169
|
let dirs;
|
|
20990
21170
|
try {
|
|
20991
|
-
dirs =
|
|
21171
|
+
dirs = import_fs42.default.readdirSync(projectsDir);
|
|
20992
21172
|
} catch {
|
|
20993
21173
|
return freezeClaudeCost(acc);
|
|
20994
21174
|
}
|
|
@@ -21000,7 +21180,7 @@ function loadClaudeCost(start, end, projectsDir) {
|
|
|
21000
21180
|
function processCodexCostFile(filePath, start, end, acc) {
|
|
21001
21181
|
let lines;
|
|
21002
21182
|
try {
|
|
21003
|
-
lines =
|
|
21183
|
+
lines = import_fs42.default.readFileSync(filePath, "utf-8").split("\n");
|
|
21004
21184
|
} catch {
|
|
21005
21185
|
return;
|
|
21006
21186
|
}
|
|
@@ -21055,31 +21235,31 @@ function processCodexCostFile(filePath, start, end, acc) {
|
|
|
21055
21235
|
}
|
|
21056
21236
|
function listCodexSessionFiles2(sessionsBase) {
|
|
21057
21237
|
const jsonlFiles = [];
|
|
21058
|
-
if (!
|
|
21238
|
+
if (!import_fs42.default.existsSync(sessionsBase)) return jsonlFiles;
|
|
21059
21239
|
try {
|
|
21060
|
-
for (const year of
|
|
21061
|
-
const yearPath =
|
|
21240
|
+
for (const year of import_fs42.default.readdirSync(sessionsBase)) {
|
|
21241
|
+
const yearPath = import_path43.default.join(sessionsBase, year);
|
|
21062
21242
|
try {
|
|
21063
|
-
if (!
|
|
21243
|
+
if (!import_fs42.default.statSync(yearPath).isDirectory()) continue;
|
|
21064
21244
|
} catch {
|
|
21065
21245
|
continue;
|
|
21066
21246
|
}
|
|
21067
|
-
for (const month of
|
|
21068
|
-
const monthPath =
|
|
21247
|
+
for (const month of import_fs42.default.readdirSync(yearPath)) {
|
|
21248
|
+
const monthPath = import_path43.default.join(yearPath, month);
|
|
21069
21249
|
try {
|
|
21070
|
-
if (!
|
|
21250
|
+
if (!import_fs42.default.statSync(monthPath).isDirectory()) continue;
|
|
21071
21251
|
} catch {
|
|
21072
21252
|
continue;
|
|
21073
21253
|
}
|
|
21074
|
-
for (const day of
|
|
21075
|
-
const dayPath =
|
|
21254
|
+
for (const day of import_fs42.default.readdirSync(monthPath)) {
|
|
21255
|
+
const dayPath = import_path43.default.join(monthPath, day);
|
|
21076
21256
|
try {
|
|
21077
|
-
if (!
|
|
21257
|
+
if (!import_fs42.default.statSync(dayPath).isDirectory()) continue;
|
|
21078
21258
|
} catch {
|
|
21079
21259
|
continue;
|
|
21080
21260
|
}
|
|
21081
|
-
for (const file of
|
|
21082
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
21261
|
+
for (const file of import_fs42.default.readdirSync(dayPath)) {
|
|
21262
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path43.default.join(dayPath, file));
|
|
21083
21263
|
}
|
|
21084
21264
|
}
|
|
21085
21265
|
}
|
|
@@ -21144,13 +21324,13 @@ function freezeGeminiCost(acc) {
|
|
|
21144
21324
|
function processGeminiCostFile(filePath, projectKey, start, end, acc) {
|
|
21145
21325
|
const startMs = start.getTime();
|
|
21146
21326
|
try {
|
|
21147
|
-
if (
|
|
21327
|
+
if (import_fs42.default.statSync(filePath).mtimeMs < startMs) return;
|
|
21148
21328
|
} catch {
|
|
21149
21329
|
return;
|
|
21150
21330
|
}
|
|
21151
21331
|
let raw;
|
|
21152
21332
|
try {
|
|
21153
|
-
raw =
|
|
21333
|
+
raw = import_fs42.default.readFileSync(filePath, "utf-8");
|
|
21154
21334
|
} catch {
|
|
21155
21335
|
return;
|
|
21156
21336
|
}
|
|
@@ -21199,30 +21379,30 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
|
|
|
21199
21379
|
const out = [];
|
|
21200
21380
|
let dirs;
|
|
21201
21381
|
try {
|
|
21202
|
-
if (!
|
|
21203
|
-
dirs =
|
|
21382
|
+
if (!import_fs42.default.statSync(geminiTmpDir2).isDirectory()) return out;
|
|
21383
|
+
dirs = import_fs42.default.readdirSync(geminiTmpDir2);
|
|
21204
21384
|
} catch {
|
|
21205
21385
|
return out;
|
|
21206
21386
|
}
|
|
21207
21387
|
for (const proj of dirs) {
|
|
21208
|
-
const chatsDir =
|
|
21388
|
+
const chatsDir = import_path43.default.join(geminiTmpDir2, proj, "chats");
|
|
21209
21389
|
let files;
|
|
21210
21390
|
try {
|
|
21211
|
-
if (!
|
|
21212
|
-
files =
|
|
21391
|
+
if (!import_fs42.default.statSync(chatsDir).isDirectory()) continue;
|
|
21392
|
+
files = import_fs42.default.readdirSync(chatsDir);
|
|
21213
21393
|
} catch {
|
|
21214
21394
|
continue;
|
|
21215
21395
|
}
|
|
21216
21396
|
for (const f of files) {
|
|
21217
21397
|
if (!f.endsWith(".jsonl")) continue;
|
|
21218
|
-
out.push({ projectKey: proj, file:
|
|
21398
|
+
out.push({ projectKey: proj, file: import_path43.default.join(chatsDir, f) });
|
|
21219
21399
|
}
|
|
21220
21400
|
}
|
|
21221
21401
|
return out;
|
|
21222
21402
|
}
|
|
21223
21403
|
function loadGeminiCost(start, end, geminiTmpDir2) {
|
|
21224
21404
|
const acc = emptyGeminiAccumulator();
|
|
21225
|
-
if (!
|
|
21405
|
+
if (!import_fs42.default.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
|
|
21226
21406
|
for (const { projectKey, file } of listGeminiSessionFiles2(geminiTmpDir2)) {
|
|
21227
21407
|
processGeminiCostFile(file, projectKey, start, end, acc);
|
|
21228
21408
|
}
|
|
@@ -21230,11 +21410,11 @@ function loadGeminiCost(start, end, geminiTmpDir2) {
|
|
|
21230
21410
|
}
|
|
21231
21411
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
21232
21412
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
21233
|
-
const auditLogPath = opts.auditLogPath ??
|
|
21234
|
-
const claudeProjectsDir = opts.claudeProjectsDir ??
|
|
21235
|
-
const codexSessionsDir2 = opts.codexSessionsDir ??
|
|
21236
|
-
const geminiTmpDir2 = opts.geminiTmpDir ??
|
|
21237
|
-
const hasAuditFile =
|
|
21413
|
+
const auditLogPath = opts.auditLogPath ?? import_path43.default.join(import_os38.default.homedir(), ".node9", "audit.log");
|
|
21414
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? import_path43.default.join(import_os38.default.homedir(), ".claude", "projects");
|
|
21415
|
+
const codexSessionsDir2 = opts.codexSessionsDir ?? import_path43.default.join(import_os38.default.homedir(), ".codex", "sessions");
|
|
21416
|
+
const geminiTmpDir2 = opts.geminiTmpDir ?? import_path43.default.join(import_os38.default.homedir(), ".gemini", "tmp");
|
|
21417
|
+
const hasAuditFile = import_fs42.default.existsSync(auditLogPath);
|
|
21238
21418
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
|
|
21239
21419
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
21240
21420
|
const { start, end } = getDateRange(period, now);
|
|
@@ -21930,9 +22110,9 @@ function registerDaemonCommand(program2) {
|
|
|
21930
22110
|
|
|
21931
22111
|
// src/cli/commands/status.ts
|
|
21932
22112
|
var import_chalk15 = __toESM(require("chalk"));
|
|
21933
|
-
var
|
|
21934
|
-
var
|
|
21935
|
-
var
|
|
22113
|
+
var import_fs43 = __toESM(require("fs"));
|
|
22114
|
+
var import_path44 = __toESM(require("path"));
|
|
22115
|
+
var import_os39 = __toESM(require("os"));
|
|
21936
22116
|
init_core();
|
|
21937
22117
|
init_daemon();
|
|
21938
22118
|
function printAgentSection(label2, hookPairs, wrapped) {
|
|
@@ -21988,20 +22168,20 @@ function registerStatusCommand(program2) {
|
|
|
21988
22168
|
console.log("");
|
|
21989
22169
|
const modeLabel = settings.mode === "audit" ? import_chalk15.default.blue("audit") : settings.mode === "strict" ? import_chalk15.default.red("strict") : import_chalk15.default.white("standard");
|
|
21990
22170
|
console.log(` Mode: ${modeLabel}`);
|
|
21991
|
-
const projectConfig =
|
|
21992
|
-
const globalConfig =
|
|
22171
|
+
const projectConfig = import_path44.default.join(process.cwd(), "node9.config.json");
|
|
22172
|
+
const globalConfig = import_path44.default.join(import_os39.default.homedir(), ".node9", "config.json");
|
|
21993
22173
|
console.log(
|
|
21994
|
-
` Local: ${
|
|
22174
|
+
` Local: ${import_fs43.default.existsSync(projectConfig) ? import_chalk15.default.green("Active (node9.config.json)") : import_chalk15.default.gray("Not present")}`
|
|
21995
22175
|
);
|
|
21996
22176
|
console.log(
|
|
21997
|
-
` Global: ${
|
|
22177
|
+
` Global: ${import_fs43.default.existsSync(globalConfig) ? import_chalk15.default.green("Active (~/.node9/config.json)") : import_chalk15.default.gray("Not present")}`
|
|
21998
22178
|
);
|
|
21999
22179
|
if (mergedConfig.policy.sandboxPaths.length > 0) {
|
|
22000
22180
|
console.log(
|
|
22001
22181
|
` Sandbox: ${import_chalk15.default.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
|
|
22002
22182
|
);
|
|
22003
22183
|
}
|
|
22004
|
-
const wiring = getAgentWiring(
|
|
22184
|
+
const wiring = getAgentWiring(import_os39.default.homedir()).filter((a) => a.present);
|
|
22005
22185
|
if (wiring.length > 0) {
|
|
22006
22186
|
console.log("");
|
|
22007
22187
|
console.log(import_chalk15.default.bold(" Agent Wiring:"));
|
|
@@ -22036,9 +22216,9 @@ function registerStatusCommand(program2) {
|
|
|
22036
22216
|
|
|
22037
22217
|
// src/cli/commands/init.ts
|
|
22038
22218
|
var import_chalk16 = __toESM(require("chalk"));
|
|
22039
|
-
var
|
|
22040
|
-
var
|
|
22041
|
-
var
|
|
22219
|
+
var import_fs44 = __toESM(require("fs"));
|
|
22220
|
+
var import_path45 = __toESM(require("path"));
|
|
22221
|
+
var import_os40 = __toESM(require("os"));
|
|
22042
22222
|
var import_https4 = __toESM(require("https"));
|
|
22043
22223
|
init_core();
|
|
22044
22224
|
init_setup();
|
|
@@ -22128,16 +22308,16 @@ function registerInitCommand(program2) {
|
|
|
22128
22308
|
}
|
|
22129
22309
|
console.log("");
|
|
22130
22310
|
}
|
|
22131
|
-
const configPath2 =
|
|
22132
|
-
const isFirstInstall = !
|
|
22133
|
-
if (
|
|
22311
|
+
const configPath2 = import_path45.default.join(import_os40.default.homedir(), ".node9", "config.json");
|
|
22312
|
+
const isFirstInstall = !import_fs44.default.existsSync(configPath2);
|
|
22313
|
+
if (import_fs44.default.existsSync(configPath2) && !options.force) {
|
|
22134
22314
|
try {
|
|
22135
|
-
const existing = JSON.parse(
|
|
22315
|
+
const existing = JSON.parse(import_fs44.default.readFileSync(configPath2, "utf-8"));
|
|
22136
22316
|
const settings = existing.settings ?? {};
|
|
22137
22317
|
if (settings.mode !== chosenMode) {
|
|
22138
22318
|
settings.mode = chosenMode;
|
|
22139
22319
|
existing.settings = settings;
|
|
22140
|
-
|
|
22320
|
+
import_fs44.default.writeFileSync(configPath2, JSON.stringify(existing, null, 2) + "\n");
|
|
22141
22321
|
console.log(import_chalk16.default.green(`\u2705 Mode updated: ${chosenMode}`));
|
|
22142
22322
|
} else {
|
|
22143
22323
|
console.log(import_chalk16.default.blue(`\u2139\uFE0F Config already exists: ${configPath2}`));
|
|
@@ -22150,9 +22330,9 @@ function registerInitCommand(program2) {
|
|
|
22150
22330
|
...DEFAULT_CONFIG,
|
|
22151
22331
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
22152
22332
|
};
|
|
22153
|
-
const dir =
|
|
22154
|
-
if (!
|
|
22155
|
-
|
|
22333
|
+
const dir = import_path45.default.dirname(configPath2);
|
|
22334
|
+
if (!import_fs44.default.existsSync(dir)) import_fs44.default.mkdirSync(dir, { recursive: true });
|
|
22335
|
+
import_fs44.default.writeFileSync(configPath2, JSON.stringify(configToSave, null, 2) + "\n");
|
|
22156
22336
|
console.log(import_chalk16.default.green(`\u2705 Config created: ${configPath2}`));
|
|
22157
22337
|
console.log(import_chalk16.default.gray(` Mode: ${chosenMode}`));
|
|
22158
22338
|
}
|
|
@@ -22257,7 +22437,7 @@ function registerInitCommand(program2) {
|
|
|
22257
22437
|
}
|
|
22258
22438
|
|
|
22259
22439
|
// src/cli/commands/undo.ts
|
|
22260
|
-
var
|
|
22440
|
+
var import_path46 = __toESM(require("path"));
|
|
22261
22441
|
var import_chalk18 = __toESM(require("chalk"));
|
|
22262
22442
|
|
|
22263
22443
|
// src/tui/undo-navigator.ts
|
|
@@ -22416,7 +22596,7 @@ function findMatchingCwd(startDir, history) {
|
|
|
22416
22596
|
let dir = startDir;
|
|
22417
22597
|
while (true) {
|
|
22418
22598
|
if (cwds.has(dir)) return dir;
|
|
22419
|
-
const parent =
|
|
22599
|
+
const parent = import_path46.default.dirname(dir);
|
|
22420
22600
|
if (parent === dir) return null;
|
|
22421
22601
|
dir = parent;
|
|
22422
22602
|
}
|
|
@@ -23051,9 +23231,9 @@ function registerMcpGatewayCommand(program2) {
|
|
|
23051
23231
|
|
|
23052
23232
|
// src/mcp-server/index.ts
|
|
23053
23233
|
var import_readline5 = __toESM(require("readline"));
|
|
23054
|
-
var
|
|
23055
|
-
var
|
|
23056
|
-
var
|
|
23234
|
+
var import_fs45 = __toESM(require("fs"));
|
|
23235
|
+
var import_os41 = __toESM(require("os"));
|
|
23236
|
+
var import_path47 = __toESM(require("path"));
|
|
23057
23237
|
var import_child_process11 = require("child_process");
|
|
23058
23238
|
init_core();
|
|
23059
23239
|
init_daemon();
|
|
@@ -23304,13 +23484,13 @@ function handleStatus() {
|
|
|
23304
23484
|
lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
|
|
23305
23485
|
lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
|
|
23306
23486
|
lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
|
|
23307
|
-
const projectConfig =
|
|
23308
|
-
const globalConfig =
|
|
23487
|
+
const projectConfig = import_path47.default.join(process.cwd(), "node9.config.json");
|
|
23488
|
+
const globalConfig = import_path47.default.join(import_os41.default.homedir(), ".node9", "config.json");
|
|
23309
23489
|
lines.push(
|
|
23310
|
-
`Project config (node9.config.json): ${
|
|
23490
|
+
`Project config (node9.config.json): ${import_fs45.default.existsSync(projectConfig) ? "present" : "not found"}`
|
|
23311
23491
|
);
|
|
23312
23492
|
lines.push(
|
|
23313
|
-
`Global config (~/.node9/config.json): ${
|
|
23493
|
+
`Global config (~/.node9/config.json): ${import_fs45.default.existsSync(globalConfig) ? "present" : "not found"}`
|
|
23314
23494
|
);
|
|
23315
23495
|
return lines.join("\n");
|
|
23316
23496
|
}
|
|
@@ -23384,21 +23564,21 @@ function handleShieldDisable(args) {
|
|
|
23384
23564
|
writeActiveShields(active.filter((s) => s !== name));
|
|
23385
23565
|
return `Shield "${name}" disabled.`;
|
|
23386
23566
|
}
|
|
23387
|
-
var GLOBAL_CONFIG_PATH =
|
|
23567
|
+
var GLOBAL_CONFIG_PATH = import_path47.default.join(import_os41.default.homedir(), ".node9", "config.json");
|
|
23388
23568
|
var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
|
|
23389
23569
|
function readGlobalConfigRaw() {
|
|
23390
23570
|
try {
|
|
23391
|
-
if (
|
|
23392
|
-
return JSON.parse(
|
|
23571
|
+
if (import_fs45.default.existsSync(GLOBAL_CONFIG_PATH)) {
|
|
23572
|
+
return JSON.parse(import_fs45.default.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
|
|
23393
23573
|
}
|
|
23394
23574
|
} catch {
|
|
23395
23575
|
}
|
|
23396
23576
|
return {};
|
|
23397
23577
|
}
|
|
23398
23578
|
function writeGlobalConfigRaw(data) {
|
|
23399
|
-
const dir =
|
|
23400
|
-
if (!
|
|
23401
|
-
|
|
23579
|
+
const dir = import_path47.default.dirname(GLOBAL_CONFIG_PATH);
|
|
23580
|
+
if (!import_fs45.default.existsSync(dir)) import_fs45.default.mkdirSync(dir, { recursive: true });
|
|
23581
|
+
import_fs45.default.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
|
|
23402
23582
|
}
|
|
23403
23583
|
function handleApproverList() {
|
|
23404
23584
|
const config = getConfig();
|
|
@@ -23442,9 +23622,9 @@ function handleApproverSet(args) {
|
|
|
23442
23622
|
function handleAuditGet(args) {
|
|
23443
23623
|
const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
|
|
23444
23624
|
const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
|
|
23445
|
-
const auditPath =
|
|
23446
|
-
if (!
|
|
23447
|
-
const rawLines =
|
|
23625
|
+
const auditPath = import_path47.default.join(import_os41.default.homedir(), ".node9", "audit.log");
|
|
23626
|
+
if (!import_fs45.default.existsSync(auditPath)) return "No audit log found.";
|
|
23627
|
+
const rawLines = import_fs45.default.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
|
|
23448
23628
|
const parsed = [];
|
|
23449
23629
|
for (const line of rawLines) {
|
|
23450
23630
|
try {
|
|
@@ -23779,7 +23959,7 @@ function registerTrustCommand(program2) {
|
|
|
23779
23959
|
// src/cli/commands/mcp-pin.ts
|
|
23780
23960
|
var import_chalk21 = __toESM(require("chalk"));
|
|
23781
23961
|
init_mcp_pin();
|
|
23782
|
-
var
|
|
23962
|
+
var import_fs46 = __toESM(require("fs"));
|
|
23783
23963
|
function registerMcpPinCommand(program2) {
|
|
23784
23964
|
const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
|
|
23785
23965
|
const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
|
|
@@ -23790,7 +23970,7 @@ function registerMcpPinCommand(program2) {
|
|
|
23790
23970
|
let repoCorrupt = false;
|
|
23791
23971
|
if (found.source === "repo") {
|
|
23792
23972
|
try {
|
|
23793
|
-
const raw =
|
|
23973
|
+
const raw = import_fs46.default.readFileSync(found.path, "utf-8");
|
|
23794
23974
|
const parsed = JSON.parse(raw);
|
|
23795
23975
|
repoEntries = parsed.servers ?? {};
|
|
23796
23976
|
} catch {
|
|
@@ -24105,25 +24285,25 @@ init_scan();
|
|
|
24105
24285
|
var import_chalk25 = __toESM(require("chalk"));
|
|
24106
24286
|
|
|
24107
24287
|
// src/posture/index.ts
|
|
24108
|
-
var
|
|
24288
|
+
var import_os45 = __toESM(require("os"));
|
|
24109
24289
|
|
|
24110
24290
|
// src/posture/secrets.ts
|
|
24111
|
-
var
|
|
24112
|
-
var
|
|
24113
|
-
var
|
|
24291
|
+
var import_fs47 = __toESM(require("fs"));
|
|
24292
|
+
var import_path48 = __toESM(require("path"));
|
|
24293
|
+
var import_os42 = __toESM(require("os"));
|
|
24114
24294
|
init_dist();
|
|
24115
24295
|
var MAX_FILE_BYTES = 256 * 1024;
|
|
24116
24296
|
function displayPath(p, home) {
|
|
24117
24297
|
if (p === home) return "~";
|
|
24118
|
-
const prefix = home.endsWith(
|
|
24119
|
-
if (p.startsWith(prefix)) return "~" +
|
|
24298
|
+
const prefix = home.endsWith(import_path48.default.sep) ? home : home + import_path48.default.sep;
|
|
24299
|
+
if (p.startsWith(prefix)) return "~" + import_path48.default.sep + p.slice(prefix.length);
|
|
24120
24300
|
return p;
|
|
24121
24301
|
}
|
|
24122
24302
|
function safeRead(file) {
|
|
24123
24303
|
try {
|
|
24124
|
-
const stat =
|
|
24304
|
+
const stat = import_fs47.default.statSync(file);
|
|
24125
24305
|
if (!stat.isFile() || stat.size === 0 || stat.size > MAX_FILE_BYTES) return null;
|
|
24126
|
-
return
|
|
24306
|
+
return import_fs47.default.readFileSync(file, "utf8");
|
|
24127
24307
|
} catch {
|
|
24128
24308
|
return null;
|
|
24129
24309
|
}
|
|
@@ -24131,8 +24311,8 @@ function safeRead(file) {
|
|
|
24131
24311
|
function candidateFiles(home, cwd) {
|
|
24132
24312
|
const files = /* @__PURE__ */ new Set();
|
|
24133
24313
|
try {
|
|
24134
|
-
for (const name of
|
|
24135
|
-
if (name === ".env" || name.startsWith(".env.")) files.add(
|
|
24314
|
+
for (const name of import_fs47.default.readdirSync(cwd)) {
|
|
24315
|
+
if (name === ".env" || name.startsWith(".env.")) files.add(import_path48.default.join(cwd, name));
|
|
24136
24316
|
}
|
|
24137
24317
|
} catch {
|
|
24138
24318
|
}
|
|
@@ -24140,21 +24320,21 @@ function candidateFiles(home, cwd) {
|
|
|
24140
24320
|
if (spec.hookFile) files.add(spec.hookFile(home));
|
|
24141
24321
|
if (spec.mcpFile) files.add(spec.mcpFile(home));
|
|
24142
24322
|
}
|
|
24143
|
-
files.add(
|
|
24323
|
+
files.add(import_path48.default.join(home, ".env"));
|
|
24144
24324
|
return [...files];
|
|
24145
24325
|
}
|
|
24146
24326
|
function credentialMaterial(home) {
|
|
24147
24327
|
return [
|
|
24148
|
-
|
|
24149
|
-
|
|
24150
|
-
|
|
24151
|
-
|
|
24152
|
-
|
|
24153
|
-
|
|
24328
|
+
import_path48.default.join(home, ".ssh", "id_rsa"),
|
|
24329
|
+
import_path48.default.join(home, ".ssh", "id_dsa"),
|
|
24330
|
+
import_path48.default.join(home, ".ssh", "id_ecdsa"),
|
|
24331
|
+
import_path48.default.join(home, ".ssh", "id_ed25519"),
|
|
24332
|
+
import_path48.default.join(home, ".aws", "credentials"),
|
|
24333
|
+
import_path48.default.join(home, ".config", "gcloud", "application_default_credentials.json")
|
|
24154
24334
|
];
|
|
24155
24335
|
}
|
|
24156
24336
|
function checkSecrets(ctx) {
|
|
24157
|
-
const home = ctx.home ||
|
|
24337
|
+
const home = ctx.home || import_os42.default.homedir();
|
|
24158
24338
|
const findings = [];
|
|
24159
24339
|
const plaintext = [];
|
|
24160
24340
|
const plaintextPaths = [];
|
|
@@ -24187,7 +24367,7 @@ function checkSecrets(ctx) {
|
|
|
24187
24367
|
const credPaths = [];
|
|
24188
24368
|
for (const file of credentialMaterial(home)) {
|
|
24189
24369
|
try {
|
|
24190
|
-
if (
|
|
24370
|
+
if (import_fs47.default.statSync(file).isFile()) {
|
|
24191
24371
|
creds.push(displayPath(file, home));
|
|
24192
24372
|
credPaths.push(file);
|
|
24193
24373
|
}
|
|
@@ -24212,7 +24392,7 @@ function checkSecrets(ctx) {
|
|
|
24212
24392
|
}
|
|
24213
24393
|
|
|
24214
24394
|
// src/posture/egress.ts
|
|
24215
|
-
var
|
|
24395
|
+
var import_fs48 = __toESM(require("fs"));
|
|
24216
24396
|
init_config();
|
|
24217
24397
|
|
|
24218
24398
|
// src/sandbox/templates.ts
|
|
@@ -24334,7 +24514,7 @@ exec gosu "$RUN_AS_USER" bash -lc '
|
|
|
24334
24514
|
// src/posture/egress.ts
|
|
24335
24515
|
function sandboxEgressWallActive() {
|
|
24336
24516
|
try {
|
|
24337
|
-
return
|
|
24517
|
+
return import_fs48.default.existsSync(ALLOWED_DOMAINS_PATH);
|
|
24338
24518
|
} catch {
|
|
24339
24519
|
return false;
|
|
24340
24520
|
}
|
|
@@ -24443,26 +24623,26 @@ async function checkGate(ctx) {
|
|
|
24443
24623
|
}
|
|
24444
24624
|
|
|
24445
24625
|
// src/posture/supply-chain.ts
|
|
24446
|
-
var
|
|
24447
|
-
var
|
|
24448
|
-
var
|
|
24626
|
+
var import_fs49 = __toESM(require("fs"));
|
|
24627
|
+
var import_os43 = __toESM(require("os"));
|
|
24628
|
+
var import_path49 = __toESM(require("path"));
|
|
24449
24629
|
var import_smol_toml3 = require("smol-toml");
|
|
24450
24630
|
init_provenance();
|
|
24451
24631
|
var PACKAGE_RUNNERS = /* @__PURE__ */ new Set(["npx", "pnpx", "bunx", "dlx", "yarn", "pnpm", "bun"]);
|
|
24452
24632
|
function isNode9Managed(command, args = []) {
|
|
24453
24633
|
if (!command) return false;
|
|
24454
|
-
if (
|
|
24455
|
-
if (PACKAGE_RUNNERS.has(
|
|
24456
|
-
return args.some((a) => a === "node9" ||
|
|
24634
|
+
if (import_path49.default.basename(command).toLowerCase() === "node9") return true;
|
|
24635
|
+
if (PACKAGE_RUNNERS.has(import_path49.default.basename(command).toLowerCase())) {
|
|
24636
|
+
return args.some((a) => a === "node9" || import_path49.default.basename(a).toLowerCase() === "node9");
|
|
24457
24637
|
}
|
|
24458
24638
|
return false;
|
|
24459
24639
|
}
|
|
24460
24640
|
var MAX_CONFIG_BYTES = 10 * 1024 * 1024;
|
|
24461
24641
|
function readServers(file, format, agent) {
|
|
24462
24642
|
try {
|
|
24463
|
-
const stat =
|
|
24643
|
+
const stat = import_fs49.default.statSync(file);
|
|
24464
24644
|
if (!stat.isFile() || stat.size > MAX_CONFIG_BYTES) return [];
|
|
24465
|
-
const text =
|
|
24645
|
+
const text = import_fs49.default.readFileSync(file, "utf8");
|
|
24466
24646
|
const map = format === "toml" ? (0, import_smol_toml3.parse)(text)?.mcp_servers : JSON.parse(text)?.mcpServers;
|
|
24467
24647
|
if (!map || typeof map !== "object") return [];
|
|
24468
24648
|
return Object.entries(map).map(([name, v]) => ({
|
|
@@ -24476,7 +24656,7 @@ function readServers(file, format, agent) {
|
|
|
24476
24656
|
}
|
|
24477
24657
|
}
|
|
24478
24658
|
function checkSupplyChain(ctx) {
|
|
24479
|
-
const home = ctx.home ||
|
|
24659
|
+
const home = ctx.home || import_os43.default.homedir();
|
|
24480
24660
|
const servers = [];
|
|
24481
24661
|
for (const spec of AGENT_SPECS) {
|
|
24482
24662
|
if (!spec.mcpFile) continue;
|
|
@@ -24558,12 +24738,12 @@ async function checkPrivilege(ctx) {
|
|
|
24558
24738
|
}
|
|
24559
24739
|
|
|
24560
24740
|
// src/posture/containment.ts
|
|
24561
|
-
var
|
|
24741
|
+
var import_fs50 = __toESM(require("fs"));
|
|
24562
24742
|
var ISOLATION_WEIGHT = 12;
|
|
24563
24743
|
function inContainer() {
|
|
24564
|
-
if (
|
|
24744
|
+
if (import_fs50.default.existsSync("/.dockerenv") || import_fs50.default.existsSync("/run/.containerenv")) return true;
|
|
24565
24745
|
try {
|
|
24566
|
-
const cgroup =
|
|
24746
|
+
const cgroup = import_fs50.default.readFileSync("/proc/1/cgroup", "utf8");
|
|
24567
24747
|
if (/docker|kubepods|containerd|lxc|libpod/.test(cgroup)) return true;
|
|
24568
24748
|
} catch {
|
|
24569
24749
|
}
|
|
@@ -24602,7 +24782,7 @@ Lighter \u2014 harden in place, keep full host access (about +${Math.round(
|
|
|
24602
24782
|
}
|
|
24603
24783
|
|
|
24604
24784
|
// src/posture/inbound.ts
|
|
24605
|
-
var
|
|
24785
|
+
var import_fs51 = __toESM(require("fs"));
|
|
24606
24786
|
var DB_EXPOSURE_WEIGHT = 4;
|
|
24607
24787
|
var KNOWN_SERVICE_PORTS = {
|
|
24608
24788
|
5432: "PostgreSQL",
|
|
@@ -24689,7 +24869,7 @@ function collectListeners() {
|
|
|
24689
24869
|
const byPort = /* @__PURE__ */ new Map();
|
|
24690
24870
|
for (const file of ["/proc/net/tcp", "/proc/net/tcp6"]) {
|
|
24691
24871
|
try {
|
|
24692
|
-
for (const l of parseListeners(
|
|
24872
|
+
for (const l of parseListeners(import_fs51.default.readFileSync(file, "utf8"))) {
|
|
24693
24873
|
if (!byPort.has(l.port)) byPort.set(l.port, l);
|
|
24694
24874
|
}
|
|
24695
24875
|
} catch {
|
|
@@ -24701,11 +24881,11 @@ function readProc(pid) {
|
|
|
24701
24881
|
let comm = "unknown";
|
|
24702
24882
|
let cmdline = "";
|
|
24703
24883
|
try {
|
|
24704
|
-
comm =
|
|
24884
|
+
comm = import_fs51.default.readFileSync(`/proc/${pid}/comm`, "utf8").trim().replace(/-MainThread$/, "") || "unknown";
|
|
24705
24885
|
} catch {
|
|
24706
24886
|
}
|
|
24707
24887
|
try {
|
|
24708
|
-
cmdline =
|
|
24888
|
+
cmdline = import_fs51.default.readFileSync(`/proc/${pid}/cmdline`).toString().replace(/\0/g, " ").trim();
|
|
24709
24889
|
} catch {
|
|
24710
24890
|
}
|
|
24711
24891
|
return { comm, cmdline };
|
|
@@ -24715,21 +24895,21 @@ function resolveProcesses(inodes) {
|
|
|
24715
24895
|
if (inodes.size === 0) return map;
|
|
24716
24896
|
let pids;
|
|
24717
24897
|
try {
|
|
24718
|
-
pids =
|
|
24898
|
+
pids = import_fs51.default.readdirSync("/proc").filter((d) => /^\d+$/.test(d));
|
|
24719
24899
|
} catch {
|
|
24720
24900
|
return map;
|
|
24721
24901
|
}
|
|
24722
24902
|
for (const pid of pids) {
|
|
24723
24903
|
let fds;
|
|
24724
24904
|
try {
|
|
24725
|
-
fds =
|
|
24905
|
+
fds = import_fs51.default.readdirSync(`/proc/${pid}/fd`);
|
|
24726
24906
|
} catch {
|
|
24727
24907
|
continue;
|
|
24728
24908
|
}
|
|
24729
24909
|
for (const fd of fds) {
|
|
24730
24910
|
let link;
|
|
24731
24911
|
try {
|
|
24732
|
-
link =
|
|
24912
|
+
link = import_fs51.default.readlinkSync(`/proc/${pid}/fd/${fd}`);
|
|
24733
24913
|
} catch {
|
|
24734
24914
|
continue;
|
|
24735
24915
|
}
|
|
@@ -24799,10 +24979,10 @@ function checkInbound(ctx) {
|
|
|
24799
24979
|
}
|
|
24800
24980
|
|
|
24801
24981
|
// src/posture/coverage.ts
|
|
24802
|
-
var
|
|
24982
|
+
var import_os44 = __toESM(require("os"));
|
|
24803
24983
|
init_config();
|
|
24804
24984
|
function checkCoverage(ctx) {
|
|
24805
|
-
const home = ctx.home ||
|
|
24985
|
+
const home = ctx.home || import_os44.default.homedir();
|
|
24806
24986
|
const findings = [];
|
|
24807
24987
|
const protectedAgents = getAgentWiring(home).filter((r) => r.isProtected);
|
|
24808
24988
|
if (protectedAgents.length === 0) {
|
|
@@ -25010,7 +25190,7 @@ async function runChecks(checks, ctx) {
|
|
|
25010
25190
|
}
|
|
25011
25191
|
async function runPosture(opts = {}) {
|
|
25012
25192
|
const ctx = {
|
|
25013
|
-
home: opts.home ??
|
|
25193
|
+
home: opts.home ?? import_os45.default.homedir(),
|
|
25014
25194
|
cwd: opts.cwd ?? process.cwd(),
|
|
25015
25195
|
agent: opts.agent
|
|
25016
25196
|
};
|
|
@@ -25278,9 +25458,9 @@ function registerPostureCommand(program2) {
|
|
|
25278
25458
|
|
|
25279
25459
|
// src/cli/commands/egress.ts
|
|
25280
25460
|
var import_chalk26 = __toESM(require("chalk"));
|
|
25281
|
-
var
|
|
25282
|
-
var
|
|
25283
|
-
var
|
|
25461
|
+
var import_fs52 = __toESM(require("fs"));
|
|
25462
|
+
var import_os46 = __toESM(require("os"));
|
|
25463
|
+
var import_path50 = __toESM(require("path"));
|
|
25284
25464
|
init_config();
|
|
25285
25465
|
init_dist();
|
|
25286
25466
|
var DEFAULT_EGRESS = {
|
|
@@ -25291,12 +25471,12 @@ var DEFAULT_EGRESS = {
|
|
|
25291
25471
|
allowPrivate: true
|
|
25292
25472
|
};
|
|
25293
25473
|
function configPath() {
|
|
25294
|
-
return
|
|
25474
|
+
return import_path50.default.join(import_os46.default.homedir(), ".node9", "config.json");
|
|
25295
25475
|
}
|
|
25296
25476
|
function readRawConfig() {
|
|
25297
25477
|
let text;
|
|
25298
25478
|
try {
|
|
25299
|
-
text =
|
|
25479
|
+
text = import_fs52.default.readFileSync(configPath(), "utf8");
|
|
25300
25480
|
} catch (err2) {
|
|
25301
25481
|
if (err2.code === "ENOENT") return {};
|
|
25302
25482
|
throw err2;
|
|
@@ -25311,8 +25491,8 @@ function readRawConfig() {
|
|
|
25311
25491
|
}
|
|
25312
25492
|
function writeRawConfig(config) {
|
|
25313
25493
|
const p = configPath();
|
|
25314
|
-
|
|
25315
|
-
|
|
25494
|
+
import_fs52.default.mkdirSync(import_path50.default.dirname(p), { recursive: true });
|
|
25495
|
+
import_fs52.default.writeFileSync(p, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
25316
25496
|
}
|
|
25317
25497
|
function applyEgress(config, change) {
|
|
25318
25498
|
const policy = config.policy = config.policy ?? {};
|
|
@@ -25405,14 +25585,14 @@ function registerEgressCommand(program2) {
|
|
|
25405
25585
|
|
|
25406
25586
|
// src/cli/commands/sandbox.ts
|
|
25407
25587
|
var import_chalk27 = __toESM(require("chalk"));
|
|
25408
|
-
var
|
|
25409
|
-
var
|
|
25588
|
+
var import_fs55 = __toESM(require("fs"));
|
|
25589
|
+
var import_path53 = __toESM(require("path"));
|
|
25410
25590
|
var import_child_process13 = require("child_process");
|
|
25411
25591
|
init_config();
|
|
25412
25592
|
|
|
25413
25593
|
// src/sandbox/config.ts
|
|
25414
|
-
var
|
|
25415
|
-
var
|
|
25594
|
+
var import_fs53 = __toESM(require("fs"));
|
|
25595
|
+
var import_path51 = __toESM(require("path"));
|
|
25416
25596
|
var import_yaml = require("yaml");
|
|
25417
25597
|
var SANDBOX_CONFIG_FILE = "node9.sandbox.yaml";
|
|
25418
25598
|
var FORBIDDEN_ENV = /* @__PURE__ */ new Set(["NODE9_API_KEY", "NODE9_API_URL"]);
|
|
@@ -25485,16 +25665,16 @@ function scaffoldSandboxYaml(agent) {
|
|
|
25485
25665
|
return header + (0, import_yaml.stringify)(defaultSandboxConfig(agent));
|
|
25486
25666
|
}
|
|
25487
25667
|
function sandboxConfigPath(cwd = process.cwd()) {
|
|
25488
|
-
return
|
|
25668
|
+
return import_path51.default.join(cwd, SANDBOX_CONFIG_FILE);
|
|
25489
25669
|
}
|
|
25490
25670
|
function loadSandboxConfig(cwd = process.cwd(), fallbackAgent = "claude") {
|
|
25491
25671
|
const p = sandboxConfigPath(cwd);
|
|
25492
|
-
if (!
|
|
25672
|
+
if (!import_fs53.default.existsSync(p)) {
|
|
25493
25673
|
throw new Error(`sandbox: ${SANDBOX_CONFIG_FILE} not found \u2014 run \`node9 sandbox new\` first.`);
|
|
25494
25674
|
}
|
|
25495
25675
|
let raw;
|
|
25496
25676
|
try {
|
|
25497
|
-
raw = (0, import_yaml.parse)(
|
|
25677
|
+
raw = (0, import_yaml.parse)(import_fs53.default.readFileSync(p, "utf-8"));
|
|
25498
25678
|
} catch (err2) {
|
|
25499
25679
|
throw new Error(
|
|
25500
25680
|
`sandbox: ${SANDBOX_CONFIG_FILE} is not valid YAML \u2014 ${err2.message}`
|
|
@@ -25549,13 +25729,13 @@ function compileAllowlist(input) {
|
|
|
25549
25729
|
}
|
|
25550
25730
|
|
|
25551
25731
|
// src/sandbox/runtime.ts
|
|
25552
|
-
var
|
|
25553
|
-
var
|
|
25554
|
-
var
|
|
25732
|
+
var import_fs54 = __toESM(require("fs"));
|
|
25733
|
+
var import_os47 = __toESM(require("os"));
|
|
25734
|
+
var import_path52 = __toESM(require("path"));
|
|
25555
25735
|
var import_crypto13 = __toESM(require("crypto"));
|
|
25556
25736
|
var import_child_process12 = require("child_process");
|
|
25557
25737
|
function sandboxDataDir(cwd = process.cwd()) {
|
|
25558
|
-
return
|
|
25738
|
+
return import_path52.default.join(cwd, ".node9", "sandbox", "data");
|
|
25559
25739
|
}
|
|
25560
25740
|
function detectEngine(engine) {
|
|
25561
25741
|
const r = (0, import_child_process12.spawnSync)(engine, ["--version"], { encoding: "utf-8" });
|
|
@@ -25566,7 +25746,7 @@ function detectEngine(engine) {
|
|
|
25566
25746
|
}
|
|
25567
25747
|
function agentCredentialsMount(agent) {
|
|
25568
25748
|
const rel = agent === "codex" ? ".codex/auth.json" : ".claude/.credentials.json";
|
|
25569
|
-
return { hostPath:
|
|
25749
|
+
return { hostPath: import_path52.default.join(import_os47.default.homedir(), rel), target: `/home/${RUN_AS_USER}/${rel}` };
|
|
25570
25750
|
}
|
|
25571
25751
|
function buildRunArgs(opts) {
|
|
25572
25752
|
const { config, workspaceHostPath, dataHostPath, allowlistHostPath, agentArgs } = opts;
|
|
@@ -25576,7 +25756,7 @@ function buildRunArgs(opts) {
|
|
|
25576
25756
|
args.push("-v", `${allowlistHostPath}:${ALLOWED_DOMAINS_PATH}:ro`);
|
|
25577
25757
|
if (config.node9.mountAgentCredentials) {
|
|
25578
25758
|
const creds = agentCredentialsMount(config.agent);
|
|
25579
|
-
if (
|
|
25759
|
+
if (import_fs54.default.existsSync(creds.hostPath)) {
|
|
25580
25760
|
args.push("-v", `${creds.hostPath}:${creds.target}`);
|
|
25581
25761
|
}
|
|
25582
25762
|
}
|
|
@@ -25594,30 +25774,30 @@ function imageContentHash(dockerfile, entrypoint) {
|
|
|
25594
25774
|
return import_crypto13.default.createHash("sha256").update(dockerfile).update("\0").update(entrypoint).digest("hex").slice(0, 16);
|
|
25595
25775
|
}
|
|
25596
25776
|
function sandboxBuildDir(cwd = process.cwd()) {
|
|
25597
|
-
return
|
|
25777
|
+
return import_path52.default.join(cwd, ".node9", "sandbox", "build");
|
|
25598
25778
|
}
|
|
25599
25779
|
function writeBuildContext(cwd, dockerfile, entrypoint) {
|
|
25600
25780
|
const dir = sandboxBuildDir(cwd);
|
|
25601
|
-
|
|
25602
|
-
|
|
25603
|
-
|
|
25781
|
+
import_fs54.default.mkdirSync(dir, { recursive: true });
|
|
25782
|
+
import_fs54.default.writeFileSync(import_path52.default.join(dir, "Dockerfile"), dockerfile);
|
|
25783
|
+
import_fs54.default.writeFileSync(import_path52.default.join(dir, "entrypoint.sh"), entrypoint);
|
|
25604
25784
|
return dir;
|
|
25605
25785
|
}
|
|
25606
25786
|
function writeAllowlist(cwd, hosts) {
|
|
25607
|
-
const dir =
|
|
25608
|
-
|
|
25609
|
-
const p =
|
|
25610
|
-
|
|
25787
|
+
const dir = import_path52.default.join(cwd, ".node9", "sandbox");
|
|
25788
|
+
import_fs54.default.mkdirSync(dir, { recursive: true });
|
|
25789
|
+
const p = import_path52.default.join(dir, "allowed-domains.txt");
|
|
25790
|
+
import_fs54.default.writeFileSync(p, hosts.join("\n") + "\n");
|
|
25611
25791
|
return p;
|
|
25612
25792
|
}
|
|
25613
25793
|
function resolveHomePath(p) {
|
|
25614
|
-
return p.startsWith("~") ?
|
|
25794
|
+
return p.startsWith("~") ? import_path52.default.join(import_os47.default.homedir(), p.slice(1)) : import_path52.default.resolve(p);
|
|
25615
25795
|
}
|
|
25616
25796
|
|
|
25617
25797
|
// src/cli/commands/sandbox.ts
|
|
25618
25798
|
function seedDataDirConfig(dataDir, sandbox) {
|
|
25619
|
-
|
|
25620
|
-
const configPath2 =
|
|
25799
|
+
import_fs55.default.mkdirSync(dataDir, { recursive: true });
|
|
25800
|
+
const configPath2 = import_path53.default.join(dataDir, "config.json");
|
|
25621
25801
|
const seed = {
|
|
25622
25802
|
settings: {
|
|
25623
25803
|
approvers: {
|
|
@@ -25628,7 +25808,7 @@ function seedDataDirConfig(dataDir, sandbox) {
|
|
|
25628
25808
|
}
|
|
25629
25809
|
}
|
|
25630
25810
|
};
|
|
25631
|
-
|
|
25811
|
+
import_fs55.default.writeFileSync(configPath2, JSON.stringify(seed, null, 2), { mode: 384 });
|
|
25632
25812
|
}
|
|
25633
25813
|
function registerSandboxCommand(program2, version2) {
|
|
25634
25814
|
const node9Version2 = pinnedNode9Version(version2);
|
|
@@ -25636,13 +25816,13 @@ function registerSandboxCommand(program2, version2) {
|
|
|
25636
25816
|
cmd.command("new").description(`Scaffold ${SANDBOX_CONFIG_FILE} in this project`).option("--agent <agent>", "claude (default) or codex", "claude").action((opts) => {
|
|
25637
25817
|
const agent = opts.agent === "codex" ? "codex" : "claude";
|
|
25638
25818
|
const p = sandboxConfigPath();
|
|
25639
|
-
if (
|
|
25819
|
+
if (import_fs55.default.existsSync(p)) {
|
|
25640
25820
|
console.log(
|
|
25641
25821
|
import_chalk27.default.yellow(` ${SANDBOX_CONFIG_FILE} already exists \u2014 leaving it untouched.`)
|
|
25642
25822
|
);
|
|
25643
25823
|
return;
|
|
25644
25824
|
}
|
|
25645
|
-
|
|
25825
|
+
import_fs55.default.writeFileSync(p, scaffoldSandboxYaml(agent));
|
|
25646
25826
|
console.log(
|
|
25647
25827
|
import_chalk27.default.green(` \u2713 wrote ${SANDBOX_CONFIG_FILE}`) + import_chalk27.default.dim(` (agent: ${agent})`)
|
|
25648
25828
|
);
|
|
@@ -25682,8 +25862,8 @@ function registerSandboxCommand(program2, version2) {
|
|
|
25682
25862
|
const buildDir = writeBuildContext(cwd, dockerfile, entrypoint);
|
|
25683
25863
|
const hash = imageContentHash(dockerfile, entrypoint);
|
|
25684
25864
|
const image = sandbox.runtime.image;
|
|
25685
|
-
const hashFile =
|
|
25686
|
-
const lastHash =
|
|
25865
|
+
const hashFile = import_path53.default.join(sandboxBuildDir(cwd), ".image-hash");
|
|
25866
|
+
const lastHash = import_fs55.default.existsSync(hashFile) ? import_fs55.default.readFileSync(hashFile, "utf-8").trim() : "";
|
|
25687
25867
|
const imageExists = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, ["image", "inspect", image], { stdio: "ignore" }).status === 0;
|
|
25688
25868
|
const needBuild = sandbox.runtime.rebuild === "always" || !imageExists || sandbox.runtime.rebuild !== "never" && lastHash !== hash;
|
|
25689
25869
|
if (needBuild) {
|
|
@@ -25695,7 +25875,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
25695
25875
|
console.error(import_chalk27.default.red(" build failed."));
|
|
25696
25876
|
process.exit(b.status ?? 1);
|
|
25697
25877
|
}
|
|
25698
|
-
|
|
25878
|
+
import_fs55.default.writeFileSync(hashFile, hash);
|
|
25699
25879
|
}
|
|
25700
25880
|
const dataDir = sandboxDataDir(cwd);
|
|
25701
25881
|
seedDataDirConfig(dataDir, sandbox);
|
|
@@ -25709,7 +25889,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
25709
25889
|
});
|
|
25710
25890
|
if (sandbox.node9.mountAgentCredentials) {
|
|
25711
25891
|
const creds = agentCredentialsMount(sandbox.agent);
|
|
25712
|
-
if (
|
|
25892
|
+
if (import_fs55.default.existsSync(creds.hostPath)) {
|
|
25713
25893
|
console.log(import_chalk27.default.dim(` mounting ${creds.hostPath} (agent credentials, rw)`));
|
|
25714
25894
|
} else {
|
|
25715
25895
|
console.log(
|
|
@@ -25725,20 +25905,20 @@ function registerSandboxCommand(program2, version2) {
|
|
|
25725
25905
|
process.exit(r.status ?? 0);
|
|
25726
25906
|
});
|
|
25727
25907
|
cmd.command("tail").description("Stream the sandbox's audit log (host-side)").action(() => {
|
|
25728
|
-
const auditPath =
|
|
25729
|
-
if (!
|
|
25908
|
+
const auditPath = import_path53.default.join(sandboxDataDir(), "audit.log");
|
|
25909
|
+
if (!import_fs55.default.existsSync(auditPath)) {
|
|
25730
25910
|
console.log(import_chalk27.default.dim(" no sandbox audit yet."));
|
|
25731
25911
|
return;
|
|
25732
25912
|
}
|
|
25733
25913
|
(0, import_child_process13.spawnSync)("tail", ["-f", auditPath], { stdio: "inherit" });
|
|
25734
25914
|
});
|
|
25735
25915
|
cmd.command("logs").description("Dump the sandbox's audit log").action(() => {
|
|
25736
|
-
const auditPath =
|
|
25737
|
-
if (!
|
|
25916
|
+
const auditPath = import_path53.default.join(sandboxDataDir(), "audit.log");
|
|
25917
|
+
if (!import_fs55.default.existsSync(auditPath)) {
|
|
25738
25918
|
console.log(import_chalk27.default.dim(" no sandbox audit yet."));
|
|
25739
25919
|
return;
|
|
25740
25920
|
}
|
|
25741
|
-
process.stdout.write(
|
|
25921
|
+
process.stdout.write(import_fs55.default.readFileSync(auditPath, "utf-8"));
|
|
25742
25922
|
});
|
|
25743
25923
|
cmd.command("clean").description("Remove the sandbox image, build context, and data").action(() => {
|
|
25744
25924
|
const cwd = process.cwd();
|
|
@@ -25752,16 +25932,16 @@ function registerSandboxCommand(program2, version2) {
|
|
|
25752
25932
|
stdio: "ignore"
|
|
25753
25933
|
});
|
|
25754
25934
|
}
|
|
25755
|
-
|
|
25935
|
+
import_fs55.default.rmSync(import_path53.default.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
|
|
25756
25936
|
console.log(import_chalk27.default.green(" \u2713 sandbox image + build + data removed."));
|
|
25757
25937
|
});
|
|
25758
25938
|
}
|
|
25759
25939
|
|
|
25760
25940
|
// src/cli/commands/sessions.ts
|
|
25761
25941
|
var import_chalk28 = __toESM(require("chalk"));
|
|
25762
|
-
var
|
|
25763
|
-
var
|
|
25764
|
-
var
|
|
25942
|
+
var import_fs56 = __toESM(require("fs"));
|
|
25943
|
+
var import_path54 = __toESM(require("path"));
|
|
25944
|
+
var import_os48 = __toESM(require("os"));
|
|
25765
25945
|
init_scan_summary();
|
|
25766
25946
|
init_litellm();
|
|
25767
25947
|
init_cost_gemini();
|
|
@@ -25782,10 +25962,10 @@ function encodeProjectPath(projectPath) {
|
|
|
25782
25962
|
}
|
|
25783
25963
|
function sessionJsonlPath(projectPath, sessionId) {
|
|
25784
25964
|
const encoded = encodeProjectPath(projectPath);
|
|
25785
|
-
return
|
|
25965
|
+
return import_path54.default.join(import_os48.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
|
|
25786
25966
|
}
|
|
25787
25967
|
function projectLabel(projectPath) {
|
|
25788
|
-
return projectPath.replace(
|
|
25968
|
+
return projectPath.replace(import_os48.default.homedir(), "~");
|
|
25789
25969
|
}
|
|
25790
25970
|
function parseHistoryLines(lines) {
|
|
25791
25971
|
const entries = [];
|
|
@@ -25854,10 +26034,10 @@ function parseSessionLines(lines) {
|
|
|
25854
26034
|
return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
|
|
25855
26035
|
}
|
|
25856
26036
|
function loadAuditEntries(auditPath) {
|
|
25857
|
-
const aPath = auditPath ??
|
|
26037
|
+
const aPath = auditPath ?? import_path54.default.join(import_os48.default.homedir(), ".node9", "audit.log");
|
|
25858
26038
|
let raw;
|
|
25859
26039
|
try {
|
|
25860
|
-
raw =
|
|
26040
|
+
raw = import_fs56.default.readFileSync(aPath, "utf-8");
|
|
25861
26041
|
} catch {
|
|
25862
26042
|
return [];
|
|
25863
26043
|
}
|
|
@@ -25893,8 +26073,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
25893
26073
|
return result;
|
|
25894
26074
|
}
|
|
25895
26075
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
25896
|
-
const tmpDir =
|
|
25897
|
-
if (!
|
|
26076
|
+
const tmpDir = import_path54.default.join(import_os48.default.homedir(), ".gemini", "tmp");
|
|
26077
|
+
if (!import_fs56.default.existsSync(tmpDir)) return [];
|
|
25898
26078
|
const cutoff = days !== null ? (() => {
|
|
25899
26079
|
const d = /* @__PURE__ */ new Date();
|
|
25900
26080
|
d.setDate(d.getDate() - days);
|
|
@@ -25903,35 +26083,35 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
25903
26083
|
})() : null;
|
|
25904
26084
|
let slugDirs;
|
|
25905
26085
|
try {
|
|
25906
|
-
slugDirs =
|
|
26086
|
+
slugDirs = import_fs56.default.readdirSync(tmpDir);
|
|
25907
26087
|
} catch {
|
|
25908
26088
|
return [];
|
|
25909
26089
|
}
|
|
25910
26090
|
const summaries = [];
|
|
25911
26091
|
for (const slug of slugDirs) {
|
|
25912
|
-
const slugPath =
|
|
26092
|
+
const slugPath = import_path54.default.join(tmpDir, slug);
|
|
25913
26093
|
try {
|
|
25914
|
-
if (!
|
|
26094
|
+
if (!import_fs56.default.statSync(slugPath).isDirectory()) continue;
|
|
25915
26095
|
} catch {
|
|
25916
26096
|
continue;
|
|
25917
26097
|
}
|
|
25918
|
-
let projectRoot =
|
|
26098
|
+
let projectRoot = import_path54.default.join(import_os48.default.homedir(), slug);
|
|
25919
26099
|
try {
|
|
25920
|
-
projectRoot =
|
|
26100
|
+
projectRoot = import_fs56.default.readFileSync(import_path54.default.join(slugPath, ".project_root"), "utf-8").trim();
|
|
25921
26101
|
} catch {
|
|
25922
26102
|
}
|
|
25923
|
-
const chatsDir =
|
|
25924
|
-
if (!
|
|
26103
|
+
const chatsDir = import_path54.default.join(slugPath, "chats");
|
|
26104
|
+
if (!import_fs56.default.existsSync(chatsDir)) continue;
|
|
25925
26105
|
let chatFiles;
|
|
25926
26106
|
try {
|
|
25927
|
-
chatFiles =
|
|
26107
|
+
chatFiles = import_fs56.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
25928
26108
|
} catch {
|
|
25929
26109
|
continue;
|
|
25930
26110
|
}
|
|
25931
26111
|
for (const chatFile of chatFiles) {
|
|
25932
26112
|
let raw;
|
|
25933
26113
|
try {
|
|
25934
|
-
raw =
|
|
26114
|
+
raw = import_fs56.default.readFileSync(import_path54.default.join(chatsDir, chatFile), "utf-8");
|
|
25935
26115
|
} catch {
|
|
25936
26116
|
continue;
|
|
25937
26117
|
}
|
|
@@ -26011,8 +26191,8 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
26011
26191
|
return summaries;
|
|
26012
26192
|
}
|
|
26013
26193
|
function buildCodexSessions(days, allAuditEntries) {
|
|
26014
|
-
const sessionsBase =
|
|
26015
|
-
if (!
|
|
26194
|
+
const sessionsBase = import_path54.default.join(import_os48.default.homedir(), ".codex", "sessions");
|
|
26195
|
+
if (!import_fs56.default.existsSync(sessionsBase)) return [];
|
|
26016
26196
|
const cutoff = days !== null ? (() => {
|
|
26017
26197
|
const d = /* @__PURE__ */ new Date();
|
|
26018
26198
|
d.setDate(d.getDate() - days);
|
|
@@ -26021,29 +26201,29 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
26021
26201
|
})() : null;
|
|
26022
26202
|
const jsonlFiles = [];
|
|
26023
26203
|
try {
|
|
26024
|
-
for (const year of
|
|
26025
|
-
const yearPath =
|
|
26204
|
+
for (const year of import_fs56.default.readdirSync(sessionsBase)) {
|
|
26205
|
+
const yearPath = import_path54.default.join(sessionsBase, year);
|
|
26026
26206
|
try {
|
|
26027
|
-
if (!
|
|
26207
|
+
if (!import_fs56.default.statSync(yearPath).isDirectory()) continue;
|
|
26028
26208
|
} catch {
|
|
26029
26209
|
continue;
|
|
26030
26210
|
}
|
|
26031
|
-
for (const month of
|
|
26032
|
-
const monthPath =
|
|
26211
|
+
for (const month of import_fs56.default.readdirSync(yearPath)) {
|
|
26212
|
+
const monthPath = import_path54.default.join(yearPath, month);
|
|
26033
26213
|
try {
|
|
26034
|
-
if (!
|
|
26214
|
+
if (!import_fs56.default.statSync(monthPath).isDirectory()) continue;
|
|
26035
26215
|
} catch {
|
|
26036
26216
|
continue;
|
|
26037
26217
|
}
|
|
26038
|
-
for (const day of
|
|
26039
|
-
const dayPath =
|
|
26218
|
+
for (const day of import_fs56.default.readdirSync(monthPath)) {
|
|
26219
|
+
const dayPath = import_path54.default.join(monthPath, day);
|
|
26040
26220
|
try {
|
|
26041
|
-
if (!
|
|
26221
|
+
if (!import_fs56.default.statSync(dayPath).isDirectory()) continue;
|
|
26042
26222
|
} catch {
|
|
26043
26223
|
continue;
|
|
26044
26224
|
}
|
|
26045
|
-
for (const file of
|
|
26046
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
26225
|
+
for (const file of import_fs56.default.readdirSync(dayPath)) {
|
|
26226
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path54.default.join(dayPath, file));
|
|
26047
26227
|
}
|
|
26048
26228
|
}
|
|
26049
26229
|
}
|
|
@@ -26055,7 +26235,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
26055
26235
|
for (const filePath of jsonlFiles) {
|
|
26056
26236
|
let lines;
|
|
26057
26237
|
try {
|
|
26058
|
-
lines =
|
|
26238
|
+
lines = import_fs56.default.readFileSync(filePath, "utf-8").split("\n");
|
|
26059
26239
|
} catch {
|
|
26060
26240
|
continue;
|
|
26061
26241
|
}
|
|
@@ -26141,10 +26321,10 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
26141
26321
|
return summaries;
|
|
26142
26322
|
}
|
|
26143
26323
|
function buildSessions(days, historyPath) {
|
|
26144
|
-
const hPath = historyPath ??
|
|
26324
|
+
const hPath = historyPath ?? import_path54.default.join(import_os48.default.homedir(), ".claude", "history.jsonl");
|
|
26145
26325
|
let historyRaw = "";
|
|
26146
26326
|
try {
|
|
26147
|
-
historyRaw =
|
|
26327
|
+
historyRaw = import_fs56.default.readFileSync(hPath, "utf-8");
|
|
26148
26328
|
} catch {
|
|
26149
26329
|
}
|
|
26150
26330
|
const cutoff = days !== null ? (() => {
|
|
@@ -26168,7 +26348,7 @@ function buildSessions(days, historyPath) {
|
|
|
26168
26348
|
const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
|
|
26169
26349
|
let sessionLines = [];
|
|
26170
26350
|
try {
|
|
26171
|
-
sessionLines =
|
|
26351
|
+
sessionLines = import_fs56.default.readFileSync(jsonlFile, "utf-8").split("\n");
|
|
26172
26352
|
} catch {
|
|
26173
26353
|
}
|
|
26174
26354
|
const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
|
|
@@ -26562,12 +26742,12 @@ function registerSessionTaintCommand(program2) {
|
|
|
26562
26742
|
|
|
26563
26743
|
// src/cli/commands/skill-pin.ts
|
|
26564
26744
|
var import_chalk30 = __toESM(require("chalk"));
|
|
26565
|
-
var
|
|
26566
|
-
var
|
|
26567
|
-
var
|
|
26745
|
+
var import_fs57 = __toESM(require("fs"));
|
|
26746
|
+
var import_os49 = __toESM(require("os"));
|
|
26747
|
+
var import_path55 = __toESM(require("path"));
|
|
26568
26748
|
function wipeSkillSessions() {
|
|
26569
26749
|
try {
|
|
26570
|
-
|
|
26750
|
+
import_fs57.default.rmSync(import_path55.default.join(import_os49.default.homedir(), ".node9", "skill-sessions"), {
|
|
26571
26751
|
recursive: true,
|
|
26572
26752
|
force: true
|
|
26573
26753
|
});
|
|
@@ -26649,15 +26829,15 @@ function registerSkillPinCommand(program2) {
|
|
|
26649
26829
|
}
|
|
26650
26830
|
|
|
26651
26831
|
// src/cli/commands/decisions.ts
|
|
26652
|
-
var
|
|
26653
|
-
var
|
|
26654
|
-
var
|
|
26832
|
+
var import_fs58 = __toESM(require("fs"));
|
|
26833
|
+
var import_os50 = __toESM(require("os"));
|
|
26834
|
+
var import_path56 = __toESM(require("path"));
|
|
26655
26835
|
var import_chalk31 = __toESM(require("chalk"));
|
|
26656
|
-
var DECISIONS_FILE2 =
|
|
26836
|
+
var DECISIONS_FILE2 = import_path56.default.join(import_os50.default.homedir(), ".node9", "decisions.json");
|
|
26657
26837
|
function readDecisions() {
|
|
26658
26838
|
try {
|
|
26659
|
-
if (!
|
|
26660
|
-
const raw =
|
|
26839
|
+
if (!import_fs58.default.existsSync(DECISIONS_FILE2)) return {};
|
|
26840
|
+
const raw = import_fs58.default.readFileSync(DECISIONS_FILE2, "utf-8");
|
|
26661
26841
|
const parsed = JSON.parse(raw);
|
|
26662
26842
|
const out = {};
|
|
26663
26843
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -26669,11 +26849,11 @@ function readDecisions() {
|
|
|
26669
26849
|
}
|
|
26670
26850
|
}
|
|
26671
26851
|
function writeDecisions(d) {
|
|
26672
|
-
const dir =
|
|
26673
|
-
if (!
|
|
26852
|
+
const dir = import_path56.default.dirname(DECISIONS_FILE2);
|
|
26853
|
+
if (!import_fs58.default.existsSync(dir)) import_fs58.default.mkdirSync(dir, { recursive: true });
|
|
26674
26854
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
26675
|
-
|
|
26676
|
-
|
|
26855
|
+
import_fs58.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
26856
|
+
import_fs58.default.renameSync(tmp, DECISIONS_FILE2);
|
|
26677
26857
|
}
|
|
26678
26858
|
function registerDecisionsCommand(program2) {
|
|
26679
26859
|
const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
|
|
@@ -26730,18 +26910,18 @@ Persistent decisions (${entries.length})
|
|
|
26730
26910
|
|
|
26731
26911
|
// src/cli/commands/dlp.ts
|
|
26732
26912
|
var import_chalk32 = __toESM(require("chalk"));
|
|
26733
|
-
var
|
|
26734
|
-
var
|
|
26735
|
-
var
|
|
26736
|
-
var AUDIT_LOG =
|
|
26737
|
-
var RESOLVED_FILE =
|
|
26913
|
+
var import_fs59 = __toESM(require("fs"));
|
|
26914
|
+
var import_path57 = __toESM(require("path"));
|
|
26915
|
+
var import_os51 = __toESM(require("os"));
|
|
26916
|
+
var AUDIT_LOG = import_path57.default.join(import_os51.default.homedir(), ".node9", "audit.log");
|
|
26917
|
+
var RESOLVED_FILE = import_path57.default.join(import_os51.default.homedir(), ".node9", "dlp-resolved.json");
|
|
26738
26918
|
var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
|
|
26739
26919
|
function stripAnsi(s) {
|
|
26740
26920
|
return s.replace(ANSI_RE, "");
|
|
26741
26921
|
}
|
|
26742
26922
|
function loadResolved() {
|
|
26743
26923
|
try {
|
|
26744
|
-
const raw = JSON.parse(
|
|
26924
|
+
const raw = JSON.parse(import_fs59.default.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
26745
26925
|
return new Set(raw);
|
|
26746
26926
|
} catch {
|
|
26747
26927
|
return /* @__PURE__ */ new Set();
|
|
@@ -26749,13 +26929,13 @@ function loadResolved() {
|
|
|
26749
26929
|
}
|
|
26750
26930
|
function saveResolved(resolved) {
|
|
26751
26931
|
try {
|
|
26752
|
-
|
|
26932
|
+
import_fs59.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
26753
26933
|
} catch {
|
|
26754
26934
|
}
|
|
26755
26935
|
}
|
|
26756
26936
|
function loadDlpFindings() {
|
|
26757
|
-
if (!
|
|
26758
|
-
return
|
|
26937
|
+
if (!import_fs59.default.existsSync(AUDIT_LOG)) return [];
|
|
26938
|
+
return import_fs59.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
26759
26939
|
if (!line.trim()) return [];
|
|
26760
26940
|
try {
|
|
26761
26941
|
const e = JSON.parse(line);
|
|
@@ -26853,15 +27033,15 @@ function registerDlpCommand(program2) {
|
|
|
26853
27033
|
|
|
26854
27034
|
// src/cli/commands/mask.ts
|
|
26855
27035
|
var import_chalk33 = __toESM(require("chalk"));
|
|
26856
|
-
var
|
|
26857
|
-
var
|
|
26858
|
-
var
|
|
27036
|
+
var import_fs60 = __toESM(require("fs"));
|
|
27037
|
+
var import_path58 = __toESM(require("path"));
|
|
27038
|
+
var import_os52 = __toESM(require("os"));
|
|
26859
27039
|
init_dlp();
|
|
26860
27040
|
function findJsonlFiles(dir) {
|
|
26861
27041
|
const results = [];
|
|
26862
|
-
if (!
|
|
26863
|
-
for (const entry of
|
|
26864
|
-
const full =
|
|
27042
|
+
if (!import_fs60.default.existsSync(dir)) return results;
|
|
27043
|
+
for (const entry of import_fs60.default.readdirSync(dir, { withFileTypes: true })) {
|
|
27044
|
+
const full = import_path58.default.join(dir, entry.name);
|
|
26865
27045
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
26866
27046
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
26867
27047
|
}
|
|
@@ -26904,7 +27084,7 @@ function redactJson(obj) {
|
|
|
26904
27084
|
function processFile(filePath, dryRun) {
|
|
26905
27085
|
let raw;
|
|
26906
27086
|
try {
|
|
26907
|
-
raw =
|
|
27087
|
+
raw = import_fs60.default.readFileSync(filePath, "utf-8");
|
|
26908
27088
|
} catch {
|
|
26909
27089
|
return { redactedLines: 0, patterns: [] };
|
|
26910
27090
|
}
|
|
@@ -26936,14 +27116,14 @@ function processFile(filePath, dryRun) {
|
|
|
26936
27116
|
}
|
|
26937
27117
|
}
|
|
26938
27118
|
if (!dryRun && redactedLines > 0) {
|
|
26939
|
-
|
|
27119
|
+
import_fs60.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
26940
27120
|
}
|
|
26941
27121
|
return { redactedLines, patterns };
|
|
26942
27122
|
}
|
|
26943
27123
|
function processJsonFile(filePath, dryRun) {
|
|
26944
27124
|
let raw;
|
|
26945
27125
|
try {
|
|
26946
|
-
raw =
|
|
27126
|
+
raw = import_fs60.default.readFileSync(filePath, "utf-8");
|
|
26947
27127
|
} catch {
|
|
26948
27128
|
return { redactedLines: 0, patterns: [] };
|
|
26949
27129
|
}
|
|
@@ -26956,15 +27136,15 @@ function processJsonFile(filePath, dryRun) {
|
|
|
26956
27136
|
const { value, modified, found } = redactJson(parsed);
|
|
26957
27137
|
if (!modified) return { redactedLines: 0, patterns: [] };
|
|
26958
27138
|
if (!dryRun) {
|
|
26959
|
-
|
|
27139
|
+
import_fs60.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
|
|
26960
27140
|
}
|
|
26961
27141
|
return { redactedLines: 1, patterns: found };
|
|
26962
27142
|
}
|
|
26963
27143
|
function findJsonFiles(dir) {
|
|
26964
27144
|
const results = [];
|
|
26965
|
-
if (!
|
|
26966
|
-
for (const entry of
|
|
26967
|
-
const full =
|
|
27145
|
+
if (!import_fs60.default.existsSync(dir)) return results;
|
|
27146
|
+
for (const entry of import_fs60.default.readdirSync(dir, { withFileTypes: true })) {
|
|
27147
|
+
const full = import_path58.default.join(dir, entry.name);
|
|
26968
27148
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
26969
27149
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
26970
27150
|
}
|
|
@@ -26973,9 +27153,9 @@ function findJsonFiles(dir) {
|
|
|
26973
27153
|
function registerMaskCommand(program2) {
|
|
26974
27154
|
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) => {
|
|
26975
27155
|
const dryRun = !!options.dryRun;
|
|
26976
|
-
const home =
|
|
26977
|
-
const claudeDir =
|
|
26978
|
-
const geminiDir =
|
|
27156
|
+
const home = import_os52.default.homedir();
|
|
27157
|
+
const claudeDir = import_path58.default.join(home, ".claude", "projects");
|
|
27158
|
+
const geminiDir = import_path58.default.join(home, ".gemini", "tmp");
|
|
26979
27159
|
const allFiles = [
|
|
26980
27160
|
...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
|
|
26981
27161
|
...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
|
|
@@ -26983,7 +27163,7 @@ function registerMaskCommand(program2) {
|
|
|
26983
27163
|
const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
26984
27164
|
const filtered = cutoff ? allFiles.filter((f) => {
|
|
26985
27165
|
try {
|
|
26986
|
-
return
|
|
27166
|
+
return import_fs60.default.statSync(f.path).mtime >= cutoff;
|
|
26987
27167
|
} catch {
|
|
26988
27168
|
return false;
|
|
26989
27169
|
}
|
|
@@ -27039,20 +27219,20 @@ function registerMaskCommand(program2) {
|
|
|
27039
27219
|
// src/cli.ts
|
|
27040
27220
|
init_blast();
|
|
27041
27221
|
var { version } = JSON.parse(
|
|
27042
|
-
|
|
27222
|
+
import_fs63.default.readFileSync(import_path61.default.join(__dirname, "../package.json"), "utf-8")
|
|
27043
27223
|
);
|
|
27044
27224
|
var program = new import_commander.Command();
|
|
27045
27225
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
27046
27226
|
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) => {
|
|
27047
27227
|
const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
|
|
27048
|
-
const credPath =
|
|
27049
|
-
if (!
|
|
27050
|
-
|
|
27228
|
+
const credPath = import_path61.default.join(import_os55.default.homedir(), ".node9", "credentials.json");
|
|
27229
|
+
if (!import_fs63.default.existsSync(import_path61.default.dirname(credPath)))
|
|
27230
|
+
import_fs63.default.mkdirSync(import_path61.default.dirname(credPath), { recursive: true });
|
|
27051
27231
|
const profileName = options.profile || "default";
|
|
27052
27232
|
let existingCreds = {};
|
|
27053
27233
|
try {
|
|
27054
|
-
if (
|
|
27055
|
-
const raw = JSON.parse(
|
|
27234
|
+
if (import_fs63.default.existsSync(credPath)) {
|
|
27235
|
+
const raw = JSON.parse(import_fs63.default.readFileSync(credPath, "utf-8"));
|
|
27056
27236
|
if (raw.apiKey) {
|
|
27057
27237
|
existingCreds = {
|
|
27058
27238
|
default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
|
|
@@ -27064,14 +27244,14 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
27064
27244
|
} catch {
|
|
27065
27245
|
}
|
|
27066
27246
|
existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
|
|
27067
|
-
|
|
27247
|
+
import_fs63.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
|
|
27068
27248
|
let effectiveCloud = null;
|
|
27069
27249
|
if (profileName === "default") {
|
|
27070
|
-
const configPath2 =
|
|
27250
|
+
const configPath2 = import_path61.default.join(import_os55.default.homedir(), ".node9", "config.json");
|
|
27071
27251
|
let config = {};
|
|
27072
27252
|
try {
|
|
27073
|
-
if (
|
|
27074
|
-
config = JSON.parse(
|
|
27253
|
+
if (import_fs63.default.existsSync(configPath2))
|
|
27254
|
+
config = JSON.parse(import_fs63.default.readFileSync(configPath2, "utf-8"));
|
|
27075
27255
|
} catch {
|
|
27076
27256
|
}
|
|
27077
27257
|
if (!config.settings || typeof config.settings !== "object") config.settings = {};
|
|
@@ -27086,9 +27266,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
27086
27266
|
approvers.cloud = false;
|
|
27087
27267
|
}
|
|
27088
27268
|
s.approvers = approvers;
|
|
27089
|
-
if (!
|
|
27090
|
-
|
|
27091
|
-
|
|
27269
|
+
if (!import_fs63.default.existsSync(import_path61.default.dirname(configPath2)))
|
|
27270
|
+
import_fs63.default.mkdirSync(import_path61.default.dirname(configPath2), { recursive: true });
|
|
27271
|
+
import_fs63.default.writeFileSync(configPath2, JSON.stringify(config, null, 2), { mode: 384 });
|
|
27092
27272
|
effectiveCloud = approvers.cloud === true;
|
|
27093
27273
|
}
|
|
27094
27274
|
if (options.profile && profileName !== "default") {
|
|
@@ -27266,15 +27446,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
27266
27446
|
}
|
|
27267
27447
|
}
|
|
27268
27448
|
if (options.purge) {
|
|
27269
|
-
const node9Dir =
|
|
27270
|
-
if (
|
|
27449
|
+
const node9Dir = import_path61.default.join(import_os55.default.homedir(), ".node9");
|
|
27450
|
+
if (import_fs63.default.existsSync(node9Dir)) {
|
|
27271
27451
|
const confirmed = await (0, import_prompts2.confirm)({
|
|
27272
27452
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
27273
27453
|
default: false
|
|
27274
27454
|
});
|
|
27275
27455
|
if (confirmed) {
|
|
27276
|
-
|
|
27277
|
-
if (
|
|
27456
|
+
import_fs63.default.rmSync(node9Dir, { recursive: true });
|
|
27457
|
+
if (import_fs63.default.existsSync(node9Dir)) {
|
|
27278
27458
|
console.error(
|
|
27279
27459
|
import_chalk35.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
27280
27460
|
);
|
|
@@ -27389,7 +27569,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
|
|
|
27389
27569
|
});
|
|
27390
27570
|
program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
|
|
27391
27571
|
try {
|
|
27392
|
-
const dashboardPath =
|
|
27572
|
+
const dashboardPath = import_path61.default.join(__dirname, "dashboard.mjs");
|
|
27393
27573
|
const dynamicImport = new Function("id", "return import(id)");
|
|
27394
27574
|
const mod = await dynamicImport(`file://${dashboardPath}`);
|
|
27395
27575
|
await mod.startMonitor();
|
|
@@ -27427,14 +27607,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
|
|
|
27427
27607
|
Run "node9 addto claude" to register it as the statusLine.`
|
|
27428
27608
|
).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
|
|
27429
27609
|
if (subcommand === "debug") {
|
|
27430
|
-
const flagFile =
|
|
27610
|
+
const flagFile = import_path61.default.join(import_os55.default.homedir(), ".node9", "hud-debug");
|
|
27431
27611
|
if (state === "on") {
|
|
27432
|
-
|
|
27433
|
-
|
|
27612
|
+
import_fs63.default.mkdirSync(import_path61.default.dirname(flagFile), { recursive: true });
|
|
27613
|
+
import_fs63.default.writeFileSync(flagFile, "");
|
|
27434
27614
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
27435
27615
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
27436
27616
|
} else if (state === "off") {
|
|
27437
|
-
if (
|
|
27617
|
+
if (import_fs63.default.existsSync(flagFile)) import_fs63.default.unlinkSync(flagFile);
|
|
27438
27618
|
console.log("HUD debug logging disabled.");
|
|
27439
27619
|
} else {
|
|
27440
27620
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -27555,9 +27735,9 @@ if (process.argv[2] !== "daemon") {
|
|
|
27555
27735
|
const isCheckHook = process.argv[2] === "check";
|
|
27556
27736
|
if (isCheckHook) {
|
|
27557
27737
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
27558
|
-
const logPath =
|
|
27738
|
+
const logPath = import_path61.default.join(import_os55.default.homedir(), ".node9", "hook-debug.log");
|
|
27559
27739
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
27560
|
-
|
|
27740
|
+
import_fs63.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
27561
27741
|
`);
|
|
27562
27742
|
}
|
|
27563
27743
|
process.exit(0);
|