@node9/proxy 1.51.0 → 1.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +733 -579
- package/dist/cli.mjs +1582 -1428
- package/dist/dashboard.mjs +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -240,8 +240,8 @@ function sanitizeConfig(raw) {
|
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
242
|
const lines = result.error.issues.map((issue) => {
|
|
243
|
-
const
|
|
244
|
-
return ` \u2022 ${
|
|
243
|
+
const path66 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
244
|
+
return ` \u2022 ${path66}: ${issue.message}`;
|
|
245
245
|
});
|
|
246
246
|
return {
|
|
247
247
|
sanitized,
|
|
@@ -1362,9 +1362,9 @@ function matchesPattern(text, patterns) {
|
|
|
1362
1362
|
const withoutDotSlash = text.replace(/^\.\//, "");
|
|
1363
1363
|
return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
|
|
1364
1364
|
}
|
|
1365
|
-
function getNestedValue(obj,
|
|
1365
|
+
function getNestedValue(obj, path66) {
|
|
1366
1366
|
if (!obj || typeof obj !== "object") return null;
|
|
1367
|
-
const segments =
|
|
1367
|
+
const segments = path66.split(".");
|
|
1368
1368
|
for (const seg of segments) {
|
|
1369
1369
|
if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
|
|
1370
1370
|
}
|
|
@@ -4297,11 +4297,11 @@ function getGlobalSettings() {
|
|
|
4297
4297
|
};
|
|
4298
4298
|
}
|
|
4299
4299
|
function getCredentials() {
|
|
4300
|
-
const
|
|
4300
|
+
const DEFAULT_API_URL3 = "https://api.node9.ai/api/v1/intercept";
|
|
4301
4301
|
if (process.env.NODE9_API_KEY) {
|
|
4302
4302
|
return {
|
|
4303
4303
|
apiKey: process.env.NODE9_API_KEY,
|
|
4304
|
-
apiUrl: process.env.NODE9_API_URL ||
|
|
4304
|
+
apiUrl: process.env.NODE9_API_URL || DEFAULT_API_URL3
|
|
4305
4305
|
};
|
|
4306
4306
|
}
|
|
4307
4307
|
try {
|
|
@@ -4313,13 +4313,13 @@ function getCredentials() {
|
|
|
4313
4313
|
if (profile?.apiKey) {
|
|
4314
4314
|
return {
|
|
4315
4315
|
apiKey: profile.apiKey,
|
|
4316
|
-
apiUrl: profile.apiUrl ||
|
|
4316
|
+
apiUrl: profile.apiUrl || DEFAULT_API_URL3
|
|
4317
4317
|
};
|
|
4318
4318
|
}
|
|
4319
4319
|
if (creds.apiKey) {
|
|
4320
4320
|
return {
|
|
4321
4321
|
apiKey: creds.apiKey,
|
|
4322
|
-
apiUrl: creds.apiUrl ||
|
|
4322
|
+
apiUrl: creds.apiUrl || DEFAULT_API_URL3
|
|
4323
4323
|
};
|
|
4324
4324
|
}
|
|
4325
4325
|
}
|
|
@@ -7787,6 +7787,35 @@ var init_setup_pi_shim = __esm({
|
|
|
7787
7787
|
});
|
|
7788
7788
|
|
|
7789
7789
|
// src/setup.ts
|
|
7790
|
+
function isNonInteractive() {
|
|
7791
|
+
return process.env.NODE9_NONINTERACTIVE === "1";
|
|
7792
|
+
}
|
|
7793
|
+
async function confirm(opts) {
|
|
7794
|
+
if (isNonInteractive()) return opts.default ?? false;
|
|
7795
|
+
return (0, import_prompts.confirm)(opts);
|
|
7796
|
+
}
|
|
7797
|
+
async function setupAgent(agent) {
|
|
7798
|
+
if (agent === "claude") await setupClaude();
|
|
7799
|
+
else if (agent === "gemini") await setupGemini();
|
|
7800
|
+
else if (agent === "antigravity") await setupAntigravity();
|
|
7801
|
+
else if (agent === "copilot") await setupCopilot();
|
|
7802
|
+
else if (agent === "cursor") await setupCursor();
|
|
7803
|
+
else if (agent === "codex") await setupCodex();
|
|
7804
|
+
else if (agent === "windsurf") await setupWindsurf();
|
|
7805
|
+
else if (agent === "vscode") await setupVSCode();
|
|
7806
|
+
else if (agent === "claudeDesktop") await setupClaudeDesktop();
|
|
7807
|
+
else if (agent === "opencode") await setupOpencode();
|
|
7808
|
+
else if (agent === "pi") await setupPi();
|
|
7809
|
+
else if (agent === "hermes") setupHermes();
|
|
7810
|
+
}
|
|
7811
|
+
async function setupDetectedAgents() {
|
|
7812
|
+
const detected = detectAgents();
|
|
7813
|
+
const found = Object.keys(detected).filter((k) => detected[k]);
|
|
7814
|
+
for (const agent of found) {
|
|
7815
|
+
await setupAgent(agent);
|
|
7816
|
+
}
|
|
7817
|
+
return found;
|
|
7818
|
+
}
|
|
7790
7819
|
function hasNode9McpServer(servers) {
|
|
7791
7820
|
const entry = servers["node9"];
|
|
7792
7821
|
return !!entry && entry.command === "node9" && Array.isArray(entry.args) && entry.args[0] === "mcp-server";
|
|
@@ -8107,7 +8136,7 @@ async function setupClaude() {
|
|
|
8107
8136
|
console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
|
|
8108
8137
|
}
|
|
8109
8138
|
console.log("");
|
|
8110
|
-
const proceed = await
|
|
8139
|
+
const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
|
|
8111
8140
|
if (proceed) {
|
|
8112
8141
|
for (const { name, upstream } of serversToWrap) {
|
|
8113
8142
|
servers[name] = {
|
|
@@ -8212,7 +8241,7 @@ async function setupGemini() {
|
|
|
8212
8241
|
console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
|
|
8213
8242
|
}
|
|
8214
8243
|
console.log("");
|
|
8215
|
-
const proceed = await
|
|
8244
|
+
const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
|
|
8216
8245
|
if (proceed) {
|
|
8217
8246
|
for (const { name, upstream } of serversToWrap) {
|
|
8218
8247
|
servers[name] = {
|
|
@@ -8338,7 +8367,7 @@ async function setupAntigravity() {
|
|
|
8338
8367
|
" \u26A0\uFE0F Found node9 hooks for the legacy Gemini CLI in ~/.gemini/settings.json.\n Gemini CLI stops serving AI Pro/Ultra and free tiers on 2026-06-18.\n Keep them only if you still use Gemini CLI (e.g. enterprise Code Assist)."
|
|
8339
8368
|
)
|
|
8340
8369
|
);
|
|
8341
|
-
const clean = await
|
|
8370
|
+
const clean = await confirm({
|
|
8342
8371
|
message: "Remove the legacy Gemini CLI hooks?",
|
|
8343
8372
|
default: false
|
|
8344
8373
|
});
|
|
@@ -8360,7 +8389,7 @@ async function setupAntigravity() {
|
|
|
8360
8389
|
console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
|
|
8361
8390
|
}
|
|
8362
8391
|
console.log("");
|
|
8363
|
-
const proceed = await
|
|
8392
|
+
const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
|
|
8364
8393
|
if (proceed) {
|
|
8365
8394
|
for (const { name, upstream } of serversToWrap) {
|
|
8366
8395
|
servers[name] = {
|
|
@@ -8505,7 +8534,7 @@ async function setupCopilot() {
|
|
|
8505
8534
|
console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
|
|
8506
8535
|
}
|
|
8507
8536
|
console.log("");
|
|
8508
|
-
const proceed = await
|
|
8537
|
+
const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
|
|
8509
8538
|
if (proceed) {
|
|
8510
8539
|
for (const { name, upstream } of serversToWrap) {
|
|
8511
8540
|
servers[name] = {
|
|
@@ -8706,7 +8735,7 @@ async function setupCursor() {
|
|
|
8706
8735
|
console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
|
|
8707
8736
|
}
|
|
8708
8737
|
console.log("");
|
|
8709
|
-
const proceed = await
|
|
8738
|
+
const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
|
|
8710
8739
|
if (proceed) {
|
|
8711
8740
|
for (const { name, upstream } of serversToWrap) {
|
|
8712
8741
|
servers[name] = {
|
|
@@ -8857,7 +8886,7 @@ async function setupCodex() {
|
|
|
8857
8886
|
console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
|
|
8858
8887
|
}
|
|
8859
8888
|
console.log("");
|
|
8860
|
-
const proceed = await
|
|
8889
|
+
const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
|
|
8861
8890
|
if (proceed) {
|
|
8862
8891
|
for (const { name, upstream } of serversToWrap) {
|
|
8863
8892
|
servers[name] = {
|
|
@@ -9034,7 +9063,7 @@ async function setupWindsurf() {
|
|
|
9034
9063
|
console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
|
|
9035
9064
|
}
|
|
9036
9065
|
console.log("");
|
|
9037
|
-
const proceed = await
|
|
9066
|
+
const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
|
|
9038
9067
|
if (proceed) {
|
|
9039
9068
|
for (const { name, upstream } of serversToWrap) {
|
|
9040
9069
|
servers[name] = {
|
|
@@ -9138,7 +9167,7 @@ async function setupVSCode() {
|
|
|
9138
9167
|
console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
|
|
9139
9168
|
}
|
|
9140
9169
|
console.log("");
|
|
9141
|
-
const proceed = await
|
|
9170
|
+
const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
|
|
9142
9171
|
if (proceed) {
|
|
9143
9172
|
for (const { name, upstream } of serversToWrap) {
|
|
9144
9173
|
servers[name] = {
|
|
@@ -9238,7 +9267,7 @@ async function setupClaudeDesktop() {
|
|
|
9238
9267
|
console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
|
|
9239
9268
|
}
|
|
9240
9269
|
console.log("");
|
|
9241
|
-
const proceed = await
|
|
9270
|
+
const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
|
|
9242
9271
|
if (proceed) {
|
|
9243
9272
|
for (const { name, upstream } of serversToWrap) {
|
|
9244
9273
|
servers[name] = {
|
|
@@ -16880,7 +16909,7 @@ function readCredentials() {
|
|
|
16880
16909
|
if (process.env.NODE9_API_KEY) {
|
|
16881
16910
|
return {
|
|
16882
16911
|
apiKey: process.env.NODE9_API_KEY,
|
|
16883
|
-
apiUrl: process.env.NODE9_API_URL ??
|
|
16912
|
+
apiUrl: process.env.NODE9_API_URL ?? DEFAULT_API_URL2
|
|
16884
16913
|
};
|
|
16885
16914
|
}
|
|
16886
16915
|
try {
|
|
@@ -16899,11 +16928,11 @@ function readCredentials() {
|
|
|
16899
16928
|
// Anything else is taken as-is so users can override the full
|
|
16900
16929
|
// URL via NODE9_API_URL or a non-standard apiUrl.
|
|
16901
16930
|
/\/intercept$/.test(profile.apiUrl) ? profile.apiUrl + "/policies/sync" : profile.apiUrl
|
|
16902
|
-
) :
|
|
16931
|
+
) : DEFAULT_API_URL2
|
|
16903
16932
|
};
|
|
16904
16933
|
}
|
|
16905
16934
|
if (typeof creds.apiKey === "string" && creds.apiKey.length > 0) {
|
|
16906
|
-
return { apiKey: creds.apiKey, apiUrl:
|
|
16935
|
+
return { apiKey: creds.apiKey, apiUrl: DEFAULT_API_URL2 };
|
|
16907
16936
|
}
|
|
16908
16937
|
} catch {
|
|
16909
16938
|
}
|
|
@@ -16917,6 +16946,23 @@ function readCachedEtag() {
|
|
|
16917
16946
|
return void 0;
|
|
16918
16947
|
}
|
|
16919
16948
|
}
|
|
16949
|
+
function readCachedSyncIntervalHours() {
|
|
16950
|
+
try {
|
|
16951
|
+
const raw = JSON.parse(import_fs32.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
16952
|
+
return typeof raw.syncIntervalHours === "number" ? raw.syncIntervalHours : void 0;
|
|
16953
|
+
} catch {
|
|
16954
|
+
return void 0;
|
|
16955
|
+
}
|
|
16956
|
+
}
|
|
16957
|
+
function pickSyncIntervalMs(cloudHours, localSettings) {
|
|
16958
|
+
if (typeof cloudHours === "number" && Number.isFinite(cloudHours)) {
|
|
16959
|
+
return resolveSyncIntervalMs({ cloudSyncIntervalHours: cloudHours });
|
|
16960
|
+
}
|
|
16961
|
+
return resolveSyncIntervalMs(localSettings);
|
|
16962
|
+
}
|
|
16963
|
+
function effectiveSyncIntervalMs() {
|
|
16964
|
+
return pickSyncIntervalMs(readCachedSyncIntervalHours(), getConfig().settings);
|
|
16965
|
+
}
|
|
16920
16966
|
function fetchCloudPolicy(apiKey, apiUrl, ifNoneMatch) {
|
|
16921
16967
|
const parsed = new URL(apiUrl);
|
|
16922
16968
|
const headers = {
|
|
@@ -17226,11 +17272,14 @@ function getCloudRules() {
|
|
|
17226
17272
|
}
|
|
17227
17273
|
}
|
|
17228
17274
|
function startCloudSync() {
|
|
17229
|
-
const
|
|
17230
|
-
|
|
17231
|
-
|
|
17232
|
-
|
|
17233
|
-
|
|
17275
|
+
const scheduleNext = (ms) => {
|
|
17276
|
+
const t = setTimeout(() => {
|
|
17277
|
+
void syncOnce().catch(() => {
|
|
17278
|
+
}).finally(() => scheduleNext(effectiveSyncIntervalMs()));
|
|
17279
|
+
}, ms);
|
|
17280
|
+
t.unref();
|
|
17281
|
+
};
|
|
17282
|
+
scheduleNext(3e4);
|
|
17234
17283
|
}
|
|
17235
17284
|
function startForensicBroadcast() {
|
|
17236
17285
|
const tick = async () => {
|
|
@@ -17251,7 +17300,7 @@ function startForensicBroadcast() {
|
|
|
17251
17300
|
const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
|
|
17252
17301
|
recurring.unref();
|
|
17253
17302
|
}
|
|
17254
|
-
var import_fs32, import_https4, import_os29, import_path31, FINDING_TO_SIGNAL3, rulesCacheFile,
|
|
17303
|
+
var import_fs32, import_https4, import_os29, import_path31, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL2, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_SECONDS, MAX_INTERVAL_SECONDS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
|
|
17255
17304
|
var init_sync = __esm({
|
|
17256
17305
|
"src/daemon/sync.ts"() {
|
|
17257
17306
|
"use strict";
|
|
@@ -17283,7 +17332,7 @@ var init_sync = __esm({
|
|
|
17283
17332
|
"long-output-redacted": "longOutputRedactions"
|
|
17284
17333
|
};
|
|
17285
17334
|
rulesCacheFile = () => import_path31.default.join(import_os29.default.homedir(), ".node9", "rules-cache.json");
|
|
17286
|
-
|
|
17335
|
+
DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept/policies/sync";
|
|
17287
17336
|
DEFAULT_INTERVAL_HOURS = 5;
|
|
17288
17337
|
MIN_INTERVAL_SECONDS = 15;
|
|
17289
17338
|
MAX_INTERVAL_SECONDS = 24 * 60 * 60;
|
|
@@ -19085,10 +19134,10 @@ function readSessionUsage() {
|
|
|
19085
19134
|
}
|
|
19086
19135
|
}
|
|
19087
19136
|
function formatContextStat(stat) {
|
|
19088
|
-
const pctColor = stat.fillPct >= 80 ?
|
|
19137
|
+
const pctColor = stat.fillPct >= 80 ? import_chalk36.default.red : stat.fillPct >= 50 ? import_chalk36.default.yellow : import_chalk36.default.cyan;
|
|
19089
19138
|
const k = (n) => `${Math.round(n / 1e3)}k`;
|
|
19090
19139
|
const modelShort = stat.model.replace(/@.*$/, "").replace(/-\d{8}$/, "").replace(/^claude-/, "");
|
|
19091
|
-
return
|
|
19140
|
+
return import_chalk36.default.dim("ctx: ") + pctColor(`${stat.fillPct}%`) + import_chalk36.default.dim(
|
|
19092
19141
|
` (${k(stat.inputTokens)}/${k(getModelContextLimit(stat.model))} out ${k(stat.outputTokens)} \xB7 ${modelShort})`
|
|
19093
19142
|
);
|
|
19094
19143
|
}
|
|
@@ -19111,11 +19160,11 @@ function agentLabel(agent, mcpServer, sessionId) {
|
|
|
19111
19160
|
const tag = sessionTag(sessionId);
|
|
19112
19161
|
const tagSuffix = tag ? `\xB7${tag}` : "";
|
|
19113
19162
|
if (!agent || agent === "Terminal") {
|
|
19114
|
-
return mcpServer ?
|
|
19163
|
+
return mcpServer ? import_chalk36.default.dim(`[\u2192 ${mcpServer}] `) : "";
|
|
19115
19164
|
}
|
|
19116
19165
|
const short = agent === "Claude Code" ? "Claude" : agent === "Gemini CLI" ? "Gemini" : agent === "Unknown Agent" ? "" : agent.split(" ")[0];
|
|
19117
|
-
if (!short) return mcpServer ?
|
|
19118
|
-
return mcpServer ?
|
|
19166
|
+
if (!short) return mcpServer ? import_chalk36.default.dim(`[\u2192 ${mcpServer}] `) : "";
|
|
19167
|
+
return mcpServer ? import_chalk36.default.dim(`[${short}${tagSuffix} \u2192 ${mcpServer}] `) : import_chalk36.default.dim(`[${short}${tagSuffix}] `);
|
|
19119
19168
|
}
|
|
19120
19169
|
function formatBase(activity) {
|
|
19121
19170
|
const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
|
|
@@ -19123,20 +19172,20 @@ function formatBase(activity) {
|
|
|
19123
19172
|
const toolName = activity.tool.slice(0, 16).padEnd(16);
|
|
19124
19173
|
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os55.default.homedir(), "~");
|
|
19125
19174
|
const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
|
|
19126
|
-
return `${
|
|
19175
|
+
return `${import_chalk36.default.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${import_chalk36.default.white.bold(toolName)} ${import_chalk36.default.dim(argsPreview)}`;
|
|
19127
19176
|
}
|
|
19128
19177
|
function renderResult(activity, result) {
|
|
19129
19178
|
const base = formatBase(activity);
|
|
19130
19179
|
let status;
|
|
19131
19180
|
if (result.status === "allow") {
|
|
19132
|
-
status =
|
|
19181
|
+
status = import_chalk36.default.green("\u2713 ALLOW");
|
|
19133
19182
|
} else if (result.status === "dlp") {
|
|
19134
|
-
status =
|
|
19183
|
+
status = import_chalk36.default.bgRed.white.bold(" \u{1F6E1}\uFE0F DLP ");
|
|
19135
19184
|
} else {
|
|
19136
|
-
status =
|
|
19185
|
+
status = import_chalk36.default.red("\u2717 BLOCK");
|
|
19137
19186
|
}
|
|
19138
19187
|
const cost = result.costEstimate ?? activity.costEstimate;
|
|
19139
|
-
const costSuffix = cost == null ? "" :
|
|
19188
|
+
const costSuffix = cost == null ? "" : import_chalk36.default.dim(` ~$${cost >= 1e-3 ? cost.toFixed(3) : "0.000"}`);
|
|
19140
19189
|
if (process.stdout.isTTY) {
|
|
19141
19190
|
if (pendingShownForId === activity.id && pendingWrappedLines > 1) {
|
|
19142
19191
|
import_readline6.default.moveCursor(process.stdout, 0, -(pendingWrappedLines - 1));
|
|
@@ -19153,7 +19202,7 @@ function renderResult(activity, result) {
|
|
|
19153
19202
|
}
|
|
19154
19203
|
function renderPending(activity) {
|
|
19155
19204
|
if (!process.stdout.isTTY) return;
|
|
19156
|
-
const line = `${formatBase(activity)} ${
|
|
19205
|
+
const line = `${formatBase(activity)} ${import_chalk36.default.yellow("\u25CF \u2026")}`;
|
|
19157
19206
|
pendingShownForId = activity.id;
|
|
19158
19207
|
pendingWrappedLines = wrappedLineCount(line);
|
|
19159
19208
|
process.stdout.write(`${line}\r`);
|
|
@@ -19165,7 +19214,7 @@ async function ensureDaemon() {
|
|
|
19165
19214
|
const { port } = JSON.parse(import_fs64.default.readFileSync(PID_FILE, "utf-8"));
|
|
19166
19215
|
pidPort = port;
|
|
19167
19216
|
} catch {
|
|
19168
|
-
console.error(
|
|
19217
|
+
console.error(import_chalk36.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
19169
19218
|
}
|
|
19170
19219
|
}
|
|
19171
19220
|
const checkPort = pidPort ?? DAEMON_PORT;
|
|
@@ -19176,7 +19225,7 @@ async function ensureDaemon() {
|
|
|
19176
19225
|
if (res.ok) return checkPort;
|
|
19177
19226
|
} catch {
|
|
19178
19227
|
}
|
|
19179
|
-
console.log(
|
|
19228
|
+
console.log(import_chalk36.default.dim("\u{1F6E1}\uFE0F Starting Node9 daemon..."));
|
|
19180
19229
|
const child = (0, import_child_process14.spawn)(process.execPath, [process.argv[1], "daemon"], {
|
|
19181
19230
|
detached: true,
|
|
19182
19231
|
stdio: "ignore",
|
|
@@ -19193,7 +19242,7 @@ async function ensureDaemon() {
|
|
|
19193
19242
|
} catch {
|
|
19194
19243
|
}
|
|
19195
19244
|
}
|
|
19196
|
-
console.error(
|
|
19245
|
+
console.error(import_chalk36.default.red("\u274C Daemon failed to start. Try: node9 daemon start"));
|
|
19197
19246
|
process.exit(1);
|
|
19198
19247
|
}
|
|
19199
19248
|
function postDecisionHttp(id, decision, authToken, port, opts) {
|
|
@@ -19203,7 +19252,7 @@ function postDecisionHttp(id, decision, authToken, port, opts) {
|
|
|
19203
19252
|
if (opts?.trustDuration) bodyObj.trustDuration = opts.trustDuration;
|
|
19204
19253
|
if (opts?.reason) bodyObj.reason = opts.reason;
|
|
19205
19254
|
const body = JSON.stringify(bodyObj);
|
|
19206
|
-
const req =
|
|
19255
|
+
const req = import_http5.default.request(
|
|
19207
19256
|
{
|
|
19208
19257
|
hostname: "127.0.0.1",
|
|
19209
19258
|
port,
|
|
@@ -19262,7 +19311,7 @@ function buildCardLines(req, localCount = 0) {
|
|
|
19262
19311
|
const severityIcon = isBlock ? `${RED}\u{1F6D1}` : `${YELLOW}\u26A0 `;
|
|
19263
19312
|
const rawDesc = req.riskMetadata?.ruleDescription ?? "";
|
|
19264
19313
|
const description = rawDesc ? cleanReason(rawDesc) : "";
|
|
19265
|
-
const agentSuffix = req.agent && req.agent !== "Terminal" ? ` ${RESET2}${
|
|
19314
|
+
const agentSuffix = req.agent && req.agent !== "Terminal" ? ` ${RESET2}${import_chalk36.default.dim(`(${req.agent})`)}` : "";
|
|
19266
19315
|
const lines = [
|
|
19267
19316
|
``,
|
|
19268
19317
|
`${BOLD2}${CYAN}\u2554\u2550\u2550 Node9 Approval Required \u2550\u2550\u2557${RESET2}`,
|
|
@@ -19331,7 +19380,7 @@ function approverStatusLine() {
|
|
|
19331
19380
|
const a = readApproversFromDisk();
|
|
19332
19381
|
const fmt = (label2, key) => {
|
|
19333
19382
|
const on = a[key] !== false;
|
|
19334
|
-
return `[${key[0]}]${label2.slice(1)} ${on ?
|
|
19383
|
+
return `[${key[0]}]${label2.slice(1)} ${on ? import_chalk36.default.green("\u2713") : import_chalk36.default.dim("\u2717")}`;
|
|
19335
19384
|
};
|
|
19336
19385
|
return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
|
|
19337
19386
|
}
|
|
@@ -19354,7 +19403,7 @@ async function startTail(options = {}) {
|
|
|
19354
19403
|
const port = await ensureDaemon();
|
|
19355
19404
|
if (options.clear) {
|
|
19356
19405
|
const result = await new Promise((resolve) => {
|
|
19357
|
-
const req2 =
|
|
19406
|
+
const req2 = import_http5.default.request(
|
|
19358
19407
|
{ method: "POST", hostname: "127.0.0.1", port, path: "/events/clear" },
|
|
19359
19408
|
(res) => {
|
|
19360
19409
|
const status = res.statusCode ?? 0;
|
|
@@ -19376,7 +19425,7 @@ async function startTail(options = {}) {
|
|
|
19376
19425
|
req2.end();
|
|
19377
19426
|
});
|
|
19378
19427
|
if (result.ok) {
|
|
19379
|
-
console.log(
|
|
19428
|
+
console.log(import_chalk36.default.green("\u2713 Flight Recorder buffer cleared."));
|
|
19380
19429
|
} else if (result.code === "ECONNREFUSED") {
|
|
19381
19430
|
throw new Error("Daemon is not running. Start it with: node9 daemon start");
|
|
19382
19431
|
} else if (result.code === "ETIMEDOUT") {
|
|
@@ -19422,7 +19471,7 @@ async function startTail(options = {}) {
|
|
|
19422
19471
|
const channel = name === "n" ? "native" : name === "c" ? "cloud" : name === "t" ? "terminal" : null;
|
|
19423
19472
|
if (channel) {
|
|
19424
19473
|
toggleApprover(channel);
|
|
19425
|
-
console.log(
|
|
19474
|
+
console.log(import_chalk36.default.dim(` Approvers: ${approverStatusLine()}`));
|
|
19426
19475
|
}
|
|
19427
19476
|
};
|
|
19428
19477
|
process.stdin.on("keypress", idleKeypressHandler);
|
|
@@ -19488,7 +19537,7 @@ async function startTail(options = {}) {
|
|
|
19488
19537
|
localAllowCounts.get(req2.toolName) ?? 0
|
|
19489
19538
|
)
|
|
19490
19539
|
);
|
|
19491
|
-
const decisionStamp = action === "always-allow" ?
|
|
19540
|
+
const decisionStamp = action === "always-allow" ? import_chalk36.default.yellow("\u2605 ALWAYS ALLOW") : action === "trust" ? import_chalk36.default.cyan("\u23F1 TRUST 30m") : action === "allow" ? import_chalk36.default.green("\u2713 ALLOWED") : action === "redirect" ? import_chalk36.default.yellow("\u21A9 REDIRECT AI") : import_chalk36.default.red("\u2717 DENIED");
|
|
19492
19541
|
stampedLines.push(` ${BOLD2}\u2192${RESET2} ${decisionStamp} ${GRAY}(terminal)${RESET2}`, ``);
|
|
19493
19542
|
for (const line of stampedLines) process.stdout.write(line + "\n");
|
|
19494
19543
|
process.stdout.write(SHOW_CURSOR);
|
|
@@ -19539,7 +19588,7 @@ async function startTail(options = {}) {
|
|
|
19539
19588
|
);
|
|
19540
19589
|
const stampedLines = buildCardLines(req2, priorCount);
|
|
19541
19590
|
if (externalDecision) {
|
|
19542
|
-
const source = externalDecision === "allow" ?
|
|
19591
|
+
const source = externalDecision === "allow" ? import_chalk36.default.green("\u2713 ALLOWED") : import_chalk36.default.red("\u2717 DENIED");
|
|
19543
19592
|
stampedLines.push(` ${BOLD2}\u2192${RESET2} ${source} ${GRAY}(external)${RESET2}`, ``);
|
|
19544
19593
|
}
|
|
19545
19594
|
for (const line of stampedLines) process.stdout.write(line + "\n");
|
|
@@ -19587,25 +19636,25 @@ async function startTail(options = {}) {
|
|
|
19587
19636
|
if (unackedDlp > 0) {
|
|
19588
19637
|
console.log("");
|
|
19589
19638
|
console.log(
|
|
19590
|
-
|
|
19639
|
+
import_chalk36.default.bgRed.white.bold(
|
|
19591
19640
|
` \u26A0\uFE0F DLP ALERT: ${unackedDlp} secret${unackedDlp !== 1 ? "s" : ""} found in Claude response text \u2014 run: node9 dlp `
|
|
19592
19641
|
)
|
|
19593
19642
|
);
|
|
19594
19643
|
}
|
|
19595
19644
|
} catch {
|
|
19596
19645
|
}
|
|
19597
|
-
console.log(
|
|
19646
|
+
console.log(import_chalk36.default.cyan.bold(`
|
|
19598
19647
|
\u{1F6F0}\uFE0F Node9 tail`));
|
|
19599
19648
|
if (canApprove) {
|
|
19600
|
-
console.log(
|
|
19601
|
-
console.log(
|
|
19649
|
+
console.log(import_chalk36.default.dim("Card: [\u21B5/y] Allow [n] Deny [a] Always [t] Trust 30m"));
|
|
19650
|
+
console.log(import_chalk36.default.dim(`Approvers (toggle): ${approverStatusLine()} [q] quit`));
|
|
19602
19651
|
}
|
|
19603
19652
|
const ctxStat = readSessionUsage();
|
|
19604
19653
|
if (ctxStat) console.log(" " + formatContextStat(ctxStat));
|
|
19605
19654
|
if (options.history) {
|
|
19606
|
-
console.log(
|
|
19655
|
+
console.log(import_chalk36.default.dim("Showing history + live events.\n"));
|
|
19607
19656
|
} else {
|
|
19608
|
-
console.log(
|
|
19657
|
+
console.log(import_chalk36.default.dim("Showing live events only. Use --history to include past.\n"));
|
|
19609
19658
|
}
|
|
19610
19659
|
process.on("SIGINT", () => {
|
|
19611
19660
|
exitIdleMode();
|
|
@@ -19615,7 +19664,7 @@ async function startTail(options = {}) {
|
|
|
19615
19664
|
import_readline6.default.clearLine(process.stdout, 0);
|
|
19616
19665
|
import_readline6.default.cursorTo(process.stdout, 0);
|
|
19617
19666
|
}
|
|
19618
|
-
console.log(
|
|
19667
|
+
console.log(import_chalk36.default.dim("\n\u{1F6F0}\uFE0F Disconnected."));
|
|
19619
19668
|
process.exit(0);
|
|
19620
19669
|
});
|
|
19621
19670
|
const STALL_THRESHOLD_MS = 6e4;
|
|
@@ -19627,7 +19676,7 @@ async function startTail(options = {}) {
|
|
|
19627
19676
|
if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
|
|
19628
19677
|
console.log("");
|
|
19629
19678
|
console.log(
|
|
19630
|
-
|
|
19679
|
+
import_chalk36.default.yellow(
|
|
19631
19680
|
"\u26A0\uFE0F Tail appears stalled \u2014 hooks are firing but no events are arriving. Try: node9 daemon restart"
|
|
19632
19681
|
)
|
|
19633
19682
|
);
|
|
@@ -19637,14 +19686,14 @@ async function startTail(options = {}) {
|
|
|
19637
19686
|
}, STALL_THRESHOLD_MS / 2);
|
|
19638
19687
|
stallWatchdog.unref();
|
|
19639
19688
|
const sseUrl = `http://127.0.0.1:${port}/events?capabilities=input`;
|
|
19640
|
-
const req =
|
|
19689
|
+
const req = import_http5.default.get(
|
|
19641
19690
|
sseUrl,
|
|
19642
19691
|
{
|
|
19643
19692
|
headers: authToken ? { "X-Node9-Internal": authToken } : {}
|
|
19644
19693
|
},
|
|
19645
19694
|
(res) => {
|
|
19646
19695
|
if (res.statusCode !== 200) {
|
|
19647
|
-
console.error(
|
|
19696
|
+
console.error(import_chalk36.default.red(`Failed to connect: HTTP ${res.statusCode}`));
|
|
19648
19697
|
process.exit(1);
|
|
19649
19698
|
}
|
|
19650
19699
|
if (canApprove) enterIdleMode();
|
|
@@ -19675,7 +19724,7 @@ async function startTail(options = {}) {
|
|
|
19675
19724
|
import_readline6.default.clearLine(process.stdout, 0);
|
|
19676
19725
|
import_readline6.default.cursorTo(process.stdout, 0);
|
|
19677
19726
|
}
|
|
19678
|
-
console.log(
|
|
19727
|
+
console.log(import_chalk36.default.red("\n\u274C Daemon disconnected."));
|
|
19679
19728
|
process.exit(1);
|
|
19680
19729
|
});
|
|
19681
19730
|
}
|
|
@@ -19688,7 +19737,7 @@ async function startTail(options = {}) {
|
|
|
19688
19737
|
const parsed = JSON.parse(rawData);
|
|
19689
19738
|
const msg = parsed.message ?? "Flight recorder is down \u2014 run: node9 daemon restart";
|
|
19690
19739
|
console.log("");
|
|
19691
|
-
console.log(
|
|
19740
|
+
console.log(import_chalk36.default.bgRed.white.bold(` \u26A0\uFE0F ${msg} `));
|
|
19692
19741
|
} catch {
|
|
19693
19742
|
}
|
|
19694
19743
|
return;
|
|
@@ -19773,9 +19822,9 @@ async function startTail(options = {}) {
|
|
|
19773
19822
|
const rawSummary = data.argsSummary ?? data.tool;
|
|
19774
19823
|
const summary = shortenPathSummary(rawSummary);
|
|
19775
19824
|
const fileCount = data.fileCount ?? 0;
|
|
19776
|
-
const files = fileCount > 0 ?
|
|
19825
|
+
const files = fileCount > 0 ? import_chalk36.default.dim(` \xB7 ${fileCount} file${fileCount === 1 ? "" : "s"}`) : "";
|
|
19777
19826
|
process.stdout.write(
|
|
19778
|
-
`${
|
|
19827
|
+
`${import_chalk36.default.dim(time)} ${import_chalk36.default.cyan("\u{1F4F8} snapshot")} ${import_chalk36.default.dim(hash)} ${summary}${files}
|
|
19779
19828
|
`
|
|
19780
19829
|
);
|
|
19781
19830
|
return;
|
|
@@ -19792,28 +19841,28 @@ async function startTail(options = {}) {
|
|
|
19792
19841
|
if (event === "execution-result") {
|
|
19793
19842
|
const exec = data;
|
|
19794
19843
|
const time = new Date(Date.now()).toLocaleTimeString([], { hour12: false });
|
|
19795
|
-
const arrow = exec.isError ?
|
|
19844
|
+
const arrow = exec.isError ? import_chalk36.default.red(" \u21B3 \u2717") : import_chalk36.default.green(" \u21B3 \u2713");
|
|
19796
19845
|
const label2 = agentLabel(exec.agent, exec.mcpServer);
|
|
19797
19846
|
const tool = (exec.tool ?? "").slice(0, 16);
|
|
19798
|
-
const duration = typeof exec.durationMs === "number" ?
|
|
19847
|
+
const duration = typeof exec.durationMs === "number" ? import_chalk36.default.dim(` (${exec.durationMs}ms)`) : "";
|
|
19799
19848
|
console.log(
|
|
19800
|
-
`${
|
|
19849
|
+
`${import_chalk36.default.gray(time)} ${arrow} ${label2}${import_chalk36.default.dim(tool)}${import_chalk36.default.dim(" completed")}${duration}`
|
|
19801
19850
|
);
|
|
19802
19851
|
}
|
|
19803
19852
|
}
|
|
19804
19853
|
req.on("error", (err2) => {
|
|
19805
19854
|
const msg = err2.code === "ECONNREFUSED" ? "Daemon is not running. Start it with: node9 daemon start" : err2.message;
|
|
19806
|
-
console.error(
|
|
19855
|
+
console.error(import_chalk36.default.red(`
|
|
19807
19856
|
\u274C ${msg}`));
|
|
19808
19857
|
process.exit(1);
|
|
19809
19858
|
});
|
|
19810
19859
|
}
|
|
19811
|
-
var
|
|
19860
|
+
var import_http5, import_chalk36, import_fs64, import_os55, import_path62, import_readline6, import_child_process14, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
|
|
19812
19861
|
var init_tail = __esm({
|
|
19813
19862
|
"src/tui/tail.ts"() {
|
|
19814
19863
|
"use strict";
|
|
19815
|
-
|
|
19816
|
-
|
|
19864
|
+
import_http5 = __toESM(require("http"));
|
|
19865
|
+
import_chalk36 = __toESM(require("chalk"));
|
|
19817
19866
|
import_fs64 = __toESM(require("fs"));
|
|
19818
19867
|
import_os55 = __toESM(require("os"));
|
|
19819
19868
|
import_path62 = __toESM(require("path"));
|
|
@@ -19886,7 +19935,7 @@ function queryDaemon() {
|
|
|
19886
19935
|
return new Promise((resolve) => {
|
|
19887
19936
|
const timeout = setTimeout(() => resolve(null), 50);
|
|
19888
19937
|
try {
|
|
19889
|
-
const req =
|
|
19938
|
+
const req = import_http6.default.get(
|
|
19890
19939
|
`http://${DAEMON_HOST}:${DAEMON_PORT}/status`,
|
|
19891
19940
|
{ timeout: 50 },
|
|
19892
19941
|
(res) => {
|
|
@@ -20214,14 +20263,14 @@ async function main() {
|
|
|
20214
20263
|
renderOffline();
|
|
20215
20264
|
}
|
|
20216
20265
|
}
|
|
20217
|
-
var import_fs65, import_path63, import_os56,
|
|
20266
|
+
var import_fs65, import_path63, import_os56, import_http6, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
|
|
20218
20267
|
var init_hud = __esm({
|
|
20219
20268
|
"src/cli/hud.ts"() {
|
|
20220
20269
|
"use strict";
|
|
20221
20270
|
import_fs65 = __toESM(require("fs"));
|
|
20222
20271
|
import_path63 = __toESM(require("path"));
|
|
20223
20272
|
import_os56 = __toESM(require("os"));
|
|
20224
|
-
|
|
20273
|
+
import_http6 = __toESM(require("http"));
|
|
20225
20274
|
init_daemon();
|
|
20226
20275
|
RESET3 = "\x1B[0m";
|
|
20227
20276
|
BOLD3 = "\x1B[1m";
|
|
@@ -20278,8 +20327,69 @@ function agentTeardownTargets() {
|
|
|
20278
20327
|
|
|
20279
20328
|
// src/cli.ts
|
|
20280
20329
|
init_agent_wiring();
|
|
20330
|
+
|
|
20331
|
+
// src/credentials.ts
|
|
20332
|
+
var fs15 = __toESM(require("fs"));
|
|
20333
|
+
var os14 = __toESM(require("os"));
|
|
20334
|
+
var path17 = __toESM(require("path"));
|
|
20335
|
+
var DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept";
|
|
20336
|
+
function writeCredentialsAndConfig(apiKey, opts = {}) {
|
|
20337
|
+
const profileName = opts.profileName || "default";
|
|
20338
|
+
const home = opts.homeDir ?? os14.homedir();
|
|
20339
|
+
const credPath = path17.join(home, ".node9", "credentials.json");
|
|
20340
|
+
if (!fs15.existsSync(path17.dirname(credPath))) {
|
|
20341
|
+
fs15.mkdirSync(path17.dirname(credPath), { recursive: true });
|
|
20342
|
+
}
|
|
20343
|
+
let existingCreds = {};
|
|
20344
|
+
try {
|
|
20345
|
+
if (fs15.existsSync(credPath)) {
|
|
20346
|
+
const raw = JSON.parse(fs15.readFileSync(credPath, "utf-8"));
|
|
20347
|
+
existingCreds = raw.apiKey ? { default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL } } : raw;
|
|
20348
|
+
}
|
|
20349
|
+
} catch {
|
|
20350
|
+
}
|
|
20351
|
+
existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL };
|
|
20352
|
+
fs15.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), {
|
|
20353
|
+
mode: 384
|
|
20354
|
+
});
|
|
20355
|
+
let effectiveCloud = null;
|
|
20356
|
+
if (profileName === "default") {
|
|
20357
|
+
const configPath = path17.join(home, ".node9", "config.json");
|
|
20358
|
+
let config = {};
|
|
20359
|
+
try {
|
|
20360
|
+
if (fs15.existsSync(configPath)) {
|
|
20361
|
+
config = JSON.parse(fs15.readFileSync(configPath, "utf-8"));
|
|
20362
|
+
}
|
|
20363
|
+
} catch {
|
|
20364
|
+
}
|
|
20365
|
+
if (!config.settings || typeof config.settings !== "object") {
|
|
20366
|
+
config.settings = {};
|
|
20367
|
+
}
|
|
20368
|
+
const s = config.settings;
|
|
20369
|
+
const approvers = s.approvers || {
|
|
20370
|
+
native: true,
|
|
20371
|
+
browser: true,
|
|
20372
|
+
cloud: true,
|
|
20373
|
+
terminal: true
|
|
20374
|
+
};
|
|
20375
|
+
if (opts.isLocal) {
|
|
20376
|
+
approvers.cloud = false;
|
|
20377
|
+
}
|
|
20378
|
+
s.approvers = approvers;
|
|
20379
|
+
if (!fs15.existsSync(path17.dirname(configPath))) {
|
|
20380
|
+
fs15.mkdirSync(path17.dirname(configPath), { recursive: true });
|
|
20381
|
+
}
|
|
20382
|
+
fs15.writeFileSync(configPath, JSON.stringify(config, null, 2), {
|
|
20383
|
+
mode: 384
|
|
20384
|
+
});
|
|
20385
|
+
effectiveCloud = approvers.cloud === true;
|
|
20386
|
+
}
|
|
20387
|
+
return { profileName, effectiveCloud };
|
|
20388
|
+
}
|
|
20389
|
+
|
|
20390
|
+
// src/cli.ts
|
|
20281
20391
|
init_daemon2();
|
|
20282
|
-
var
|
|
20392
|
+
var import_chalk37 = __toESM(require("chalk"));
|
|
20283
20393
|
var import_fs66 = __toESM(require("fs"));
|
|
20284
20394
|
var import_path64 = __toESM(require("path"));
|
|
20285
20395
|
var import_os57 = __toESM(require("os"));
|
|
@@ -24154,18 +24264,7 @@ function registerInitCommand(program2) {
|
|
|
24154
24264
|
console.log("");
|
|
24155
24265
|
for (const agent of found) {
|
|
24156
24266
|
console.log(import_chalk16.default.bold(`Wiring ${agent}...`));
|
|
24157
|
-
|
|
24158
|
-
else if (agent === "gemini") await setupGemini();
|
|
24159
|
-
else if (agent === "antigravity") await setupAntigravity();
|
|
24160
|
-
else if (agent === "copilot") await setupCopilot();
|
|
24161
|
-
else if (agent === "cursor") await setupCursor();
|
|
24162
|
-
else if (agent === "codex") await setupCodex();
|
|
24163
|
-
else if (agent === "windsurf") await setupWindsurf();
|
|
24164
|
-
else if (agent === "vscode") await setupVSCode();
|
|
24165
|
-
else if (agent === "claudeDesktop") await setupClaudeDesktop();
|
|
24166
|
-
else if (agent === "opencode") await setupOpencode();
|
|
24167
|
-
else if (agent === "pi") await setupPi();
|
|
24168
|
-
else if (agent === "hermes") setupHermes();
|
|
24267
|
+
await setupAgent(agent);
|
|
24169
24268
|
console.log("");
|
|
24170
24269
|
}
|
|
24171
24270
|
if ((process.platform === "darwin" || process.platform === "linux") && process.stdout.isTTY) {
|
|
@@ -24228,13 +24327,110 @@ function registerInitCommand(program2) {
|
|
|
24228
24327
|
);
|
|
24229
24328
|
}
|
|
24230
24329
|
|
|
24330
|
+
// src/cli/commands/connect.ts
|
|
24331
|
+
var import_http4 = __toESM(require("http"));
|
|
24332
|
+
var import_https7 = __toESM(require("https"));
|
|
24333
|
+
var import_url3 = require("url");
|
|
24334
|
+
var import_chalk17 = __toESM(require("chalk"));
|
|
24335
|
+
init_setup();
|
|
24336
|
+
init_sync();
|
|
24337
|
+
var DEFAULT_CONNECT_URL = "https://api.node9.ai/api/v1/cli/connect";
|
|
24338
|
+
function resolveConnectUrl(apiUrl) {
|
|
24339
|
+
if (apiUrl) return apiUrl;
|
|
24340
|
+
const base = process.env.NODE9_API_URL;
|
|
24341
|
+
if (base) return base.replace(/\/intercept\/?$/, "") + "/cli/connect";
|
|
24342
|
+
return DEFAULT_CONNECT_URL;
|
|
24343
|
+
}
|
|
24344
|
+
function postConnect(url, token) {
|
|
24345
|
+
return new Promise((resolve, reject) => {
|
|
24346
|
+
const body = JSON.stringify({ token });
|
|
24347
|
+
const u = new import_url3.URL(url);
|
|
24348
|
+
const lib = u.protocol === "http:" ? import_http4.default : import_https7.default;
|
|
24349
|
+
const req = lib.request(
|
|
24350
|
+
{
|
|
24351
|
+
method: "POST",
|
|
24352
|
+
hostname: u.hostname,
|
|
24353
|
+
port: u.port || (u.protocol === "http:" ? 80 : 443),
|
|
24354
|
+
path: u.pathname + u.search,
|
|
24355
|
+
headers: {
|
|
24356
|
+
"Content-Type": "application/json",
|
|
24357
|
+
"Content-Length": Buffer.byteLength(body)
|
|
24358
|
+
},
|
|
24359
|
+
timeout: 15e3
|
|
24360
|
+
},
|
|
24361
|
+
(res) => {
|
|
24362
|
+
let data = "";
|
|
24363
|
+
res.on("data", (c) => data += c);
|
|
24364
|
+
res.on("end", () => {
|
|
24365
|
+
const code = res.statusCode ?? 0;
|
|
24366
|
+
if (code >= 200 && code < 300) {
|
|
24367
|
+
try {
|
|
24368
|
+
resolve(JSON.parse(data));
|
|
24369
|
+
} catch {
|
|
24370
|
+
reject(new Error("Unexpected response from the server."));
|
|
24371
|
+
}
|
|
24372
|
+
} else if (code === 400 || code === 401) {
|
|
24373
|
+
reject(
|
|
24374
|
+
new Error(
|
|
24375
|
+
"This connect link expired or was already used \u2014 generate a new one in the dashboard."
|
|
24376
|
+
)
|
|
24377
|
+
);
|
|
24378
|
+
} else {
|
|
24379
|
+
reject(new Error(`Connect failed (HTTP ${code}).`));
|
|
24380
|
+
}
|
|
24381
|
+
});
|
|
24382
|
+
}
|
|
24383
|
+
);
|
|
24384
|
+
req.on("error", (e) => reject(e));
|
|
24385
|
+
req.on("timeout", () => {
|
|
24386
|
+
req.destroy();
|
|
24387
|
+
reject(new Error("Connection timed out."));
|
|
24388
|
+
});
|
|
24389
|
+
req.write(body);
|
|
24390
|
+
req.end();
|
|
24391
|
+
});
|
|
24392
|
+
}
|
|
24393
|
+
function registerConnectCommand(program2) {
|
|
24394
|
+
program2.command("connect").argument("<token>", "A connect token from the dashboard").option("--profile <name>", 'Save as a named profile (default: "default")').option("--api-url <url>", "Override the connect endpoint (self-host / dev)").description("Connect this machine to a node9 workspace using a dashboard token").action(async (token, options) => {
|
|
24395
|
+
let resp;
|
|
24396
|
+
try {
|
|
24397
|
+
resp = await postConnect(resolveConnectUrl(options.apiUrl), token);
|
|
24398
|
+
} catch (e) {
|
|
24399
|
+
console.error(import_chalk17.default.red(`\u2717 ${e instanceof Error ? e.message : "Connect failed."}`));
|
|
24400
|
+
process.exitCode = 1;
|
|
24401
|
+
return;
|
|
24402
|
+
}
|
|
24403
|
+
writeCredentialsAndConfig(resp.apiKey, { profileName: options.profile });
|
|
24404
|
+
process.env.NODE9_NONINTERACTIVE = "1";
|
|
24405
|
+
let wired = [];
|
|
24406
|
+
try {
|
|
24407
|
+
wired = await setupDetectedAgents();
|
|
24408
|
+
} catch {
|
|
24409
|
+
}
|
|
24410
|
+
if (!isTestingMode()) {
|
|
24411
|
+
try {
|
|
24412
|
+
await runCloudSync();
|
|
24413
|
+
} catch {
|
|
24414
|
+
}
|
|
24415
|
+
}
|
|
24416
|
+
console.log(import_chalk17.default.green(`\u2705 Connected to ${resp.workspaceName}`));
|
|
24417
|
+
if (wired.length) {
|
|
24418
|
+
console.log(import_chalk17.default.gray(` Wired: ${wired.join(", ")}`));
|
|
24419
|
+
} else {
|
|
24420
|
+
console.log(
|
|
24421
|
+
import_chalk17.default.gray(" No agents detected yet \u2014 run `node9 init` after installing one.")
|
|
24422
|
+
);
|
|
24423
|
+
}
|
|
24424
|
+
});
|
|
24425
|
+
}
|
|
24426
|
+
|
|
24231
24427
|
// src/cli/commands/undo.ts
|
|
24232
24428
|
var import_path50 = __toESM(require("path"));
|
|
24233
|
-
var
|
|
24429
|
+
var import_chalk19 = __toESM(require("chalk"));
|
|
24234
24430
|
|
|
24235
24431
|
// src/tui/undo-navigator.ts
|
|
24236
24432
|
var import_readline3 = __toESM(require("readline"));
|
|
24237
|
-
var
|
|
24433
|
+
var import_chalk18 = __toESM(require("chalk"));
|
|
24238
24434
|
var RESET = "\x1B[0m";
|
|
24239
24435
|
var BOLD = "\x1B[1m";
|
|
24240
24436
|
var CLEAR_SCREEN = "\x1B[2J\x1B[H";
|
|
@@ -24252,15 +24448,15 @@ function renderDiff(raw) {
|
|
|
24252
24448
|
);
|
|
24253
24449
|
for (const line of lines) {
|
|
24254
24450
|
if (line.startsWith("+++") || line.startsWith("---")) {
|
|
24255
|
-
process.stdout.write(
|
|
24451
|
+
process.stdout.write(import_chalk18.default.bold(line) + "\n");
|
|
24256
24452
|
} else if (line.startsWith("+")) {
|
|
24257
|
-
process.stdout.write(
|
|
24453
|
+
process.stdout.write(import_chalk18.default.green(line) + "\n");
|
|
24258
24454
|
} else if (line.startsWith("-")) {
|
|
24259
|
-
process.stdout.write(
|
|
24455
|
+
process.stdout.write(import_chalk18.default.red(line) + "\n");
|
|
24260
24456
|
} else if (line.startsWith("@@")) {
|
|
24261
|
-
process.stdout.write(
|
|
24457
|
+
process.stdout.write(import_chalk18.default.cyan(line) + "\n");
|
|
24262
24458
|
} else {
|
|
24263
|
-
process.stdout.write(
|
|
24459
|
+
process.stdout.write(import_chalk18.default.gray(line) + "\n");
|
|
24264
24460
|
}
|
|
24265
24461
|
}
|
|
24266
24462
|
}
|
|
@@ -24279,23 +24475,23 @@ function render(entries, idx) {
|
|
|
24279
24475
|
const step = idx + 1;
|
|
24280
24476
|
process.stdout.write(CLEAR_SCREEN);
|
|
24281
24477
|
process.stdout.write(
|
|
24282
|
-
|
|
24478
|
+
import_chalk18.default.magenta.bold(`\u23EA Node9 Undo`) + import_chalk18.default.gray(` \u2500\u2500 step ${step} of ${total}`) + (entry.files?.length ? import_chalk18.default.gray(
|
|
24283
24479
|
` \u2500\u2500 ${entry.files.slice(0, 2).join(", ")}${entry.files.length > 2 ? ` +${entry.files.length - 2} more` : ""}`
|
|
24284
24480
|
) : "") + "\n\n"
|
|
24285
24481
|
);
|
|
24286
24482
|
process.stdout.write(
|
|
24287
|
-
` ${BOLD}Tool:${RESET} ${
|
|
24483
|
+
` ${BOLD}Tool:${RESET} ${import_chalk18.default.cyan(entry.tool)}` + (entry.argsSummary ? import_chalk18.default.gray(" \u2192 " + entry.argsSummary) : "") + "\n"
|
|
24288
24484
|
);
|
|
24289
|
-
process.stdout.write(` ${BOLD}When:${RESET} ${
|
|
24485
|
+
process.stdout.write(` ${BOLD}When:${RESET} ${import_chalk18.default.gray(formatAge(entry.timestamp))}
|
|
24290
24486
|
`);
|
|
24291
|
-
process.stdout.write(` ${BOLD}Dir: ${RESET} ${
|
|
24487
|
+
process.stdout.write(` ${BOLD}Dir: ${RESET} ${import_chalk18.default.gray(entry.cwd)}
|
|
24292
24488
|
`);
|
|
24293
24489
|
if (entry.files && entry.files.length > 0) {
|
|
24294
|
-
process.stdout.write(` ${BOLD}Files:${RESET} ${
|
|
24490
|
+
process.stdout.write(` ${BOLD}Files:${RESET} ${import_chalk18.default.gray(entry.files.join(", "))}
|
|
24295
24491
|
`);
|
|
24296
24492
|
}
|
|
24297
24493
|
if (idx < total - 1 && isSessionBoundary(entries, idx + 1)) {
|
|
24298
|
-
process.stdout.write(
|
|
24494
|
+
process.stdout.write(import_chalk18.default.gray("\n \u2500\u2500 session boundary above \u2500\u2500\n"));
|
|
24299
24495
|
}
|
|
24300
24496
|
process.stdout.write("\n");
|
|
24301
24497
|
const diff = entry.diff ?? computeUndoDiff(entry.hash, entry.cwd);
|
|
@@ -24303,12 +24499,12 @@ function render(entries, idx) {
|
|
|
24303
24499
|
renderDiff(diff);
|
|
24304
24500
|
} else {
|
|
24305
24501
|
process.stdout.write(
|
|
24306
|
-
|
|
24502
|
+
import_chalk18.default.gray(" (no diff \u2014 working tree may already match this snapshot)\n")
|
|
24307
24503
|
);
|
|
24308
24504
|
}
|
|
24309
24505
|
process.stdout.write("\n");
|
|
24310
24506
|
process.stdout.write(
|
|
24311
|
-
|
|
24507
|
+
import_chalk18.default.gray(" ") + (idx < total - 1 ? import_chalk18.default.white("[\u2190] older") : import_chalk18.default.gray("[\u2190] older")) + import_chalk18.default.gray(" ") + (idx > 0 ? import_chalk18.default.white("[\u2192] newer") : import_chalk18.default.gray("[\u2192] newer")) + import_chalk18.default.gray(" ") + import_chalk18.default.green("[\u21B5] restore here") + import_chalk18.default.gray(" ") + import_chalk18.default.yellow("[s] session start") + import_chalk18.default.gray(" ") + import_chalk18.default.gray("[q] quit") + "\n"
|
|
24312
24508
|
);
|
|
24313
24509
|
}
|
|
24314
24510
|
async function runUndoNavigator(entries) {
|
|
@@ -24362,19 +24558,19 @@ async function runUndoNavigator(entries) {
|
|
|
24362
24558
|
cleanup();
|
|
24363
24559
|
process.stdout.write(CLEAR_SCREEN);
|
|
24364
24560
|
const entry = display[idx];
|
|
24365
|
-
process.stdout.write(
|
|
24561
|
+
process.stdout.write(import_chalk18.default.magenta.bold("\n\u23EA Restoring snapshot...\n\n"));
|
|
24366
24562
|
if (applyUndo(entry.hash, entry.cwd)) {
|
|
24367
|
-
process.stdout.write(
|
|
24563
|
+
process.stdout.write(import_chalk18.default.green("\u2705 Reverted successfully.\n\n"));
|
|
24368
24564
|
resolve({ restored: true });
|
|
24369
24565
|
} else {
|
|
24370
|
-
process.stdout.write(
|
|
24566
|
+
process.stdout.write(import_chalk18.default.red("\u274C Undo failed.\n\n"));
|
|
24371
24567
|
resolve({ restored: false });
|
|
24372
24568
|
}
|
|
24373
24569
|
} else if (name === "q" || key?.ctrl && name === "c") {
|
|
24374
24570
|
done = true;
|
|
24375
24571
|
cleanup();
|
|
24376
24572
|
process.stdout.write(CLEAR_SCREEN);
|
|
24377
|
-
process.stdout.write(
|
|
24573
|
+
process.stdout.write(import_chalk18.default.gray("\nCancelled.\n\n"));
|
|
24378
24574
|
resolve({ restored: false });
|
|
24379
24575
|
}
|
|
24380
24576
|
};
|
|
@@ -24410,39 +24606,39 @@ function registerUndoCommand(program2) {
|
|
|
24410
24606
|
if (history.length === 0) {
|
|
24411
24607
|
if (!options.all && allHistory.length > 0) {
|
|
24412
24608
|
console.log(
|
|
24413
|
-
|
|
24609
|
+
import_chalk19.default.yellow(
|
|
24414
24610
|
`
|
|
24415
24611
|
\u2139\uFE0F No snapshots found for the current directory (${process.cwd()}).
|
|
24416
|
-
Run ${
|
|
24612
|
+
Run ${import_chalk19.default.cyan("node9 undo --all")} to see snapshots from all projects.
|
|
24417
24613
|
`
|
|
24418
24614
|
)
|
|
24419
24615
|
);
|
|
24420
24616
|
} else {
|
|
24421
|
-
console.log(
|
|
24617
|
+
console.log(import_chalk19.default.yellow("\n\u2139\uFE0F No undo snapshots found.\n"));
|
|
24422
24618
|
}
|
|
24423
24619
|
return;
|
|
24424
24620
|
}
|
|
24425
24621
|
if (options.list) {
|
|
24426
|
-
console.log(
|
|
24622
|
+
console.log(import_chalk19.default.magenta.bold("\n\u23EA Snapshot History\n"));
|
|
24427
24623
|
console.log(
|
|
24428
|
-
|
|
24624
|
+
import_chalk19.default.gray(
|
|
24429
24625
|
` ${"#".padEnd(3)} ${"File / Command".padEnd(30)} ${"Tool".padEnd(8)} ${"When".padEnd(10)} Dir`
|
|
24430
24626
|
)
|
|
24431
24627
|
);
|
|
24432
|
-
console.log(
|
|
24628
|
+
console.log(import_chalk19.default.gray(" " + "\u2500".repeat(80)));
|
|
24433
24629
|
const display = [...history].reverse();
|
|
24434
24630
|
let prevTs = null;
|
|
24435
24631
|
for (let i = 0; i < display.length; i++) {
|
|
24436
24632
|
const e = display[i];
|
|
24437
24633
|
const isGap = prevTs !== null && prevTs - e.timestamp > 6e4;
|
|
24438
|
-
if (isGap) console.log(
|
|
24634
|
+
if (isGap) console.log(import_chalk19.default.gray(" \u2500\u2500 earlier \u2500\u2500"));
|
|
24439
24635
|
const label2 = (e.argsSummary || e.files?.[0] || "\u2014").slice(0, 30).padEnd(30);
|
|
24440
24636
|
const tool = e.tool.slice(0, 8).padEnd(8);
|
|
24441
24637
|
const when = formatAge2(e.timestamp).padEnd(10);
|
|
24442
24638
|
const dir = e.cwd.length > 30 ? "\u2026" + e.cwd.slice(-29) : e.cwd;
|
|
24443
24639
|
console.log(
|
|
24444
|
-
|
|
24445
|
-
` ${String(i + 1).padEnd(3)} ${label2} ${
|
|
24640
|
+
import_chalk19.default.white(
|
|
24641
|
+
` ${String(i + 1).padEnd(3)} ${label2} ${import_chalk19.default.cyan(tool)} ${import_chalk19.default.gray(when)} ${import_chalk19.default.gray(dir)}`
|
|
24446
24642
|
)
|
|
24447
24643
|
);
|
|
24448
24644
|
prevTs = e.timestamp;
|
|
@@ -24455,7 +24651,7 @@ function registerUndoCommand(program2) {
|
|
|
24455
24651
|
const idx = history.length - steps;
|
|
24456
24652
|
if (idx < 0) {
|
|
24457
24653
|
console.log(
|
|
24458
|
-
|
|
24654
|
+
import_chalk19.default.yellow(
|
|
24459
24655
|
`
|
|
24460
24656
|
\u2139\uFE0F Only ${history.length} snapshot(s) available, cannot go back ${steps}.
|
|
24461
24657
|
`
|
|
@@ -24466,47 +24662,47 @@ function registerUndoCommand(program2) {
|
|
|
24466
24662
|
const snapshot = history[idx];
|
|
24467
24663
|
const ageStr = formatAge2(snapshot.timestamp);
|
|
24468
24664
|
console.log(
|
|
24469
|
-
|
|
24665
|
+
import_chalk19.default.magenta.bold(`
|
|
24470
24666
|
\u23EA Node9 Undo${steps > 1 ? ` (${steps} steps back)` : ""}`)
|
|
24471
24667
|
);
|
|
24472
24668
|
console.log(
|
|
24473
|
-
|
|
24474
|
-
` Tool: ${
|
|
24669
|
+
import_chalk19.default.white(
|
|
24670
|
+
` Tool: ${import_chalk19.default.cyan(snapshot.tool)}${snapshot.argsSummary ? import_chalk19.default.gray(" \u2192 " + snapshot.argsSummary) : ""}`
|
|
24475
24671
|
)
|
|
24476
24672
|
);
|
|
24477
|
-
console.log(
|
|
24478
|
-
console.log(
|
|
24673
|
+
console.log(import_chalk19.default.white(` When: ${import_chalk19.default.gray(ageStr)}`));
|
|
24674
|
+
console.log(import_chalk19.default.white(` Dir: ${import_chalk19.default.gray(snapshot.cwd)}`));
|
|
24479
24675
|
if (steps > 1)
|
|
24480
24676
|
console.log(
|
|
24481
|
-
|
|
24677
|
+
import_chalk19.default.yellow(` Note: This will also undo the ${steps - 1} action(s) after it.`)
|
|
24482
24678
|
);
|
|
24483
24679
|
console.log("");
|
|
24484
24680
|
const diff = snapshot.diff ?? computeUndoDiff(snapshot.hash, snapshot.cwd);
|
|
24485
24681
|
if (diff) {
|
|
24486
24682
|
const lines = diff.split("\n").filter((l) => !l.startsWith("diff --git") && !l.startsWith("index "));
|
|
24487
24683
|
for (const line of lines) {
|
|
24488
|
-
if (line.startsWith("+++") || line.startsWith("---")) console.log(
|
|
24489
|
-
else if (line.startsWith("+")) console.log(
|
|
24490
|
-
else if (line.startsWith("-")) console.log(
|
|
24491
|
-
else if (line.startsWith("@@")) console.log(
|
|
24492
|
-
else console.log(
|
|
24684
|
+
if (line.startsWith("+++") || line.startsWith("---")) console.log(import_chalk19.default.bold(line));
|
|
24685
|
+
else if (line.startsWith("+")) console.log(import_chalk19.default.green(line));
|
|
24686
|
+
else if (line.startsWith("-")) console.log(import_chalk19.default.red(line));
|
|
24687
|
+
else if (line.startsWith("@@")) console.log(import_chalk19.default.cyan(line));
|
|
24688
|
+
else console.log(import_chalk19.default.gray(line));
|
|
24493
24689
|
}
|
|
24494
24690
|
console.log("");
|
|
24495
24691
|
} else {
|
|
24496
24692
|
console.log(
|
|
24497
|
-
|
|
24693
|
+
import_chalk19.default.gray(" (no diff available \u2014 working tree may already match snapshot)\n")
|
|
24498
24694
|
);
|
|
24499
24695
|
}
|
|
24500
24696
|
const { confirm: confirm3 } = await import("@inquirer/prompts");
|
|
24501
24697
|
const proceed = await confirm3({ message: `Revert to this snapshot?`, default: false });
|
|
24502
24698
|
if (proceed) {
|
|
24503
24699
|
if (applyUndo(snapshot.hash, snapshot.cwd)) {
|
|
24504
|
-
console.log(
|
|
24700
|
+
console.log(import_chalk19.default.green("\n\u2705 Reverted successfully.\n"));
|
|
24505
24701
|
} else {
|
|
24506
|
-
console.error(
|
|
24702
|
+
console.error(import_chalk19.default.red("\n\u274C Undo failed. Ensure you are in a Git repository.\n"));
|
|
24507
24703
|
}
|
|
24508
24704
|
} else {
|
|
24509
|
-
console.log(
|
|
24705
|
+
console.log(import_chalk19.default.gray("\nCancelled.\n"));
|
|
24510
24706
|
}
|
|
24511
24707
|
return;
|
|
24512
24708
|
}
|
|
@@ -24516,7 +24712,7 @@ function registerUndoCommand(program2) {
|
|
|
24516
24712
|
|
|
24517
24713
|
// src/mcp-gateway/index.ts
|
|
24518
24714
|
var import_readline4 = __toESM(require("readline"));
|
|
24519
|
-
var
|
|
24715
|
+
var import_chalk20 = __toESM(require("chalk"));
|
|
24520
24716
|
var import_child_process10 = require("child_process");
|
|
24521
24717
|
var import_execa3 = require("execa");
|
|
24522
24718
|
init_orchestrator();
|
|
@@ -24652,13 +24848,13 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
24652
24848
|
const prov = checkProvenance(executable);
|
|
24653
24849
|
if (prov.trustLevel === "suspect") {
|
|
24654
24850
|
console.error(
|
|
24655
|
-
|
|
24851
|
+
import_chalk20.default.red(
|
|
24656
24852
|
`\u26A0\uFE0F Node9: Upstream MCP server binary is suspect \u2014 ${prov.reason} (${prov.resolvedPath})`
|
|
24657
24853
|
)
|
|
24658
24854
|
);
|
|
24659
|
-
console.error(
|
|
24855
|
+
console.error(import_chalk20.default.red(" Verify this binary is trusted before proceeding."));
|
|
24660
24856
|
}
|
|
24661
|
-
console.error(
|
|
24857
|
+
console.error(import_chalk20.default.green(`\u{1F680} Node9 MCP Gateway: Monitoring [${upstreamCommand}]`));
|
|
24662
24858
|
const UPSTREAM_INJECTOR_VARS = /* @__PURE__ */ new Set([
|
|
24663
24859
|
"NODE_OPTIONS",
|
|
24664
24860
|
"NODE_PATH",
|
|
@@ -24771,10 +24967,10 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
24771
24967
|
mcpServer
|
|
24772
24968
|
});
|
|
24773
24969
|
if (!result.approved) {
|
|
24774
|
-
console.error(
|
|
24970
|
+
console.error(import_chalk20.default.red(`
|
|
24775
24971
|
\u{1F6D1} Node9 MCP Gateway: Action Blocked`));
|
|
24776
|
-
console.error(
|
|
24777
|
-
console.error(
|
|
24972
|
+
console.error(import_chalk20.default.gray(` Tool: ${toolName}`));
|
|
24973
|
+
console.error(import_chalk20.default.gray(` Reason: ${result.reason ?? "Security Policy"}
|
|
24778
24974
|
`));
|
|
24779
24975
|
const blockedByLabel = result.blockedByLabel ?? result.reason ?? "Security Policy";
|
|
24780
24976
|
const isHumanDecision = blockedByLabel.toLowerCase().includes("user") || blockedByLabel.toLowerCase().includes("daemon") || blockedByLabel.toLowerCase().includes("decision");
|
|
@@ -24887,7 +25083,7 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
24887
25083
|
updatePin(serverKey, upstreamCommand, currentHash, toolNames);
|
|
24888
25084
|
pinState = "validated";
|
|
24889
25085
|
console.error(
|
|
24890
|
-
|
|
25086
|
+
import_chalk20.default.green(
|
|
24891
25087
|
`\u{1F512} Node9: Pinned ${toolNames.length} tool definition(s) for this MCP server`
|
|
24892
25088
|
)
|
|
24893
25089
|
);
|
|
@@ -24900,11 +25096,11 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
24900
25096
|
} else if (pinStatus === "corrupt") {
|
|
24901
25097
|
pinState = "quarantined";
|
|
24902
25098
|
console.error(
|
|
24903
|
-
|
|
25099
|
+
import_chalk20.default.red("\n\u{1F6A8} Node9: MCP pin file is corrupt or unreadable \u2014 session quarantined!")
|
|
24904
25100
|
);
|
|
24905
|
-
console.error(
|
|
25101
|
+
console.error(import_chalk20.default.red(" Tool calls are blocked until the pin file is repaired."));
|
|
24906
25102
|
console.error(
|
|
24907
|
-
|
|
25103
|
+
import_chalk20.default.yellow(` Run: node9 mcp pin reset (to clear and re-pin on next connect)
|
|
24908
25104
|
`)
|
|
24909
25105
|
);
|
|
24910
25106
|
const errorResponse = {
|
|
@@ -24921,13 +25117,13 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
24921
25117
|
} else {
|
|
24922
25118
|
pinState = "quarantined";
|
|
24923
25119
|
console.error(
|
|
24924
|
-
|
|
25120
|
+
import_chalk20.default.red("\n\u{1F6A8} Node9: MCP tool definitions have changed since last verified!")
|
|
24925
25121
|
);
|
|
24926
25122
|
console.error(
|
|
24927
|
-
|
|
25123
|
+
import_chalk20.default.red(" This could indicate a supply chain attack (tool poisoning / rug pull).")
|
|
24928
25124
|
);
|
|
24929
|
-
console.error(
|
|
24930
|
-
console.error(
|
|
25125
|
+
console.error(import_chalk20.default.red(" Session quarantined \u2014 all tool calls blocked."));
|
|
25126
|
+
console.error(import_chalk20.default.yellow(` Run: node9 mcp pin update ${serverKey}
|
|
24931
25127
|
`));
|
|
24932
25128
|
reportPinMismatchToCloud(serverKey, clientName);
|
|
24933
25129
|
const errorResponse = {
|
|
@@ -24971,7 +25167,7 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
24971
25167
|
const toolName = callId !== void 0 ? pendingCallNames.get(callId) ?? "unknown" : "unknown";
|
|
24972
25168
|
if (callId !== void 0) pendingCallNames.delete(callId);
|
|
24973
25169
|
console.error(
|
|
24974
|
-
|
|
25170
|
+
import_chalk20.default.yellow(
|
|
24975
25171
|
`\u26A1 Node9: Large MCP response from '${toolName}' (${(line.length / 1024).toFixed(0)}KB) \u2014 context window enlarged`
|
|
24976
25172
|
)
|
|
24977
25173
|
);
|
|
@@ -25938,7 +26134,7 @@ function registerMcpServerCommand(program2) {
|
|
|
25938
26134
|
}
|
|
25939
26135
|
|
|
25940
26136
|
// src/cli/commands/trust.ts
|
|
25941
|
-
var
|
|
26137
|
+
var import_chalk21 = __toESM(require("chalk"));
|
|
25942
26138
|
init_trusted_hosts();
|
|
25943
26139
|
function isValidHost(host) {
|
|
25944
26140
|
return /^(\*\.)?[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/.test(host);
|
|
@@ -25949,51 +26145,51 @@ function registerTrustCommand(program2) {
|
|
|
25949
26145
|
const normalized = normalizeHost(host.trim());
|
|
25950
26146
|
if (!isValidHost(normalized)) {
|
|
25951
26147
|
console.error(
|
|
25952
|
-
|
|
26148
|
+
import_chalk21.default.red(`
|
|
25953
26149
|
\u274C Invalid host: "${host}"
|
|
25954
|
-
`) +
|
|
26150
|
+
`) + import_chalk21.default.gray(" Use an FQDN like api.mycompany.com or *.mycompany.com\n")
|
|
25955
26151
|
);
|
|
25956
26152
|
process.exit(1);
|
|
25957
26153
|
}
|
|
25958
26154
|
addTrustedHost(normalized);
|
|
25959
|
-
console.log(
|
|
26155
|
+
console.log(import_chalk21.default.green(`
|
|
25960
26156
|
\u2705 ${normalized} added to trusted hosts.`));
|
|
25961
26157
|
console.log(
|
|
25962
|
-
|
|
26158
|
+
import_chalk21.default.gray(" Pipe-chain blocks to this host: critical \u2192 review, high \u2192 allow\n")
|
|
25963
26159
|
);
|
|
25964
26160
|
});
|
|
25965
26161
|
trustCmd.command("remove <host>").description("Remove a trusted host").action((host) => {
|
|
25966
26162
|
const normalized = normalizeHost(host.trim());
|
|
25967
26163
|
const removed = removeTrustedHost(normalized);
|
|
25968
26164
|
if (!removed) {
|
|
25969
|
-
console.error(
|
|
26165
|
+
console.error(import_chalk21.default.yellow(`
|
|
25970
26166
|
\u26A0\uFE0F "${normalized}" is not in the trusted hosts list.
|
|
25971
26167
|
`));
|
|
25972
26168
|
process.exit(1);
|
|
25973
26169
|
}
|
|
25974
|
-
console.log(
|
|
26170
|
+
console.log(import_chalk21.default.green(`
|
|
25975
26171
|
\u2705 ${normalized} removed from trusted hosts.
|
|
25976
26172
|
`));
|
|
25977
26173
|
});
|
|
25978
26174
|
trustCmd.command("list").description("Show all trusted hosts").action(() => {
|
|
25979
26175
|
const hosts = readTrustedHosts();
|
|
25980
26176
|
if (hosts.length === 0) {
|
|
25981
|
-
console.log(
|
|
25982
|
-
console.log(` Add one: ${
|
|
26177
|
+
console.log(import_chalk21.default.gray("\n No trusted hosts configured.\n"));
|
|
26178
|
+
console.log(` Add one: ${import_chalk21.default.cyan("node9 trust add api.mycompany.com")}
|
|
25983
26179
|
`);
|
|
25984
26180
|
return;
|
|
25985
26181
|
}
|
|
25986
|
-
console.log(
|
|
26182
|
+
console.log(import_chalk21.default.bold("\n\u{1F513} Trusted Hosts\n"));
|
|
25987
26183
|
for (const entry of hosts) {
|
|
25988
26184
|
const date = new Date(entry.addedAt).toLocaleDateString();
|
|
25989
|
-
console.log(` ${
|
|
26185
|
+
console.log(` ${import_chalk21.default.cyan(entry.host.padEnd(40))} ${import_chalk21.default.gray(`added ${date}`)}`);
|
|
25990
26186
|
}
|
|
25991
26187
|
console.log("");
|
|
25992
26188
|
});
|
|
25993
26189
|
}
|
|
25994
26190
|
|
|
25995
26191
|
// src/cli/commands/mcp-pin.ts
|
|
25996
|
-
var
|
|
26192
|
+
var import_chalk22 = __toESM(require("chalk"));
|
|
25997
26193
|
init_mcp_pin();
|
|
25998
26194
|
var import_fs54 = __toESM(require("fs"));
|
|
25999
26195
|
function registerMcpPinCommand(program2) {
|
|
@@ -26014,14 +26210,14 @@ function registerMcpPinCommand(program2) {
|
|
|
26014
26210
|
}
|
|
26015
26211
|
}
|
|
26016
26212
|
if (repoCorrupt) {
|
|
26017
|
-
console.error(
|
|
26213
|
+
console.error(import_chalk22.default.red(`
|
|
26018
26214
|
\u274C Repo pin file at ${found.path} is corrupt or unreadable.`));
|
|
26019
26215
|
process.exit(1);
|
|
26020
26216
|
}
|
|
26021
26217
|
if (!homeResult.ok && homeResult.reason === "corrupt") {
|
|
26022
|
-
console.error(
|
|
26218
|
+
console.error(import_chalk22.default.red(`
|
|
26023
26219
|
\u274C Home pin file is corrupt: ${homeResult.detail}`));
|
|
26024
|
-
console.error(
|
|
26220
|
+
console.error(import_chalk22.default.yellow(" Run: node9 mcp pin reset\n"));
|
|
26025
26221
|
process.exit(1);
|
|
26026
26222
|
}
|
|
26027
26223
|
const homeEntries = homeResult.ok ? homeResult.pins.servers : {};
|
|
@@ -26033,25 +26229,25 @@ function registerMcpPinCommand(program2) {
|
|
|
26033
26229
|
merged.set(key, { entry, source: "repo" });
|
|
26034
26230
|
}
|
|
26035
26231
|
if (merged.size === 0) {
|
|
26036
|
-
console.log(
|
|
26232
|
+
console.log(import_chalk22.default.gray("\nNo MCP servers are pinned yet."));
|
|
26037
26233
|
console.log(
|
|
26038
|
-
|
|
26234
|
+
import_chalk22.default.gray("Pins are created automatically when the MCP gateway first connects.\n")
|
|
26039
26235
|
);
|
|
26040
26236
|
return;
|
|
26041
26237
|
}
|
|
26042
|
-
console.log(
|
|
26238
|
+
console.log(import_chalk22.default.bold("\n\u{1F512} Pinned MCP Servers\n"));
|
|
26043
26239
|
const showSource = found.source === "repo";
|
|
26044
26240
|
for (const [key, { entry, source }] of merged) {
|
|
26045
|
-
const tag = showSource ? ` ${
|
|
26046
|
-
console.log(` ${
|
|
26047
|
-
console.log(` Tools (${entry.toolCount}): ${
|
|
26048
|
-
console.log(` Hash: ${
|
|
26049
|
-
console.log(` Pinned: ${
|
|
26241
|
+
const tag = showSource ? ` ${import_chalk22.default.yellow(`[${source}]`)}` : "";
|
|
26242
|
+
console.log(` ${import_chalk22.default.cyan(key)}${tag} ${import_chalk22.default.gray(entry.label)}`);
|
|
26243
|
+
console.log(` Tools (${entry.toolCount}): ${import_chalk22.default.white(entry.toolNames.join(", "))}`);
|
|
26244
|
+
console.log(` Hash: ${import_chalk22.default.gray(entry.toolsHash.slice(0, 16))}...`);
|
|
26245
|
+
console.log(` Pinned: ${import_chalk22.default.gray(entry.pinnedAt)}`);
|
|
26050
26246
|
console.log("");
|
|
26051
26247
|
}
|
|
26052
26248
|
if (showSource) {
|
|
26053
|
-
console.log(
|
|
26054
|
-
console.log(
|
|
26249
|
+
console.log(import_chalk22.default.gray(` [repo] entries come from ${found.path}`));
|
|
26250
|
+
console.log(import_chalk22.default.gray(" [home] entries come from ~/.node9/mcp-pins.json\n"));
|
|
26055
26251
|
}
|
|
26056
26252
|
});
|
|
26057
26253
|
pinSubCmd.command("promote <serverKey>").description(
|
|
@@ -26061,22 +26257,22 @@ function registerMcpPinCommand(program2) {
|
|
|
26061
26257
|
const { repoPath, created } = promotePin(serverKey, process.cwd());
|
|
26062
26258
|
if (created) {
|
|
26063
26259
|
console.log(
|
|
26064
|
-
|
|
26260
|
+
import_chalk22.default.green(
|
|
26065
26261
|
`
|
|
26066
|
-
\u2705 Created ${repoPath} with the promoted pin for ${
|
|
26262
|
+
\u2705 Created ${repoPath} with the promoted pin for ${import_chalk22.default.cyan(serverKey)}.`
|
|
26067
26263
|
)
|
|
26068
26264
|
);
|
|
26069
26265
|
} else {
|
|
26070
|
-
console.log(
|
|
26071
|
-
\u2705 Promoted ${
|
|
26266
|
+
console.log(import_chalk22.default.green(`
|
|
26267
|
+
\u2705 Promoted ${import_chalk22.default.cyan(serverKey)} into ${repoPath}.`));
|
|
26072
26268
|
}
|
|
26073
|
-
console.log(
|
|
26074
|
-
console.log(
|
|
26075
|
-
console.log(
|
|
26269
|
+
console.log(import_chalk22.default.gray(" Review the change and commit it:"));
|
|
26270
|
+
console.log(import_chalk22.default.cyan(` git add ${repoPath}`));
|
|
26271
|
+
console.log(import_chalk22.default.cyan(` git commit -m "pin ${serverKey} (node9)"`));
|
|
26076
26272
|
console.log("");
|
|
26077
26273
|
} catch (err2) {
|
|
26078
26274
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
26079
|
-
console.error(
|
|
26275
|
+
console.error(import_chalk22.default.red(`
|
|
26080
26276
|
\u274C ${msg}
|
|
26081
26277
|
`));
|
|
26082
26278
|
process.exit(1);
|
|
@@ -26089,138 +26285,138 @@ function registerMcpPinCommand(program2) {
|
|
|
26089
26285
|
try {
|
|
26090
26286
|
pins = readMcpPins();
|
|
26091
26287
|
} catch {
|
|
26092
|
-
console.error(
|
|
26093
|
-
console.error(
|
|
26288
|
+
console.error(import_chalk22.default.red("\n\u274C Pin file is corrupt."));
|
|
26289
|
+
console.error(import_chalk22.default.yellow(" Run: node9 mcp pin reset\n"));
|
|
26094
26290
|
process.exit(1);
|
|
26095
26291
|
}
|
|
26096
26292
|
if (!pins.servers[serverKey]) {
|
|
26097
|
-
console.error(
|
|
26293
|
+
console.error(import_chalk22.default.red(`
|
|
26098
26294
|
\u274C No pin found for server key "${serverKey}"
|
|
26099
26295
|
`));
|
|
26100
|
-
console.error(`Run ${
|
|
26296
|
+
console.error(`Run ${import_chalk22.default.cyan("node9 mcp pin list")} to see pinned servers.
|
|
26101
26297
|
`);
|
|
26102
26298
|
process.exit(1);
|
|
26103
26299
|
}
|
|
26104
26300
|
const label2 = pins.servers[serverKey].label;
|
|
26105
26301
|
removePin(serverKey);
|
|
26106
|
-
console.log(
|
|
26107
|
-
\u{1F513} Pin removed for ${
|
|
26108
|
-
console.log(
|
|
26109
|
-
console.log(
|
|
26302
|
+
console.log(import_chalk22.default.green(`
|
|
26303
|
+
\u{1F513} Pin removed for ${import_chalk22.default.cyan(serverKey)}`));
|
|
26304
|
+
console.log(import_chalk22.default.gray(` Server: ${label2}`));
|
|
26305
|
+
console.log(import_chalk22.default.gray(" Next connection will re-pin with current tool definitions.\n"));
|
|
26110
26306
|
});
|
|
26111
26307
|
pinSubCmd.command("reset").description("Clear all MCP pins (next connection to each server will re-pin)").action(() => {
|
|
26112
26308
|
const result = readMcpPinsSafe();
|
|
26113
26309
|
if (!result.ok && result.reason === "missing") {
|
|
26114
|
-
console.log(
|
|
26310
|
+
console.log(import_chalk22.default.gray("\nNo pins to clear.\n"));
|
|
26115
26311
|
return;
|
|
26116
26312
|
}
|
|
26117
26313
|
const count = result.ok ? Object.keys(result.pins.servers).length : "?";
|
|
26118
26314
|
clearAllPins();
|
|
26119
|
-
console.log(
|
|
26315
|
+
console.log(import_chalk22.default.green(`
|
|
26120
26316
|
\u{1F513} Cleared ${count} MCP pin(s).`));
|
|
26121
|
-
console.log(
|
|
26317
|
+
console.log(import_chalk22.default.gray(" Next connection to each server will re-pin.\n"));
|
|
26122
26318
|
});
|
|
26123
26319
|
}
|
|
26124
26320
|
|
|
26125
26321
|
// src/cli/commands/sync.ts
|
|
26126
|
-
var
|
|
26322
|
+
var import_chalk23 = __toESM(require("chalk"));
|
|
26127
26323
|
init_sync();
|
|
26128
26324
|
function registerSyncCommand(program2) {
|
|
26129
26325
|
const policy = program2.command("policy").description("Manage cloud policy rules");
|
|
26130
26326
|
policy.command("push").description("Push this machine's effective policy to the node9 dashboard").action(async () => {
|
|
26131
|
-
process.stdout.write(
|
|
26327
|
+
process.stdout.write(import_chalk23.default.cyan("Pushing policy to the dashboard\u2026"));
|
|
26132
26328
|
const result = await runPolicyPush();
|
|
26133
26329
|
process.stdout.write("\n");
|
|
26134
26330
|
if (!result.ok) {
|
|
26135
|
-
console.error(
|
|
26331
|
+
console.error(import_chalk23.default.red(`\u2717 ${result.reason}`));
|
|
26136
26332
|
process.exit(1);
|
|
26137
26333
|
}
|
|
26138
|
-
console.log(
|
|
26139
|
-
console.log(
|
|
26334
|
+
console.log(import_chalk23.default.green("\u2713 Policy mirrored to the dashboard"));
|
|
26335
|
+
console.log(import_chalk23.default.gray(" See it under Security Policy \u2192 Machines"));
|
|
26140
26336
|
});
|
|
26141
26337
|
policy.command("sync").description("Sync cloud policy rules to local cache (~/.node9/rules-cache.json)").action(async () => {
|
|
26142
|
-
process.stdout.write(
|
|
26338
|
+
process.stdout.write(import_chalk23.default.cyan("Syncing cloud policy rules\u2026"));
|
|
26143
26339
|
const result = await runCloudSync();
|
|
26144
26340
|
process.stdout.write("\n");
|
|
26145
26341
|
if (!result.ok) {
|
|
26146
|
-
console.error(
|
|
26342
|
+
console.error(import_chalk23.default.red(`\u2717 ${result.reason}`));
|
|
26147
26343
|
process.exit(1);
|
|
26148
26344
|
}
|
|
26149
26345
|
if (result.unchanged) {
|
|
26150
26346
|
console.log(
|
|
26151
|
-
|
|
26347
|
+
import_chalk23.default.green(
|
|
26152
26348
|
`\u2713 Already up to date \u2014 ${result.rules} rule${result.rules === 1 ? "" : "s"} cached`
|
|
26153
26349
|
)
|
|
26154
26350
|
);
|
|
26155
|
-
console.log(
|
|
26156
|
-
console.log(
|
|
26351
|
+
console.log(import_chalk23.default.gray(` Cached at: ${result.fetchedAt}`));
|
|
26352
|
+
console.log(import_chalk23.default.gray(` Server returned 304 (no changes since last sync)`));
|
|
26157
26353
|
} else {
|
|
26158
26354
|
console.log(
|
|
26159
|
-
|
|
26355
|
+
import_chalk23.default.green(`\u2713 Synced ${result.rules} rule${result.rules === 1 ? "" : "s"} from cloud`)
|
|
26160
26356
|
);
|
|
26161
|
-
console.log(
|
|
26162
|
-
console.log(
|
|
26357
|
+
console.log(import_chalk23.default.gray(` Cached at: ${result.fetchedAt}`));
|
|
26358
|
+
console.log(import_chalk23.default.gray(` File: ~/.node9/rules-cache.json`));
|
|
26163
26359
|
}
|
|
26164
26360
|
});
|
|
26165
26361
|
policy.command("show").description("List all cloud policy rules in the local cache").action(() => {
|
|
26166
26362
|
const status = getCloudSyncStatus();
|
|
26167
26363
|
if (!status.cached) {
|
|
26168
|
-
console.log(
|
|
26364
|
+
console.log(import_chalk23.default.yellow("\n No cloud rules cached \u2014 run: node9 policy sync\n"));
|
|
26169
26365
|
return;
|
|
26170
26366
|
}
|
|
26171
26367
|
const rules = getCloudRules() ?? [];
|
|
26172
26368
|
const age = Math.round((Date.now() - new Date(status.fetchedAt).getTime()) / 6e4);
|
|
26173
26369
|
console.log(
|
|
26174
|
-
|
|
26175
|
-
Cloud policy rules`) +
|
|
26370
|
+
import_chalk23.default.bold(`
|
|
26371
|
+
Cloud policy rules`) + import_chalk23.default.gray(
|
|
26176
26372
|
` (${rules.length} rule${rules.length === 1 ? "" : "s"}, synced ${age}m ago)
|
|
26177
26373
|
`
|
|
26178
26374
|
)
|
|
26179
26375
|
);
|
|
26180
26376
|
if (rules.length === 0) {
|
|
26181
|
-
console.log(
|
|
26377
|
+
console.log(import_chalk23.default.gray(" No rules defined in cloud policy.\n"));
|
|
26182
26378
|
return;
|
|
26183
26379
|
}
|
|
26184
26380
|
for (const rule of rules) {
|
|
26185
26381
|
const r = rule;
|
|
26186
|
-
const verdictColor = r.verdict === "block" ?
|
|
26382
|
+
const verdictColor = r.verdict === "block" ? import_chalk23.default.red : r.verdict === "allow" ? import_chalk23.default.green : import_chalk23.default.yellow;
|
|
26187
26383
|
console.log(
|
|
26188
26384
|
` ${verdictColor(
|
|
26189
26385
|
String(r.verdict ?? "unknown").toUpperCase().padEnd(6)
|
|
26190
|
-
)} ${
|
|
26386
|
+
)} ${import_chalk23.default.white(String(r.name ?? "(unnamed)"))}`
|
|
26191
26387
|
);
|
|
26192
|
-
if (r.reason) console.log(
|
|
26388
|
+
if (r.reason) console.log(import_chalk23.default.gray(` ${String(r.reason)}`));
|
|
26193
26389
|
}
|
|
26194
26390
|
console.log("");
|
|
26195
26391
|
});
|
|
26196
26392
|
policy.command("status").description("Show current cloud policy cache status").action(() => {
|
|
26197
26393
|
const s = getCloudSyncStatus();
|
|
26198
26394
|
if (!s.cached) {
|
|
26199
|
-
console.log(
|
|
26395
|
+
console.log(import_chalk23.default.yellow("\n No cache yet \u2014 run: node9 policy sync\n"));
|
|
26200
26396
|
return;
|
|
26201
26397
|
}
|
|
26202
26398
|
const age = Math.round((Date.now() - new Date(s.fetchedAt).getTime()) / 6e4);
|
|
26203
26399
|
console.log(`
|
|
26204
|
-
Rules : ${
|
|
26400
|
+
Rules : ${import_chalk23.default.green(String(s.rules))} cloud rules loaded`);
|
|
26205
26401
|
console.log(
|
|
26206
|
-
` Synced : ${
|
|
26402
|
+
` Synced : ${import_chalk23.default.gray(`${age} minute${age === 1 ? "" : "s"} ago`)} (${s.fetchedAt})`
|
|
26207
26403
|
);
|
|
26208
26404
|
if (s.workspaceId) {
|
|
26209
|
-
console.log(` Workspace: ${
|
|
26405
|
+
console.log(` Workspace: ${import_chalk23.default.gray(s.workspaceId)}`);
|
|
26210
26406
|
}
|
|
26211
26407
|
if (s.panicMode) {
|
|
26212
26408
|
console.log(
|
|
26213
|
-
` ${
|
|
26409
|
+
` ${import_chalk23.default.red.bold("\u{1F6A8} Panic mode : ON")} ` + import_chalk23.default.dim("(every review-verdict becomes block)")
|
|
26214
26410
|
);
|
|
26215
26411
|
}
|
|
26216
26412
|
if (s.shadowMode) {
|
|
26217
26413
|
console.log(
|
|
26218
|
-
` ${
|
|
26414
|
+
` ${import_chalk23.default.yellow.bold("\u{1F441} Shadow mode : ON")} ` + import_chalk23.default.dim("(blocks become would-block log entries)")
|
|
26219
26415
|
);
|
|
26220
26416
|
}
|
|
26221
26417
|
if (s.syncIntervalHours) {
|
|
26222
26418
|
console.log(
|
|
26223
|
-
|
|
26419
|
+
import_chalk23.default.gray(
|
|
26224
26420
|
` Polling : every ${s.syncIntervalHours} hour${s.syncIntervalHours === 1 ? "" : "s"}`
|
|
26225
26421
|
)
|
|
26226
26422
|
);
|
|
@@ -26230,7 +26426,7 @@ function registerSyncCommand(program2) {
|
|
|
26230
26426
|
}
|
|
26231
26427
|
|
|
26232
26428
|
// src/cli/commands/agents.ts
|
|
26233
|
-
var
|
|
26429
|
+
var import_chalk24 = __toESM(require("chalk"));
|
|
26234
26430
|
init_setup();
|
|
26235
26431
|
var SETUP_FN = {
|
|
26236
26432
|
claude: setupClaude,
|
|
@@ -26274,30 +26470,30 @@ function registerAgentsCommand(program2) {
|
|
|
26274
26470
|
console.log(` ${"Agent".padEnd(14)}${"Installed".padEnd(11)}${"Wired".padEnd(8)}Mode`);
|
|
26275
26471
|
console.log(" " + "\u2500".repeat(44));
|
|
26276
26472
|
for (const s of statuses) {
|
|
26277
|
-
const installed = s.installed ?
|
|
26278
|
-
const wired = !s.installed ?
|
|
26279
|
-
const mode = s.mode ?
|
|
26280
|
-
const hint = s.installed && !s.wired ?
|
|
26473
|
+
const installed = s.installed ? import_chalk24.default.green("\u2713") : import_chalk24.default.gray("\u2717");
|
|
26474
|
+
const wired = !s.installed ? import_chalk24.default.gray("\u2014") : s.wired ? import_chalk24.default.green("\u2713") : import_chalk24.default.yellow("\u2717");
|
|
26475
|
+
const mode = s.mode ? import_chalk24.default.gray(s.mode) : import_chalk24.default.gray("\u2014");
|
|
26476
|
+
const hint = s.installed && !s.wired ? import_chalk24.default.gray(` \u2190 node9 agents add ${s.name}`) : "";
|
|
26281
26477
|
console.log(` ${s.label.padEnd(14)}${installed} ${wired} ${mode}${hint}`);
|
|
26282
26478
|
}
|
|
26283
26479
|
console.log("");
|
|
26284
26480
|
if (!anyInstalled) {
|
|
26285
26481
|
console.log(
|
|
26286
|
-
|
|
26482
|
+
import_chalk24.default.gray(" No AI agents detected. Install Claude Code, Gemini CLI, Cursor,\n") + import_chalk24.default.gray(" Windsurf, VSCode, or Codex then run: node9 agents list\n")
|
|
26287
26483
|
);
|
|
26288
26484
|
return;
|
|
26289
26485
|
}
|
|
26290
26486
|
const unwired = statuses.filter((s) => s.installed && !s.wired);
|
|
26291
26487
|
if (unwired.length > 0) {
|
|
26292
26488
|
console.log(
|
|
26293
|
-
|
|
26489
|
+
import_chalk24.default.yellow(` ${unwired.length} agent(s) not yet wired. Run: `) + import_chalk24.default.white(`node9 agents add ${unwired[0].name}`) + "\n"
|
|
26294
26490
|
);
|
|
26295
26491
|
}
|
|
26296
26492
|
if (statuses.some((s) => s.name === "gemini" && s.installed)) {
|
|
26297
26493
|
console.log(
|
|
26298
|
-
|
|
26494
|
+
import_chalk24.default.yellow(
|
|
26299
26495
|
" \u26A0\uFE0F Gemini CLI stops serving AI Pro/Ultra and free tiers on 2026-06-18.\n"
|
|
26300
|
-
) +
|
|
26496
|
+
) + import_chalk24.default.gray(" Migrate to Antigravity: ") + import_chalk24.default.white("node9 agents add antigravity") + "\n"
|
|
26301
26497
|
);
|
|
26302
26498
|
}
|
|
26303
26499
|
});
|
|
@@ -26305,7 +26501,7 @@ function registerAgentsCommand(program2) {
|
|
|
26305
26501
|
const name = resolveAgentName(agent);
|
|
26306
26502
|
const fn = SETUP_FN[name];
|
|
26307
26503
|
if (!fn) {
|
|
26308
|
-
console.error(
|
|
26504
|
+
console.error(import_chalk24.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
|
|
26309
26505
|
process.exit(1);
|
|
26310
26506
|
}
|
|
26311
26507
|
await fn();
|
|
@@ -26314,14 +26510,14 @@ function registerAgentsCommand(program2) {
|
|
|
26314
26510
|
const name = resolveAgentName(agent);
|
|
26315
26511
|
const fn = TEARDOWN_FN[name];
|
|
26316
26512
|
if (!fn) {
|
|
26317
|
-
console.error(
|
|
26513
|
+
console.error(import_chalk24.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
|
|
26318
26514
|
process.exit(1);
|
|
26319
26515
|
}
|
|
26320
|
-
console.log(
|
|
26516
|
+
console.log(import_chalk24.default.cyan(`
|
|
26321
26517
|
\u{1F6E1}\uFE0F Node9: removing from ${name}...
|
|
26322
26518
|
`));
|
|
26323
26519
|
fn();
|
|
26324
|
-
console.log(
|
|
26520
|
+
console.log(import_chalk24.default.gray("\n Restart the agent for changes to take effect."));
|
|
26325
26521
|
});
|
|
26326
26522
|
}
|
|
26327
26523
|
|
|
@@ -26329,22 +26525,22 @@ function registerAgentsCommand(program2) {
|
|
|
26329
26525
|
init_scan();
|
|
26330
26526
|
|
|
26331
26527
|
// src/cli/commands/posture.ts
|
|
26332
|
-
var
|
|
26528
|
+
var import_chalk26 = __toESM(require("chalk"));
|
|
26333
26529
|
init_posture();
|
|
26334
26530
|
|
|
26335
26531
|
// src/posture/render.ts
|
|
26336
|
-
var
|
|
26532
|
+
var import_chalk25 = __toESM(require("chalk"));
|
|
26337
26533
|
init_score();
|
|
26338
26534
|
var ICON = {
|
|
26339
|
-
critical:
|
|
26340
|
-
high:
|
|
26341
|
-
medium:
|
|
26342
|
-
advisory:
|
|
26535
|
+
critical: import_chalk25.default.red("\u274C"),
|
|
26536
|
+
high: import_chalk25.default.red("\u274C"),
|
|
26537
|
+
medium: import_chalk25.default.yellow("\u26A0\uFE0F "),
|
|
26538
|
+
advisory: import_chalk25.default.gray("\u26A0\uFE0F ")
|
|
26343
26539
|
};
|
|
26344
26540
|
var TIER_LABEL = {
|
|
26345
|
-
good:
|
|
26346
|
-
"at-risk":
|
|
26347
|
-
critical:
|
|
26541
|
+
good: import_chalk25.default.green("Good"),
|
|
26542
|
+
"at-risk": import_chalk25.default.yellow("At risk"),
|
|
26543
|
+
critical: import_chalk25.default.red("Critical")
|
|
26348
26544
|
};
|
|
26349
26545
|
function wrap(text, width) {
|
|
26350
26546
|
const out = [];
|
|
@@ -26362,35 +26558,35 @@ function wrap(text, width) {
|
|
|
26362
26558
|
}
|
|
26363
26559
|
var LABEL_WIDTH = 14;
|
|
26364
26560
|
function label(category) {
|
|
26365
|
-
return
|
|
26561
|
+
return import_chalk25.default.bold(category.padEnd(Math.max(LABEL_WIDTH, category.length + 1)));
|
|
26366
26562
|
}
|
|
26367
26563
|
function renderFinding(f, showWeight = false) {
|
|
26368
26564
|
const lines = [];
|
|
26369
|
-
const wt = showWeight && f.scoreWeight ?
|
|
26565
|
+
const wt = showWeight && f.scoreWeight ? import_chalk25.default.cyan.bold(`+${f.scoreWeight} `) : "";
|
|
26370
26566
|
lines.push(` ${ICON[f.severity]} ${label(f.category)}${wt}${f.title}`);
|
|
26371
26567
|
const indent = " ".repeat(2 + 3 + LABEL_WIDTH);
|
|
26372
26568
|
const width = 80 - indent.length;
|
|
26373
26569
|
for (const s of [f.what, f.why, f.who]) {
|
|
26374
|
-
if (s) for (const l of wrap(s, width)) lines.push(indent +
|
|
26570
|
+
if (s) for (const l of wrap(s, width)) lines.push(indent + import_chalk25.default.gray(l));
|
|
26375
26571
|
}
|
|
26376
|
-
for (const d of f.detail) lines.push(indent +
|
|
26572
|
+
for (const d of f.detail) lines.push(indent + import_chalk25.default.gray(d));
|
|
26377
26573
|
if (f.fix) {
|
|
26378
26574
|
let first = true;
|
|
26379
26575
|
for (const seg of f.fix.split("\n")) {
|
|
26380
26576
|
for (const l of wrap(seg, width - 2)) {
|
|
26381
|
-
lines.push(indent +
|
|
26577
|
+
lines.push(indent + import_chalk25.default.cyan(first ? "\u2192 " + l : " " + l));
|
|
26382
26578
|
first = false;
|
|
26383
26579
|
}
|
|
26384
26580
|
}
|
|
26385
26581
|
}
|
|
26386
26582
|
const tradeoff = [
|
|
26387
|
-
[f.gain, "gain: ",
|
|
26388
|
-
[f.cost, "cost: ",
|
|
26583
|
+
[f.gain, "gain: ", import_chalk25.default.green],
|
|
26584
|
+
[f.cost, "cost: ", import_chalk25.default.yellow]
|
|
26389
26585
|
];
|
|
26390
26586
|
for (const [text, lbl, color2] of tradeoff) {
|
|
26391
26587
|
if (!text) continue;
|
|
26392
26588
|
wrap(text, width - 6).forEach((l, i) => {
|
|
26393
|
-
lines.push(indent + (i === 0 ? color2(lbl) : " ") +
|
|
26589
|
+
lines.push(indent + (i === 0 ? color2(lbl) : " ") + import_chalk25.default.gray(l));
|
|
26394
26590
|
});
|
|
26395
26591
|
}
|
|
26396
26592
|
return lines;
|
|
@@ -26400,12 +26596,12 @@ function renderPosture(result) {
|
|
|
26400
26596
|
const tier = TIER_LABEL[result.tier];
|
|
26401
26597
|
lines.push("");
|
|
26402
26598
|
lines.push(
|
|
26403
|
-
|
|
26599
|
+
import_chalk25.default.cyan.bold(`\u{1F6E1}\uFE0F Node9 Posture`) + import_chalk25.default.gray(` \u2014 ${result.agent}`) + ` ${import_chalk25.default.bold(`Score: ${result.score}/100`)} (${tier})`
|
|
26404
26600
|
);
|
|
26405
26601
|
const headroom = openHeadroom(result.findings);
|
|
26406
26602
|
if (headroom > 0) {
|
|
26407
26603
|
lines.push(
|
|
26408
|
-
" " +
|
|
26604
|
+
" " + import_chalk25.default.gray(
|
|
26409
26605
|
`${headroom} pts of headroom below \u2014 each layer adds security at some cost to flexibility. You choose which to close.`
|
|
26410
26606
|
)
|
|
26411
26607
|
);
|
|
@@ -26413,21 +26609,21 @@ function renderPosture(result) {
|
|
|
26413
26609
|
lines.push("");
|
|
26414
26610
|
if (result.headline) {
|
|
26415
26611
|
const indent = " ";
|
|
26416
|
-
lines.push(` ${
|
|
26417
|
-
for (const l of wrap(result.headline.risk, 74)) lines.push(indent +
|
|
26612
|
+
lines.push(` ${import_chalk25.default.red.bold("\u{1F525} Biggest risk")}`);
|
|
26613
|
+
for (const l of wrap(result.headline.risk, 74)) lines.push(indent + import_chalk25.default.white(l));
|
|
26418
26614
|
const action = wrap(`Do this first: ${result.headline.action}`, 72);
|
|
26419
|
-
action.forEach((l, i) => lines.push(indent +
|
|
26615
|
+
action.forEach((l, i) => lines.push(indent + import_chalk25.default.cyan(i === 0 ? "\u2192 " + l : " " + l)));
|
|
26420
26616
|
lines.push("");
|
|
26421
26617
|
}
|
|
26422
26618
|
const covered = result.findings.filter((f) => f.coverage?.state === "covered");
|
|
26423
26619
|
const open = result.findings.filter((f) => f.coverage?.state !== "covered");
|
|
26424
26620
|
if (covered.length > 0) {
|
|
26425
|
-
lines.push(" " +
|
|
26621
|
+
lines.push(" " + import_chalk25.default.green("\u{1F7E2} ON NOW \u2014 node9 is enforcing these (your floor)"));
|
|
26426
26622
|
for (const f of covered) {
|
|
26427
26623
|
const gated = f.coverage?.level === "review" ? "approval-gating" : "blocking";
|
|
26428
26624
|
const via = f.coverage?.via ?? "node9";
|
|
26429
26625
|
lines.push(
|
|
26430
|
-
` ${
|
|
26626
|
+
` ${import_chalk25.default.green("\u2705")} ${label(f.category)}${import_chalk25.default.gray(`${via} is ${gated} this`)}`
|
|
26431
26627
|
);
|
|
26432
26628
|
}
|
|
26433
26629
|
lines.push("");
|
|
@@ -26436,24 +26632,24 @@ function renderPosture(result) {
|
|
|
26436
26632
|
const reduceOpen = open.filter((f) => f.owner !== "node9" && f.node9Reduces);
|
|
26437
26633
|
const osOpen = open.filter((f) => f.owner !== "node9" && !f.node9Reduces);
|
|
26438
26634
|
if (node9Open.length > 0) {
|
|
26439
|
-
lines.push(" " +
|
|
26635
|
+
lines.push(" " + import_chalk25.default.cyan.bold("\u{1F527} node9 can fix these \u2014 run the command"));
|
|
26440
26636
|
for (const f of node9Open) lines.push(...renderFinding(f, true));
|
|
26441
26637
|
}
|
|
26442
26638
|
if (reduceOpen.length > 0) {
|
|
26443
26639
|
if (node9Open.length > 0) lines.push("");
|
|
26444
|
-
lines.push(" " +
|
|
26640
|
+
lines.push(" " + import_chalk25.default.yellow.bold("\u{1F512} AVAILABLE \u2014 turn on to harden (each has a tradeoff)"));
|
|
26445
26641
|
for (const f of reduceOpen) lines.push(...renderFinding(f, true));
|
|
26446
26642
|
}
|
|
26447
26643
|
if (osOpen.length > 0) {
|
|
26448
26644
|
if (node9Open.length > 0 || reduceOpen.length > 0) lines.push("");
|
|
26449
|
-
lines.push(" " +
|
|
26645
|
+
lines.push(" " + import_chalk25.default.bold("\u{1F9F1} YOUR PART \u2014 node9 can't fix these (OS-level)"));
|
|
26450
26646
|
for (const f of osOpen) lines.push(...renderFinding(f));
|
|
26451
26647
|
}
|
|
26452
26648
|
for (const cat of result.passedCategories) {
|
|
26453
|
-
lines.push(` ${
|
|
26649
|
+
lines.push(` ${import_chalk25.default.green("\u2705")} ${label(cat)}${import_chalk25.default.gray("no issues found")}`);
|
|
26454
26650
|
}
|
|
26455
26651
|
for (const cat of result.erroredCategories) {
|
|
26456
|
-
lines.push(` ${
|
|
26652
|
+
lines.push(` ${import_chalk25.default.gray("\u2022")} ${label(cat)}${import_chalk25.default.gray("could not be checked")}`);
|
|
26457
26653
|
}
|
|
26458
26654
|
lines.push("");
|
|
26459
26655
|
const crit = open.filter((f) => f.severity === "critical").length;
|
|
@@ -26461,16 +26657,16 @@ function renderPosture(result) {
|
|
|
26461
26657
|
const med = open.filter((f) => f.severity === "medium").length;
|
|
26462
26658
|
const adv = open.filter((f) => f.severity === "advisory").length;
|
|
26463
26659
|
const parts = [];
|
|
26464
|
-
if (crit) parts.push(
|
|
26465
|
-
if (high) parts.push(
|
|
26466
|
-
if (med) parts.push(
|
|
26467
|
-
if (adv) parts.push(
|
|
26468
|
-
const summary = parts.length ? parts.join(" \xB7 ") :
|
|
26660
|
+
if (crit) parts.push(import_chalk25.default.red(`${crit} critical`));
|
|
26661
|
+
if (high) parts.push(import_chalk25.default.red(`${high} high`));
|
|
26662
|
+
if (med) parts.push(import_chalk25.default.yellow(`${med} medium`));
|
|
26663
|
+
if (adv) parts.push(import_chalk25.default.gray(`${adv} advisory`));
|
|
26664
|
+
const summary = parts.length ? parts.join(" \xB7 ") : import_chalk25.default.green("no findings");
|
|
26469
26665
|
lines.push(` ${summary}`);
|
|
26470
26666
|
lines.push("");
|
|
26471
|
-
lines.push(" " +
|
|
26667
|
+
lines.push(" " + import_chalk25.default.bold("Track this across your fleet & keep it green:"));
|
|
26472
26668
|
lines.push(
|
|
26473
|
-
" " +
|
|
26669
|
+
" " + import_chalk25.default.dim("\u2192 ") + import_chalk25.default.cyan.underline("https://node9.ai/auth/signup?ref=cli_posture")
|
|
26474
26670
|
);
|
|
26475
26671
|
lines.push("");
|
|
26476
26672
|
return lines.join("\n");
|
|
@@ -26490,11 +26686,11 @@ function registerPostureCommand(program2) {
|
|
|
26490
26686
|
if (opts.ship) {
|
|
26491
26687
|
const creds = readCredentials();
|
|
26492
26688
|
if (!creds) {
|
|
26493
|
-
console.error(
|
|
26689
|
+
console.error(import_chalk26.default.gray(" Run `node9 login` to ship this to your dashboard."));
|
|
26494
26690
|
} else {
|
|
26495
26691
|
const ok2 = await shipPosture(result, creds);
|
|
26496
26692
|
console.error(
|
|
26497
|
-
ok2 ?
|
|
26693
|
+
ok2 ? import_chalk26.default.gray(" \u2713 Shipped to your node9 dashboard.") : import_chalk26.default.gray(" Could not reach the dashboard \u2014 saved locally only.")
|
|
26498
26694
|
);
|
|
26499
26695
|
}
|
|
26500
26696
|
}
|
|
@@ -26503,7 +26699,7 @@ function registerPostureCommand(program2) {
|
|
|
26503
26699
|
}
|
|
26504
26700
|
|
|
26505
26701
|
// src/cli/commands/egress.ts
|
|
26506
|
-
var
|
|
26702
|
+
var import_chalk27 = __toESM(require("chalk"));
|
|
26507
26703
|
init_config();
|
|
26508
26704
|
init_dist();
|
|
26509
26705
|
function guard(fn) {
|
|
@@ -26511,7 +26707,7 @@ function guard(fn) {
|
|
|
26511
26707
|
fn();
|
|
26512
26708
|
return true;
|
|
26513
26709
|
} catch (err2) {
|
|
26514
|
-
console.error(
|
|
26710
|
+
console.error(import_chalk27.default.red(`
|
|
26515
26711
|
\u2717 ${err2.message}
|
|
26516
26712
|
`));
|
|
26517
26713
|
process.exitCode = 1;
|
|
@@ -26526,19 +26722,19 @@ function addHost(list, host) {
|
|
|
26526
26722
|
}
|
|
26527
26723
|
function showStatus() {
|
|
26528
26724
|
const e = getConfig().policy.egress;
|
|
26529
|
-
const state = !e.enabled ?
|
|
26530
|
-
console.log(
|
|
26725
|
+
const state = !e.enabled ? import_chalk27.default.red("OFF \u2014 your agent can reach any host") : e.mode === "block" ? import_chalk27.default.green("LOCKED (block) \u2014 unknown hosts are denied") : import_chalk27.default.yellow("WATCHING (review) \u2014 unknown hosts prompt you");
|
|
26726
|
+
console.log(import_chalk27.default.cyan.bold("\n\u{1F310} Egress control"));
|
|
26531
26727
|
console.log(" State: " + state);
|
|
26532
26728
|
console.log(
|
|
26533
|
-
|
|
26729
|
+
import_chalk27.default.gray(
|
|
26534
26730
|
` ${DEFAULT_EGRESS_ALLOWLIST.length} common dev/LLM hosts are always allowed (github, npm, pypi, anthropic, \u2026).`
|
|
26535
26731
|
)
|
|
26536
26732
|
);
|
|
26537
26733
|
if (e.allow.length) console.log(" Your allow: " + e.allow.join(", "));
|
|
26538
26734
|
if (e.deny.length) console.log(" Your deny: " + e.deny.join(", "));
|
|
26539
26735
|
if (!e.enabled) {
|
|
26540
|
-
console.log(
|
|
26541
|
-
console.log(
|
|
26736
|
+
console.log(import_chalk27.default.gray("\n Turn it on: node9 egress watch (prompt on unknown hosts)"));
|
|
26737
|
+
console.log(import_chalk27.default.gray(" node9 egress lock (hard-block unknown hosts)"));
|
|
26542
26738
|
}
|
|
26543
26739
|
console.log("");
|
|
26544
26740
|
}
|
|
@@ -26546,43 +26742,43 @@ function registerEgressCommand(program2) {
|
|
|
26546
26742
|
const egress = program2.command("egress").description("Control where your agent can send data (egress allowlist)");
|
|
26547
26743
|
egress.command("watch").description("Prompt before the agent reaches an unknown host (review mode)").action(() => {
|
|
26548
26744
|
if (!mutate({ enabled: true, mode: "review" })) return;
|
|
26549
|
-
console.log(
|
|
26745
|
+
console.log(import_chalk27.default.green("\n\u2713 Egress is now watched (review mode)."));
|
|
26550
26746
|
console.log(
|
|
26551
|
-
|
|
26747
|
+
import_chalk27.default.gray(" Routine hosts (LLM APIs, package registries, localhost) are allowed.")
|
|
26552
26748
|
);
|
|
26553
26749
|
console.log(
|
|
26554
|
-
|
|
26750
|
+
import_chalk27.default.gray(" An unknown host will prompt you \u2014 run `node9 egress lock` to hard-block.\n")
|
|
26555
26751
|
);
|
|
26556
26752
|
});
|
|
26557
26753
|
egress.command("lock").description("Block the agent from reaching unknown hosts (block mode)").action(() => {
|
|
26558
26754
|
if (!mutate({ enabled: true, mode: "block" })) return;
|
|
26559
|
-
console.log(
|
|
26560
|
-
console.log(
|
|
26561
|
-
console.log(
|
|
26755
|
+
console.log(import_chalk27.default.green("\n\u2713 Egress is now locked (block mode)."));
|
|
26756
|
+
console.log(import_chalk27.default.gray(" Routine hosts are still allowed; unknown hosts are denied."));
|
|
26757
|
+
console.log(import_chalk27.default.gray(" Allow a specific host with `node9 egress allow <host>`.\n"));
|
|
26562
26758
|
});
|
|
26563
26759
|
egress.command("allow <host>").description("Allow an extra host (glob, e.g. *.mycorp.com)").action((host) => {
|
|
26564
26760
|
if (!addHost("allow", host)) return;
|
|
26565
|
-
console.log(
|
|
26761
|
+
console.log(import_chalk27.default.green(`
|
|
26566
26762
|
\u2713 Allowed egress to ${host}.
|
|
26567
26763
|
`));
|
|
26568
26764
|
});
|
|
26569
26765
|
egress.command("deny <host>").description("Block an extra host (deny always wins)").action((host) => {
|
|
26570
26766
|
if (!addHost("deny", host)) return;
|
|
26571
|
-
console.log(
|
|
26767
|
+
console.log(import_chalk27.default.green(`
|
|
26572
26768
|
\u2713 Denied egress to ${host}.
|
|
26573
26769
|
`));
|
|
26574
26770
|
});
|
|
26575
26771
|
egress.command("off").description("Turn egress control off").action(() => {
|
|
26576
26772
|
if (!mutate({ enabled: false })) return;
|
|
26577
26773
|
console.log(
|
|
26578
|
-
|
|
26774
|
+
import_chalk27.default.yellow("\n\u2713 Egress control is off \u2014 the agent can reach any host again.\n")
|
|
26579
26775
|
);
|
|
26580
26776
|
});
|
|
26581
26777
|
egress.action(showStatus);
|
|
26582
26778
|
}
|
|
26583
26779
|
|
|
26584
26780
|
// src/cli/commands/jail.ts
|
|
26585
|
-
var
|
|
26781
|
+
var import_chalk28 = __toESM(require("chalk"));
|
|
26586
26782
|
|
|
26587
26783
|
// src/shields/jail.ts
|
|
26588
26784
|
var import_fs55 = __toESM(require("fs"));
|
|
@@ -26677,20 +26873,20 @@ function registerJailCommand(program2) {
|
|
|
26677
26873
|
regenerateUserJail(paths);
|
|
26678
26874
|
appendConfigAudit({ event: "jail-add", path: p.trim(), verdict });
|
|
26679
26875
|
} catch (err2) {
|
|
26680
|
-
console.error(
|
|
26876
|
+
console.error(import_chalk28.default.red(`
|
|
26681
26877
|
\u274C ${err2.message}
|
|
26682
26878
|
`));
|
|
26683
26879
|
process.exit(1);
|
|
26684
26880
|
return;
|
|
26685
26881
|
}
|
|
26686
|
-
console.log(
|
|
26882
|
+
console.log(import_chalk28.default.green(`
|
|
26687
26883
|
\u2705 Jailed ${p} (${verdict}).`));
|
|
26688
26884
|
console.log(
|
|
26689
|
-
|
|
26885
|
+
import_chalk28.default.gray(
|
|
26690
26886
|
` AI reads of this path now ${verdict === "block" ? "BLOCK" : "require approval"}.`
|
|
26691
26887
|
)
|
|
26692
26888
|
);
|
|
26693
|
-
console.log(
|
|
26889
|
+
console.log(import_chalk28.default.gray(` Preview: ${import_chalk28.default.cyan(`node9 explain bash "cat ${p}"`)}
|
|
26694
26890
|
`));
|
|
26695
26891
|
});
|
|
26696
26892
|
jail.command("remove <path>").description("Remove a user-added jail path (built-in paths are not removable)").action((p) => {
|
|
@@ -26698,17 +26894,17 @@ function registerJailCommand(program2) {
|
|
|
26698
26894
|
try {
|
|
26699
26895
|
result = removeJailPath(p);
|
|
26700
26896
|
} catch (err2) {
|
|
26701
|
-
console.error(
|
|
26897
|
+
console.error(import_chalk28.default.red(`
|
|
26702
26898
|
\u274C ${err2.message}
|
|
26703
26899
|
`));
|
|
26704
26900
|
process.exit(1);
|
|
26705
26901
|
return;
|
|
26706
26902
|
}
|
|
26707
26903
|
if (!result.removed) {
|
|
26708
|
-
console.error(
|
|
26904
|
+
console.error(import_chalk28.default.yellow(`
|
|
26709
26905
|
\u2139\uFE0F "${p}" is not a user-added jail path.
|
|
26710
26906
|
`));
|
|
26711
|
-
console.error(
|
|
26907
|
+
console.error(import_chalk28.default.gray(` Run ${import_chalk28.default.cyan("node9 jail list")} to see your paths.
|
|
26712
26908
|
`));
|
|
26713
26909
|
process.exit(1);
|
|
26714
26910
|
return;
|
|
@@ -26717,39 +26913,39 @@ function registerJailCommand(program2) {
|
|
|
26717
26913
|
regenerateUserJail(result.paths);
|
|
26718
26914
|
appendConfigAudit({ event: "jail-remove", path: p.trim() });
|
|
26719
26915
|
} catch (err2) {
|
|
26720
|
-
console.error(
|
|
26916
|
+
console.error(import_chalk28.default.red(`
|
|
26721
26917
|
\u274C ${err2.message}
|
|
26722
26918
|
`));
|
|
26723
26919
|
process.exit(1);
|
|
26724
26920
|
return;
|
|
26725
26921
|
}
|
|
26726
|
-
console.log(
|
|
26922
|
+
console.log(import_chalk28.default.green(`
|
|
26727
26923
|
\u2705 Removed ${p} from the jail.
|
|
26728
26924
|
`));
|
|
26729
26925
|
});
|
|
26730
26926
|
jail.command("list").description("Show built-in + user-added jail paths").action(() => {
|
|
26731
|
-
console.log(
|
|
26732
|
-
console.log(
|
|
26733
|
-
for (const b of BUILTIN_JAIL) console.log(` ${
|
|
26927
|
+
console.log(import_chalk28.default.bold("\n\u{1F512} Credential Jail\n"));
|
|
26928
|
+
console.log(import_chalk28.default.gray(" Built-in (always on, not removable):"));
|
|
26929
|
+
for (const b of BUILTIN_JAIL) console.log(` ${import_chalk28.default.gray("\u2022")} ${b}`);
|
|
26734
26930
|
console.log("");
|
|
26735
26931
|
let user;
|
|
26736
26932
|
try {
|
|
26737
26933
|
user = readJailPaths();
|
|
26738
26934
|
} catch (err2) {
|
|
26739
|
-
console.error(
|
|
26935
|
+
console.error(import_chalk28.default.red(` \u2717 ${err2.message}
|
|
26740
26936
|
`));
|
|
26741
26937
|
process.exit(1);
|
|
26742
26938
|
return;
|
|
26743
26939
|
}
|
|
26744
26940
|
if (user.length === 0) {
|
|
26745
26941
|
console.log(
|
|
26746
|
-
|
|
26942
|
+
import_chalk28.default.gray(" Your paths: (none) \u2014 add one with ") + import_chalk28.default.cyan("node9 jail add <path>")
|
|
26747
26943
|
);
|
|
26748
26944
|
} else {
|
|
26749
|
-
console.log(
|
|
26945
|
+
console.log(import_chalk28.default.gray(" Your paths (removable):"));
|
|
26750
26946
|
for (const u of user) {
|
|
26751
|
-
const v = u.verdict === "block" ?
|
|
26752
|
-
console.log(` ${v} ${
|
|
26947
|
+
const v = u.verdict === "block" ? import_chalk28.default.red("block ") : import_chalk28.default.yellow("review");
|
|
26948
|
+
console.log(` ${v} ${import_chalk28.default.cyan(u.path)}`);
|
|
26753
26949
|
}
|
|
26754
26950
|
}
|
|
26755
26951
|
console.log("");
|
|
@@ -26757,7 +26953,7 @@ function registerJailCommand(program2) {
|
|
|
26757
26953
|
}
|
|
26758
26954
|
|
|
26759
26955
|
// src/cli/commands/sandbox.ts
|
|
26760
|
-
var
|
|
26956
|
+
var import_chalk29 = __toESM(require("chalk"));
|
|
26761
26957
|
var import_fs58 = __toESM(require("fs"));
|
|
26762
26958
|
var import_path56 = __toESM(require("path"));
|
|
26763
26959
|
var import_child_process13 = require("child_process");
|
|
@@ -26995,16 +27191,16 @@ function registerSandboxCommand(program2, version2) {
|
|
|
26995
27191
|
const p = sandboxConfigPath();
|
|
26996
27192
|
if (import_fs58.default.existsSync(p)) {
|
|
26997
27193
|
console.log(
|
|
26998
|
-
|
|
27194
|
+
import_chalk29.default.yellow(` ${SANDBOX_CONFIG_FILE} already exists \u2014 leaving it untouched.`)
|
|
26999
27195
|
);
|
|
27000
27196
|
return;
|
|
27001
27197
|
}
|
|
27002
27198
|
import_fs58.default.writeFileSync(p, scaffoldSandboxYaml(agent));
|
|
27003
27199
|
console.log(
|
|
27004
|
-
|
|
27200
|
+
import_chalk29.default.green(` \u2713 wrote ${SANDBOX_CONFIG_FILE}`) + import_chalk29.default.dim(` (agent: ${agent})`)
|
|
27005
27201
|
);
|
|
27006
27202
|
console.log(
|
|
27007
|
-
|
|
27203
|
+
import_chalk29.default.dim(" Edit it (mounts / allow / expose), then: ") + import_chalk29.default.cyan("node9 sandbox run")
|
|
27008
27204
|
);
|
|
27009
27205
|
});
|
|
27010
27206
|
cmd.command("run [agent]").description("Build (if needed) + run the agent jailed. Extra args after -- go to the agent.").allowUnknownOption(true).allowExcessArguments(true).action((agentArg, _opts, command) => {
|
|
@@ -27014,7 +27210,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
27014
27210
|
const engine = detectEngine(sandbox.runtime.engine);
|
|
27015
27211
|
if (!engine.available) {
|
|
27016
27212
|
console.error(
|
|
27017
|
-
|
|
27213
|
+
import_chalk29.default.red(` ${sandbox.runtime.engine} not found.`) + import_chalk29.default.dim(` Install it first \u2014 node9 sandbox needs a container runtime.`)
|
|
27018
27214
|
);
|
|
27019
27215
|
process.exit(1);
|
|
27020
27216
|
}
|
|
@@ -27027,11 +27223,11 @@ function registerSandboxCommand(program2, version2) {
|
|
|
27027
27223
|
});
|
|
27028
27224
|
if (compiled.rejected.length) {
|
|
27029
27225
|
console.log(
|
|
27030
|
-
|
|
27226
|
+
import_chalk29.default.yellow(` \u26A0 ignoring invalid allow hosts: ${compiled.rejected.join(", ")}`)
|
|
27031
27227
|
);
|
|
27032
27228
|
}
|
|
27033
27229
|
if (compiled.denied.length) {
|
|
27034
|
-
console.log(
|
|
27230
|
+
console.log(import_chalk29.default.dim(` (denied: ${compiled.denied.join(", ")})`));
|
|
27035
27231
|
}
|
|
27036
27232
|
const allowlistPath = writeAllowlist(cwd, compiled.allow);
|
|
27037
27233
|
const dockerfile = renderDockerfile(sandbox, node9Version2);
|
|
@@ -27044,12 +27240,12 @@ function registerSandboxCommand(program2, version2) {
|
|
|
27044
27240
|
const imageExists = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, ["image", "inspect", image], { stdio: "ignore" }).status === 0;
|
|
27045
27241
|
const needBuild = sandbox.runtime.rebuild === "always" || !imageExists || sandbox.runtime.rebuild !== "never" && lastHash !== hash;
|
|
27046
27242
|
if (needBuild) {
|
|
27047
|
-
console.log(
|
|
27243
|
+
console.log(import_chalk29.default.dim(` building ${image} \u2026`));
|
|
27048
27244
|
const b = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, ["build", "-t", image, buildDir], {
|
|
27049
27245
|
stdio: "inherit"
|
|
27050
27246
|
});
|
|
27051
27247
|
if (b.status !== 0) {
|
|
27052
|
-
console.error(
|
|
27248
|
+
console.error(import_chalk29.default.red(" build failed."));
|
|
27053
27249
|
process.exit(b.status ?? 1);
|
|
27054
27250
|
}
|
|
27055
27251
|
import_fs58.default.writeFileSync(hashFile, hash);
|
|
@@ -27067,15 +27263,15 @@ function registerSandboxCommand(program2, version2) {
|
|
|
27067
27263
|
if (sandbox.node9.mountAgentCredentials) {
|
|
27068
27264
|
const creds = agentCredentialsMount(sandbox.agent);
|
|
27069
27265
|
if (import_fs58.default.existsSync(creds.hostPath)) {
|
|
27070
|
-
console.log(
|
|
27266
|
+
console.log(import_chalk29.default.dim(` mounting ${creds.hostPath} (agent credentials, rw)`));
|
|
27071
27267
|
} else {
|
|
27072
27268
|
console.log(
|
|
27073
|
-
|
|
27269
|
+
import_chalk29.default.yellow(` \u26A0 ${creds.hostPath} not found \u2014 `) + import_chalk29.default.dim(`the agent must auth via an env key in env.pass.`)
|
|
27074
27270
|
);
|
|
27075
27271
|
}
|
|
27076
27272
|
}
|
|
27077
27273
|
console.log(
|
|
27078
|
-
|
|
27274
|
+
import_chalk29.default.green(` \u{1F6E1}\uFE0F ${sandbox.agent} jailed \u2014 ${compiled.allow.length} hosts allowed
|
|
27079
27275
|
`)
|
|
27080
27276
|
);
|
|
27081
27277
|
const r = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, runArgs, { stdio: "inherit" });
|
|
@@ -27084,7 +27280,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
27084
27280
|
cmd.command("tail").description("Stream the sandbox's audit log (host-side)").action(() => {
|
|
27085
27281
|
const auditPath = import_path56.default.join(sandboxDataDir(), "audit.log");
|
|
27086
27282
|
if (!import_fs58.default.existsSync(auditPath)) {
|
|
27087
|
-
console.log(
|
|
27283
|
+
console.log(import_chalk29.default.dim(" no sandbox audit yet."));
|
|
27088
27284
|
return;
|
|
27089
27285
|
}
|
|
27090
27286
|
(0, import_child_process13.spawnSync)("tail", ["-f", auditPath], { stdio: "inherit" });
|
|
@@ -27092,7 +27288,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
27092
27288
|
cmd.command("logs").description("Dump the sandbox's audit log").action(() => {
|
|
27093
27289
|
const auditPath = import_path56.default.join(sandboxDataDir(), "audit.log");
|
|
27094
27290
|
if (!import_fs58.default.existsSync(auditPath)) {
|
|
27095
|
-
console.log(
|
|
27291
|
+
console.log(import_chalk29.default.dim(" no sandbox audit yet."));
|
|
27096
27292
|
return;
|
|
27097
27293
|
}
|
|
27098
27294
|
process.stdout.write(import_fs58.default.readFileSync(auditPath, "utf-8"));
|
|
@@ -27110,12 +27306,12 @@ function registerSandboxCommand(program2, version2) {
|
|
|
27110
27306
|
});
|
|
27111
27307
|
}
|
|
27112
27308
|
import_fs58.default.rmSync(import_path56.default.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
|
|
27113
|
-
console.log(
|
|
27309
|
+
console.log(import_chalk29.default.green(" \u2713 sandbox image + build + data removed."));
|
|
27114
27310
|
});
|
|
27115
27311
|
}
|
|
27116
27312
|
|
|
27117
27313
|
// src/cli/commands/sessions.ts
|
|
27118
|
-
var
|
|
27314
|
+
var import_chalk30 = __toESM(require("chalk"));
|
|
27119
27315
|
var import_fs59 = __toESM(require("fs"));
|
|
27120
27316
|
var import_path57 = __toESM(require("path"));
|
|
27121
27317
|
var import_os50 = __toESM(require("os"));
|
|
@@ -27611,11 +27807,11 @@ function toolInputSummary(tool, input) {
|
|
|
27611
27807
|
}
|
|
27612
27808
|
function toolColor(tool) {
|
|
27613
27809
|
const t = tool.toLowerCase();
|
|
27614
|
-
if (t === "bash" || t === "execute_bash") return
|
|
27615
|
-
if (t === "write") return
|
|
27616
|
-
if (t === "edit" || t === "notebookedit") return
|
|
27617
|
-
if (t === "read") return
|
|
27618
|
-
return
|
|
27810
|
+
if (t === "bash" || t === "execute_bash") return import_chalk30.default.red;
|
|
27811
|
+
if (t === "write") return import_chalk30.default.green;
|
|
27812
|
+
if (t === "edit" || t === "notebookedit") return import_chalk30.default.yellow;
|
|
27813
|
+
if (t === "read") return import_chalk30.default.cyan;
|
|
27814
|
+
return import_chalk30.default.gray;
|
|
27619
27815
|
}
|
|
27620
27816
|
function barStr2(value, max, width) {
|
|
27621
27817
|
if (max === 0 || width <= 0) return "\u2591".repeat(width);
|
|
@@ -27625,7 +27821,7 @@ function barStr2(value, max, width) {
|
|
|
27625
27821
|
function colorBar2(value, max, width) {
|
|
27626
27822
|
const s = barStr2(value, max, width);
|
|
27627
27823
|
const filled = Math.max(1, Math.round(max > 0 ? value / max * width : 0));
|
|
27628
|
-
return
|
|
27824
|
+
return import_chalk30.default.cyan(s.slice(0, filled)) + import_chalk30.default.dim(s.slice(filled));
|
|
27629
27825
|
}
|
|
27630
27826
|
function renderSummary(summaries) {
|
|
27631
27827
|
const totalTools = summaries.reduce((n, s) => n + s.toolCalls.length, 0);
|
|
@@ -27655,45 +27851,45 @@ function renderSummary(summaries) {
|
|
|
27655
27851
|
}
|
|
27656
27852
|
const topProjects = [...projCosts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
27657
27853
|
const W = 20;
|
|
27658
|
-
console.log(
|
|
27854
|
+
console.log(import_chalk30.default.dim(" " + "\u2500".repeat(70)));
|
|
27659
27855
|
console.log(
|
|
27660
|
-
" " +
|
|
27856
|
+
" " + import_chalk30.default.bold.white(String(summaries.length).padEnd(4)) + import_chalk30.default.dim("sessions ") + import_chalk30.default.bold.yellow(fmtCost3(totalCost).padEnd(10)) + import_chalk30.default.dim("total ") + import_chalk30.default.bold.white(String(totalTools).padEnd(6)) + import_chalk30.default.dim("tool calls ") + import_chalk30.default.bold.white(String(totalFiles)) + import_chalk30.default.dim(" files modified") + (totalBlocked > 0 ? import_chalk30.default.dim(" ") + import_chalk30.default.red.bold(String(totalBlocked)) + import_chalk30.default.dim(" blocked by node9") : "")
|
|
27661
27857
|
);
|
|
27662
27858
|
console.log(
|
|
27663
|
-
" " +
|
|
27859
|
+
" " + import_chalk30.default.dim("avg ") + import_chalk30.default.white(fmtCost3(avgCost).padEnd(10)) + import_chalk30.default.dim("/session ") + import_chalk30.default.green(String(snapshots)) + import_chalk30.default.dim(` of ${summaries.length} sessions had snapshots`)
|
|
27664
27860
|
);
|
|
27665
27861
|
console.log("");
|
|
27666
|
-
console.log(" " +
|
|
27862
|
+
console.log(" " + import_chalk30.default.dim("Tool breakdown:"));
|
|
27667
27863
|
const maxGroup = Math.max(...Object.values(groups));
|
|
27668
27864
|
for (const [label2, count] of Object.entries(groups)) {
|
|
27669
27865
|
if (count === 0) continue;
|
|
27670
27866
|
const pct = totalTools > 0 ? Math.round(count / totalTools * 100) : 0;
|
|
27671
27867
|
console.log(
|
|
27672
|
-
" " + label2.padEnd(6) + " " + colorBar2(count, maxGroup, W) + " " +
|
|
27868
|
+
" " + label2.padEnd(6) + " " + colorBar2(count, maxGroup, W) + " " + import_chalk30.default.white(String(count).padStart(4)) + import_chalk30.default.dim(` (${String(pct)}%)`)
|
|
27673
27869
|
);
|
|
27674
27870
|
}
|
|
27675
27871
|
console.log("");
|
|
27676
27872
|
if (topProjects.length > 1) {
|
|
27677
|
-
console.log(" " +
|
|
27873
|
+
console.log(" " + import_chalk30.default.dim("Cost by project:"));
|
|
27678
27874
|
const maxProjCost = topProjects[0][1];
|
|
27679
27875
|
for (const [proj, cost] of topProjects) {
|
|
27680
27876
|
console.log(
|
|
27681
|
-
" " + proj.slice(0, 28).padEnd(28) + " " + colorBar2(cost, maxProjCost, W) + " " +
|
|
27877
|
+
" " + proj.slice(0, 28).padEnd(28) + " " + colorBar2(cost, maxProjCost, W) + " " + import_chalk30.default.yellow(fmtCost3(cost))
|
|
27682
27878
|
);
|
|
27683
27879
|
}
|
|
27684
27880
|
console.log("");
|
|
27685
27881
|
}
|
|
27686
|
-
console.log(
|
|
27882
|
+
console.log(import_chalk30.default.dim(" " + "\u2500".repeat(70)));
|
|
27687
27883
|
console.log("");
|
|
27688
27884
|
}
|
|
27689
27885
|
function renderList(summaries, totalCost) {
|
|
27690
27886
|
if (summaries.length === 0) {
|
|
27691
|
-
console.log(
|
|
27887
|
+
console.log(import_chalk30.default.yellow(" No sessions found in the requested range.\n"));
|
|
27692
27888
|
return;
|
|
27693
27889
|
}
|
|
27694
|
-
const totalLabel = totalCost > 0 ?
|
|
27890
|
+
const totalLabel = totalCost > 0 ? import_chalk30.default.dim(" ~" + fmtCost3(totalCost) + " total") : "";
|
|
27695
27891
|
console.log(
|
|
27696
|
-
" " +
|
|
27892
|
+
" " + import_chalk30.default.white(String(summaries.length)) + import_chalk30.default.dim(` session${summaries.length !== 1 ? "s" : ""}`) + totalLabel
|
|
27697
27893
|
);
|
|
27698
27894
|
console.log("");
|
|
27699
27895
|
let lastGroup = "";
|
|
@@ -27701,51 +27897,51 @@ function renderList(summaries, totalCost) {
|
|
|
27701
27897
|
const activeDate = fmtDate2(s.lastActiveTime);
|
|
27702
27898
|
const group = activeDate + " " + s.projectLabel;
|
|
27703
27899
|
if (group !== lastGroup) {
|
|
27704
|
-
console.log(
|
|
27900
|
+
console.log(import_chalk30.default.dim(" \u2500\u2500\u2500 ") + import_chalk30.default.bold(activeDate) + import_chalk30.default.dim(" " + s.projectLabel));
|
|
27705
27901
|
lastGroup = group;
|
|
27706
27902
|
}
|
|
27707
27903
|
const startDate = fmtDate2(s.startTime);
|
|
27708
|
-
const dateRange = startDate !== activeDate ?
|
|
27709
|
-
const timeStr =
|
|
27710
|
-
const prompt =
|
|
27711
|
-
const tools = s.toolCalls.length > 0 ?
|
|
27712
|
-
const cost = s.costUSD > 0 ?
|
|
27713
|
-
const blocked = s.blockedCalls.length > 0 ?
|
|
27714
|
-
const snap = s.hasSnapshot ?
|
|
27715
|
-
const agentBadge =
|
|
27904
|
+
const dateRange = startDate !== activeDate ? import_chalk30.default.dim(" (" + startDate + " \u2192 " + activeDate + ")") : "";
|
|
27905
|
+
const timeStr = import_chalk30.default.dim(fmtTime(s.startTime));
|
|
27906
|
+
const prompt = import_chalk30.default.white(truncate(s.firstPrompt.replace(/\n/g, " "), 50).padEnd(50));
|
|
27907
|
+
const tools = s.toolCalls.length > 0 ? import_chalk30.default.dim(String(s.toolCalls.length).padStart(3) + " tools") : import_chalk30.default.dim(" 0 tools");
|
|
27908
|
+
const cost = s.costUSD > 0 ? import_chalk30.default.dim(" " + fmtCost3(s.costUSD).padEnd(8)) : " ";
|
|
27909
|
+
const blocked = s.blockedCalls.length > 0 ? import_chalk30.default.red(" \u{1F6D1} " + String(s.blockedCalls.length)) : "";
|
|
27910
|
+
const snap = s.hasSnapshot ? import_chalk30.default.green(" \u{1F4F8}") : "";
|
|
27911
|
+
const agentBadge = import_chalk30.default[agentColorName(s.agent ?? "claude")](
|
|
27716
27912
|
" " + agentBadgeText(s.agent ?? "claude", 0)
|
|
27717
27913
|
);
|
|
27718
|
-
const sid =
|
|
27914
|
+
const sid = import_chalk30.default.dim(" " + s.sessionId.slice(0, 8));
|
|
27719
27915
|
console.log(
|
|
27720
27916
|
` ${timeStr} ${prompt} ${tools}${cost}${blocked}${snap}${agentBadge}${sid}${dateRange}`
|
|
27721
27917
|
);
|
|
27722
27918
|
}
|
|
27723
27919
|
console.log("");
|
|
27724
27920
|
console.log(
|
|
27725
|
-
|
|
27921
|
+
import_chalk30.default.dim(" Run") + " " + import_chalk30.default.cyan("node9 sessions --detail <session-id>") + import_chalk30.default.dim(" for full tool trace.")
|
|
27726
27922
|
);
|
|
27727
27923
|
console.log("");
|
|
27728
27924
|
}
|
|
27729
27925
|
function renderDetail(s) {
|
|
27730
27926
|
console.log("");
|
|
27731
|
-
console.log(
|
|
27927
|
+
console.log(import_chalk30.default.bold(" Session ") + import_chalk30.default.dim(s.sessionId));
|
|
27732
27928
|
console.log(
|
|
27733
|
-
|
|
27929
|
+
import_chalk30.default.bold(" Prompt ") + import_chalk30.default.white(s.firstPrompt.replace(/\n/g, " ").slice(0, 120))
|
|
27734
27930
|
);
|
|
27735
|
-
console.log(
|
|
27931
|
+
console.log(import_chalk30.default.bold(" Project ") + import_chalk30.default.white(s.projectLabel));
|
|
27736
27932
|
if (s.agent) {
|
|
27737
|
-
const agentLabel2 =
|
|
27738
|
-
console.log(
|
|
27933
|
+
const agentLabel2 = import_chalk30.default[agentColorName(s.agent)](agentDisplayName(s.agent));
|
|
27934
|
+
console.log(import_chalk30.default.bold(" Agent ") + agentLabel2);
|
|
27739
27935
|
}
|
|
27740
|
-
console.log(
|
|
27936
|
+
console.log(import_chalk30.default.bold(" When ") + import_chalk30.default.white(fmtDateTime(s.startTime)));
|
|
27741
27937
|
if (s.costUSD > 0)
|
|
27742
|
-
console.log(
|
|
27938
|
+
console.log(import_chalk30.default.bold(" Cost ") + import_chalk30.default.yellow("~" + fmtCost3(s.costUSD)));
|
|
27743
27939
|
console.log(
|
|
27744
|
-
|
|
27940
|
+
import_chalk30.default.bold(" Snapshot ") + (s.hasSnapshot ? import_chalk30.default.green("\u2713 taken") : import_chalk30.default.dim("none"))
|
|
27745
27941
|
);
|
|
27746
27942
|
console.log("");
|
|
27747
27943
|
if (s.toolCalls.length === 0 && s.blockedCalls.length === 0) {
|
|
27748
|
-
console.log(
|
|
27944
|
+
console.log(import_chalk30.default.dim(" No tool calls recorded.\n"));
|
|
27749
27945
|
return;
|
|
27750
27946
|
}
|
|
27751
27947
|
const timeline = [
|
|
@@ -27758,32 +27954,32 @@ function renderDetail(s) {
|
|
|
27758
27954
|
});
|
|
27759
27955
|
const headerParts = [`Tool calls (${s.toolCalls.length})`];
|
|
27760
27956
|
if (s.blockedCalls.length > 0)
|
|
27761
|
-
headerParts.push(
|
|
27762
|
-
console.log(
|
|
27957
|
+
headerParts.push(import_chalk30.default.red(`${s.blockedCalls.length} blocked by node9`));
|
|
27958
|
+
console.log(import_chalk30.default.bold(" " + headerParts.join(" \xB7 ")));
|
|
27763
27959
|
console.log("");
|
|
27764
27960
|
for (const entry of timeline) {
|
|
27765
27961
|
if (entry.kind === "tool") {
|
|
27766
27962
|
const tc = entry.tc;
|
|
27767
27963
|
const colorFn = toolColor(tc.tool);
|
|
27768
27964
|
const toolPad = colorFn(tc.tool.padEnd(16));
|
|
27769
|
-
const detail =
|
|
27770
|
-
const ts = tc.timestamp ?
|
|
27965
|
+
const detail = import_chalk30.default.gray(truncate(toolInputSummary(tc.tool, tc.input), 70));
|
|
27966
|
+
const ts = tc.timestamp ? import_chalk30.default.dim(fmtTime(tc.timestamp) + " ") : " ";
|
|
27771
27967
|
console.log(` ${ts}${toolPad} ${detail}`);
|
|
27772
27968
|
} else {
|
|
27773
27969
|
const bc = entry.bc;
|
|
27774
|
-
const ts = bc.timestamp ?
|
|
27775
|
-
const label2 =
|
|
27776
|
-
const toolName =
|
|
27777
|
-
const argsSummary = bc.args ?
|
|
27778
|
-
const reason = bc.checkedBy ?
|
|
27970
|
+
const ts = bc.timestamp ? import_chalk30.default.dim(fmtTime(bc.timestamp) + " ") : " ";
|
|
27971
|
+
const label2 = import_chalk30.default.red("\u{1F6D1} BLOCKED".padEnd(16));
|
|
27972
|
+
const toolName = import_chalk30.default.red(bc.tool.padEnd(10));
|
|
27973
|
+
const argsSummary = bc.args ? import_chalk30.default.gray(truncate(toolInputSummary(bc.tool, bc.args), 40)) : import_chalk30.default.dim("[args not logged]");
|
|
27974
|
+
const reason = bc.checkedBy ? import_chalk30.default.dim(" \u2190 " + bc.checkedBy) : "";
|
|
27779
27975
|
console.log(` ${ts}${label2} ${toolName} ${argsSummary}${reason}`);
|
|
27780
27976
|
}
|
|
27781
27977
|
}
|
|
27782
27978
|
console.log("");
|
|
27783
27979
|
if (s.modifiedFiles.length > 0) {
|
|
27784
|
-
console.log(
|
|
27980
|
+
console.log(import_chalk30.default.bold(` Files modified (${s.modifiedFiles.length}):`));
|
|
27785
27981
|
for (const f of s.modifiedFiles) {
|
|
27786
|
-
console.log(" " +
|
|
27982
|
+
console.log(" " + import_chalk30.default.yellow(f));
|
|
27787
27983
|
}
|
|
27788
27984
|
console.log("");
|
|
27789
27985
|
}
|
|
@@ -27791,13 +27987,13 @@ function renderDetail(s) {
|
|
|
27791
27987
|
function registerSessionsCommand(program2) {
|
|
27792
27988
|
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) => {
|
|
27793
27989
|
console.log("");
|
|
27794
|
-
console.log(
|
|
27990
|
+
console.log(import_chalk30.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk30.default.dim(" \u2014 what your AI agent did"));
|
|
27795
27991
|
console.log("");
|
|
27796
27992
|
const days = options.detail || options.all ? null : Math.max(1, parseInt(options.days, 10) || 7);
|
|
27797
27993
|
const rangeLabel = options.detail ? "all time" : options.all ? "all time" : `last ${String(days)} days`;
|
|
27798
|
-
console.log(
|
|
27994
|
+
console.log(import_chalk30.default.dim(" " + rangeLabel));
|
|
27799
27995
|
console.log("");
|
|
27800
|
-
process.stdout.write(
|
|
27996
|
+
process.stdout.write(import_chalk30.default.dim(" Loading\u2026"));
|
|
27801
27997
|
const summaries = buildSessions(days);
|
|
27802
27998
|
if (process.stdout.isTTY) {
|
|
27803
27999
|
process.stdout.clearLine(0);
|
|
@@ -27810,8 +28006,8 @@ function registerSessionsCommand(program2) {
|
|
|
27810
28006
|
(s) => s.sessionId === options.detail || s.sessionId.startsWith(options.detail)
|
|
27811
28007
|
);
|
|
27812
28008
|
if (!target) {
|
|
27813
|
-
console.log(
|
|
27814
|
-
console.log(
|
|
28009
|
+
console.log(import_chalk30.default.red(` Session not found: ${options.detail}`));
|
|
28010
|
+
console.log(import_chalk30.default.dim(" Run `node9 sessions` to list recent sessions.\n"));
|
|
27815
28011
|
return;
|
|
27816
28012
|
}
|
|
27817
28013
|
renderDetail(target);
|
|
@@ -27824,7 +28020,7 @@ function registerSessionsCommand(program2) {
|
|
|
27824
28020
|
}
|
|
27825
28021
|
|
|
27826
28022
|
// src/cli/commands/session-taint.ts
|
|
27827
|
-
var
|
|
28023
|
+
var import_chalk31 = __toESM(require("chalk"));
|
|
27828
28024
|
init_daemon();
|
|
27829
28025
|
function resolveSessionId(records, query) {
|
|
27830
28026
|
const exact = records.find((r) => r.sessionId === query);
|
|
@@ -27851,22 +28047,22 @@ function registerSessionTaintCommand(program2) {
|
|
|
27851
28047
|
const records = await listSessionTaints();
|
|
27852
28048
|
console.log("");
|
|
27853
28049
|
if (records.length === 0) {
|
|
27854
|
-
console.log(
|
|
27855
|
-
console.log(
|
|
28050
|
+
console.log(import_chalk31.default.dim(" No tainted sessions."));
|
|
28051
|
+
console.log(import_chalk31.default.dim(" (Taint lives in the daemon \u2014 a stopped daemon has none.)") + "\n");
|
|
27856
28052
|
return;
|
|
27857
28053
|
}
|
|
27858
28054
|
console.log(
|
|
27859
|
-
" " +
|
|
28055
|
+
" " + import_chalk31.default.bold(String(records.length)) + import_chalk31.default.dim(` tainted session${records.length !== 1 ? "s" : ""}`)
|
|
27860
28056
|
);
|
|
27861
28057
|
console.log("");
|
|
27862
28058
|
for (const r of records) {
|
|
27863
28059
|
console.log(
|
|
27864
|
-
" " +
|
|
28060
|
+
" " + import_chalk31.default.yellow(r.sessionId.slice(0, 8).padEnd(10)) + import_chalk31.default.red(r.source) + sourceGap(r.source) + import_chalk31.default.dim("clears in " + fmtRemaining(r.expiresAt))
|
|
27865
28061
|
);
|
|
27866
28062
|
}
|
|
27867
28063
|
console.log("");
|
|
27868
28064
|
console.log(
|
|
27869
|
-
|
|
28065
|
+
import_chalk31.default.dim(" Run ") + import_chalk31.default.cyan("node9 session-taint clear <id>") + import_chalk31.default.dim(" to release one, or ") + import_chalk31.default.cyan("--all") + import_chalk31.default.dim(" for every session.") + "\n"
|
|
27870
28066
|
);
|
|
27871
28067
|
});
|
|
27872
28068
|
cmd.command("clear").description("Clear a session's taint so its next network/write action isn't held for review").argument("[sessionId]", "Session id to clear (the 8-char prefix from `list` is accepted)").option("--all", "Clear every session taint").action(async (sessionId, opts) => {
|
|
@@ -27874,32 +28070,32 @@ function registerSessionTaintCommand(program2) {
|
|
|
27874
28070
|
if (opts.all) {
|
|
27875
28071
|
const res2 = await clearSessionTaint({ all: true });
|
|
27876
28072
|
if (res2.daemonUnavailable) {
|
|
27877
|
-
console.log(
|
|
28073
|
+
console.log(import_chalk31.default.dim(" node9 daemon not running \u2014 no active taints to clear.") + "\n");
|
|
27878
28074
|
return;
|
|
27879
28075
|
}
|
|
27880
28076
|
console.log(
|
|
27881
|
-
|
|
28077
|
+
import_chalk31.default.green(" \u2713 ") + `Cleared ${import_chalk31.default.bold(String(res2.cleared))} session taint${res2.cleared !== 1 ? "s" : ""}.
|
|
27882
28078
|
`
|
|
27883
28079
|
);
|
|
27884
28080
|
return;
|
|
27885
28081
|
}
|
|
27886
28082
|
if (!sessionId) {
|
|
27887
|
-
console.log(
|
|
27888
|
-
console.log(
|
|
28083
|
+
console.log(import_chalk31.default.red(" Provide a session id or --all."));
|
|
28084
|
+
console.log(import_chalk31.default.dim(" Run `node9 session-taint list` to see tainted sessions.") + "\n");
|
|
27889
28085
|
return;
|
|
27890
28086
|
}
|
|
27891
28087
|
const records = await listSessionTaints();
|
|
27892
28088
|
if (records.length === 0) {
|
|
27893
|
-
console.log(
|
|
28089
|
+
console.log(import_chalk31.default.dim(" No tainted sessions \u2014 nothing to clear.") + "\n");
|
|
27894
28090
|
return;
|
|
27895
28091
|
}
|
|
27896
28092
|
const resolved = resolveSessionId(records, sessionId);
|
|
27897
28093
|
if ("error" in resolved) {
|
|
27898
28094
|
if (resolved.error === "not-found") {
|
|
27899
|
-
console.log(
|
|
28095
|
+
console.log(import_chalk31.default.red(` No tainted session matches "${sessionId}".`));
|
|
27900
28096
|
} else {
|
|
27901
|
-
console.log(
|
|
27902
|
-
for (const m of resolved.matches) console.log(
|
|
28097
|
+
console.log(import_chalk31.default.red(` "${sessionId}" is ambiguous \u2014 matches:`));
|
|
28098
|
+
for (const m of resolved.matches) console.log(import_chalk31.default.dim(" " + m));
|
|
27903
28099
|
}
|
|
27904
28100
|
console.log("");
|
|
27905
28101
|
return;
|
|
@@ -27907,18 +28103,18 @@ function registerSessionTaintCommand(program2) {
|
|
|
27907
28103
|
const res = await clearSessionTaint({ sessionId: resolved.record.sessionId });
|
|
27908
28104
|
if (res.cleared > 0) {
|
|
27909
28105
|
console.log(
|
|
27910
|
-
|
|
28106
|
+
import_chalk31.default.green(" \u2713 ") + `Cleared taint for ${import_chalk31.default.yellow(resolved.record.sessionId.slice(0, 8))} ` + import_chalk31.default.dim(`(was flagged by ${resolved.record.source}).`) + "\n"
|
|
27911
28107
|
);
|
|
27912
28108
|
} else {
|
|
27913
28109
|
console.log(
|
|
27914
|
-
|
|
28110
|
+
import_chalk31.default.dim(` Session ${resolved.record.sessionId.slice(0, 8)} was already clear.`) + "\n"
|
|
27915
28111
|
);
|
|
27916
28112
|
}
|
|
27917
28113
|
});
|
|
27918
28114
|
}
|
|
27919
28115
|
|
|
27920
28116
|
// src/cli/commands/skill-pin.ts
|
|
27921
|
-
var
|
|
28117
|
+
var import_chalk32 = __toESM(require("chalk"));
|
|
27922
28118
|
var import_fs60 = __toESM(require("fs"));
|
|
27923
28119
|
var import_os51 = __toESM(require("os"));
|
|
27924
28120
|
var import_path58 = __toESM(require("path"));
|
|
@@ -27938,29 +28134,29 @@ function registerSkillPinCommand(program2) {
|
|
|
27938
28134
|
const result = readSkillPinsSafe();
|
|
27939
28135
|
if (!result.ok) {
|
|
27940
28136
|
if (result.reason === "missing") {
|
|
27941
|
-
console.log(
|
|
28137
|
+
console.log(import_chalk32.default.gray("\nNo skill roots are pinned yet."));
|
|
27942
28138
|
console.log(
|
|
27943
|
-
|
|
28139
|
+
import_chalk32.default.gray("Pins are created automatically on the first tool call of each session.\n")
|
|
27944
28140
|
);
|
|
27945
28141
|
return;
|
|
27946
28142
|
}
|
|
27947
|
-
console.error(
|
|
28143
|
+
console.error(import_chalk32.default.red(`
|
|
27948
28144
|
\u274C Pin file is corrupt: ${result.detail}`));
|
|
27949
|
-
console.error(
|
|
28145
|
+
console.error(import_chalk32.default.yellow(" Run: node9 skill pin reset\n"));
|
|
27950
28146
|
process.exit(1);
|
|
27951
28147
|
}
|
|
27952
28148
|
const entries = Object.entries(result.pins.roots);
|
|
27953
28149
|
if (entries.length === 0) {
|
|
27954
|
-
console.log(
|
|
28150
|
+
console.log(import_chalk32.default.gray("\nNo skill roots are pinned yet.\n"));
|
|
27955
28151
|
return;
|
|
27956
28152
|
}
|
|
27957
|
-
console.log(
|
|
28153
|
+
console.log(import_chalk32.default.bold("\n\u{1F512} Pinned Skill Roots\n"));
|
|
27958
28154
|
for (const [key, entry] of entries) {
|
|
27959
|
-
const missing = entry.exists ? "" :
|
|
27960
|
-
console.log(` ${
|
|
28155
|
+
const missing = entry.exists ? "" : import_chalk32.default.yellow(" (not present at pin time)");
|
|
28156
|
+
console.log(` ${import_chalk32.default.cyan(key)} ${import_chalk32.default.gray(entry.rootPath)}${missing}`);
|
|
27961
28157
|
console.log(` Files (${entry.fileCount})`);
|
|
27962
|
-
console.log(` Hash: ${
|
|
27963
|
-
console.log(` Pinned: ${
|
|
28158
|
+
console.log(` Hash: ${import_chalk32.default.gray(entry.contentHash.slice(0, 16))}...`);
|
|
28159
|
+
console.log(` Pinned: ${import_chalk32.default.gray(entry.pinnedAt)}
|
|
27964
28160
|
`);
|
|
27965
28161
|
}
|
|
27966
28162
|
});
|
|
@@ -27969,39 +28165,39 @@ function registerSkillPinCommand(program2) {
|
|
|
27969
28165
|
try {
|
|
27970
28166
|
pins = readSkillPins();
|
|
27971
28167
|
} catch {
|
|
27972
|
-
console.error(
|
|
27973
|
-
console.error(
|
|
28168
|
+
console.error(import_chalk32.default.red("\n\u274C Pin file is corrupt."));
|
|
28169
|
+
console.error(import_chalk32.default.yellow(" Run: node9 skill pin reset\n"));
|
|
27974
28170
|
process.exit(1);
|
|
27975
28171
|
}
|
|
27976
28172
|
if (!pins.roots[rootKey]) {
|
|
27977
|
-
console.error(
|
|
28173
|
+
console.error(import_chalk32.default.red(`
|
|
27978
28174
|
\u274C No pin found for root key "${rootKey}"
|
|
27979
28175
|
`));
|
|
27980
|
-
console.error(`Run ${
|
|
28176
|
+
console.error(`Run ${import_chalk32.default.cyan("node9 skill pin list")} to see pinned roots.
|
|
27981
28177
|
`);
|
|
27982
28178
|
process.exit(1);
|
|
27983
28179
|
}
|
|
27984
28180
|
const rootPath = pins.roots[rootKey].rootPath;
|
|
27985
28181
|
removePin2(rootKey);
|
|
27986
28182
|
wipeSkillSessions();
|
|
27987
|
-
console.log(
|
|
27988
|
-
\u{1F513} Pin removed for ${
|
|
27989
|
-
console.log(
|
|
27990
|
-
console.log(
|
|
28183
|
+
console.log(import_chalk32.default.green(`
|
|
28184
|
+
\u{1F513} Pin removed for ${import_chalk32.default.cyan(rootKey)}`));
|
|
28185
|
+
console.log(import_chalk32.default.gray(` ${rootPath}`));
|
|
28186
|
+
console.log(import_chalk32.default.gray(" Next session will re-pin with current state.\n"));
|
|
27991
28187
|
});
|
|
27992
28188
|
pinSubCmd.command("reset").description("Clear all skill pins and wipe session verification flags").action(() => {
|
|
27993
28189
|
const result = readSkillPinsSafe();
|
|
27994
28190
|
if (!result.ok && result.reason === "missing") {
|
|
27995
28191
|
wipeSkillSessions();
|
|
27996
|
-
console.log(
|
|
28192
|
+
console.log(import_chalk32.default.gray("\nNo pins to clear.\n"));
|
|
27997
28193
|
return;
|
|
27998
28194
|
}
|
|
27999
28195
|
const count = result.ok ? Object.keys(result.pins.roots).length : "?";
|
|
28000
28196
|
clearAllPins2();
|
|
28001
28197
|
wipeSkillSessions();
|
|
28002
|
-
console.log(
|
|
28198
|
+
console.log(import_chalk32.default.green(`
|
|
28003
28199
|
\u{1F513} Cleared ${count} skill pin(s).`));
|
|
28004
|
-
console.log(
|
|
28200
|
+
console.log(import_chalk32.default.gray(" Next session will re-pin with current state.\n"));
|
|
28005
28201
|
});
|
|
28006
28202
|
}
|
|
28007
28203
|
|
|
@@ -28009,7 +28205,7 @@ function registerSkillPinCommand(program2) {
|
|
|
28009
28205
|
var import_fs61 = __toESM(require("fs"));
|
|
28010
28206
|
var import_os52 = __toESM(require("os"));
|
|
28011
28207
|
var import_path59 = __toESM(require("path"));
|
|
28012
|
-
var
|
|
28208
|
+
var import_chalk33 = __toESM(require("chalk"));
|
|
28013
28209
|
var DECISIONS_FILE2 = import_path59.default.join(import_os52.default.homedir(), ".node9", "decisions.json");
|
|
28014
28210
|
function readDecisions() {
|
|
28015
28211
|
try {
|
|
@@ -28038,55 +28234,55 @@ function registerDecisionsCommand(program2) {
|
|
|
28038
28234
|
const decisions = readDecisions();
|
|
28039
28235
|
const entries = Object.entries(decisions);
|
|
28040
28236
|
if (entries.length === 0) {
|
|
28041
|
-
console.log(
|
|
28237
|
+
console.log(import_chalk33.default.gray(" No persistent decisions stored."));
|
|
28042
28238
|
console.log(
|
|
28043
|
-
|
|
28044
|
-
`) +
|
|
28239
|
+
import_chalk33.default.gray(` File: ${DECISIONS_FILE2}
|
|
28240
|
+
`) + import_chalk33.default.gray(' Decisions are written when you click "Always Allow" or')
|
|
28045
28241
|
);
|
|
28046
|
-
console.log(
|
|
28242
|
+
console.log(import_chalk33.default.gray(' "Always Deny" in node9 tail or the native popup.'));
|
|
28047
28243
|
return;
|
|
28048
28244
|
}
|
|
28049
|
-
console.log(
|
|
28245
|
+
console.log(import_chalk33.default.bold(`
|
|
28050
28246
|
Persistent decisions (${entries.length})
|
|
28051
28247
|
`));
|
|
28052
28248
|
const w = Math.max(...entries.map(([k]) => k.length));
|
|
28053
28249
|
for (const [tool, verdict] of entries.sort()) {
|
|
28054
|
-
const colored = verdict === "allow" ?
|
|
28250
|
+
const colored = verdict === "allow" ? import_chalk33.default.green(verdict) : import_chalk33.default.red(verdict);
|
|
28055
28251
|
console.log(` ${tool.padEnd(w)} ${colored}`);
|
|
28056
28252
|
}
|
|
28057
28253
|
console.log(
|
|
28058
|
-
|
|
28254
|
+
import_chalk33.default.gray(`
|
|
28059
28255
|
Stored in ${DECISIONS_FILE2}
|
|
28060
|
-
`) +
|
|
28256
|
+
`) + import_chalk33.default.gray(" Run `node9 decisions clear <tool>` to remove an entry.")
|
|
28061
28257
|
);
|
|
28062
28258
|
});
|
|
28063
28259
|
cmd.command("clear <toolName>").description("Remove a persistent decision for one tool").action((toolName) => {
|
|
28064
28260
|
const decisions = readDecisions();
|
|
28065
28261
|
if (!(toolName in decisions)) {
|
|
28066
|
-
console.log(
|
|
28262
|
+
console.log(import_chalk33.default.yellow(` No persistent decision for "${toolName}". Nothing to clear.`));
|
|
28067
28263
|
process.exitCode = 1;
|
|
28068
28264
|
return;
|
|
28069
28265
|
}
|
|
28070
28266
|
delete decisions[toolName];
|
|
28071
28267
|
writeDecisions(decisions);
|
|
28072
|
-
console.log(
|
|
28268
|
+
console.log(import_chalk33.default.green(` \u2713 Cleared persistent decision for "${toolName}".`));
|
|
28073
28269
|
});
|
|
28074
28270
|
cmd.command("clear-all").description("Remove every persistent decision (irreversible)").action(() => {
|
|
28075
28271
|
const decisions = readDecisions();
|
|
28076
28272
|
const count = Object.keys(decisions).length;
|
|
28077
28273
|
if (count === 0) {
|
|
28078
|
-
console.log(
|
|
28274
|
+
console.log(import_chalk33.default.gray(" Nothing to clear \u2014 no persistent decisions stored."));
|
|
28079
28275
|
return;
|
|
28080
28276
|
}
|
|
28081
28277
|
writeDecisions({});
|
|
28082
28278
|
console.log(
|
|
28083
|
-
|
|
28279
|
+
import_chalk33.default.green(` \u2713 Cleared ${count} persistent decision${count === 1 ? "" : "s"}.`)
|
|
28084
28280
|
);
|
|
28085
28281
|
});
|
|
28086
28282
|
}
|
|
28087
28283
|
|
|
28088
28284
|
// src/cli/commands/dlp.ts
|
|
28089
|
-
var
|
|
28285
|
+
var import_chalk34 = __toESM(require("chalk"));
|
|
28090
28286
|
var import_fs62 = __toESM(require("fs"));
|
|
28091
28287
|
var import_path60 = __toESM(require("path"));
|
|
28092
28288
|
var import_os53 = __toESM(require("os"));
|
|
@@ -28141,14 +28337,14 @@ function registerDlpCommand(program2) {
|
|
|
28141
28337
|
cmd.command("resolve").description("Mark all current DLP findings as resolved").action(() => {
|
|
28142
28338
|
const findings = loadDlpFindings();
|
|
28143
28339
|
if (findings.length === 0) {
|
|
28144
|
-
console.log(
|
|
28340
|
+
console.log(import_chalk34.default.green("\n \u2705 No response-DLP findings to resolve.\n"));
|
|
28145
28341
|
return;
|
|
28146
28342
|
}
|
|
28147
28343
|
const resolved = loadResolved();
|
|
28148
28344
|
for (const e of findings) resolved.add(entryKey2(e));
|
|
28149
28345
|
saveResolved(resolved);
|
|
28150
28346
|
console.log(
|
|
28151
|
-
|
|
28347
|
+
import_chalk34.default.green(
|
|
28152
28348
|
`
|
|
28153
28349
|
\u2705 ${findings.length} finding${findings.length !== 1 ? "s" : ""} marked as resolved.
|
|
28154
28350
|
`
|
|
@@ -28162,54 +28358,54 @@ function registerDlpCommand(program2) {
|
|
|
28162
28358
|
const resolvedCount = findings.length - open.length;
|
|
28163
28359
|
console.log("");
|
|
28164
28360
|
console.log(
|
|
28165
|
-
|
|
28361
|
+
import_chalk34.default.bold.cyan("\u{1F510} node9 dlp") + import_chalk34.default.dim(" \u2014 secrets found in Claude response text")
|
|
28166
28362
|
);
|
|
28167
28363
|
console.log("");
|
|
28168
28364
|
if (open.length === 0) {
|
|
28169
28365
|
if (resolvedCount > 0) {
|
|
28170
|
-
console.log(
|
|
28366
|
+
console.log(import_chalk34.default.green(` \u2705 No open findings \xB7 ${resolvedCount} previously resolved`));
|
|
28171
28367
|
} else {
|
|
28172
28368
|
console.log(
|
|
28173
|
-
|
|
28369
|
+
import_chalk34.default.green(" \u2705 No findings \u2014 Claude has not leaked secrets in response text")
|
|
28174
28370
|
);
|
|
28175
28371
|
}
|
|
28176
28372
|
console.log("");
|
|
28177
28373
|
return;
|
|
28178
28374
|
}
|
|
28179
28375
|
console.log(
|
|
28180
|
-
|
|
28376
|
+
import_chalk34.default.bgRed.white.bold(` \u26A0\uFE0F ${open.length} open finding${open.length !== 1 ? "s" : ""} `) + import_chalk34.default.dim(resolvedCount > 0 ? ` (${resolvedCount} resolved)` : "")
|
|
28181
28377
|
);
|
|
28182
28378
|
console.log("");
|
|
28183
28379
|
console.log(
|
|
28184
|
-
|
|
28380
|
+
import_chalk34.default.dim(" These secrets were included in Claude's response text \u2014 NOT blocked.")
|
|
28185
28381
|
);
|
|
28186
|
-
console.log(
|
|
28382
|
+
console.log(import_chalk34.default.dim(" Rotate each affected key immediately.\n"));
|
|
28187
28383
|
for (const e of open) {
|
|
28188
28384
|
console.log(
|
|
28189
|
-
" " +
|
|
28385
|
+
" " + import_chalk34.default.red("\u25CF") + " " + import_chalk34.default.white(e.dlpPattern ?? "Secret") + import_chalk34.default.dim(" " + fmtDate3(e.ts))
|
|
28190
28386
|
);
|
|
28191
28387
|
if (e.dlpSample) {
|
|
28192
|
-
console.log(" " +
|
|
28388
|
+
console.log(" " + import_chalk34.default.dim("Sample: ") + import_chalk34.default.yellow(stripAnsi(e.dlpSample)));
|
|
28193
28389
|
}
|
|
28194
28390
|
if (e.project) {
|
|
28195
|
-
console.log(" " +
|
|
28391
|
+
console.log(" " + import_chalk34.default.dim("Project: ") + import_chalk34.default.dim(stripAnsi(e.project)));
|
|
28196
28392
|
}
|
|
28197
28393
|
console.log("");
|
|
28198
28394
|
}
|
|
28199
|
-
console.log(" " +
|
|
28200
|
-
console.log(" " +
|
|
28395
|
+
console.log(" " + import_chalk34.default.bold("Next steps:"));
|
|
28396
|
+
console.log(" " + import_chalk34.default.cyan("1.") + " Rotate any exposed keys shown above");
|
|
28201
28397
|
console.log(
|
|
28202
|
-
" " +
|
|
28398
|
+
" " + import_chalk34.default.cyan("2.") + " Run " + import_chalk34.default.white("node9 dlp resolve") + " to acknowledge"
|
|
28203
28399
|
);
|
|
28204
28400
|
console.log(
|
|
28205
|
-
" " +
|
|
28401
|
+
" " + import_chalk34.default.cyan("3.") + " Run " + import_chalk34.default.white("node9 report") + " for full audit history"
|
|
28206
28402
|
);
|
|
28207
28403
|
console.log("");
|
|
28208
28404
|
});
|
|
28209
28405
|
}
|
|
28210
28406
|
|
|
28211
28407
|
// src/cli/commands/mask.ts
|
|
28212
|
-
var
|
|
28408
|
+
var import_chalk35 = __toESM(require("chalk"));
|
|
28213
28409
|
var import_fs63 = __toESM(require("fs"));
|
|
28214
28410
|
var import_path61 = __toESM(require("path"));
|
|
28215
28411
|
var import_os54 = __toESM(require("os"));
|
|
@@ -28346,12 +28542,12 @@ function registerMaskCommand(program2) {
|
|
|
28346
28542
|
}
|
|
28347
28543
|
}) : allFiles;
|
|
28348
28544
|
if (filtered.length === 0) {
|
|
28349
|
-
console.log(
|
|
28545
|
+
console.log(import_chalk35.default.yellow(" No session files found."));
|
|
28350
28546
|
return;
|
|
28351
28547
|
}
|
|
28352
28548
|
console.log("");
|
|
28353
28549
|
if (dryRun) {
|
|
28354
|
-
console.log(
|
|
28550
|
+
console.log(import_chalk35.default.dim(" Dry run \u2014 no files will be modified.\n"));
|
|
28355
28551
|
}
|
|
28356
28552
|
let totalFiles = 0;
|
|
28357
28553
|
let totalLines = 0;
|
|
@@ -28367,23 +28563,23 @@ function registerMaskCommand(program2) {
|
|
|
28367
28563
|
});
|
|
28368
28564
|
const verb = dryRun ? "Would redact" : "Redacted";
|
|
28369
28565
|
console.log(
|
|
28370
|
-
" " +
|
|
28566
|
+
" " + import_chalk35.default.dim(shortPath.slice(0, 60).padEnd(62)) + import_chalk35.default.red(`${verb}: `) + import_chalk35.default.yellow(patterns.join(", ")) + import_chalk35.default.dim(` (${redactedLines} line${redactedLines !== 1 ? "s" : ""})`)
|
|
28371
28567
|
);
|
|
28372
28568
|
}
|
|
28373
28569
|
}
|
|
28374
28570
|
console.log("");
|
|
28375
28571
|
if (totalFiles === 0) {
|
|
28376
|
-
console.log(
|
|
28572
|
+
console.log(import_chalk35.default.green(" No secrets found in session history."));
|
|
28377
28573
|
} else {
|
|
28378
28574
|
const verb = dryRun ? "would be modified" : "modified";
|
|
28379
28575
|
console.log(
|
|
28380
|
-
|
|
28576
|
+
import_chalk35.default.bold(` ${totalFiles} file${totalFiles !== 1 ? "s" : ""} ${verb}`) + import_chalk35.default.dim(`, ${totalLines} line${totalLines !== 1 ? "s" : ""} redacted`)
|
|
28381
28577
|
);
|
|
28382
|
-
console.log(" Patterns: " +
|
|
28578
|
+
console.log(" Patterns: " + import_chalk35.default.yellow(totalPatterns.join(", ")));
|
|
28383
28579
|
if (!dryRun) {
|
|
28384
28580
|
console.log("");
|
|
28385
28581
|
console.log(
|
|
28386
|
-
|
|
28582
|
+
import_chalk35.default.dim(
|
|
28387
28583
|
" Note: secrets were already sent to the AI provider during the active session.\n This cleans your local disk only. Rotate any exposed keys."
|
|
28388
28584
|
)
|
|
28389
28585
|
);
|
|
@@ -28401,77 +28597,34 @@ var { version } = JSON.parse(
|
|
|
28401
28597
|
var program = new import_commander.Command();
|
|
28402
28598
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
28403
28599
|
program.command("login").argument("<apiKey>").option("--local", "Save key for audit/logging only \u2014 local config still controls all decisions").option("--profile <name>", 'Save as a named profile (default: "default")').action((apiKey, options) => {
|
|
28404
|
-
const
|
|
28405
|
-
|
|
28406
|
-
|
|
28407
|
-
|
|
28408
|
-
const profileName = options.profile || "default";
|
|
28409
|
-
let existingCreds = {};
|
|
28410
|
-
try {
|
|
28411
|
-
if (import_fs66.default.existsSync(credPath)) {
|
|
28412
|
-
const raw = JSON.parse(import_fs66.default.readFileSync(credPath, "utf-8"));
|
|
28413
|
-
if (raw.apiKey) {
|
|
28414
|
-
existingCreds = {
|
|
28415
|
-
default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
|
|
28416
|
-
};
|
|
28417
|
-
} else {
|
|
28418
|
-
existingCreds = raw;
|
|
28419
|
-
}
|
|
28420
|
-
}
|
|
28421
|
-
} catch {
|
|
28422
|
-
}
|
|
28423
|
-
existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
|
|
28424
|
-
import_fs66.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
|
|
28425
|
-
let effectiveCloud = null;
|
|
28426
|
-
if (profileName === "default") {
|
|
28427
|
-
const configPath = import_path64.default.join(import_os57.default.homedir(), ".node9", "config.json");
|
|
28428
|
-
let config = {};
|
|
28429
|
-
try {
|
|
28430
|
-
if (import_fs66.default.existsSync(configPath))
|
|
28431
|
-
config = JSON.parse(import_fs66.default.readFileSync(configPath, "utf-8"));
|
|
28432
|
-
} catch {
|
|
28433
|
-
}
|
|
28434
|
-
if (!config.settings || typeof config.settings !== "object") config.settings = {};
|
|
28435
|
-
const s = config.settings;
|
|
28436
|
-
const approvers = s.approvers || {
|
|
28437
|
-
native: true,
|
|
28438
|
-
browser: true,
|
|
28439
|
-
cloud: true,
|
|
28440
|
-
terminal: true
|
|
28441
|
-
};
|
|
28442
|
-
if (options.local) {
|
|
28443
|
-
approvers.cloud = false;
|
|
28444
|
-
}
|
|
28445
|
-
s.approvers = approvers;
|
|
28446
|
-
if (!import_fs66.default.existsSync(import_path64.default.dirname(configPath)))
|
|
28447
|
-
import_fs66.default.mkdirSync(import_path64.default.dirname(configPath), { recursive: true });
|
|
28448
|
-
import_fs66.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
28449
|
-
effectiveCloud = approvers.cloud === true;
|
|
28450
|
-
}
|
|
28600
|
+
const { profileName, effectiveCloud } = writeCredentialsAndConfig(apiKey, {
|
|
28601
|
+
profileName: options.profile,
|
|
28602
|
+
isLocal: options.local
|
|
28603
|
+
});
|
|
28451
28604
|
if (options.profile && profileName !== "default") {
|
|
28452
|
-
console.log(
|
|
28453
|
-
console.log(
|
|
28605
|
+
console.log(import_chalk37.default.green(`\u2705 Profile "${profileName}" saved`));
|
|
28606
|
+
console.log(import_chalk37.default.gray(` Switch to it per-session: NODE9_PROFILE=${profileName} claude`));
|
|
28454
28607
|
} else if (options.local || effectiveCloud === false) {
|
|
28455
|
-
console.log(
|
|
28456
|
-
console.log(
|
|
28608
|
+
console.log(import_chalk37.default.green(`\u2705 Key saved \u2014 Privacy mode \u{1F6E1}\uFE0F`));
|
|
28609
|
+
console.log(import_chalk37.default.gray(` All decisions stay on this machine. Nothing syncs to the cloud.`));
|
|
28457
28610
|
if (!options.local) {
|
|
28458
28611
|
console.log(
|
|
28459
|
-
|
|
28612
|
+
import_chalk37.default.yellow(` Your config has cloud approvals OFF (settings.approvers.cloud).`)
|
|
28460
28613
|
);
|
|
28461
28614
|
console.log(
|
|
28462
|
-
|
|
28615
|
+
import_chalk37.default.gray(` To enable team policy + dashboard sync: set it to true, or re-init.`)
|
|
28463
28616
|
);
|
|
28464
28617
|
}
|
|
28465
28618
|
} else {
|
|
28466
|
-
console.log(
|
|
28467
|
-
console.log(
|
|
28619
|
+
console.log(import_chalk37.default.green(`\u2705 Logged in \u2014 agent mode`));
|
|
28620
|
+
console.log(import_chalk37.default.gray(` Team policy enforced for all calls via Node9 cloud.`));
|
|
28468
28621
|
}
|
|
28469
28622
|
});
|
|
28470
28623
|
program.command("signup").description("Create your node9 account / open the dashboard in your browser").option("--login", "Open the login page instead of signup").action((options) => {
|
|
28471
28624
|
const route = options.login ? "auth/login" : "auth/signup";
|
|
28472
28625
|
const url = `https://node9.ai/${route}?ref=cli_cmd`;
|
|
28473
28626
|
console.log("");
|
|
28474
|
-
console.log(" " +
|
|
28627
|
+
console.log(" " + import_chalk37.default.dim("Opening ") + import_chalk37.default.cyan.underline(url));
|
|
28475
28628
|
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
28476
28629
|
try {
|
|
28477
28630
|
const child = (0, import_child_process15.spawn)(opener, [url], {
|
|
@@ -28504,7 +28657,7 @@ program.command("addto", { hidden: true }).description("Integrate Node9 with an
|
|
|
28504
28657
|
if (target === "hermes") return setupHermes();
|
|
28505
28658
|
if (target === "hud") return setupHud();
|
|
28506
28659
|
console.error(
|
|
28507
|
-
|
|
28660
|
+
import_chalk37.default.red(
|
|
28508
28661
|
`Unknown target: "${target}". Supported: claude, antigravity, copilot, gemini, cursor, codex, windsurf, vscode, hermes, hud`
|
|
28509
28662
|
)
|
|
28510
28663
|
);
|
|
@@ -28518,20 +28671,20 @@ program.command("setup", { hidden: true }).description('Alias for "addto" \u2014
|
|
|
28518
28671
|
"The agent to protect: claude | antigravity | copilot | gemini | cursor | codex | windsurf | vscode | hud"
|
|
28519
28672
|
).action(async (target) => {
|
|
28520
28673
|
if (!target) {
|
|
28521
|
-
console.log(
|
|
28522
|
-
console.log(" Usage: " +
|
|
28674
|
+
console.log(import_chalk37.default.cyan("\n\u{1F6E1}\uFE0F Node9 Setup \u2014 integrate with your AI agent\n"));
|
|
28675
|
+
console.log(" Usage: " + import_chalk37.default.white("node9 setup <target>") + "\n");
|
|
28523
28676
|
console.log(" Targets:");
|
|
28524
|
-
console.log(" " +
|
|
28525
|
-
console.log(" " +
|
|
28526
|
-
console.log(" " +
|
|
28527
|
-
console.log(" " +
|
|
28528
|
-
console.log(" " +
|
|
28529
|
-
console.log(" " +
|
|
28530
|
-
console.log(" " +
|
|
28531
|
-
console.log(" " +
|
|
28532
|
-
console.log(" " +
|
|
28677
|
+
console.log(" " + import_chalk37.default.green("claude") + " \u2014 Claude Code (hook mode)");
|
|
28678
|
+
console.log(" " + import_chalk37.default.green("gemini") + " \u2014 Gemini CLI (hook mode)");
|
|
28679
|
+
console.log(" " + import_chalk37.default.green("antigravity") + " \u2014 Antigravity / agy (hook mode)");
|
|
28680
|
+
console.log(" " + import_chalk37.default.green("copilot") + " \u2014 GitHub Copilot CLI (hook mode)");
|
|
28681
|
+
console.log(" " + import_chalk37.default.green("cursor") + " \u2014 Cursor (MCP proxy)");
|
|
28682
|
+
console.log(" " + import_chalk37.default.green("codex") + " \u2014 OpenAI Codex CLI (MCP proxy)");
|
|
28683
|
+
console.log(" " + import_chalk37.default.green("windsurf") + " \u2014 Windsurf (MCP proxy)");
|
|
28684
|
+
console.log(" " + import_chalk37.default.green("vscode") + " \u2014 VSCode / Copilot (MCP proxy)");
|
|
28685
|
+
console.log(" " + import_chalk37.default.green("hermes") + " \u2014 Hermes Agent (hook mode)");
|
|
28533
28686
|
process.stdout.write(
|
|
28534
|
-
" " +
|
|
28687
|
+
" " + import_chalk37.default.green("hud") + " \u2014 Claude Code security statusline\n"
|
|
28535
28688
|
);
|
|
28536
28689
|
console.log("");
|
|
28537
28690
|
return;
|
|
@@ -28548,7 +28701,7 @@ program.command("setup", { hidden: true }).description('Alias for "addto" \u2014
|
|
|
28548
28701
|
if (t === "hermes") return setupHermes();
|
|
28549
28702
|
if (t === "hud") return setupHud();
|
|
28550
28703
|
console.error(
|
|
28551
|
-
|
|
28704
|
+
import_chalk37.default.red(
|
|
28552
28705
|
`Unknown target: "${target}". Supported: claude, antigravity, copilot, gemini, cursor, codex, windsurf, vscode, hermes, hud`
|
|
28553
28706
|
)
|
|
28554
28707
|
);
|
|
@@ -28559,32 +28712,32 @@ program.command("removefrom", { hidden: true }).description("Remove Node9 hooks
|
|
|
28559
28712
|
const agent = resolveAgentTeardown(target);
|
|
28560
28713
|
if (!agent) {
|
|
28561
28714
|
console.error(
|
|
28562
|
-
|
|
28715
|
+
import_chalk37.default.red(`Unknown target: "${target}". Supported: ${agentTeardownTargets().join(", ")}`)
|
|
28563
28716
|
);
|
|
28564
28717
|
process.exit(1);
|
|
28565
28718
|
return;
|
|
28566
28719
|
}
|
|
28567
|
-
console.log(
|
|
28720
|
+
console.log(import_chalk37.default.cyan(`
|
|
28568
28721
|
\u{1F6E1}\uFE0F Node9: removing hooks from ${agent.label}...
|
|
28569
28722
|
`));
|
|
28570
28723
|
try {
|
|
28571
28724
|
agent.fn();
|
|
28572
28725
|
} catch (err2) {
|
|
28573
|
-
console.error(
|
|
28726
|
+
console.error(import_chalk37.default.red(` \u26A0\uFE0F Failed: ${err2 instanceof Error ? err2.message : String(err2)}`));
|
|
28574
28727
|
process.exit(1);
|
|
28575
28728
|
}
|
|
28576
|
-
console.log(
|
|
28729
|
+
console.log(import_chalk37.default.gray("\n Restart the agent for changes to take effect."));
|
|
28577
28730
|
});
|
|
28578
28731
|
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) => {
|
|
28579
|
-
console.log(
|
|
28580
|
-
console.log(
|
|
28732
|
+
console.log(import_chalk37.default.cyan("\n\u{1F6E1}\uFE0F Node9 Uninstall\n"));
|
|
28733
|
+
console.log(import_chalk37.default.bold("Stopping daemon..."));
|
|
28581
28734
|
try {
|
|
28582
28735
|
stopDaemon();
|
|
28583
|
-
console.log(
|
|
28736
|
+
console.log(import_chalk37.default.green(" \u2705 Daemon stopped"));
|
|
28584
28737
|
} catch {
|
|
28585
|
-
console.log(
|
|
28738
|
+
console.log(import_chalk37.default.blue(" \u2139\uFE0F Daemon was not running"));
|
|
28586
28739
|
}
|
|
28587
|
-
console.log(
|
|
28740
|
+
console.log(import_chalk37.default.bold("\nRemoving hooks..."));
|
|
28588
28741
|
let teardownFailed = false;
|
|
28589
28742
|
for (const { label: label2, fn } of AGENT_TEARDOWNS) {
|
|
28590
28743
|
try {
|
|
@@ -28592,7 +28745,7 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
28592
28745
|
} catch (err2) {
|
|
28593
28746
|
teardownFailed = true;
|
|
28594
28747
|
console.error(
|
|
28595
|
-
|
|
28748
|
+
import_chalk37.default.red(
|
|
28596
28749
|
` \u26A0\uFE0F Failed to remove ${label2} hooks: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
28597
28750
|
)
|
|
28598
28751
|
);
|
|
@@ -28601,12 +28754,12 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
28601
28754
|
try {
|
|
28602
28755
|
const residual = getAgentWiring().filter((a) => a.wireState === "wired");
|
|
28603
28756
|
if (residual.length === 0) {
|
|
28604
|
-
console.log(
|
|
28757
|
+
console.log(import_chalk37.default.green(" \u2705 Verified \u2014 no node9 hooks or plugin shims remain"));
|
|
28605
28758
|
} else {
|
|
28606
28759
|
teardownFailed = true;
|
|
28607
|
-
console.error(
|
|
28760
|
+
console.error(import_chalk37.default.red(" \u26A0\uFE0F Still wired after teardown:"));
|
|
28608
28761
|
for (const a of residual) {
|
|
28609
|
-
console.error(
|
|
28762
|
+
console.error(import_chalk37.default.red(` \u2022 ${a.label} \u2014 ${a.settingsPath}`));
|
|
28610
28763
|
}
|
|
28611
28764
|
}
|
|
28612
28765
|
} catch {
|
|
@@ -28622,28 +28775,28 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
28622
28775
|
import_fs66.default.rmSync(node9Dir, { recursive: true });
|
|
28623
28776
|
if (import_fs66.default.existsSync(node9Dir)) {
|
|
28624
28777
|
console.error(
|
|
28625
|
-
|
|
28778
|
+
import_chalk37.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
28626
28779
|
);
|
|
28627
28780
|
} else {
|
|
28628
|
-
console.log(
|
|
28781
|
+
console.log(import_chalk37.default.green("\n \u2705 Deleted ~/.node9/ (config, audit log, credentials)"));
|
|
28629
28782
|
}
|
|
28630
28783
|
} else {
|
|
28631
|
-
console.log(
|
|
28784
|
+
console.log(import_chalk37.default.yellow("\n Skipped \u2014 ~/.node9/ was not deleted."));
|
|
28632
28785
|
}
|
|
28633
28786
|
} else {
|
|
28634
|
-
console.log(
|
|
28787
|
+
console.log(import_chalk37.default.blue("\n \u2139\uFE0F ~/.node9/ not found \u2014 nothing to delete"));
|
|
28635
28788
|
}
|
|
28636
28789
|
} else {
|
|
28637
28790
|
console.log(
|
|
28638
|
-
|
|
28791
|
+
import_chalk37.default.gray("\n ~/.node9/ kept \u2014 run with --purge to delete config and audit log")
|
|
28639
28792
|
);
|
|
28640
28793
|
}
|
|
28641
28794
|
if (teardownFailed) {
|
|
28642
|
-
console.error(
|
|
28795
|
+
console.error(import_chalk37.default.red("\n \u26A0\uFE0F Some hooks could not be removed \u2014 see errors above."));
|
|
28643
28796
|
process.exit(1);
|
|
28644
28797
|
}
|
|
28645
|
-
console.log(
|
|
28646
|
-
console.log(
|
|
28798
|
+
console.log(import_chalk37.default.green.bold("\n\u{1F6E1}\uFE0F Node9 removed. Run: npm uninstall -g node9-ai"));
|
|
28799
|
+
console.log(import_chalk37.default.gray(" Restart any open AI agent sessions for changes to take effect.\n"));
|
|
28647
28800
|
});
|
|
28648
28801
|
registerDoctorCommand(program, version);
|
|
28649
28802
|
program.command("explain").description(
|
|
@@ -28656,7 +28809,7 @@ program.command("explain").description(
|
|
|
28656
28809
|
try {
|
|
28657
28810
|
args = JSON.parse(trimmed);
|
|
28658
28811
|
} catch {
|
|
28659
|
-
console.error(
|
|
28812
|
+
console.error(import_chalk37.default.red(`
|
|
28660
28813
|
\u274C Invalid JSON: ${trimmed}
|
|
28661
28814
|
`));
|
|
28662
28815
|
process.exit(1);
|
|
@@ -28667,67 +28820,68 @@ program.command("explain").description(
|
|
|
28667
28820
|
}
|
|
28668
28821
|
const result = await explainPolicy(tool, args);
|
|
28669
28822
|
console.log("");
|
|
28670
|
-
console.log(
|
|
28823
|
+
console.log(import_chalk37.default.cyan.bold("\u{1F6E1}\uFE0F Node9 Explain"));
|
|
28671
28824
|
console.log("");
|
|
28672
|
-
console.log(` ${
|
|
28825
|
+
console.log(` ${import_chalk37.default.bold("Tool:")} ${import_chalk37.default.white(result.tool)}`);
|
|
28673
28826
|
if (argsRaw) {
|
|
28674
28827
|
const preview2 = argsRaw.length > 80 ? argsRaw.slice(0, 77) + "\u2026" : argsRaw;
|
|
28675
|
-
console.log(` ${
|
|
28828
|
+
console.log(` ${import_chalk37.default.bold("Input:")} ${import_chalk37.default.gray(preview2)}`);
|
|
28676
28829
|
}
|
|
28677
28830
|
console.log("");
|
|
28678
|
-
console.log(
|
|
28831
|
+
console.log(import_chalk37.default.bold("Config Sources (Waterfall):"));
|
|
28679
28832
|
for (const tier of result.waterfall) {
|
|
28680
|
-
const num3 =
|
|
28833
|
+
const num3 = import_chalk37.default.gray(` ${tier.tier}.`);
|
|
28681
28834
|
const label2 = tier.label.padEnd(16);
|
|
28682
28835
|
let statusStr;
|
|
28683
28836
|
if (tier.tier === 1) {
|
|
28684
|
-
statusStr =
|
|
28837
|
+
statusStr = import_chalk37.default.gray(tier.note ?? "");
|
|
28685
28838
|
} else if (tier.status === "active") {
|
|
28686
|
-
const loc = tier.path ?
|
|
28687
|
-
const note = tier.note ?
|
|
28688
|
-
statusStr =
|
|
28839
|
+
const loc = tier.path ? import_chalk37.default.gray(tier.path) : "";
|
|
28840
|
+
const note = tier.note ? import_chalk37.default.gray(`(${tier.note})`) : "";
|
|
28841
|
+
statusStr = import_chalk37.default.green("\u2713 active") + (loc ? " " + loc : "") + (note ? " " + note : "");
|
|
28689
28842
|
} else {
|
|
28690
|
-
statusStr =
|
|
28843
|
+
statusStr = import_chalk37.default.gray("\u25CB " + (tier.note ?? "not found"));
|
|
28691
28844
|
}
|
|
28692
|
-
console.log(`${num3} ${
|
|
28845
|
+
console.log(`${num3} ${import_chalk37.default.white(label2)} ${statusStr}`);
|
|
28693
28846
|
}
|
|
28694
28847
|
console.log("");
|
|
28695
|
-
console.log(
|
|
28848
|
+
console.log(import_chalk37.default.bold("Policy Evaluation:"));
|
|
28696
28849
|
for (const step of result.steps) {
|
|
28697
28850
|
const isFinal = step.isFinal;
|
|
28698
28851
|
let icon;
|
|
28699
|
-
if (step.outcome === "allow") icon =
|
|
28700
|
-
else if (step.outcome === "block") icon =
|
|
28701
|
-
else if (step.outcome === "review") icon =
|
|
28702
|
-
else if (step.outcome === "skip") icon =
|
|
28703
|
-
else icon =
|
|
28852
|
+
if (step.outcome === "allow") icon = import_chalk37.default.green(" \u2705");
|
|
28853
|
+
else if (step.outcome === "block") icon = import_chalk37.default.red(" \u{1F6D1}");
|
|
28854
|
+
else if (step.outcome === "review") icon = import_chalk37.default.red(" \u{1F534}");
|
|
28855
|
+
else if (step.outcome === "skip") icon = import_chalk37.default.gray(" \u2500 ");
|
|
28856
|
+
else icon = import_chalk37.default.gray(" \u25CB ");
|
|
28704
28857
|
const name = step.name.padEnd(18);
|
|
28705
|
-
const nameStr = isFinal ?
|
|
28706
|
-
const detail = isFinal ?
|
|
28707
|
-
const arrow = isFinal ?
|
|
28858
|
+
const nameStr = isFinal ? import_chalk37.default.white.bold(name) : import_chalk37.default.white(name);
|
|
28859
|
+
const detail = isFinal ? import_chalk37.default.white(step.detail) : import_chalk37.default.gray(step.detail);
|
|
28860
|
+
const arrow = isFinal ? import_chalk37.default.yellow(" \u2190 STOP") : "";
|
|
28708
28861
|
console.log(`${icon} ${nameStr} ${detail}${arrow}`);
|
|
28709
28862
|
}
|
|
28710
28863
|
console.log("");
|
|
28711
28864
|
if (result.decision === "allow") {
|
|
28712
|
-
console.log(
|
|
28865
|
+
console.log(import_chalk37.default.green.bold(" Decision: \u2705 ALLOW") + import_chalk37.default.gray(" \u2014 no approval needed"));
|
|
28713
28866
|
} else if (result.decision === "block") {
|
|
28714
28867
|
console.log(
|
|
28715
|
-
|
|
28868
|
+
import_chalk37.default.red.bold(" Decision: \u{1F6D1} BLOCK") + import_chalk37.default.gray(" \u2014 this action is blocked")
|
|
28716
28869
|
);
|
|
28717
28870
|
if (result.blockedByLabel) {
|
|
28718
|
-
console.log(
|
|
28871
|
+
console.log(import_chalk37.default.gray(` Reason: ${result.blockedByLabel}`));
|
|
28719
28872
|
}
|
|
28720
28873
|
} else {
|
|
28721
28874
|
console.log(
|
|
28722
|
-
|
|
28875
|
+
import_chalk37.default.red.bold(" Decision: \u{1F534} REVIEW") + import_chalk37.default.gray(" \u2014 human approval required")
|
|
28723
28876
|
);
|
|
28724
28877
|
if (result.blockedByLabel) {
|
|
28725
|
-
console.log(
|
|
28878
|
+
console.log(import_chalk37.default.gray(` Reason: ${result.blockedByLabel}`));
|
|
28726
28879
|
}
|
|
28727
28880
|
}
|
|
28728
28881
|
console.log("");
|
|
28729
28882
|
});
|
|
28730
28883
|
registerInitCommand(program);
|
|
28884
|
+
registerConnectCommand(program);
|
|
28731
28885
|
registerAuditCommand(program);
|
|
28732
28886
|
registerReportCommand(program);
|
|
28733
28887
|
registerStatusCommand(program);
|
|
@@ -28737,7 +28891,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
|
|
|
28737
28891
|
try {
|
|
28738
28892
|
await startTail2(options);
|
|
28739
28893
|
} catch (err2) {
|
|
28740
|
-
console.error(
|
|
28894
|
+
console.error(import_chalk37.default.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
|
|
28741
28895
|
process.exit(1);
|
|
28742
28896
|
}
|
|
28743
28897
|
});
|
|
@@ -28748,7 +28902,7 @@ program.command("monitor").description("Live interactive dashboard \u2014 activi
|
|
|
28748
28902
|
const mod = await dynamicImport(`file://${dashboardPath}`);
|
|
28749
28903
|
await mod.startMonitor();
|
|
28750
28904
|
} catch (err2) {
|
|
28751
|
-
console.error(
|
|
28905
|
+
console.error(import_chalk37.default.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
|
|
28752
28906
|
process.exit(1);
|
|
28753
28907
|
}
|
|
28754
28908
|
});
|
|
@@ -28803,7 +28957,7 @@ program.command("pause").description("Temporarily disable Node9 protection for a
|
|
|
28803
28957
|
const ms = parseDuration(options.duration);
|
|
28804
28958
|
if (ms === null) {
|
|
28805
28959
|
console.error(
|
|
28806
|
-
|
|
28960
|
+
import_chalk37.default.red(`
|
|
28807
28961
|
\u274C Invalid duration: "${options.duration}". Use format like 15m, 1h, 30s.
|
|
28808
28962
|
`)
|
|
28809
28963
|
);
|
|
@@ -28811,20 +28965,20 @@ program.command("pause").description("Temporarily disable Node9 protection for a
|
|
|
28811
28965
|
}
|
|
28812
28966
|
pauseNode9(ms, options.duration);
|
|
28813
28967
|
const expiresAt = new Date(Date.now() + ms).toLocaleTimeString();
|
|
28814
|
-
console.log(
|
|
28968
|
+
console.log(import_chalk37.default.yellow(`
|
|
28815
28969
|
\u23F8 Node9 paused until ${expiresAt}`));
|
|
28816
|
-
console.log(
|
|
28817
|
-
console.log(
|
|
28970
|
+
console.log(import_chalk37.default.gray(` All tool calls will be allowed without review.`));
|
|
28971
|
+
console.log(import_chalk37.default.gray(` Run "node9 resume" to re-enable early.
|
|
28818
28972
|
`));
|
|
28819
28973
|
});
|
|
28820
28974
|
program.command("resume").description("Re-enable Node9 protection immediately").action(() => {
|
|
28821
28975
|
const { paused } = checkPause();
|
|
28822
28976
|
if (!paused) {
|
|
28823
|
-
console.log(
|
|
28977
|
+
console.log(import_chalk37.default.gray("\nNode9 is already active \u2014 nothing to resume.\n"));
|
|
28824
28978
|
return;
|
|
28825
28979
|
}
|
|
28826
28980
|
resumeNode9();
|
|
28827
|
-
console.log(
|
|
28981
|
+
console.log(import_chalk37.default.green("\n\u25B6 Node9 resumed \u2014 protection is active.\n"));
|
|
28828
28982
|
});
|
|
28829
28983
|
var HOOK_BASED_AGENTS = {
|
|
28830
28984
|
claude: "claude",
|
|
@@ -28840,15 +28994,15 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
|
|
|
28840
28994
|
if (HOOK_BASED_AGENTS[firstArg2] !== void 0) {
|
|
28841
28995
|
const target = HOOK_BASED_AGENTS[firstArg2];
|
|
28842
28996
|
console.error(
|
|
28843
|
-
|
|
28997
|
+
import_chalk37.default.yellow(`
|
|
28844
28998
|
\u26A0\uFE0F Node9 proxy mode does not support "${target}" directly.`)
|
|
28845
28999
|
);
|
|
28846
|
-
console.error(
|
|
29000
|
+
console.error(import_chalk37.default.white(`
|
|
28847
29001
|
"${target}" uses its own hook system. Use:`));
|
|
28848
29002
|
console.error(
|
|
28849
|
-
|
|
29003
|
+
import_chalk37.default.green(` node9 addto ${target} `) + import_chalk37.default.gray("# one-time setup")
|
|
28850
29004
|
);
|
|
28851
|
-
console.error(
|
|
29005
|
+
console.error(import_chalk37.default.green(` ${target} `) + import_chalk37.default.gray("# run normally"));
|
|
28852
29006
|
process.exit(1);
|
|
28853
29007
|
}
|
|
28854
29008
|
const runArgs = firstArg2 === "shell" ? commandArgs.slice(1) : commandArgs;
|
|
@@ -28865,7 +29019,7 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
|
|
|
28865
29019
|
}
|
|
28866
29020
|
);
|
|
28867
29021
|
if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && getConfig().settings.autoStartDaemon) {
|
|
28868
|
-
console.error(
|
|
29022
|
+
console.error(import_chalk37.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically..."));
|
|
28869
29023
|
const daemonReady = await autoStartDaemonAndWait();
|
|
28870
29024
|
if (daemonReady) result = await authorizeHeadless("shell", { command: fullCommand });
|
|
28871
29025
|
}
|
|
@@ -28878,12 +29032,12 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
|
|
|
28878
29032
|
}
|
|
28879
29033
|
if (!result.approved) {
|
|
28880
29034
|
console.error(
|
|
28881
|
-
|
|
29035
|
+
import_chalk37.default.red(`
|
|
28882
29036
|
\u274C Node9 Blocked: ${result.reason || "Dangerous command detected."}`)
|
|
28883
29037
|
);
|
|
28884
29038
|
process.exit(1);
|
|
28885
29039
|
}
|
|
28886
|
-
console.error(
|
|
29040
|
+
console.error(import_chalk37.default.green("\n\u2705 Approved \u2014 running command...\n"));
|
|
28887
29041
|
await runProxy(fullCommand);
|
|
28888
29042
|
} else {
|
|
28889
29043
|
program.help();
|