@node9/proxy 1.21.0 → 1.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +325 -387
- package/dist/cli.mjs +324 -386
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -13728,10 +13728,10 @@ function readSessionUsage() {
|
|
|
13728
13728
|
}
|
|
13729
13729
|
}
|
|
13730
13730
|
function formatContextStat(stat) {
|
|
13731
|
-
const pctColor = stat.fillPct >= 80 ?
|
|
13731
|
+
const pctColor = stat.fillPct >= 80 ? import_chalk29.default.red : stat.fillPct >= 50 ? import_chalk29.default.yellow : import_chalk29.default.cyan;
|
|
13732
13732
|
const k = (n) => `${Math.round(n / 1e3)}k`;
|
|
13733
13733
|
const modelShort = stat.model.replace(/@.*$/, "").replace(/-\d{8}$/, "").replace(/^claude-/, "");
|
|
13734
|
-
return
|
|
13734
|
+
return import_chalk29.default.dim("ctx: ") + pctColor(`${stat.fillPct}%`) + import_chalk29.default.dim(
|
|
13735
13735
|
` (${k(stat.inputTokens)}/${k(getModelContextLimit(stat.model))} out ${k(stat.outputTokens)} \xB7 ${modelShort})`
|
|
13736
13736
|
);
|
|
13737
13737
|
}
|
|
@@ -13754,11 +13754,11 @@ function agentLabel(agent, mcpServer, sessionId) {
|
|
|
13754
13754
|
const tag = sessionTag(sessionId);
|
|
13755
13755
|
const tagSuffix = tag ? `\xB7${tag}` : "";
|
|
13756
13756
|
if (!agent || agent === "Terminal") {
|
|
13757
|
-
return mcpServer ?
|
|
13757
|
+
return mcpServer ? import_chalk29.default.dim(`[\u2192 ${mcpServer}] `) : "";
|
|
13758
13758
|
}
|
|
13759
13759
|
const short = agent === "Claude Code" ? "Claude" : agent === "Gemini CLI" ? "Gemini" : agent === "Unknown Agent" ? "" : agent.split(" ")[0];
|
|
13760
|
-
if (!short) return mcpServer ?
|
|
13761
|
-
return mcpServer ?
|
|
13760
|
+
if (!short) return mcpServer ? import_chalk29.default.dim(`[\u2192 ${mcpServer}] `) : "";
|
|
13761
|
+
return mcpServer ? import_chalk29.default.dim(`[${short}${tagSuffix} \u2192 ${mcpServer}] `) : import_chalk29.default.dim(`[${short}${tagSuffix}] `);
|
|
13762
13762
|
}
|
|
13763
13763
|
function formatBase(activity) {
|
|
13764
13764
|
const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
|
|
@@ -13766,20 +13766,20 @@ function formatBase(activity) {
|
|
|
13766
13766
|
const toolName = activity.tool.slice(0, 16).padEnd(16);
|
|
13767
13767
|
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os41.default.homedir(), "~");
|
|
13768
13768
|
const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
|
|
13769
|
-
return `${
|
|
13769
|
+
return `${import_chalk29.default.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${import_chalk29.default.white.bold(toolName)} ${import_chalk29.default.dim(argsPreview)}`;
|
|
13770
13770
|
}
|
|
13771
13771
|
function renderResult(activity, result) {
|
|
13772
13772
|
const base = formatBase(activity);
|
|
13773
13773
|
let status;
|
|
13774
13774
|
if (result.status === "allow") {
|
|
13775
|
-
status =
|
|
13775
|
+
status = import_chalk29.default.green("\u2713 ALLOW");
|
|
13776
13776
|
} else if (result.status === "dlp") {
|
|
13777
|
-
status =
|
|
13777
|
+
status = import_chalk29.default.bgRed.white.bold(" \u{1F6E1}\uFE0F DLP ");
|
|
13778
13778
|
} else {
|
|
13779
|
-
status =
|
|
13779
|
+
status = import_chalk29.default.red("\u2717 BLOCK");
|
|
13780
13780
|
}
|
|
13781
13781
|
const cost = result.costEstimate ?? activity.costEstimate;
|
|
13782
|
-
const costSuffix = cost == null ? "" :
|
|
13782
|
+
const costSuffix = cost == null ? "" : import_chalk29.default.dim(` ~$${cost >= 1e-3 ? cost.toFixed(3) : "0.000"}`);
|
|
13783
13783
|
if (process.stdout.isTTY) {
|
|
13784
13784
|
if (pendingShownForId === activity.id && pendingWrappedLines > 1) {
|
|
13785
13785
|
import_readline6.default.moveCursor(process.stdout, 0, -(pendingWrappedLines - 1));
|
|
@@ -13796,7 +13796,7 @@ function renderResult(activity, result) {
|
|
|
13796
13796
|
}
|
|
13797
13797
|
function renderPending(activity) {
|
|
13798
13798
|
if (!process.stdout.isTTY) return;
|
|
13799
|
-
const line = `${formatBase(activity)} ${
|
|
13799
|
+
const line = `${formatBase(activity)} ${import_chalk29.default.yellow("\u25CF \u2026")}`;
|
|
13800
13800
|
pendingShownForId = activity.id;
|
|
13801
13801
|
pendingWrappedLines = wrappedLineCount(line);
|
|
13802
13802
|
process.stdout.write(`${line}\r`);
|
|
@@ -13808,7 +13808,7 @@ async function ensureDaemon() {
|
|
|
13808
13808
|
const { port } = JSON.parse(import_fs45.default.readFileSync(PID_FILE, "utf-8"));
|
|
13809
13809
|
pidPort = port;
|
|
13810
13810
|
} catch {
|
|
13811
|
-
console.error(
|
|
13811
|
+
console.error(import_chalk29.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
13812
13812
|
}
|
|
13813
13813
|
}
|
|
13814
13814
|
const checkPort = pidPort ?? DAEMON_PORT;
|
|
@@ -13819,8 +13819,8 @@ async function ensureDaemon() {
|
|
|
13819
13819
|
if (res.ok) return checkPort;
|
|
13820
13820
|
} catch {
|
|
13821
13821
|
}
|
|
13822
|
-
console.log(
|
|
13823
|
-
const child = (0,
|
|
13822
|
+
console.log(import_chalk29.default.dim("\u{1F6E1}\uFE0F Starting Node9 daemon..."));
|
|
13823
|
+
const child = (0, import_child_process12.spawn)(process.execPath, [process.argv[1], "daemon"], {
|
|
13824
13824
|
detached: true,
|
|
13825
13825
|
stdio: "ignore",
|
|
13826
13826
|
env: { ...process.env, NODE9_AUTO_STARTED: "1" }
|
|
@@ -13836,7 +13836,7 @@ async function ensureDaemon() {
|
|
|
13836
13836
|
} catch {
|
|
13837
13837
|
}
|
|
13838
13838
|
}
|
|
13839
|
-
console.error(
|
|
13839
|
+
console.error(import_chalk29.default.red("\u274C Daemon failed to start. Try: node9 daemon start"));
|
|
13840
13840
|
process.exit(1);
|
|
13841
13841
|
}
|
|
13842
13842
|
function postDecisionHttp(id, decision, authToken, port, opts) {
|
|
@@ -13905,7 +13905,7 @@ function buildCardLines(req, localCount = 0) {
|
|
|
13905
13905
|
const severityIcon = isBlock ? `${RED}\u{1F6D1}` : `${YELLOW}\u26A0 `;
|
|
13906
13906
|
const rawDesc = req.riskMetadata?.ruleDescription ?? "";
|
|
13907
13907
|
const description = rawDesc ? cleanReason(rawDesc) : "";
|
|
13908
|
-
const agentSuffix = req.agent && req.agent !== "Terminal" ? ` ${RESET2}${
|
|
13908
|
+
const agentSuffix = req.agent && req.agent !== "Terminal" ? ` ${RESET2}${import_chalk29.default.dim(`(${req.agent})`)}` : "";
|
|
13909
13909
|
const lines = [
|
|
13910
13910
|
``,
|
|
13911
13911
|
`${BOLD2}${CYAN}\u2554\u2550\u2550 Node9 Approval Required \u2550\u2550\u2557${RESET2}`,
|
|
@@ -13974,7 +13974,7 @@ function approverStatusLine() {
|
|
|
13974
13974
|
const a = readApproversFromDisk();
|
|
13975
13975
|
const fmt = (label, key) => {
|
|
13976
13976
|
const on = a[key] !== false;
|
|
13977
|
-
return `[${key[0]}]${label.slice(1)} ${on ?
|
|
13977
|
+
return `[${key[0]}]${label.slice(1)} ${on ? import_chalk29.default.green("\u2713") : import_chalk29.default.dim("\u2717")}`;
|
|
13978
13978
|
};
|
|
13979
13979
|
return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
|
|
13980
13980
|
}
|
|
@@ -14019,7 +14019,7 @@ async function startTail(options = {}) {
|
|
|
14019
14019
|
req2.end();
|
|
14020
14020
|
});
|
|
14021
14021
|
if (result.ok) {
|
|
14022
|
-
console.log(
|
|
14022
|
+
console.log(import_chalk29.default.green("\u2713 Flight Recorder buffer cleared."));
|
|
14023
14023
|
} else if (result.code === "ECONNREFUSED") {
|
|
14024
14024
|
throw new Error("Daemon is not running. Start it with: node9 daemon start");
|
|
14025
14025
|
} else if (result.code === "ETIMEDOUT") {
|
|
@@ -14065,7 +14065,7 @@ async function startTail(options = {}) {
|
|
|
14065
14065
|
const channel = name === "n" ? "native" : name === "c" ? "cloud" : name === "t" ? "terminal" : null;
|
|
14066
14066
|
if (channel) {
|
|
14067
14067
|
toggleApprover(channel);
|
|
14068
|
-
console.log(
|
|
14068
|
+
console.log(import_chalk29.default.dim(` Approvers: ${approverStatusLine()}`));
|
|
14069
14069
|
}
|
|
14070
14070
|
};
|
|
14071
14071
|
process.stdin.on("keypress", idleKeypressHandler);
|
|
@@ -14131,7 +14131,7 @@ async function startTail(options = {}) {
|
|
|
14131
14131
|
localAllowCounts.get(req2.toolName) ?? 0
|
|
14132
14132
|
)
|
|
14133
14133
|
);
|
|
14134
|
-
const decisionStamp = action === "always-allow" ?
|
|
14134
|
+
const decisionStamp = action === "always-allow" ? import_chalk29.default.yellow("\u2605 ALWAYS ALLOW") : action === "trust" ? import_chalk29.default.cyan("\u23F1 TRUST 30m") : action === "allow" ? import_chalk29.default.green("\u2713 ALLOWED") : action === "redirect" ? import_chalk29.default.yellow("\u21A9 REDIRECT AI") : import_chalk29.default.red("\u2717 DENIED");
|
|
14135
14135
|
stampedLines.push(` ${BOLD2}\u2192${RESET2} ${decisionStamp} ${GRAY}(terminal)${RESET2}`, ``);
|
|
14136
14136
|
for (const line of stampedLines) process.stdout.write(line + "\n");
|
|
14137
14137
|
process.stdout.write(SHOW_CURSOR);
|
|
@@ -14182,7 +14182,7 @@ async function startTail(options = {}) {
|
|
|
14182
14182
|
);
|
|
14183
14183
|
const stampedLines = buildCardLines(req2, priorCount);
|
|
14184
14184
|
if (externalDecision) {
|
|
14185
|
-
const source = externalDecision === "allow" ?
|
|
14185
|
+
const source = externalDecision === "allow" ? import_chalk29.default.green("\u2713 ALLOWED") : import_chalk29.default.red("\u2717 DENIED");
|
|
14186
14186
|
stampedLines.push(` ${BOLD2}\u2192${RESET2} ${source} ${GRAY}(external)${RESET2}`, ``);
|
|
14187
14187
|
}
|
|
14188
14188
|
for (const line of stampedLines) process.stdout.write(line + "\n");
|
|
@@ -14230,25 +14230,25 @@ async function startTail(options = {}) {
|
|
|
14230
14230
|
if (unackedDlp > 0) {
|
|
14231
14231
|
console.log("");
|
|
14232
14232
|
console.log(
|
|
14233
|
-
|
|
14233
|
+
import_chalk29.default.bgRed.white.bold(
|
|
14234
14234
|
` \u26A0\uFE0F DLP ALERT: ${unackedDlp} secret${unackedDlp !== 1 ? "s" : ""} found in Claude response text \u2014 run: node9 dlp `
|
|
14235
14235
|
)
|
|
14236
14236
|
);
|
|
14237
14237
|
}
|
|
14238
14238
|
} catch {
|
|
14239
14239
|
}
|
|
14240
|
-
console.log(
|
|
14240
|
+
console.log(import_chalk29.default.cyan.bold(`
|
|
14241
14241
|
\u{1F6F0}\uFE0F Node9 tail`));
|
|
14242
14242
|
if (canApprove) {
|
|
14243
|
-
console.log(
|
|
14244
|
-
console.log(
|
|
14243
|
+
console.log(import_chalk29.default.dim("Card: [\u21B5/y] Allow [n] Deny [a] Always [t] Trust 30m"));
|
|
14244
|
+
console.log(import_chalk29.default.dim(`Approvers (toggle): ${approverStatusLine()} [q] quit`));
|
|
14245
14245
|
}
|
|
14246
14246
|
const ctxStat = readSessionUsage();
|
|
14247
14247
|
if (ctxStat) console.log(" " + formatContextStat(ctxStat));
|
|
14248
14248
|
if (options.history) {
|
|
14249
|
-
console.log(
|
|
14249
|
+
console.log(import_chalk29.default.dim("Showing history + live events.\n"));
|
|
14250
14250
|
} else {
|
|
14251
|
-
console.log(
|
|
14251
|
+
console.log(import_chalk29.default.dim("Showing live events only. Use --history to include past.\n"));
|
|
14252
14252
|
}
|
|
14253
14253
|
process.on("SIGINT", () => {
|
|
14254
14254
|
exitIdleMode();
|
|
@@ -14258,7 +14258,7 @@ async function startTail(options = {}) {
|
|
|
14258
14258
|
import_readline6.default.clearLine(process.stdout, 0);
|
|
14259
14259
|
import_readline6.default.cursorTo(process.stdout, 0);
|
|
14260
14260
|
}
|
|
14261
|
-
console.log(
|
|
14261
|
+
console.log(import_chalk29.default.dim("\n\u{1F6F0}\uFE0F Disconnected."));
|
|
14262
14262
|
process.exit(0);
|
|
14263
14263
|
});
|
|
14264
14264
|
const STALL_THRESHOLD_MS = 6e4;
|
|
@@ -14270,7 +14270,7 @@ async function startTail(options = {}) {
|
|
|
14270
14270
|
if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
|
|
14271
14271
|
console.log("");
|
|
14272
14272
|
console.log(
|
|
14273
|
-
|
|
14273
|
+
import_chalk29.default.yellow(
|
|
14274
14274
|
"\u26A0\uFE0F Tail appears stalled \u2014 hooks are firing but no events are arriving. Try: node9 daemon restart"
|
|
14275
14275
|
)
|
|
14276
14276
|
);
|
|
@@ -14287,7 +14287,7 @@ async function startTail(options = {}) {
|
|
|
14287
14287
|
},
|
|
14288
14288
|
(res) => {
|
|
14289
14289
|
if (res.statusCode !== 200) {
|
|
14290
|
-
console.error(
|
|
14290
|
+
console.error(import_chalk29.default.red(`Failed to connect: HTTP ${res.statusCode}`));
|
|
14291
14291
|
process.exit(1);
|
|
14292
14292
|
}
|
|
14293
14293
|
if (canApprove) enterIdleMode();
|
|
@@ -14318,7 +14318,7 @@ async function startTail(options = {}) {
|
|
|
14318
14318
|
import_readline6.default.clearLine(process.stdout, 0);
|
|
14319
14319
|
import_readline6.default.cursorTo(process.stdout, 0);
|
|
14320
14320
|
}
|
|
14321
|
-
console.log(
|
|
14321
|
+
console.log(import_chalk29.default.red("\n\u274C Daemon disconnected."));
|
|
14322
14322
|
process.exit(1);
|
|
14323
14323
|
});
|
|
14324
14324
|
}
|
|
@@ -14331,7 +14331,7 @@ async function startTail(options = {}) {
|
|
|
14331
14331
|
const parsed = JSON.parse(rawData);
|
|
14332
14332
|
const msg = parsed.message ?? "Flight recorder is down \u2014 run: node9 daemon restart";
|
|
14333
14333
|
console.log("");
|
|
14334
|
-
console.log(
|
|
14334
|
+
console.log(import_chalk29.default.bgRed.white.bold(` \u26A0\uFE0F ${msg} `));
|
|
14335
14335
|
} catch {
|
|
14336
14336
|
}
|
|
14337
14337
|
return;
|
|
@@ -14416,9 +14416,9 @@ async function startTail(options = {}) {
|
|
|
14416
14416
|
const rawSummary = data.argsSummary ?? data.tool;
|
|
14417
14417
|
const summary = shortenPathSummary(rawSummary);
|
|
14418
14418
|
const fileCount = data.fileCount ?? 0;
|
|
14419
|
-
const files = fileCount > 0 ?
|
|
14419
|
+
const files = fileCount > 0 ? import_chalk29.default.dim(` \xB7 ${fileCount} file${fileCount === 1 ? "" : "s"}`) : "";
|
|
14420
14420
|
process.stdout.write(
|
|
14421
|
-
`${
|
|
14421
|
+
`${import_chalk29.default.dim(time)} ${import_chalk29.default.cyan("\u{1F4F8} snapshot")} ${import_chalk29.default.dim(hash)} ${summary}${files}
|
|
14422
14422
|
`
|
|
14423
14423
|
);
|
|
14424
14424
|
return;
|
|
@@ -14435,33 +14435,33 @@ async function startTail(options = {}) {
|
|
|
14435
14435
|
if (event === "execution-result") {
|
|
14436
14436
|
const exec = data;
|
|
14437
14437
|
const time = new Date(Date.now()).toLocaleTimeString([], { hour12: false });
|
|
14438
|
-
const arrow = exec.isError ?
|
|
14438
|
+
const arrow = exec.isError ? import_chalk29.default.red(" \u21B3 \u2717") : import_chalk29.default.green(" \u21B3 \u2713");
|
|
14439
14439
|
const label = agentLabel(exec.agent, exec.mcpServer);
|
|
14440
14440
|
const tool = (exec.tool ?? "").slice(0, 16);
|
|
14441
|
-
const duration = typeof exec.durationMs === "number" ?
|
|
14441
|
+
const duration = typeof exec.durationMs === "number" ? import_chalk29.default.dim(` (${exec.durationMs}ms)`) : "";
|
|
14442
14442
|
console.log(
|
|
14443
|
-
`${
|
|
14443
|
+
`${import_chalk29.default.gray(time)} ${arrow} ${label}${import_chalk29.default.dim(tool)}${import_chalk29.default.dim(" completed")}${duration}`
|
|
14444
14444
|
);
|
|
14445
14445
|
}
|
|
14446
14446
|
}
|
|
14447
14447
|
req.on("error", (err2) => {
|
|
14448
14448
|
const msg = err2.code === "ECONNREFUSED" ? "Daemon is not running. Start it with: node9 daemon start" : err2.message;
|
|
14449
|
-
console.error(
|
|
14449
|
+
console.error(import_chalk29.default.red(`
|
|
14450
14450
|
\u274C ${msg}`));
|
|
14451
14451
|
process.exit(1);
|
|
14452
14452
|
});
|
|
14453
14453
|
}
|
|
14454
|
-
var import_http2,
|
|
14454
|
+
var import_http2, import_chalk29, import_fs45, import_os41, import_path47, import_readline6, import_child_process12, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
|
|
14455
14455
|
var init_tail = __esm({
|
|
14456
14456
|
"src/tui/tail.ts"() {
|
|
14457
14457
|
"use strict";
|
|
14458
14458
|
import_http2 = __toESM(require("http"));
|
|
14459
|
-
|
|
14459
|
+
import_chalk29 = __toESM(require("chalk"));
|
|
14460
14460
|
import_fs45 = __toESM(require("fs"));
|
|
14461
14461
|
import_os41 = __toESM(require("os"));
|
|
14462
14462
|
import_path47 = __toESM(require("path"));
|
|
14463
14463
|
import_readline6 = __toESM(require("readline"));
|
|
14464
|
-
|
|
14464
|
+
import_child_process12 = require("child_process");
|
|
14465
14465
|
init_daemon2();
|
|
14466
14466
|
init_daemon();
|
|
14467
14467
|
PID_FILE = import_path47.default.join(import_os41.default.homedir(), ".node9", "daemon.pid");
|
|
@@ -14889,7 +14889,7 @@ var import_commander = require("commander");
|
|
|
14889
14889
|
init_core();
|
|
14890
14890
|
init_setup();
|
|
14891
14891
|
init_daemon2();
|
|
14892
|
-
var
|
|
14892
|
+
var import_chalk30 = __toESM(require("chalk"));
|
|
14893
14893
|
var import_fs47 = __toESM(require("fs"));
|
|
14894
14894
|
var import_path49 = __toESM(require("path"));
|
|
14895
14895
|
var import_os43 = __toESM(require("os"));
|
|
@@ -15683,7 +15683,7 @@ function detectAiAgent(payload) {
|
|
|
15683
15683
|
return "Terminal";
|
|
15684
15684
|
}
|
|
15685
15685
|
function registerCheckCommand(program2) {
|
|
15686
|
-
program2.command("check").description("Hook handler \u2014 evaluates a tool call before execution").argument("[data]", "JSON string of the tool call").action(async (data) => {
|
|
15686
|
+
program2.command("check", { hidden: true }).description("Hook handler \u2014 evaluates a tool call before execution").argument("[data]", "JSON string of the tool call").action(async (data) => {
|
|
15687
15687
|
const processPayload = async (raw) => {
|
|
15688
15688
|
try {
|
|
15689
15689
|
if (!raw || raw.trim() === "") process.exit(0);
|
|
@@ -16081,7 +16081,7 @@ function sanitize3(value) {
|
|
|
16081
16081
|
return value.replace(/[\x00-\x1F\x7F]/g, "");
|
|
16082
16082
|
}
|
|
16083
16083
|
function registerLogCommand(program2) {
|
|
16084
|
-
program2.command("log").description("PostToolUse hook \u2014 records executed tool calls").argument("[data]", "JSON string of the tool call").action(async (data) => {
|
|
16084
|
+
program2.command("log", { hidden: true }).description("PostToolUse hook \u2014 records executed tool calls").argument("[data]", "JSON string of the tool call").action(async (data) => {
|
|
16085
16085
|
const logPayload = async (raw) => {
|
|
16086
16086
|
try {
|
|
16087
16087
|
if (!raw || raw.trim() === "") process.exit(0);
|
|
@@ -18247,7 +18247,7 @@ function registerInitCommand(program2) {
|
|
|
18247
18247
|
const agentList = found.join(", ");
|
|
18248
18248
|
console.log(import_chalk16.default.green.bold(`\u{1F6E1}\uFE0F Node9 is protecting ${agentList}!`));
|
|
18249
18249
|
console.log("");
|
|
18250
|
-
console.log(import_chalk16.default.white(" Watch live: ") + import_chalk16.default.cyan("node9
|
|
18250
|
+
console.log(import_chalk16.default.white(" Watch live: ") + import_chalk16.default.cyan("node9 monitor"));
|
|
18251
18251
|
console.log("");
|
|
18252
18252
|
console.log(import_chalk16.default.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
18253
18253
|
console.log(
|
|
@@ -18544,71 +18544,10 @@ function registerUndoCommand(program2) {
|
|
|
18544
18544
|
});
|
|
18545
18545
|
}
|
|
18546
18546
|
|
|
18547
|
-
// src/cli/commands/watch.ts
|
|
18548
|
-
var import_chalk19 = __toESM(require("chalk"));
|
|
18549
|
-
var import_child_process10 = require("child_process");
|
|
18550
|
-
init_daemon();
|
|
18551
|
-
function registerWatchCommand(program2) {
|
|
18552
|
-
program2.command("watch").description("Run a command under Node9 watch mode (daemon stays alive for the session)").argument("<command>", "Command to run").argument("[args...]", "Arguments for the command").action(async (cmd, args) => {
|
|
18553
|
-
let port = DAEMON_PORT;
|
|
18554
|
-
try {
|
|
18555
|
-
const res = await fetch(`http://127.0.0.1:${DAEMON_PORT}/settings`, {
|
|
18556
|
-
signal: AbortSignal.timeout(500)
|
|
18557
|
-
});
|
|
18558
|
-
if (res.ok) {
|
|
18559
|
-
const data = await res.json();
|
|
18560
|
-
if (typeof data.port === "number") port = data.port;
|
|
18561
|
-
} else {
|
|
18562
|
-
throw new Error("not running");
|
|
18563
|
-
}
|
|
18564
|
-
} catch {
|
|
18565
|
-
console.error(import_chalk19.default.dim("\u{1F6E1}\uFE0F Starting Node9 daemon (watch mode)..."));
|
|
18566
|
-
const child = (0, import_child_process10.spawn)(process.execPath, [process.argv[1], "daemon"], {
|
|
18567
|
-
detached: true,
|
|
18568
|
-
stdio: "ignore",
|
|
18569
|
-
env: { ...process.env, NODE9_AUTO_STARTED: "1", NODE9_WATCH_MODE: "1" }
|
|
18570
|
-
});
|
|
18571
|
-
child.unref();
|
|
18572
|
-
let ready = false;
|
|
18573
|
-
for (let i = 0; i < 20; i++) {
|
|
18574
|
-
await new Promise((r) => setTimeout(r, 250));
|
|
18575
|
-
try {
|
|
18576
|
-
const r = await fetch(`http://127.0.0.1:${DAEMON_PORT}/settings`, {
|
|
18577
|
-
signal: AbortSignal.timeout(500)
|
|
18578
|
-
});
|
|
18579
|
-
if (r.ok) {
|
|
18580
|
-
ready = true;
|
|
18581
|
-
break;
|
|
18582
|
-
}
|
|
18583
|
-
} catch {
|
|
18584
|
-
}
|
|
18585
|
-
}
|
|
18586
|
-
if (!ready) {
|
|
18587
|
-
console.error(import_chalk19.default.red("\u274C Daemon failed to start. Try: node9 daemon start"));
|
|
18588
|
-
process.exit(1);
|
|
18589
|
-
}
|
|
18590
|
-
}
|
|
18591
|
-
console.error(
|
|
18592
|
-
import_chalk19.default.cyan.bold("\u{1F6E1}\uFE0F Node9 watch") + import_chalk19.default.dim(` \u2192 localhost:${port}`) + import_chalk19.default.dim(
|
|
18593
|
-
"\n Tip: run `node9 tail` in another terminal to review and approve AI actions.\n"
|
|
18594
|
-
)
|
|
18595
|
-
);
|
|
18596
|
-
const result = (0, import_child_process10.spawnSync)(cmd, args, {
|
|
18597
|
-
stdio: "inherit",
|
|
18598
|
-
env: { ...process.env, NODE9_WATCH_MODE: "1" }
|
|
18599
|
-
});
|
|
18600
|
-
if (result.error) {
|
|
18601
|
-
console.error(import_chalk19.default.red(`\u274C Failed to run command: ${result.error.message}`));
|
|
18602
|
-
process.exit(1);
|
|
18603
|
-
}
|
|
18604
|
-
process.exit(result.status ?? 0);
|
|
18605
|
-
});
|
|
18606
|
-
}
|
|
18607
|
-
|
|
18608
18547
|
// src/mcp-gateway/index.ts
|
|
18609
18548
|
var import_readline4 = __toESM(require("readline"));
|
|
18610
|
-
var
|
|
18611
|
-
var
|
|
18549
|
+
var import_chalk19 = __toESM(require("chalk"));
|
|
18550
|
+
var import_child_process10 = require("child_process");
|
|
18612
18551
|
var import_execa3 = require("execa");
|
|
18613
18552
|
init_orchestrator();
|
|
18614
18553
|
init_provenance();
|
|
@@ -18769,13 +18708,13 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
18769
18708
|
const prov = checkProvenance(executable);
|
|
18770
18709
|
if (prov.trustLevel === "suspect") {
|
|
18771
18710
|
console.error(
|
|
18772
|
-
|
|
18711
|
+
import_chalk19.default.red(
|
|
18773
18712
|
`\u26A0\uFE0F Node9: Upstream MCP server binary is suspect \u2014 ${prov.reason} (${prov.resolvedPath})`
|
|
18774
18713
|
)
|
|
18775
18714
|
);
|
|
18776
|
-
console.error(
|
|
18715
|
+
console.error(import_chalk19.default.red(" Verify this binary is trusted before proceeding."));
|
|
18777
18716
|
}
|
|
18778
|
-
console.error(
|
|
18717
|
+
console.error(import_chalk19.default.green(`\u{1F680} Node9 MCP Gateway: Monitoring [${upstreamCommand}]`));
|
|
18779
18718
|
const UPSTREAM_INJECTOR_VARS = /* @__PURE__ */ new Set([
|
|
18780
18719
|
"NODE_OPTIONS",
|
|
18781
18720
|
"NODE_PATH",
|
|
@@ -18794,7 +18733,7 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
18794
18733
|
const safeEnv = Object.fromEntries(
|
|
18795
18734
|
Object.entries(process.env).filter(([k]) => !UPSTREAM_INJECTOR_VARS.has(k))
|
|
18796
18735
|
);
|
|
18797
|
-
const child = (0,
|
|
18736
|
+
const child = (0, import_child_process10.spawn)(executable, cmdArgs, {
|
|
18798
18737
|
stdio: ["pipe", "pipe", "inherit"],
|
|
18799
18738
|
// control stdin/stdout; inherit stderr
|
|
18800
18739
|
shell: false,
|
|
@@ -18888,10 +18827,10 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
18888
18827
|
mcpServer
|
|
18889
18828
|
});
|
|
18890
18829
|
if (!result.approved) {
|
|
18891
|
-
console.error(
|
|
18830
|
+
console.error(import_chalk19.default.red(`
|
|
18892
18831
|
\u{1F6D1} Node9 MCP Gateway: Action Blocked`));
|
|
18893
|
-
console.error(
|
|
18894
|
-
console.error(
|
|
18832
|
+
console.error(import_chalk19.default.gray(` Tool: ${toolName}`));
|
|
18833
|
+
console.error(import_chalk19.default.gray(` Reason: ${result.reason ?? "Security Policy"}
|
|
18895
18834
|
`));
|
|
18896
18835
|
const blockedByLabel = result.blockedByLabel ?? result.reason ?? "Security Policy";
|
|
18897
18836
|
const isHumanDecision = blockedByLabel.toLowerCase().includes("user") || blockedByLabel.toLowerCase().includes("daemon") || blockedByLabel.toLowerCase().includes("decision");
|
|
@@ -19003,7 +18942,7 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
19003
18942
|
updatePin(serverKey, upstreamCommand, currentHash, toolNames);
|
|
19004
18943
|
pinState = "validated";
|
|
19005
18944
|
console.error(
|
|
19006
|
-
|
|
18945
|
+
import_chalk19.default.green(
|
|
19007
18946
|
`\u{1F512} Node9: Pinned ${toolNames.length} tool definition(s) for this MCP server`
|
|
19008
18947
|
)
|
|
19009
18948
|
);
|
|
@@ -19016,11 +18955,11 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
19016
18955
|
} else if (pinStatus === "corrupt") {
|
|
19017
18956
|
pinState = "quarantined";
|
|
19018
18957
|
console.error(
|
|
19019
|
-
|
|
18958
|
+
import_chalk19.default.red("\n\u{1F6A8} Node9: MCP pin file is corrupt or unreadable \u2014 session quarantined!")
|
|
19020
18959
|
);
|
|
19021
|
-
console.error(
|
|
18960
|
+
console.error(import_chalk19.default.red(" Tool calls are blocked until the pin file is repaired."));
|
|
19022
18961
|
console.error(
|
|
19023
|
-
|
|
18962
|
+
import_chalk19.default.yellow(` Run: node9 mcp pin reset (to clear and re-pin on next connect)
|
|
19024
18963
|
`)
|
|
19025
18964
|
);
|
|
19026
18965
|
const errorResponse = {
|
|
@@ -19037,13 +18976,13 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
19037
18976
|
} else {
|
|
19038
18977
|
pinState = "quarantined";
|
|
19039
18978
|
console.error(
|
|
19040
|
-
|
|
18979
|
+
import_chalk19.default.red("\n\u{1F6A8} Node9: MCP tool definitions have changed since last verified!")
|
|
19041
18980
|
);
|
|
19042
18981
|
console.error(
|
|
19043
|
-
|
|
18982
|
+
import_chalk19.default.red(" This could indicate a supply chain attack (tool poisoning / rug pull).")
|
|
19044
18983
|
);
|
|
19045
|
-
console.error(
|
|
19046
|
-
console.error(
|
|
18984
|
+
console.error(import_chalk19.default.red(" Session quarantined \u2014 all tool calls blocked."));
|
|
18985
|
+
console.error(import_chalk19.default.yellow(` Run: node9 mcp pin update ${serverKey}
|
|
19047
18986
|
`));
|
|
19048
18987
|
const errorResponse = {
|
|
19049
18988
|
jsonrpc: "2.0",
|
|
@@ -19086,7 +19025,7 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
19086
19025
|
const toolName = callId !== void 0 ? pendingCallNames.get(callId) ?? "unknown" : "unknown";
|
|
19087
19026
|
if (callId !== void 0) pendingCallNames.delete(callId);
|
|
19088
19027
|
console.error(
|
|
19089
|
-
|
|
19028
|
+
import_chalk19.default.yellow(
|
|
19090
19029
|
`\u26A1 Node9: Large MCP response from '${toolName}' (${(line.length / 1024).toFixed(0)}KB) \u2014 context window enlarged`
|
|
19091
19030
|
)
|
|
19092
19031
|
);
|
|
@@ -19140,7 +19079,7 @@ var import_readline5 = __toESM(require("readline"));
|
|
|
19140
19079
|
var import_fs39 = __toESM(require("fs"));
|
|
19141
19080
|
var import_os35 = __toESM(require("os"));
|
|
19142
19081
|
var import_path41 = __toESM(require("path"));
|
|
19143
|
-
var
|
|
19082
|
+
var import_child_process11 = require("child_process");
|
|
19144
19083
|
init_core();
|
|
19145
19084
|
init_daemon();
|
|
19146
19085
|
init_shields();
|
|
@@ -19614,7 +19553,7 @@ function handleRuleAdd(args) {
|
|
|
19614
19553
|
return `Rule "${name}" added to ~/.node9/config.json \u2014 verdict: ${verdict} when ${field} matches "${pattern}"`;
|
|
19615
19554
|
}
|
|
19616
19555
|
function runCliCommand(subArgs) {
|
|
19617
|
-
const result = (0,
|
|
19556
|
+
const result = (0, import_child_process11.spawnSync)(process.execPath, [process.argv[1], ...subArgs], {
|
|
19618
19557
|
encoding: "utf-8",
|
|
19619
19558
|
timeout: 6e4,
|
|
19620
19559
|
// Disable colors — stdout is piped (not a TTY), chalk auto-detects, but be explicit
|
|
@@ -19808,7 +19747,7 @@ function registerMcpServerCommand(program2) {
|
|
|
19808
19747
|
}
|
|
19809
19748
|
|
|
19810
19749
|
// src/cli/commands/trust.ts
|
|
19811
|
-
var
|
|
19750
|
+
var import_chalk20 = __toESM(require("chalk"));
|
|
19812
19751
|
init_trusted_hosts();
|
|
19813
19752
|
function isValidHost(host) {
|
|
19814
19753
|
return /^(\*\.)?[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/.test(host);
|
|
@@ -19819,51 +19758,51 @@ function registerTrustCommand(program2) {
|
|
|
19819
19758
|
const normalized = normalizeHost(host.trim());
|
|
19820
19759
|
if (!isValidHost(normalized)) {
|
|
19821
19760
|
console.error(
|
|
19822
|
-
|
|
19761
|
+
import_chalk20.default.red(`
|
|
19823
19762
|
\u274C Invalid host: "${host}"
|
|
19824
|
-
`) +
|
|
19763
|
+
`) + import_chalk20.default.gray(" Use an FQDN like api.mycompany.com or *.mycompany.com\n")
|
|
19825
19764
|
);
|
|
19826
19765
|
process.exit(1);
|
|
19827
19766
|
}
|
|
19828
19767
|
addTrustedHost(normalized);
|
|
19829
|
-
console.log(
|
|
19768
|
+
console.log(import_chalk20.default.green(`
|
|
19830
19769
|
\u2705 ${normalized} added to trusted hosts.`));
|
|
19831
19770
|
console.log(
|
|
19832
|
-
|
|
19771
|
+
import_chalk20.default.gray(" Pipe-chain blocks to this host: critical \u2192 review, high \u2192 allow\n")
|
|
19833
19772
|
);
|
|
19834
19773
|
});
|
|
19835
19774
|
trustCmd.command("remove <host>").description("Remove a trusted host").action((host) => {
|
|
19836
19775
|
const normalized = normalizeHost(host.trim());
|
|
19837
19776
|
const removed = removeTrustedHost(normalized);
|
|
19838
19777
|
if (!removed) {
|
|
19839
|
-
console.error(
|
|
19778
|
+
console.error(import_chalk20.default.yellow(`
|
|
19840
19779
|
\u26A0\uFE0F "${normalized}" is not in the trusted hosts list.
|
|
19841
19780
|
`));
|
|
19842
19781
|
process.exit(1);
|
|
19843
19782
|
}
|
|
19844
|
-
console.log(
|
|
19783
|
+
console.log(import_chalk20.default.green(`
|
|
19845
19784
|
\u2705 ${normalized} removed from trusted hosts.
|
|
19846
19785
|
`));
|
|
19847
19786
|
});
|
|
19848
19787
|
trustCmd.command("list").description("Show all trusted hosts").action(() => {
|
|
19849
19788
|
const hosts = readTrustedHosts();
|
|
19850
19789
|
if (hosts.length === 0) {
|
|
19851
|
-
console.log(
|
|
19852
|
-
console.log(` Add one: ${
|
|
19790
|
+
console.log(import_chalk20.default.gray("\n No trusted hosts configured.\n"));
|
|
19791
|
+
console.log(` Add one: ${import_chalk20.default.cyan("node9 trust add api.mycompany.com")}
|
|
19853
19792
|
`);
|
|
19854
19793
|
return;
|
|
19855
19794
|
}
|
|
19856
|
-
console.log(
|
|
19795
|
+
console.log(import_chalk20.default.bold("\n\u{1F513} Trusted Hosts\n"));
|
|
19857
19796
|
for (const entry of hosts) {
|
|
19858
19797
|
const date = new Date(entry.addedAt).toLocaleDateString();
|
|
19859
|
-
console.log(` ${
|
|
19798
|
+
console.log(` ${import_chalk20.default.cyan(entry.host.padEnd(40))} ${import_chalk20.default.gray(`added ${date}`)}`);
|
|
19860
19799
|
}
|
|
19861
19800
|
console.log("");
|
|
19862
19801
|
});
|
|
19863
19802
|
}
|
|
19864
19803
|
|
|
19865
19804
|
// src/cli/commands/mcp-pin.ts
|
|
19866
|
-
var
|
|
19805
|
+
var import_chalk21 = __toESM(require("chalk"));
|
|
19867
19806
|
function registerMcpPinCommand(program2) {
|
|
19868
19807
|
const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
|
|
19869
19808
|
const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
|
|
@@ -19871,31 +19810,31 @@ function registerMcpPinCommand(program2) {
|
|
|
19871
19810
|
const result = readMcpPinsSafe();
|
|
19872
19811
|
if (!result.ok) {
|
|
19873
19812
|
if (result.reason === "missing") {
|
|
19874
|
-
console.log(
|
|
19813
|
+
console.log(import_chalk21.default.gray("\nNo MCP servers are pinned yet."));
|
|
19875
19814
|
console.log(
|
|
19876
|
-
|
|
19815
|
+
import_chalk21.default.gray("Pins are created automatically when the MCP gateway first connects.\n")
|
|
19877
19816
|
);
|
|
19878
19817
|
return;
|
|
19879
19818
|
}
|
|
19880
|
-
console.error(
|
|
19819
|
+
console.error(import_chalk21.default.red(`
|
|
19881
19820
|
\u274C Pin file is corrupt: ${result.detail}`));
|
|
19882
|
-
console.error(
|
|
19821
|
+
console.error(import_chalk21.default.yellow(" Run: node9 mcp pin reset\n"));
|
|
19883
19822
|
process.exit(1);
|
|
19884
19823
|
}
|
|
19885
19824
|
const entries = Object.entries(result.pins.servers);
|
|
19886
19825
|
if (entries.length === 0) {
|
|
19887
|
-
console.log(
|
|
19826
|
+
console.log(import_chalk21.default.gray("\nNo MCP servers are pinned yet."));
|
|
19888
19827
|
console.log(
|
|
19889
|
-
|
|
19828
|
+
import_chalk21.default.gray("Pins are created automatically when the MCP gateway first connects.\n")
|
|
19890
19829
|
);
|
|
19891
19830
|
return;
|
|
19892
19831
|
}
|
|
19893
|
-
console.log(
|
|
19832
|
+
console.log(import_chalk21.default.bold("\n\u{1F512} Pinned MCP Servers\n"));
|
|
19894
19833
|
for (const [key, entry] of entries) {
|
|
19895
|
-
console.log(` ${
|
|
19896
|
-
console.log(` Tools (${entry.toolCount}): ${
|
|
19897
|
-
console.log(` Hash: ${
|
|
19898
|
-
console.log(` Pinned: ${
|
|
19834
|
+
console.log(` ${import_chalk21.default.cyan(key)} ${import_chalk21.default.gray(entry.label)}`);
|
|
19835
|
+
console.log(` Tools (${entry.toolCount}): ${import_chalk21.default.white(entry.toolNames.join(", "))}`);
|
|
19836
|
+
console.log(` Hash: ${import_chalk21.default.gray(entry.toolsHash.slice(0, 16))}...`);
|
|
19837
|
+
console.log(` Pinned: ${import_chalk21.default.gray(entry.pinnedAt)}`);
|
|
19899
19838
|
console.log("");
|
|
19900
19839
|
}
|
|
19901
19840
|
});
|
|
@@ -19906,127 +19845,127 @@ function registerMcpPinCommand(program2) {
|
|
|
19906
19845
|
try {
|
|
19907
19846
|
pins = readMcpPins();
|
|
19908
19847
|
} catch {
|
|
19909
|
-
console.error(
|
|
19910
|
-
console.error(
|
|
19848
|
+
console.error(import_chalk21.default.red("\n\u274C Pin file is corrupt."));
|
|
19849
|
+
console.error(import_chalk21.default.yellow(" Run: node9 mcp pin reset\n"));
|
|
19911
19850
|
process.exit(1);
|
|
19912
19851
|
}
|
|
19913
19852
|
if (!pins.servers[serverKey]) {
|
|
19914
|
-
console.error(
|
|
19853
|
+
console.error(import_chalk21.default.red(`
|
|
19915
19854
|
\u274C No pin found for server key "${serverKey}"
|
|
19916
19855
|
`));
|
|
19917
|
-
console.error(`Run ${
|
|
19856
|
+
console.error(`Run ${import_chalk21.default.cyan("node9 mcp pin list")} to see pinned servers.
|
|
19918
19857
|
`);
|
|
19919
19858
|
process.exit(1);
|
|
19920
19859
|
}
|
|
19921
19860
|
const label = pins.servers[serverKey].label;
|
|
19922
19861
|
removePin2(serverKey);
|
|
19923
|
-
console.log(
|
|
19924
|
-
\u{1F513} Pin removed for ${
|
|
19925
|
-
console.log(
|
|
19926
|
-
console.log(
|
|
19862
|
+
console.log(import_chalk21.default.green(`
|
|
19863
|
+
\u{1F513} Pin removed for ${import_chalk21.default.cyan(serverKey)}`));
|
|
19864
|
+
console.log(import_chalk21.default.gray(` Server: ${label}`));
|
|
19865
|
+
console.log(import_chalk21.default.gray(" Next connection will re-pin with current tool definitions.\n"));
|
|
19927
19866
|
});
|
|
19928
19867
|
pinSubCmd.command("reset").description("Clear all MCP pins (next connection to each server will re-pin)").action(() => {
|
|
19929
19868
|
const result = readMcpPinsSafe();
|
|
19930
19869
|
if (!result.ok && result.reason === "missing") {
|
|
19931
|
-
console.log(
|
|
19870
|
+
console.log(import_chalk21.default.gray("\nNo pins to clear.\n"));
|
|
19932
19871
|
return;
|
|
19933
19872
|
}
|
|
19934
19873
|
const count = result.ok ? Object.keys(result.pins.servers).length : "?";
|
|
19935
19874
|
clearAllPins2();
|
|
19936
|
-
console.log(
|
|
19875
|
+
console.log(import_chalk21.default.green(`
|
|
19937
19876
|
\u{1F513} Cleared ${count} MCP pin(s).`));
|
|
19938
|
-
console.log(
|
|
19877
|
+
console.log(import_chalk21.default.gray(" Next connection to each server will re-pin.\n"));
|
|
19939
19878
|
});
|
|
19940
19879
|
}
|
|
19941
19880
|
|
|
19942
19881
|
// src/cli/commands/sync.ts
|
|
19943
|
-
var
|
|
19882
|
+
var import_chalk22 = __toESM(require("chalk"));
|
|
19944
19883
|
init_sync();
|
|
19945
19884
|
function registerSyncCommand(program2) {
|
|
19946
19885
|
const policy = program2.command("policy").description("Manage cloud policy rules");
|
|
19947
19886
|
policy.command("sync").description("Sync cloud policy rules to local cache (~/.node9/rules-cache.json)").action(async () => {
|
|
19948
|
-
process.stdout.write(
|
|
19887
|
+
process.stdout.write(import_chalk22.default.cyan("Syncing cloud policy rules\u2026"));
|
|
19949
19888
|
const result = await runCloudSync();
|
|
19950
19889
|
process.stdout.write("\n");
|
|
19951
19890
|
if (!result.ok) {
|
|
19952
|
-
console.error(
|
|
19891
|
+
console.error(import_chalk22.default.red(`\u2717 ${result.reason}`));
|
|
19953
19892
|
process.exit(1);
|
|
19954
19893
|
}
|
|
19955
19894
|
if (result.unchanged) {
|
|
19956
19895
|
console.log(
|
|
19957
|
-
|
|
19896
|
+
import_chalk22.default.green(
|
|
19958
19897
|
`\u2713 Already up to date \u2014 ${result.rules} rule${result.rules === 1 ? "" : "s"} cached`
|
|
19959
19898
|
)
|
|
19960
19899
|
);
|
|
19961
|
-
console.log(
|
|
19962
|
-
console.log(
|
|
19900
|
+
console.log(import_chalk22.default.gray(` Cached at: ${result.fetchedAt}`));
|
|
19901
|
+
console.log(import_chalk22.default.gray(` Server returned 304 (no changes since last sync)`));
|
|
19963
19902
|
} else {
|
|
19964
19903
|
console.log(
|
|
19965
|
-
|
|
19904
|
+
import_chalk22.default.green(`\u2713 Synced ${result.rules} rule${result.rules === 1 ? "" : "s"} from cloud`)
|
|
19966
19905
|
);
|
|
19967
|
-
console.log(
|
|
19968
|
-
console.log(
|
|
19906
|
+
console.log(import_chalk22.default.gray(` Cached at: ${result.fetchedAt}`));
|
|
19907
|
+
console.log(import_chalk22.default.gray(` File: ~/.node9/rules-cache.json`));
|
|
19969
19908
|
}
|
|
19970
19909
|
});
|
|
19971
19910
|
policy.command("show").description("List all cloud policy rules in the local cache").action(() => {
|
|
19972
19911
|
const status = getCloudSyncStatus();
|
|
19973
19912
|
if (!status.cached) {
|
|
19974
|
-
console.log(
|
|
19913
|
+
console.log(import_chalk22.default.yellow("\n No cloud rules cached \u2014 run: node9 policy sync\n"));
|
|
19975
19914
|
return;
|
|
19976
19915
|
}
|
|
19977
19916
|
const rules = getCloudRules() ?? [];
|
|
19978
19917
|
const age = Math.round((Date.now() - new Date(status.fetchedAt).getTime()) / 6e4);
|
|
19979
19918
|
console.log(
|
|
19980
|
-
|
|
19981
|
-
Cloud policy rules`) +
|
|
19919
|
+
import_chalk22.default.bold(`
|
|
19920
|
+
Cloud policy rules`) + import_chalk22.default.gray(
|
|
19982
19921
|
` (${rules.length} rule${rules.length === 1 ? "" : "s"}, synced ${age}m ago)
|
|
19983
19922
|
`
|
|
19984
19923
|
)
|
|
19985
19924
|
);
|
|
19986
19925
|
if (rules.length === 0) {
|
|
19987
|
-
console.log(
|
|
19926
|
+
console.log(import_chalk22.default.gray(" No rules defined in cloud policy.\n"));
|
|
19988
19927
|
return;
|
|
19989
19928
|
}
|
|
19990
19929
|
for (const rule of rules) {
|
|
19991
19930
|
const r = rule;
|
|
19992
|
-
const verdictColor = r.verdict === "block" ?
|
|
19931
|
+
const verdictColor = r.verdict === "block" ? import_chalk22.default.red : r.verdict === "allow" ? import_chalk22.default.green : import_chalk22.default.yellow;
|
|
19993
19932
|
console.log(
|
|
19994
19933
|
` ${verdictColor(
|
|
19995
19934
|
String(r.verdict ?? "unknown").toUpperCase().padEnd(6)
|
|
19996
|
-
)} ${
|
|
19935
|
+
)} ${import_chalk22.default.white(String(r.name ?? "(unnamed)"))}`
|
|
19997
19936
|
);
|
|
19998
|
-
if (r.reason) console.log(
|
|
19937
|
+
if (r.reason) console.log(import_chalk22.default.gray(` ${String(r.reason)}`));
|
|
19999
19938
|
}
|
|
20000
19939
|
console.log("");
|
|
20001
19940
|
});
|
|
20002
19941
|
policy.command("status").description("Show current cloud policy cache status").action(() => {
|
|
20003
19942
|
const s = getCloudSyncStatus();
|
|
20004
19943
|
if (!s.cached) {
|
|
20005
|
-
console.log(
|
|
19944
|
+
console.log(import_chalk22.default.yellow("\n No cache yet \u2014 run: node9 policy sync\n"));
|
|
20006
19945
|
return;
|
|
20007
19946
|
}
|
|
20008
19947
|
const age = Math.round((Date.now() - new Date(s.fetchedAt).getTime()) / 6e4);
|
|
20009
19948
|
console.log(`
|
|
20010
|
-
Rules : ${
|
|
19949
|
+
Rules : ${import_chalk22.default.green(String(s.rules))} cloud rules loaded`);
|
|
20011
19950
|
console.log(
|
|
20012
|
-
` Synced : ${
|
|
19951
|
+
` Synced : ${import_chalk22.default.gray(`${age} minute${age === 1 ? "" : "s"} ago`)} (${s.fetchedAt})`
|
|
20013
19952
|
);
|
|
20014
19953
|
if (s.workspaceId) {
|
|
20015
|
-
console.log(` Workspace: ${
|
|
19954
|
+
console.log(` Workspace: ${import_chalk22.default.gray(s.workspaceId)}`);
|
|
20016
19955
|
}
|
|
20017
19956
|
if (s.panicMode) {
|
|
20018
19957
|
console.log(
|
|
20019
|
-
` ${
|
|
19958
|
+
` ${import_chalk22.default.red.bold("\u{1F6A8} Panic mode : ON")} ` + import_chalk22.default.dim("(every review-verdict becomes block)")
|
|
20020
19959
|
);
|
|
20021
19960
|
}
|
|
20022
19961
|
if (s.shadowMode) {
|
|
20023
19962
|
console.log(
|
|
20024
|
-
` ${
|
|
19963
|
+
` ${import_chalk22.default.yellow.bold("\u{1F441} Shadow mode : ON")} ` + import_chalk22.default.dim("(blocks become would-block log entries)")
|
|
20025
19964
|
);
|
|
20026
19965
|
}
|
|
20027
19966
|
if (s.syncIntervalHours) {
|
|
20028
19967
|
console.log(
|
|
20029
|
-
|
|
19968
|
+
import_chalk22.default.gray(
|
|
20030
19969
|
` Polling : every ${s.syncIntervalHours} hour${s.syncIntervalHours === 1 ? "" : "s"}`
|
|
20031
19970
|
)
|
|
20032
19971
|
);
|
|
@@ -20036,7 +19975,7 @@ function registerSyncCommand(program2) {
|
|
|
20036
19975
|
}
|
|
20037
19976
|
|
|
20038
19977
|
// src/cli/commands/agents.ts
|
|
20039
|
-
var
|
|
19978
|
+
var import_chalk23 = __toESM(require("chalk"));
|
|
20040
19979
|
init_setup();
|
|
20041
19980
|
var SETUP_FN = {
|
|
20042
19981
|
claude: setupClaude,
|
|
@@ -20066,23 +20005,23 @@ function registerAgentsCommand(program2) {
|
|
|
20066
20005
|
console.log(` ${"Agent".padEnd(14)}${"Installed".padEnd(11)}${"Wired".padEnd(8)}Mode`);
|
|
20067
20006
|
console.log(" " + "\u2500".repeat(44));
|
|
20068
20007
|
for (const s of statuses) {
|
|
20069
|
-
const installed = s.installed ?
|
|
20070
|
-
const wired = !s.installed ?
|
|
20071
|
-
const mode = s.mode ?
|
|
20072
|
-
const hint = s.installed && !s.wired ?
|
|
20008
|
+
const installed = s.installed ? import_chalk23.default.green("\u2713") : import_chalk23.default.gray("\u2717");
|
|
20009
|
+
const wired = !s.installed ? import_chalk23.default.gray("\u2014") : s.wired ? import_chalk23.default.green("\u2713") : import_chalk23.default.yellow("\u2717");
|
|
20010
|
+
const mode = s.mode ? import_chalk23.default.gray(s.mode) : import_chalk23.default.gray("\u2014");
|
|
20011
|
+
const hint = s.installed && !s.wired ? import_chalk23.default.gray(` \u2190 node9 agents add ${s.name}`) : "";
|
|
20073
20012
|
console.log(` ${s.label.padEnd(14)}${installed} ${wired} ${mode}${hint}`);
|
|
20074
20013
|
}
|
|
20075
20014
|
console.log("");
|
|
20076
20015
|
if (!anyInstalled) {
|
|
20077
20016
|
console.log(
|
|
20078
|
-
|
|
20017
|
+
import_chalk23.default.gray(" No AI agents detected. Install Claude Code, Gemini CLI, Cursor,\n") + import_chalk23.default.gray(" Windsurf, VSCode, or Codex then run: node9 agents list\n")
|
|
20079
20018
|
);
|
|
20080
20019
|
return;
|
|
20081
20020
|
}
|
|
20082
20021
|
const unwired = statuses.filter((s) => s.installed && !s.wired);
|
|
20083
20022
|
if (unwired.length > 0) {
|
|
20084
20023
|
console.log(
|
|
20085
|
-
|
|
20024
|
+
import_chalk23.default.yellow(` ${unwired.length} agent(s) not yet wired. Run: `) + import_chalk23.default.white(`node9 agents add ${unwired[0].name}`) + "\n"
|
|
20086
20025
|
);
|
|
20087
20026
|
}
|
|
20088
20027
|
});
|
|
@@ -20090,7 +20029,7 @@ function registerAgentsCommand(program2) {
|
|
|
20090
20029
|
const name = agent.toLowerCase();
|
|
20091
20030
|
const fn = SETUP_FN[name];
|
|
20092
20031
|
if (!fn) {
|
|
20093
|
-
console.error(
|
|
20032
|
+
console.error(import_chalk23.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
|
|
20094
20033
|
process.exit(1);
|
|
20095
20034
|
}
|
|
20096
20035
|
await fn();
|
|
@@ -20099,14 +20038,14 @@ function registerAgentsCommand(program2) {
|
|
|
20099
20038
|
const name = agent.toLowerCase();
|
|
20100
20039
|
const fn = TEARDOWN_FN[name];
|
|
20101
20040
|
if (!fn) {
|
|
20102
|
-
console.error(
|
|
20041
|
+
console.error(import_chalk23.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
|
|
20103
20042
|
process.exit(1);
|
|
20104
20043
|
}
|
|
20105
|
-
console.log(
|
|
20044
|
+
console.log(import_chalk23.default.cyan(`
|
|
20106
20045
|
\u{1F6E1}\uFE0F Node9: removing from ${name}...
|
|
20107
20046
|
`));
|
|
20108
20047
|
fn();
|
|
20109
|
-
console.log(
|
|
20048
|
+
console.log(import_chalk23.default.gray("\n Restart the agent for changes to take effect."));
|
|
20110
20049
|
});
|
|
20111
20050
|
}
|
|
20112
20051
|
|
|
@@ -20114,7 +20053,7 @@ function registerAgentsCommand(program2) {
|
|
|
20114
20053
|
init_scan();
|
|
20115
20054
|
|
|
20116
20055
|
// src/cli/commands/sessions.ts
|
|
20117
|
-
var
|
|
20056
|
+
var import_chalk24 = __toESM(require("chalk"));
|
|
20118
20057
|
var import_fs40 = __toESM(require("fs"));
|
|
20119
20058
|
var import_path42 = __toESM(require("path"));
|
|
20120
20059
|
var import_os36 = __toESM(require("os"));
|
|
@@ -20623,11 +20562,11 @@ function toolInputSummary(tool, input) {
|
|
|
20623
20562
|
}
|
|
20624
20563
|
function toolColor(tool) {
|
|
20625
20564
|
const t = tool.toLowerCase();
|
|
20626
|
-
if (t === "bash" || t === "execute_bash") return
|
|
20627
|
-
if (t === "write") return
|
|
20628
|
-
if (t === "edit" || t === "notebookedit") return
|
|
20629
|
-
if (t === "read") return
|
|
20630
|
-
return
|
|
20565
|
+
if (t === "bash" || t === "execute_bash") return import_chalk24.default.red;
|
|
20566
|
+
if (t === "write") return import_chalk24.default.green;
|
|
20567
|
+
if (t === "edit" || t === "notebookedit") return import_chalk24.default.yellow;
|
|
20568
|
+
if (t === "read") return import_chalk24.default.cyan;
|
|
20569
|
+
return import_chalk24.default.gray;
|
|
20631
20570
|
}
|
|
20632
20571
|
function barStr2(value, max, width) {
|
|
20633
20572
|
if (max === 0 || width <= 0) return "\u2591".repeat(width);
|
|
@@ -20637,7 +20576,7 @@ function barStr2(value, max, width) {
|
|
|
20637
20576
|
function colorBar2(value, max, width) {
|
|
20638
20577
|
const s = barStr2(value, max, width);
|
|
20639
20578
|
const filled = Math.max(1, Math.round(max > 0 ? value / max * width : 0));
|
|
20640
|
-
return
|
|
20579
|
+
return import_chalk24.default.cyan(s.slice(0, filled)) + import_chalk24.default.dim(s.slice(filled));
|
|
20641
20580
|
}
|
|
20642
20581
|
function renderSummary(summaries) {
|
|
20643
20582
|
const totalTools = summaries.reduce((n, s) => n + s.toolCalls.length, 0);
|
|
@@ -20667,45 +20606,45 @@ function renderSummary(summaries) {
|
|
|
20667
20606
|
}
|
|
20668
20607
|
const topProjects = [...projCosts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
20669
20608
|
const W = 20;
|
|
20670
|
-
console.log(
|
|
20609
|
+
console.log(import_chalk24.default.dim(" " + "\u2500".repeat(70)));
|
|
20671
20610
|
console.log(
|
|
20672
|
-
" " +
|
|
20611
|
+
" " + import_chalk24.default.bold.white(String(summaries.length).padEnd(4)) + import_chalk24.default.dim("sessions ") + import_chalk24.default.bold.yellow(fmtCost3(totalCost).padEnd(10)) + import_chalk24.default.dim("total ") + import_chalk24.default.bold.white(String(totalTools).padEnd(6)) + import_chalk24.default.dim("tool calls ") + import_chalk24.default.bold.white(String(totalFiles)) + import_chalk24.default.dim(" files modified") + (totalBlocked > 0 ? import_chalk24.default.dim(" ") + import_chalk24.default.red.bold(String(totalBlocked)) + import_chalk24.default.dim(" blocked by node9") : "")
|
|
20673
20612
|
);
|
|
20674
20613
|
console.log(
|
|
20675
|
-
" " +
|
|
20614
|
+
" " + import_chalk24.default.dim("avg ") + import_chalk24.default.white(fmtCost3(avgCost).padEnd(10)) + import_chalk24.default.dim("/session ") + import_chalk24.default.green(String(snapshots)) + import_chalk24.default.dim(` of ${summaries.length} sessions had snapshots`)
|
|
20676
20615
|
);
|
|
20677
20616
|
console.log("");
|
|
20678
|
-
console.log(" " +
|
|
20617
|
+
console.log(" " + import_chalk24.default.dim("Tool breakdown:"));
|
|
20679
20618
|
const maxGroup = Math.max(...Object.values(groups));
|
|
20680
20619
|
for (const [label, count] of Object.entries(groups)) {
|
|
20681
20620
|
if (count === 0) continue;
|
|
20682
20621
|
const pct = totalTools > 0 ? Math.round(count / totalTools * 100) : 0;
|
|
20683
20622
|
console.log(
|
|
20684
|
-
" " + label.padEnd(6) + " " + colorBar2(count, maxGroup, W) + " " +
|
|
20623
|
+
" " + label.padEnd(6) + " " + colorBar2(count, maxGroup, W) + " " + import_chalk24.default.white(String(count).padStart(4)) + import_chalk24.default.dim(` (${String(pct)}%)`)
|
|
20685
20624
|
);
|
|
20686
20625
|
}
|
|
20687
20626
|
console.log("");
|
|
20688
20627
|
if (topProjects.length > 1) {
|
|
20689
|
-
console.log(" " +
|
|
20628
|
+
console.log(" " + import_chalk24.default.dim("Cost by project:"));
|
|
20690
20629
|
const maxProjCost = topProjects[0][1];
|
|
20691
20630
|
for (const [proj, cost] of topProjects) {
|
|
20692
20631
|
console.log(
|
|
20693
|
-
" " + proj.slice(0, 28).padEnd(28) + " " + colorBar2(cost, maxProjCost, W) + " " +
|
|
20632
|
+
" " + proj.slice(0, 28).padEnd(28) + " " + colorBar2(cost, maxProjCost, W) + " " + import_chalk24.default.yellow(fmtCost3(cost))
|
|
20694
20633
|
);
|
|
20695
20634
|
}
|
|
20696
20635
|
console.log("");
|
|
20697
20636
|
}
|
|
20698
|
-
console.log(
|
|
20637
|
+
console.log(import_chalk24.default.dim(" " + "\u2500".repeat(70)));
|
|
20699
20638
|
console.log("");
|
|
20700
20639
|
}
|
|
20701
20640
|
function renderList(summaries, totalCost) {
|
|
20702
20641
|
if (summaries.length === 0) {
|
|
20703
|
-
console.log(
|
|
20642
|
+
console.log(import_chalk24.default.yellow(" No sessions found in the requested range.\n"));
|
|
20704
20643
|
return;
|
|
20705
20644
|
}
|
|
20706
|
-
const totalLabel = totalCost > 0 ?
|
|
20645
|
+
const totalLabel = totalCost > 0 ? import_chalk24.default.dim(" ~" + fmtCost3(totalCost) + " total") : "";
|
|
20707
20646
|
console.log(
|
|
20708
|
-
" " +
|
|
20647
|
+
" " + import_chalk24.default.white(String(summaries.length)) + import_chalk24.default.dim(` session${summaries.length !== 1 ? "s" : ""}`) + totalLabel
|
|
20709
20648
|
);
|
|
20710
20649
|
console.log("");
|
|
20711
20650
|
let lastGroup = "";
|
|
@@ -20713,49 +20652,49 @@ function renderList(summaries, totalCost) {
|
|
|
20713
20652
|
const activeDate = fmtDate2(s.lastActiveTime);
|
|
20714
20653
|
const group = activeDate + " " + s.projectLabel;
|
|
20715
20654
|
if (group !== lastGroup) {
|
|
20716
|
-
console.log(
|
|
20655
|
+
console.log(import_chalk24.default.dim(" \u2500\u2500\u2500 ") + import_chalk24.default.bold(activeDate) + import_chalk24.default.dim(" " + s.projectLabel));
|
|
20717
20656
|
lastGroup = group;
|
|
20718
20657
|
}
|
|
20719
20658
|
const startDate = fmtDate2(s.startTime);
|
|
20720
|
-
const dateRange = startDate !== activeDate ?
|
|
20721
|
-
const timeStr =
|
|
20722
|
-
const prompt =
|
|
20723
|
-
const tools = s.toolCalls.length > 0 ?
|
|
20724
|
-
const cost = s.costUSD > 0 ?
|
|
20725
|
-
const blocked = s.blockedCalls.length > 0 ?
|
|
20726
|
-
const snap = s.hasSnapshot ?
|
|
20727
|
-
const agentBadge = s.agent === "gemini" ?
|
|
20728
|
-
const sid =
|
|
20659
|
+
const dateRange = startDate !== activeDate ? import_chalk24.default.dim(" (" + startDate + " \u2192 " + activeDate + ")") : "";
|
|
20660
|
+
const timeStr = import_chalk24.default.dim(fmtTime(s.startTime));
|
|
20661
|
+
const prompt = import_chalk24.default.white(truncate(s.firstPrompt.replace(/\n/g, " "), 50).padEnd(50));
|
|
20662
|
+
const tools = s.toolCalls.length > 0 ? import_chalk24.default.dim(String(s.toolCalls.length).padStart(3) + " tools") : import_chalk24.default.dim(" 0 tools");
|
|
20663
|
+
const cost = s.costUSD > 0 ? import_chalk24.default.dim(" " + fmtCost3(s.costUSD).padEnd(8)) : " ";
|
|
20664
|
+
const blocked = s.blockedCalls.length > 0 ? import_chalk24.default.red(" \u{1F6D1} " + String(s.blockedCalls.length)) : "";
|
|
20665
|
+
const snap = s.hasSnapshot ? import_chalk24.default.green(" \u{1F4F8}") : "";
|
|
20666
|
+
const agentBadge = s.agent === "gemini" ? import_chalk24.default.blue(" [Gemini]") : s.agent === "codex" ? import_chalk24.default.magenta(" [Codex]") : import_chalk24.default.cyan(" [Claude]");
|
|
20667
|
+
const sid = import_chalk24.default.dim(" " + s.sessionId.slice(0, 8));
|
|
20729
20668
|
console.log(
|
|
20730
20669
|
` ${timeStr} ${prompt} ${tools}${cost}${blocked}${snap}${agentBadge}${sid}${dateRange}`
|
|
20731
20670
|
);
|
|
20732
20671
|
}
|
|
20733
20672
|
console.log("");
|
|
20734
20673
|
console.log(
|
|
20735
|
-
|
|
20674
|
+
import_chalk24.default.dim(" Run") + " " + import_chalk24.default.cyan("node9 sessions --detail <session-id>") + import_chalk24.default.dim(" for full tool trace.")
|
|
20736
20675
|
);
|
|
20737
20676
|
console.log("");
|
|
20738
20677
|
}
|
|
20739
20678
|
function renderDetail(s) {
|
|
20740
20679
|
console.log("");
|
|
20741
|
-
console.log(
|
|
20680
|
+
console.log(import_chalk24.default.bold(" Session ") + import_chalk24.default.dim(s.sessionId));
|
|
20742
20681
|
console.log(
|
|
20743
|
-
|
|
20682
|
+
import_chalk24.default.bold(" Prompt ") + import_chalk24.default.white(s.firstPrompt.replace(/\n/g, " ").slice(0, 120))
|
|
20744
20683
|
);
|
|
20745
|
-
console.log(
|
|
20684
|
+
console.log(import_chalk24.default.bold(" Project ") + import_chalk24.default.white(s.projectLabel));
|
|
20746
20685
|
if (s.agent) {
|
|
20747
|
-
const agentLabel2 = s.agent === "gemini" ?
|
|
20748
|
-
console.log(
|
|
20686
|
+
const agentLabel2 = s.agent === "gemini" ? import_chalk24.default.blue("Gemini CLI") : s.agent === "codex" ? import_chalk24.default.magenta("Codex") : import_chalk24.default.cyan("Claude Code");
|
|
20687
|
+
console.log(import_chalk24.default.bold(" Agent ") + agentLabel2);
|
|
20749
20688
|
}
|
|
20750
|
-
console.log(
|
|
20689
|
+
console.log(import_chalk24.default.bold(" When ") + import_chalk24.default.white(fmtDateTime(s.startTime)));
|
|
20751
20690
|
if (s.costUSD > 0)
|
|
20752
|
-
console.log(
|
|
20691
|
+
console.log(import_chalk24.default.bold(" Cost ") + import_chalk24.default.yellow("~" + fmtCost3(s.costUSD)));
|
|
20753
20692
|
console.log(
|
|
20754
|
-
|
|
20693
|
+
import_chalk24.default.bold(" Snapshot ") + (s.hasSnapshot ? import_chalk24.default.green("\u2713 taken") : import_chalk24.default.dim("none"))
|
|
20755
20694
|
);
|
|
20756
20695
|
console.log("");
|
|
20757
20696
|
if (s.toolCalls.length === 0 && s.blockedCalls.length === 0) {
|
|
20758
|
-
console.log(
|
|
20697
|
+
console.log(import_chalk24.default.dim(" No tool calls recorded.\n"));
|
|
20759
20698
|
return;
|
|
20760
20699
|
}
|
|
20761
20700
|
const timeline = [
|
|
@@ -20768,32 +20707,32 @@ function renderDetail(s) {
|
|
|
20768
20707
|
});
|
|
20769
20708
|
const headerParts = [`Tool calls (${s.toolCalls.length})`];
|
|
20770
20709
|
if (s.blockedCalls.length > 0)
|
|
20771
|
-
headerParts.push(
|
|
20772
|
-
console.log(
|
|
20710
|
+
headerParts.push(import_chalk24.default.red(`${s.blockedCalls.length} blocked by node9`));
|
|
20711
|
+
console.log(import_chalk24.default.bold(" " + headerParts.join(" \xB7 ")));
|
|
20773
20712
|
console.log("");
|
|
20774
20713
|
for (const entry of timeline) {
|
|
20775
20714
|
if (entry.kind === "tool") {
|
|
20776
20715
|
const tc = entry.tc;
|
|
20777
20716
|
const colorFn = toolColor(tc.tool);
|
|
20778
20717
|
const toolPad = colorFn(tc.tool.padEnd(16));
|
|
20779
|
-
const detail =
|
|
20780
|
-
const ts = tc.timestamp ?
|
|
20718
|
+
const detail = import_chalk24.default.gray(truncate(toolInputSummary(tc.tool, tc.input), 70));
|
|
20719
|
+
const ts = tc.timestamp ? import_chalk24.default.dim(fmtTime(tc.timestamp) + " ") : " ";
|
|
20781
20720
|
console.log(` ${ts}${toolPad} ${detail}`);
|
|
20782
20721
|
} else {
|
|
20783
20722
|
const bc = entry.bc;
|
|
20784
|
-
const ts = bc.timestamp ?
|
|
20785
|
-
const label =
|
|
20786
|
-
const toolName =
|
|
20787
|
-
const argsSummary = bc.args ?
|
|
20788
|
-
const reason = bc.checkedBy ?
|
|
20723
|
+
const ts = bc.timestamp ? import_chalk24.default.dim(fmtTime(bc.timestamp) + " ") : " ";
|
|
20724
|
+
const label = import_chalk24.default.red("\u{1F6D1} BLOCKED".padEnd(16));
|
|
20725
|
+
const toolName = import_chalk24.default.red(bc.tool.padEnd(10));
|
|
20726
|
+
const argsSummary = bc.args ? import_chalk24.default.gray(truncate(toolInputSummary(bc.tool, bc.args), 40)) : import_chalk24.default.dim("[args not logged]");
|
|
20727
|
+
const reason = bc.checkedBy ? import_chalk24.default.dim(" \u2190 " + bc.checkedBy) : "";
|
|
20789
20728
|
console.log(` ${ts}${label} ${toolName} ${argsSummary}${reason}`);
|
|
20790
20729
|
}
|
|
20791
20730
|
}
|
|
20792
20731
|
console.log("");
|
|
20793
20732
|
if (s.modifiedFiles.length > 0) {
|
|
20794
|
-
console.log(
|
|
20733
|
+
console.log(import_chalk24.default.bold(` Files modified (${s.modifiedFiles.length}):`));
|
|
20795
20734
|
for (const f of s.modifiedFiles) {
|
|
20796
|
-
console.log(" " +
|
|
20735
|
+
console.log(" " + import_chalk24.default.yellow(f));
|
|
20797
20736
|
}
|
|
20798
20737
|
console.log("");
|
|
20799
20738
|
}
|
|
@@ -20801,19 +20740,19 @@ function renderDetail(s) {
|
|
|
20801
20740
|
function registerSessionsCommand(program2) {
|
|
20802
20741
|
program2.command("sessions").description("Show what your AI agent did \u2014 sessions, tool calls, cost, and file changes").option("--all", "Show all sessions (default: last 7 days)").option("--days <n>", "Show last N days of sessions", "7").option("--detail <sessionId>", "Show full tool trace for a session").action((options) => {
|
|
20803
20742
|
console.log("");
|
|
20804
|
-
console.log(
|
|
20743
|
+
console.log(import_chalk24.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk24.default.dim(" \u2014 what your AI agent did"));
|
|
20805
20744
|
console.log("");
|
|
20806
20745
|
const historyPath = import_path42.default.join(import_os36.default.homedir(), ".claude", "history.jsonl");
|
|
20807
20746
|
if (!import_fs40.default.existsSync(historyPath)) {
|
|
20808
|
-
console.log(
|
|
20809
|
-
console.log(
|
|
20747
|
+
console.log(import_chalk24.default.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
|
|
20748
|
+
console.log(import_chalk24.default.gray(" Install Claude Code, run a few sessions, then try again.\n"));
|
|
20810
20749
|
return;
|
|
20811
20750
|
}
|
|
20812
20751
|
const days = options.detail || options.all ? null : Math.max(1, parseInt(options.days, 10) || 7);
|
|
20813
20752
|
const rangeLabel = options.detail ? "all time" : options.all ? "all time" : `last ${String(days)} days`;
|
|
20814
|
-
console.log(
|
|
20753
|
+
console.log(import_chalk24.default.dim(" " + rangeLabel));
|
|
20815
20754
|
console.log("");
|
|
20816
|
-
process.stdout.write(
|
|
20755
|
+
process.stdout.write(import_chalk24.default.dim(" Loading\u2026"));
|
|
20817
20756
|
const summaries = buildSessions(days);
|
|
20818
20757
|
if (process.stdout.isTTY) {
|
|
20819
20758
|
process.stdout.clearLine(0);
|
|
@@ -20826,8 +20765,8 @@ function registerSessionsCommand(program2) {
|
|
|
20826
20765
|
(s) => s.sessionId === options.detail || s.sessionId.startsWith(options.detail)
|
|
20827
20766
|
);
|
|
20828
20767
|
if (!target) {
|
|
20829
|
-
console.log(
|
|
20830
|
-
console.log(
|
|
20768
|
+
console.log(import_chalk24.default.red(` Session not found: ${options.detail}`));
|
|
20769
|
+
console.log(import_chalk24.default.dim(" Run `node9 sessions` to list recent sessions.\n"));
|
|
20831
20770
|
return;
|
|
20832
20771
|
}
|
|
20833
20772
|
renderDetail(target);
|
|
@@ -20840,7 +20779,7 @@ function registerSessionsCommand(program2) {
|
|
|
20840
20779
|
}
|
|
20841
20780
|
|
|
20842
20781
|
// src/cli/commands/skill-pin.ts
|
|
20843
|
-
var
|
|
20782
|
+
var import_chalk25 = __toESM(require("chalk"));
|
|
20844
20783
|
var import_fs41 = __toESM(require("fs"));
|
|
20845
20784
|
var import_os37 = __toESM(require("os"));
|
|
20846
20785
|
var import_path43 = __toESM(require("path"));
|
|
@@ -20860,29 +20799,29 @@ function registerSkillPinCommand(program2) {
|
|
|
20860
20799
|
const result = readSkillPinsSafe();
|
|
20861
20800
|
if (!result.ok) {
|
|
20862
20801
|
if (result.reason === "missing") {
|
|
20863
|
-
console.log(
|
|
20802
|
+
console.log(import_chalk25.default.gray("\nNo skill roots are pinned yet."));
|
|
20864
20803
|
console.log(
|
|
20865
|
-
|
|
20804
|
+
import_chalk25.default.gray("Pins are created automatically on the first tool call of each session.\n")
|
|
20866
20805
|
);
|
|
20867
20806
|
return;
|
|
20868
20807
|
}
|
|
20869
|
-
console.error(
|
|
20808
|
+
console.error(import_chalk25.default.red(`
|
|
20870
20809
|
\u274C Pin file is corrupt: ${result.detail}`));
|
|
20871
|
-
console.error(
|
|
20810
|
+
console.error(import_chalk25.default.yellow(" Run: node9 skill pin reset\n"));
|
|
20872
20811
|
process.exit(1);
|
|
20873
20812
|
}
|
|
20874
20813
|
const entries = Object.entries(result.pins.roots);
|
|
20875
20814
|
if (entries.length === 0) {
|
|
20876
|
-
console.log(
|
|
20815
|
+
console.log(import_chalk25.default.gray("\nNo skill roots are pinned yet.\n"));
|
|
20877
20816
|
return;
|
|
20878
20817
|
}
|
|
20879
|
-
console.log(
|
|
20818
|
+
console.log(import_chalk25.default.bold("\n\u{1F512} Pinned Skill Roots\n"));
|
|
20880
20819
|
for (const [key, entry] of entries) {
|
|
20881
|
-
const missing = entry.exists ? "" :
|
|
20882
|
-
console.log(` ${
|
|
20820
|
+
const missing = entry.exists ? "" : import_chalk25.default.yellow(" (not present at pin time)");
|
|
20821
|
+
console.log(` ${import_chalk25.default.cyan(key)} ${import_chalk25.default.gray(entry.rootPath)}${missing}`);
|
|
20883
20822
|
console.log(` Files (${entry.fileCount})`);
|
|
20884
|
-
console.log(` Hash: ${
|
|
20885
|
-
console.log(` Pinned: ${
|
|
20823
|
+
console.log(` Hash: ${import_chalk25.default.gray(entry.contentHash.slice(0, 16))}...`);
|
|
20824
|
+
console.log(` Pinned: ${import_chalk25.default.gray(entry.pinnedAt)}
|
|
20886
20825
|
`);
|
|
20887
20826
|
}
|
|
20888
20827
|
});
|
|
@@ -20891,39 +20830,39 @@ function registerSkillPinCommand(program2) {
|
|
|
20891
20830
|
try {
|
|
20892
20831
|
pins = readSkillPins();
|
|
20893
20832
|
} catch {
|
|
20894
|
-
console.error(
|
|
20895
|
-
console.error(
|
|
20833
|
+
console.error(import_chalk25.default.red("\n\u274C Pin file is corrupt."));
|
|
20834
|
+
console.error(import_chalk25.default.yellow(" Run: node9 skill pin reset\n"));
|
|
20896
20835
|
process.exit(1);
|
|
20897
20836
|
}
|
|
20898
20837
|
if (!pins.roots[rootKey]) {
|
|
20899
|
-
console.error(
|
|
20838
|
+
console.error(import_chalk25.default.red(`
|
|
20900
20839
|
\u274C No pin found for root key "${rootKey}"
|
|
20901
20840
|
`));
|
|
20902
|
-
console.error(`Run ${
|
|
20841
|
+
console.error(`Run ${import_chalk25.default.cyan("node9 skill pin list")} to see pinned roots.
|
|
20903
20842
|
`);
|
|
20904
20843
|
process.exit(1);
|
|
20905
20844
|
}
|
|
20906
20845
|
const rootPath = pins.roots[rootKey].rootPath;
|
|
20907
20846
|
removePin(rootKey);
|
|
20908
20847
|
wipeSkillSessions();
|
|
20909
|
-
console.log(
|
|
20910
|
-
\u{1F513} Pin removed for ${
|
|
20911
|
-
console.log(
|
|
20912
|
-
console.log(
|
|
20848
|
+
console.log(import_chalk25.default.green(`
|
|
20849
|
+
\u{1F513} Pin removed for ${import_chalk25.default.cyan(rootKey)}`));
|
|
20850
|
+
console.log(import_chalk25.default.gray(` ${rootPath}`));
|
|
20851
|
+
console.log(import_chalk25.default.gray(" Next session will re-pin with current state.\n"));
|
|
20913
20852
|
});
|
|
20914
20853
|
pinSubCmd.command("reset").description("Clear all skill pins and wipe session verification flags").action(() => {
|
|
20915
20854
|
const result = readSkillPinsSafe();
|
|
20916
20855
|
if (!result.ok && result.reason === "missing") {
|
|
20917
20856
|
wipeSkillSessions();
|
|
20918
|
-
console.log(
|
|
20857
|
+
console.log(import_chalk25.default.gray("\nNo pins to clear.\n"));
|
|
20919
20858
|
return;
|
|
20920
20859
|
}
|
|
20921
20860
|
const count = result.ok ? Object.keys(result.pins.roots).length : "?";
|
|
20922
20861
|
clearAllPins();
|
|
20923
20862
|
wipeSkillSessions();
|
|
20924
|
-
console.log(
|
|
20863
|
+
console.log(import_chalk25.default.green(`
|
|
20925
20864
|
\u{1F513} Cleared ${count} skill pin(s).`));
|
|
20926
|
-
console.log(
|
|
20865
|
+
console.log(import_chalk25.default.gray(" Next session will re-pin with current state.\n"));
|
|
20927
20866
|
});
|
|
20928
20867
|
}
|
|
20929
20868
|
|
|
@@ -20931,7 +20870,7 @@ function registerSkillPinCommand(program2) {
|
|
|
20931
20870
|
var import_fs42 = __toESM(require("fs"));
|
|
20932
20871
|
var import_os38 = __toESM(require("os"));
|
|
20933
20872
|
var import_path44 = __toESM(require("path"));
|
|
20934
|
-
var
|
|
20873
|
+
var import_chalk26 = __toESM(require("chalk"));
|
|
20935
20874
|
var DECISIONS_FILE2 = import_path44.default.join(import_os38.default.homedir(), ".node9", "decisions.json");
|
|
20936
20875
|
function readDecisions() {
|
|
20937
20876
|
try {
|
|
@@ -20960,55 +20899,55 @@ function registerDecisionsCommand(program2) {
|
|
|
20960
20899
|
const decisions = readDecisions();
|
|
20961
20900
|
const entries = Object.entries(decisions);
|
|
20962
20901
|
if (entries.length === 0) {
|
|
20963
|
-
console.log(
|
|
20902
|
+
console.log(import_chalk26.default.gray(" No persistent decisions stored."));
|
|
20964
20903
|
console.log(
|
|
20965
|
-
|
|
20966
|
-
`) +
|
|
20904
|
+
import_chalk26.default.gray(` File: ${DECISIONS_FILE2}
|
|
20905
|
+
`) + import_chalk26.default.gray(' Decisions are written when you click "Always Allow" or')
|
|
20967
20906
|
);
|
|
20968
|
-
console.log(
|
|
20907
|
+
console.log(import_chalk26.default.gray(' "Always Deny" in node9 tail or the native popup.'));
|
|
20969
20908
|
return;
|
|
20970
20909
|
}
|
|
20971
|
-
console.log(
|
|
20910
|
+
console.log(import_chalk26.default.bold(`
|
|
20972
20911
|
Persistent decisions (${entries.length})
|
|
20973
20912
|
`));
|
|
20974
20913
|
const w = Math.max(...entries.map(([k]) => k.length));
|
|
20975
20914
|
for (const [tool, verdict] of entries.sort()) {
|
|
20976
|
-
const colored = verdict === "allow" ?
|
|
20915
|
+
const colored = verdict === "allow" ? import_chalk26.default.green(verdict) : import_chalk26.default.red(verdict);
|
|
20977
20916
|
console.log(` ${tool.padEnd(w)} ${colored}`);
|
|
20978
20917
|
}
|
|
20979
20918
|
console.log(
|
|
20980
|
-
|
|
20919
|
+
import_chalk26.default.gray(`
|
|
20981
20920
|
Stored in ${DECISIONS_FILE2}
|
|
20982
|
-
`) +
|
|
20921
|
+
`) + import_chalk26.default.gray(" Run `node9 decisions clear <tool>` to remove an entry.")
|
|
20983
20922
|
);
|
|
20984
20923
|
});
|
|
20985
20924
|
cmd.command("clear <toolName>").description("Remove a persistent decision for one tool").action((toolName) => {
|
|
20986
20925
|
const decisions = readDecisions();
|
|
20987
20926
|
if (!(toolName in decisions)) {
|
|
20988
|
-
console.log(
|
|
20927
|
+
console.log(import_chalk26.default.yellow(` No persistent decision for "${toolName}". Nothing to clear.`));
|
|
20989
20928
|
process.exitCode = 1;
|
|
20990
20929
|
return;
|
|
20991
20930
|
}
|
|
20992
20931
|
delete decisions[toolName];
|
|
20993
20932
|
writeDecisions(decisions);
|
|
20994
|
-
console.log(
|
|
20933
|
+
console.log(import_chalk26.default.green(` \u2713 Cleared persistent decision for "${toolName}".`));
|
|
20995
20934
|
});
|
|
20996
20935
|
cmd.command("clear-all").description("Remove every persistent decision (irreversible)").action(() => {
|
|
20997
20936
|
const decisions = readDecisions();
|
|
20998
20937
|
const count = Object.keys(decisions).length;
|
|
20999
20938
|
if (count === 0) {
|
|
21000
|
-
console.log(
|
|
20939
|
+
console.log(import_chalk26.default.gray(" Nothing to clear \u2014 no persistent decisions stored."));
|
|
21001
20940
|
return;
|
|
21002
20941
|
}
|
|
21003
20942
|
writeDecisions({});
|
|
21004
20943
|
console.log(
|
|
21005
|
-
|
|
20944
|
+
import_chalk26.default.green(` \u2713 Cleared ${count} persistent decision${count === 1 ? "" : "s"}.`)
|
|
21006
20945
|
);
|
|
21007
20946
|
});
|
|
21008
20947
|
}
|
|
21009
20948
|
|
|
21010
20949
|
// src/cli/commands/dlp.ts
|
|
21011
|
-
var
|
|
20950
|
+
var import_chalk27 = __toESM(require("chalk"));
|
|
21012
20951
|
var import_fs43 = __toESM(require("fs"));
|
|
21013
20952
|
var import_path45 = __toESM(require("path"));
|
|
21014
20953
|
var import_os39 = __toESM(require("os"));
|
|
@@ -21063,14 +21002,14 @@ function registerDlpCommand(program2) {
|
|
|
21063
21002
|
cmd.command("resolve").description("Mark all current DLP findings as resolved").action(() => {
|
|
21064
21003
|
const findings = loadDlpFindings();
|
|
21065
21004
|
if (findings.length === 0) {
|
|
21066
|
-
console.log(
|
|
21005
|
+
console.log(import_chalk27.default.green("\n \u2705 No response-DLP findings to resolve.\n"));
|
|
21067
21006
|
return;
|
|
21068
21007
|
}
|
|
21069
21008
|
const resolved = loadResolved();
|
|
21070
21009
|
for (const e of findings) resolved.add(entryKey(e));
|
|
21071
21010
|
saveResolved(resolved);
|
|
21072
21011
|
console.log(
|
|
21073
|
-
|
|
21012
|
+
import_chalk27.default.green(
|
|
21074
21013
|
`
|
|
21075
21014
|
\u2705 ${findings.length} finding${findings.length !== 1 ? "s" : ""} marked as resolved.
|
|
21076
21015
|
`
|
|
@@ -21084,54 +21023,54 @@ function registerDlpCommand(program2) {
|
|
|
21084
21023
|
const resolvedCount = findings.length - open.length;
|
|
21085
21024
|
console.log("");
|
|
21086
21025
|
console.log(
|
|
21087
|
-
|
|
21026
|
+
import_chalk27.default.bold.cyan("\u{1F510} node9 dlp") + import_chalk27.default.dim(" \u2014 secrets found in Claude response text")
|
|
21088
21027
|
);
|
|
21089
21028
|
console.log("");
|
|
21090
21029
|
if (open.length === 0) {
|
|
21091
21030
|
if (resolvedCount > 0) {
|
|
21092
|
-
console.log(
|
|
21031
|
+
console.log(import_chalk27.default.green(` \u2705 No open findings \xB7 ${resolvedCount} previously resolved`));
|
|
21093
21032
|
} else {
|
|
21094
21033
|
console.log(
|
|
21095
|
-
|
|
21034
|
+
import_chalk27.default.green(" \u2705 No findings \u2014 Claude has not leaked secrets in response text")
|
|
21096
21035
|
);
|
|
21097
21036
|
}
|
|
21098
21037
|
console.log("");
|
|
21099
21038
|
return;
|
|
21100
21039
|
}
|
|
21101
21040
|
console.log(
|
|
21102
|
-
|
|
21041
|
+
import_chalk27.default.bgRed.white.bold(` \u26A0\uFE0F ${open.length} open finding${open.length !== 1 ? "s" : ""} `) + import_chalk27.default.dim(resolvedCount > 0 ? ` (${resolvedCount} resolved)` : "")
|
|
21103
21042
|
);
|
|
21104
21043
|
console.log("");
|
|
21105
21044
|
console.log(
|
|
21106
|
-
|
|
21045
|
+
import_chalk27.default.dim(" These secrets were included in Claude's response text \u2014 NOT blocked.")
|
|
21107
21046
|
);
|
|
21108
|
-
console.log(
|
|
21047
|
+
console.log(import_chalk27.default.dim(" Rotate each affected key immediately.\n"));
|
|
21109
21048
|
for (const e of open) {
|
|
21110
21049
|
console.log(
|
|
21111
|
-
" " +
|
|
21050
|
+
" " + import_chalk27.default.red("\u25CF") + " " + import_chalk27.default.white(e.dlpPattern ?? "Secret") + import_chalk27.default.dim(" " + fmtDate3(e.ts))
|
|
21112
21051
|
);
|
|
21113
21052
|
if (e.dlpSample) {
|
|
21114
|
-
console.log(" " +
|
|
21053
|
+
console.log(" " + import_chalk27.default.dim("Sample: ") + import_chalk27.default.yellow(stripAnsi(e.dlpSample)));
|
|
21115
21054
|
}
|
|
21116
21055
|
if (e.project) {
|
|
21117
|
-
console.log(" " +
|
|
21056
|
+
console.log(" " + import_chalk27.default.dim("Project: ") + import_chalk27.default.dim(stripAnsi(e.project)));
|
|
21118
21057
|
}
|
|
21119
21058
|
console.log("");
|
|
21120
21059
|
}
|
|
21121
|
-
console.log(" " +
|
|
21122
|
-
console.log(" " +
|
|
21060
|
+
console.log(" " + import_chalk27.default.bold("Next steps:"));
|
|
21061
|
+
console.log(" " + import_chalk27.default.cyan("1.") + " Rotate any exposed keys shown above");
|
|
21123
21062
|
console.log(
|
|
21124
|
-
" " +
|
|
21063
|
+
" " + import_chalk27.default.cyan("2.") + " Run " + import_chalk27.default.white("node9 dlp resolve") + " to acknowledge"
|
|
21125
21064
|
);
|
|
21126
21065
|
console.log(
|
|
21127
|
-
" " +
|
|
21066
|
+
" " + import_chalk27.default.cyan("3.") + " Run " + import_chalk27.default.white("node9 report") + " for full audit history"
|
|
21128
21067
|
);
|
|
21129
21068
|
console.log("");
|
|
21130
21069
|
});
|
|
21131
21070
|
}
|
|
21132
21071
|
|
|
21133
21072
|
// src/cli/commands/mask.ts
|
|
21134
|
-
var
|
|
21073
|
+
var import_chalk28 = __toESM(require("chalk"));
|
|
21135
21074
|
var import_fs44 = __toESM(require("fs"));
|
|
21136
21075
|
var import_path46 = __toESM(require("path"));
|
|
21137
21076
|
var import_os40 = __toESM(require("os"));
|
|
@@ -21268,12 +21207,12 @@ function registerMaskCommand(program2) {
|
|
|
21268
21207
|
}
|
|
21269
21208
|
}) : allFiles;
|
|
21270
21209
|
if (filtered.length === 0) {
|
|
21271
|
-
console.log(
|
|
21210
|
+
console.log(import_chalk28.default.yellow(" No session files found."));
|
|
21272
21211
|
return;
|
|
21273
21212
|
}
|
|
21274
21213
|
console.log("");
|
|
21275
21214
|
if (dryRun) {
|
|
21276
|
-
console.log(
|
|
21215
|
+
console.log(import_chalk28.default.dim(" Dry run \u2014 no files will be modified.\n"));
|
|
21277
21216
|
}
|
|
21278
21217
|
let totalFiles = 0;
|
|
21279
21218
|
let totalLines = 0;
|
|
@@ -21289,23 +21228,23 @@ function registerMaskCommand(program2) {
|
|
|
21289
21228
|
});
|
|
21290
21229
|
const verb = dryRun ? "Would redact" : "Redacted";
|
|
21291
21230
|
console.log(
|
|
21292
|
-
" " +
|
|
21231
|
+
" " + import_chalk28.default.dim(shortPath.slice(0, 60).padEnd(62)) + import_chalk28.default.red(`${verb}: `) + import_chalk28.default.yellow(patterns.join(", ")) + import_chalk28.default.dim(` (${redactedLines} line${redactedLines !== 1 ? "s" : ""})`)
|
|
21293
21232
|
);
|
|
21294
21233
|
}
|
|
21295
21234
|
}
|
|
21296
21235
|
console.log("");
|
|
21297
21236
|
if (totalFiles === 0) {
|
|
21298
|
-
console.log(
|
|
21237
|
+
console.log(import_chalk28.default.green(" No secrets found in session history."));
|
|
21299
21238
|
} else {
|
|
21300
21239
|
const verb = dryRun ? "would be modified" : "modified";
|
|
21301
21240
|
console.log(
|
|
21302
|
-
|
|
21241
|
+
import_chalk28.default.bold(` ${totalFiles} file${totalFiles !== 1 ? "s" : ""} ${verb}`) + import_chalk28.default.dim(`, ${totalLines} line${totalLines !== 1 ? "s" : ""} redacted`)
|
|
21303
21242
|
);
|
|
21304
|
-
console.log(" Patterns: " +
|
|
21243
|
+
console.log(" Patterns: " + import_chalk28.default.yellow(totalPatterns.join(", ")));
|
|
21305
21244
|
if (!dryRun) {
|
|
21306
21245
|
console.log("");
|
|
21307
21246
|
console.log(
|
|
21308
|
-
|
|
21247
|
+
import_chalk28.default.dim(
|
|
21309
21248
|
" Note: secrets were already sent to the AI provider during the active session.\n This cleans your local disk only. Rotate any exposed keys."
|
|
21310
21249
|
)
|
|
21311
21250
|
);
|
|
@@ -21369,17 +21308,17 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
21369
21308
|
import_fs47.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
21370
21309
|
}
|
|
21371
21310
|
if (options.profile && profileName !== "default") {
|
|
21372
|
-
console.log(
|
|
21373
|
-
console.log(
|
|
21311
|
+
console.log(import_chalk30.default.green(`\u2705 Profile "${profileName}" saved`));
|
|
21312
|
+
console.log(import_chalk30.default.gray(` Switch to it per-session: NODE9_PROFILE=${profileName} claude`));
|
|
21374
21313
|
} else if (options.local) {
|
|
21375
|
-
console.log(
|
|
21376
|
-
console.log(
|
|
21314
|
+
console.log(import_chalk30.default.green(`\u2705 Privacy mode \u{1F6E1}\uFE0F`));
|
|
21315
|
+
console.log(import_chalk30.default.gray(` All decisions stay on this machine.`));
|
|
21377
21316
|
} else {
|
|
21378
|
-
console.log(
|
|
21379
|
-
console.log(
|
|
21317
|
+
console.log(import_chalk30.default.green(`\u2705 Logged in \u2014 agent mode`));
|
|
21318
|
+
console.log(import_chalk30.default.gray(` Team policy enforced for all calls via Node9 cloud.`));
|
|
21380
21319
|
}
|
|
21381
21320
|
});
|
|
21382
|
-
program.command("addto").description("Integrate Node9 with an AI agent").addHelpText(
|
|
21321
|
+
program.command("addto", { hidden: true }).description("Integrate Node9 with an AI agent").addHelpText(
|
|
21383
21322
|
"after",
|
|
21384
21323
|
"\n Supported targets: claude gemini cursor codex windsurf vscode hud"
|
|
21385
21324
|
).argument(
|
|
@@ -21394,13 +21333,13 @@ program.command("addto").description("Integrate Node9 with an AI agent").addHelp
|
|
|
21394
21333
|
if (target === "vscode") return await setupVSCode();
|
|
21395
21334
|
if (target === "hud") return setupHud();
|
|
21396
21335
|
console.error(
|
|
21397
|
-
|
|
21336
|
+
import_chalk30.default.red(
|
|
21398
21337
|
`Unknown target: "${target}". Supported: claude, gemini, cursor, codex, windsurf, vscode, hud`
|
|
21399
21338
|
)
|
|
21400
21339
|
);
|
|
21401
21340
|
process.exit(1);
|
|
21402
21341
|
});
|
|
21403
|
-
program.command("setup").description('Alias for "addto" \u2014 integrate Node9 with an AI agent').addHelpText(
|
|
21342
|
+
program.command("setup", { hidden: true }).description('Alias for "addto" \u2014 integrate Node9 with an AI agent').addHelpText(
|
|
21404
21343
|
"after",
|
|
21405
21344
|
"\n Supported targets: claude gemini cursor codex windsurf vscode hud"
|
|
21406
21345
|
).argument(
|
|
@@ -21408,17 +21347,17 @@ program.command("setup").description('Alias for "addto" \u2014 integrate Node9 w
|
|
|
21408
21347
|
"The agent to protect: claude | gemini | cursor | codex | windsurf | vscode | hud"
|
|
21409
21348
|
).action(async (target) => {
|
|
21410
21349
|
if (!target) {
|
|
21411
|
-
console.log(
|
|
21412
|
-
console.log(" Usage: " +
|
|
21350
|
+
console.log(import_chalk30.default.cyan("\n\u{1F6E1}\uFE0F Node9 Setup \u2014 integrate with your AI agent\n"));
|
|
21351
|
+
console.log(" Usage: " + import_chalk30.default.white("node9 setup <target>") + "\n");
|
|
21413
21352
|
console.log(" Targets:");
|
|
21414
|
-
console.log(" " +
|
|
21415
|
-
console.log(" " +
|
|
21416
|
-
console.log(" " +
|
|
21417
|
-
console.log(" " +
|
|
21418
|
-
console.log(" " +
|
|
21419
|
-
console.log(" " +
|
|
21353
|
+
console.log(" " + import_chalk30.default.green("claude") + " \u2014 Claude Code (hook mode)");
|
|
21354
|
+
console.log(" " + import_chalk30.default.green("gemini") + " \u2014 Gemini CLI (hook mode)");
|
|
21355
|
+
console.log(" " + import_chalk30.default.green("cursor") + " \u2014 Cursor (MCP proxy)");
|
|
21356
|
+
console.log(" " + import_chalk30.default.green("codex") + " \u2014 OpenAI Codex CLI (MCP proxy)");
|
|
21357
|
+
console.log(" " + import_chalk30.default.green("windsurf") + " \u2014 Windsurf (MCP proxy)");
|
|
21358
|
+
console.log(" " + import_chalk30.default.green("vscode") + " \u2014 VSCode / Copilot (MCP proxy)");
|
|
21420
21359
|
process.stdout.write(
|
|
21421
|
-
" " +
|
|
21360
|
+
" " + import_chalk30.default.green("hud") + " \u2014 Claude Code security statusline\n"
|
|
21422
21361
|
);
|
|
21423
21362
|
console.log("");
|
|
21424
21363
|
return;
|
|
@@ -21432,13 +21371,13 @@ program.command("setup").description('Alias for "addto" \u2014 integrate Node9 w
|
|
|
21432
21371
|
if (t === "vscode") return await setupVSCode();
|
|
21433
21372
|
if (t === "hud") return setupHud();
|
|
21434
21373
|
console.error(
|
|
21435
|
-
|
|
21374
|
+
import_chalk30.default.red(
|
|
21436
21375
|
`Unknown target: "${target}". Supported: claude, gemini, cursor, codex, windsurf, vscode, hud`
|
|
21437
21376
|
)
|
|
21438
21377
|
);
|
|
21439
21378
|
process.exit(1);
|
|
21440
21379
|
});
|
|
21441
|
-
program.command("removefrom").description("Remove Node9 hooks from an AI agent configuration").addHelpText(
|
|
21380
|
+
program.command("removefrom", { hidden: true }).description("Remove Node9 hooks from an AI agent configuration").addHelpText(
|
|
21442
21381
|
"after",
|
|
21443
21382
|
"\n Supported targets: claude gemini cursor codex windsurf vscode hud"
|
|
21444
21383
|
).argument(
|
|
@@ -21455,33 +21394,33 @@ program.command("removefrom").description("Remove Node9 hooks from an AI agent c
|
|
|
21455
21394
|
else if (target === "hud") fn = teardownHud;
|
|
21456
21395
|
else {
|
|
21457
21396
|
console.error(
|
|
21458
|
-
|
|
21397
|
+
import_chalk30.default.red(
|
|
21459
21398
|
`Unknown target: "${target}". Supported: claude, gemini, cursor, codex, windsurf, vscode, hud`
|
|
21460
21399
|
)
|
|
21461
21400
|
);
|
|
21462
21401
|
process.exit(1);
|
|
21463
21402
|
}
|
|
21464
|
-
console.log(
|
|
21403
|
+
console.log(import_chalk30.default.cyan(`
|
|
21465
21404
|
\u{1F6E1}\uFE0F Node9: removing hooks from ${target}...
|
|
21466
21405
|
`));
|
|
21467
21406
|
try {
|
|
21468
21407
|
fn();
|
|
21469
21408
|
} catch (err2) {
|
|
21470
|
-
console.error(
|
|
21409
|
+
console.error(import_chalk30.default.red(` \u26A0\uFE0F Failed: ${err2 instanceof Error ? err2.message : String(err2)}`));
|
|
21471
21410
|
process.exit(1);
|
|
21472
21411
|
}
|
|
21473
|
-
console.log(
|
|
21412
|
+
console.log(import_chalk30.default.gray("\n Restart the agent for changes to take effect."));
|
|
21474
21413
|
});
|
|
21475
21414
|
program.command("uninstall").description("Remove all Node9 hooks and optionally delete config files").option("--purge", "Also delete ~/.node9/ directory (config, audit log, credentials)").action(async (options) => {
|
|
21476
|
-
console.log(
|
|
21477
|
-
console.log(
|
|
21415
|
+
console.log(import_chalk30.default.cyan("\n\u{1F6E1}\uFE0F Node9 Uninstall\n"));
|
|
21416
|
+
console.log(import_chalk30.default.bold("Stopping daemon..."));
|
|
21478
21417
|
try {
|
|
21479
21418
|
stopDaemon();
|
|
21480
|
-
console.log(
|
|
21419
|
+
console.log(import_chalk30.default.green(" \u2705 Daemon stopped"));
|
|
21481
21420
|
} catch {
|
|
21482
|
-
console.log(
|
|
21421
|
+
console.log(import_chalk30.default.blue(" \u2139\uFE0F Daemon was not running"));
|
|
21483
21422
|
}
|
|
21484
|
-
console.log(
|
|
21423
|
+
console.log(import_chalk30.default.bold("\nRemoving hooks..."));
|
|
21485
21424
|
let teardownFailed = false;
|
|
21486
21425
|
for (const [label, fn] of [
|
|
21487
21426
|
["Claude", teardownClaude],
|
|
@@ -21496,7 +21435,7 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
21496
21435
|
} catch (err2) {
|
|
21497
21436
|
teardownFailed = true;
|
|
21498
21437
|
console.error(
|
|
21499
|
-
|
|
21438
|
+
import_chalk30.default.red(
|
|
21500
21439
|
` \u26A0\uFE0F Failed to remove ${label} hooks: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
21501
21440
|
)
|
|
21502
21441
|
);
|
|
@@ -21513,28 +21452,28 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
21513
21452
|
import_fs47.default.rmSync(node9Dir, { recursive: true });
|
|
21514
21453
|
if (import_fs47.default.existsSync(node9Dir)) {
|
|
21515
21454
|
console.error(
|
|
21516
|
-
|
|
21455
|
+
import_chalk30.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
21517
21456
|
);
|
|
21518
21457
|
} else {
|
|
21519
|
-
console.log(
|
|
21458
|
+
console.log(import_chalk30.default.green("\n \u2705 Deleted ~/.node9/ (config, audit log, credentials)"));
|
|
21520
21459
|
}
|
|
21521
21460
|
} else {
|
|
21522
|
-
console.log(
|
|
21461
|
+
console.log(import_chalk30.default.yellow("\n Skipped \u2014 ~/.node9/ was not deleted."));
|
|
21523
21462
|
}
|
|
21524
21463
|
} else {
|
|
21525
|
-
console.log(
|
|
21464
|
+
console.log(import_chalk30.default.blue("\n \u2139\uFE0F ~/.node9/ not found \u2014 nothing to delete"));
|
|
21526
21465
|
}
|
|
21527
21466
|
} else {
|
|
21528
21467
|
console.log(
|
|
21529
|
-
|
|
21468
|
+
import_chalk30.default.gray("\n ~/.node9/ kept \u2014 run with --purge to delete config and audit log")
|
|
21530
21469
|
);
|
|
21531
21470
|
}
|
|
21532
21471
|
if (teardownFailed) {
|
|
21533
|
-
console.error(
|
|
21472
|
+
console.error(import_chalk30.default.red("\n \u26A0\uFE0F Some hooks could not be removed \u2014 see errors above."));
|
|
21534
21473
|
process.exit(1);
|
|
21535
21474
|
}
|
|
21536
|
-
console.log(
|
|
21537
|
-
console.log(
|
|
21475
|
+
console.log(import_chalk30.default.green.bold("\n\u{1F6E1}\uFE0F Node9 removed. Run: npm uninstall -g @node9/proxy"));
|
|
21476
|
+
console.log(import_chalk30.default.gray(" Restart any open AI agent sessions for changes to take effect.\n"));
|
|
21538
21477
|
});
|
|
21539
21478
|
registerDoctorCommand(program, version);
|
|
21540
21479
|
program.command("explain").description(
|
|
@@ -21547,7 +21486,7 @@ program.command("explain").description(
|
|
|
21547
21486
|
try {
|
|
21548
21487
|
args = JSON.parse(trimmed);
|
|
21549
21488
|
} catch {
|
|
21550
|
-
console.error(
|
|
21489
|
+
console.error(import_chalk30.default.red(`
|
|
21551
21490
|
\u274C Invalid JSON: ${trimmed}
|
|
21552
21491
|
`));
|
|
21553
21492
|
process.exit(1);
|
|
@@ -21558,54 +21497,54 @@ program.command("explain").description(
|
|
|
21558
21497
|
}
|
|
21559
21498
|
const result = await explainPolicy(tool, args);
|
|
21560
21499
|
console.log("");
|
|
21561
|
-
console.log(
|
|
21500
|
+
console.log(import_chalk30.default.cyan.bold("\u{1F6E1}\uFE0F Node9 Explain"));
|
|
21562
21501
|
console.log("");
|
|
21563
|
-
console.log(` ${
|
|
21502
|
+
console.log(` ${import_chalk30.default.bold("Tool:")} ${import_chalk30.default.white(result.tool)}`);
|
|
21564
21503
|
if (argsRaw) {
|
|
21565
21504
|
const preview2 = argsRaw.length > 80 ? argsRaw.slice(0, 77) + "\u2026" : argsRaw;
|
|
21566
|
-
console.log(` ${
|
|
21505
|
+
console.log(` ${import_chalk30.default.bold("Input:")} ${import_chalk30.default.gray(preview2)}`);
|
|
21567
21506
|
}
|
|
21568
21507
|
console.log("");
|
|
21569
|
-
console.log(
|
|
21508
|
+
console.log(import_chalk30.default.bold("Config Sources (Waterfall):"));
|
|
21570
21509
|
for (const tier of result.waterfall) {
|
|
21571
|
-
const num3 =
|
|
21510
|
+
const num3 = import_chalk30.default.gray(` ${tier.tier}.`);
|
|
21572
21511
|
const label = tier.label.padEnd(16);
|
|
21573
21512
|
let statusStr;
|
|
21574
21513
|
if (tier.tier === 1) {
|
|
21575
|
-
statusStr =
|
|
21514
|
+
statusStr = import_chalk30.default.gray(tier.note ?? "");
|
|
21576
21515
|
} else if (tier.status === "active") {
|
|
21577
|
-
const loc = tier.path ?
|
|
21578
|
-
const note = tier.note ?
|
|
21579
|
-
statusStr =
|
|
21516
|
+
const loc = tier.path ? import_chalk30.default.gray(tier.path) : "";
|
|
21517
|
+
const note = tier.note ? import_chalk30.default.gray(`(${tier.note})`) : "";
|
|
21518
|
+
statusStr = import_chalk30.default.green("\u2713 active") + (loc ? " " + loc : "") + (note ? " " + note : "");
|
|
21580
21519
|
} else {
|
|
21581
|
-
statusStr =
|
|
21520
|
+
statusStr = import_chalk30.default.gray("\u25CB " + (tier.note ?? "not found"));
|
|
21582
21521
|
}
|
|
21583
|
-
console.log(`${num3} ${
|
|
21522
|
+
console.log(`${num3} ${import_chalk30.default.white(label)} ${statusStr}`);
|
|
21584
21523
|
}
|
|
21585
21524
|
console.log("");
|
|
21586
|
-
console.log(
|
|
21525
|
+
console.log(import_chalk30.default.bold("Policy Evaluation:"));
|
|
21587
21526
|
for (const step of result.steps) {
|
|
21588
21527
|
const isFinal = step.isFinal;
|
|
21589
21528
|
let icon;
|
|
21590
|
-
if (step.outcome === "allow") icon =
|
|
21591
|
-
else if (step.outcome === "review") icon =
|
|
21592
|
-
else if (step.outcome === "skip") icon =
|
|
21593
|
-
else icon =
|
|
21529
|
+
if (step.outcome === "allow") icon = import_chalk30.default.green(" \u2705");
|
|
21530
|
+
else if (step.outcome === "review") icon = import_chalk30.default.red(" \u{1F534}");
|
|
21531
|
+
else if (step.outcome === "skip") icon = import_chalk30.default.gray(" \u2500 ");
|
|
21532
|
+
else icon = import_chalk30.default.gray(" \u25CB ");
|
|
21594
21533
|
const name = step.name.padEnd(18);
|
|
21595
|
-
const nameStr = isFinal ?
|
|
21596
|
-
const detail = isFinal ?
|
|
21597
|
-
const arrow = isFinal ?
|
|
21534
|
+
const nameStr = isFinal ? import_chalk30.default.white.bold(name) : import_chalk30.default.white(name);
|
|
21535
|
+
const detail = isFinal ? import_chalk30.default.white(step.detail) : import_chalk30.default.gray(step.detail);
|
|
21536
|
+
const arrow = isFinal ? import_chalk30.default.yellow(" \u2190 STOP") : "";
|
|
21598
21537
|
console.log(`${icon} ${nameStr} ${detail}${arrow}`);
|
|
21599
21538
|
}
|
|
21600
21539
|
console.log("");
|
|
21601
21540
|
if (result.decision === "allow") {
|
|
21602
|
-
console.log(
|
|
21541
|
+
console.log(import_chalk30.default.green.bold(" Decision: \u2705 ALLOW") + import_chalk30.default.gray(" \u2014 no approval needed"));
|
|
21603
21542
|
} else {
|
|
21604
21543
|
console.log(
|
|
21605
|
-
|
|
21544
|
+
import_chalk30.default.red.bold(" Decision: \u{1F534} REVIEW") + import_chalk30.default.gray(" \u2014 human approval required")
|
|
21606
21545
|
);
|
|
21607
21546
|
if (result.blockedByLabel) {
|
|
21608
|
-
console.log(
|
|
21547
|
+
console.log(import_chalk30.default.gray(` Reason: ${result.blockedByLabel}`));
|
|
21609
21548
|
}
|
|
21610
21549
|
}
|
|
21611
21550
|
console.log("");
|
|
@@ -21620,7 +21559,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
|
|
|
21620
21559
|
try {
|
|
21621
21560
|
await startTail2(options);
|
|
21622
21561
|
} catch (err2) {
|
|
21623
|
-
console.error(
|
|
21562
|
+
console.error(import_chalk30.default.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
|
|
21624
21563
|
process.exit(1);
|
|
21625
21564
|
}
|
|
21626
21565
|
});
|
|
@@ -21631,11 +21570,10 @@ program.command("monitor").description("Live interactive dashboard \u2014 activi
|
|
|
21631
21570
|
const mod = await dynamicImport(`file://${dashboardPath}`);
|
|
21632
21571
|
await mod.startMonitor();
|
|
21633
21572
|
} catch (err2) {
|
|
21634
|
-
console.error(
|
|
21573
|
+
console.error(import_chalk30.default.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
|
|
21635
21574
|
process.exit(1);
|
|
21636
21575
|
}
|
|
21637
21576
|
});
|
|
21638
|
-
registerWatchCommand(program);
|
|
21639
21577
|
registerMcpGatewayCommand(program);
|
|
21640
21578
|
registerMcpServerCommand(program);
|
|
21641
21579
|
registerMcpPinCommand(program);
|
|
@@ -21643,7 +21581,7 @@ registerSkillPinCommand(program);
|
|
|
21643
21581
|
registerDecisionsCommand(program);
|
|
21644
21582
|
registerCheckCommand(program);
|
|
21645
21583
|
registerLogCommand(program);
|
|
21646
|
-
program.command("hud").description("Render node9 security statusline (spawned by Claude Code statusLine)").addHelpText(
|
|
21584
|
+
program.command("hud", { hidden: true }).description("Render node9 security statusline (spawned by Claude Code statusLine)").addHelpText(
|
|
21647
21585
|
"after",
|
|
21648
21586
|
`
|
|
21649
21587
|
Outputs up to 3 lines to stdout, then exits:
|
|
@@ -21687,7 +21625,7 @@ program.command("pause").description("Temporarily disable Node9 protection for a
|
|
|
21687
21625
|
const ms = parseDuration(options.duration);
|
|
21688
21626
|
if (ms === null) {
|
|
21689
21627
|
console.error(
|
|
21690
|
-
|
|
21628
|
+
import_chalk30.default.red(`
|
|
21691
21629
|
\u274C Invalid duration: "${options.duration}". Use format like 15m, 1h, 30s.
|
|
21692
21630
|
`)
|
|
21693
21631
|
);
|
|
@@ -21695,20 +21633,20 @@ program.command("pause").description("Temporarily disable Node9 protection for a
|
|
|
21695
21633
|
}
|
|
21696
21634
|
pauseNode9(ms, options.duration);
|
|
21697
21635
|
const expiresAt = new Date(Date.now() + ms).toLocaleTimeString();
|
|
21698
|
-
console.log(
|
|
21636
|
+
console.log(import_chalk30.default.yellow(`
|
|
21699
21637
|
\u23F8 Node9 paused until ${expiresAt}`));
|
|
21700
|
-
console.log(
|
|
21701
|
-
console.log(
|
|
21638
|
+
console.log(import_chalk30.default.gray(` All tool calls will be allowed without review.`));
|
|
21639
|
+
console.log(import_chalk30.default.gray(` Run "node9 resume" to re-enable early.
|
|
21702
21640
|
`));
|
|
21703
21641
|
});
|
|
21704
21642
|
program.command("resume").description("Re-enable Node9 protection immediately").action(() => {
|
|
21705
21643
|
const { paused } = checkPause();
|
|
21706
21644
|
if (!paused) {
|
|
21707
|
-
console.log(
|
|
21645
|
+
console.log(import_chalk30.default.gray("\nNode9 is already active \u2014 nothing to resume.\n"));
|
|
21708
21646
|
return;
|
|
21709
21647
|
}
|
|
21710
21648
|
resumeNode9();
|
|
21711
|
-
console.log(
|
|
21649
|
+
console.log(import_chalk30.default.green("\n\u25B6 Node9 resumed \u2014 protection is active.\n"));
|
|
21712
21650
|
});
|
|
21713
21651
|
var HOOK_BASED_AGENTS = {
|
|
21714
21652
|
claude: "claude",
|
|
@@ -21721,15 +21659,15 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
|
|
|
21721
21659
|
if (HOOK_BASED_AGENTS[firstArg2] !== void 0) {
|
|
21722
21660
|
const target = HOOK_BASED_AGENTS[firstArg2];
|
|
21723
21661
|
console.error(
|
|
21724
|
-
|
|
21662
|
+
import_chalk30.default.yellow(`
|
|
21725
21663
|
\u26A0\uFE0F Node9 proxy mode does not support "${target}" directly.`)
|
|
21726
21664
|
);
|
|
21727
|
-
console.error(
|
|
21665
|
+
console.error(import_chalk30.default.white(`
|
|
21728
21666
|
"${target}" uses its own hook system. Use:`));
|
|
21729
21667
|
console.error(
|
|
21730
|
-
|
|
21668
|
+
import_chalk30.default.green(` node9 addto ${target} `) + import_chalk30.default.gray("# one-time setup")
|
|
21731
21669
|
);
|
|
21732
|
-
console.error(
|
|
21670
|
+
console.error(import_chalk30.default.green(` ${target} `) + import_chalk30.default.gray("# run normally"));
|
|
21733
21671
|
process.exit(1);
|
|
21734
21672
|
}
|
|
21735
21673
|
const runArgs = firstArg2 === "shell" ? commandArgs.slice(1) : commandArgs;
|
|
@@ -21746,7 +21684,7 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
|
|
|
21746
21684
|
}
|
|
21747
21685
|
);
|
|
21748
21686
|
if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && getConfig().settings.autoStartDaemon) {
|
|
21749
|
-
console.error(
|
|
21687
|
+
console.error(import_chalk30.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically..."));
|
|
21750
21688
|
const daemonReady = await autoStartDaemonAndWait();
|
|
21751
21689
|
if (daemonReady) result = await authorizeHeadless("shell", { command: fullCommand });
|
|
21752
21690
|
}
|
|
@@ -21759,12 +21697,12 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
|
|
|
21759
21697
|
}
|
|
21760
21698
|
if (!result.approved) {
|
|
21761
21699
|
console.error(
|
|
21762
|
-
|
|
21700
|
+
import_chalk30.default.red(`
|
|
21763
21701
|
\u274C Node9 Blocked: ${result.reason || "Dangerous command detected."}`)
|
|
21764
21702
|
);
|
|
21765
21703
|
process.exit(1);
|
|
21766
21704
|
}
|
|
21767
|
-
console.error(
|
|
21705
|
+
console.error(import_chalk30.default.green("\n\u2705 Approved \u2014 running command...\n"));
|
|
21768
21706
|
await runProxy(fullCommand);
|
|
21769
21707
|
} else {
|
|
21770
21708
|
program.help();
|