@node9/proxy 1.15.0 → 1.17.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/README.md +25 -39
- package/dist/cli.js +771 -411
- package/dist/cli.mjs +726 -366
- package/dist/index.js +8 -4
- package/dist/index.mjs +8 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -4732,15 +4732,17 @@ async function authorizeHeadless(toolName, args, meta, options) {
|
|
|
4732
4732
|
if (!options?.calledFromDaemon) {
|
|
4733
4733
|
const actId = (0, import_crypto4.randomUUID)();
|
|
4734
4734
|
const actTs = Date.now();
|
|
4735
|
+
const stripAnsi2 = (s) => s.replace(/\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g, "");
|
|
4736
|
+
const sanitizedAgent = meta?.agent ? stripAnsi2(meta.agent).slice(0, 80) : void 0;
|
|
4737
|
+
const sanitizedMcpServer = meta?.mcpServer ? stripAnsi2(meta.mcpServer).slice(0, 40) : void 0;
|
|
4735
4738
|
const socketOk = await notifyActivity({
|
|
4736
4739
|
id: actId,
|
|
4737
4740
|
ts: actTs,
|
|
4738
4741
|
tool: toolName,
|
|
4739
4742
|
args,
|
|
4740
4743
|
status: "pending",
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
agent: meta?.agent ? meta.agent.replace(/\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g, "").slice(0, 80) : void 0
|
|
4744
|
+
agent: sanitizedAgent,
|
|
4745
|
+
mcpServer: sanitizedMcpServer
|
|
4744
4746
|
});
|
|
4745
4747
|
const result = await _authorizeHeadlessCore(toolName, args, meta, {
|
|
4746
4748
|
...options,
|
|
@@ -4758,7 +4760,9 @@ async function authorizeHeadless(toolName, args, meta, options) {
|
|
|
4758
4760
|
status: result.approved ? "allow" : result.blockedByLabel?.includes("DLP") ? "dlp" : result.blockedByLabel?.includes("Taint") ? "taint" : "block",
|
|
4759
4761
|
label: result.blockedByLabel,
|
|
4760
4762
|
ruleHit: result.ruleHit,
|
|
4761
|
-
observeWouldBlock: result.observeWouldBlock
|
|
4763
|
+
observeWouldBlock: result.observeWouldBlock,
|
|
4764
|
+
agent: sanitizedAgent,
|
|
4765
|
+
mcpServer: sanitizedMcpServer
|
|
4762
4766
|
});
|
|
4763
4767
|
}
|
|
4764
4768
|
return result;
|
|
@@ -10380,7 +10384,7 @@ function openBrowserLocal() {
|
|
|
10380
10384
|
} catch {
|
|
10381
10385
|
}
|
|
10382
10386
|
}
|
|
10383
|
-
async function autoStartDaemonAndWait(
|
|
10387
|
+
async function autoStartDaemonAndWait(openBrowser = false) {
|
|
10384
10388
|
if (isTestingMode()) return false;
|
|
10385
10389
|
if (!import_path15.default.isAbsolute(process.argv[1])) return false;
|
|
10386
10390
|
let resolvedArgv1;
|
|
@@ -10400,7 +10404,7 @@ async function autoStartDaemonAndWait(openBrowser2 = true) {
|
|
|
10400
10404
|
env: {
|
|
10401
10405
|
...process.env,
|
|
10402
10406
|
NODE9_AUTO_STARTED: "1",
|
|
10403
|
-
...
|
|
10407
|
+
...openBrowser && { NODE9_BROWSER_OPENED: "1" }
|
|
10404
10408
|
}
|
|
10405
10409
|
});
|
|
10406
10410
|
child.unref();
|
|
@@ -10412,7 +10416,7 @@ async function autoStartDaemonAndWait(openBrowser2 = true) {
|
|
|
10412
10416
|
signal: AbortSignal.timeout(500)
|
|
10413
10417
|
});
|
|
10414
10418
|
if (res.ok) {
|
|
10415
|
-
if (
|
|
10419
|
+
if (openBrowser) {
|
|
10416
10420
|
openBrowserLocal();
|
|
10417
10421
|
}
|
|
10418
10422
|
return true;
|
|
@@ -11801,370 +11805,681 @@ function printRuleGroup(rule, topN, drillDown, previewWidth) {
|
|
|
11801
11805
|
);
|
|
11802
11806
|
}
|
|
11803
11807
|
}
|
|
11804
|
-
function
|
|
11805
|
-
|
|
11806
|
-
|
|
11807
|
-
|
|
11808
|
-
|
|
11809
|
-
|
|
11810
|
-
|
|
11811
|
-
|
|
11812
|
-
|
|
11813
|
-
|
|
11814
|
-
})()
|
|
11815
|
-
|
|
11816
|
-
|
|
11817
|
-
|
|
11818
|
-
|
|
11819
|
-
|
|
11820
|
-
|
|
11821
|
-
|
|
11822
|
-
|
|
11823
|
-
|
|
11824
|
-
|
|
11808
|
+
function compactRuleLabel(name) {
|
|
11809
|
+
let label = name.replace(/^shield:[^:]+:/, "");
|
|
11810
|
+
label = label.replace(/^(block|review|allow)-/, "");
|
|
11811
|
+
return label.replace(/-+/g, "-");
|
|
11812
|
+
}
|
|
11813
|
+
function renderCompactScorecard(input) {
|
|
11814
|
+
const { scan, summary, blast, blastExposures, blockedCount, reviewCount } = input;
|
|
11815
|
+
const totalRisky = scan.findings.length + scan.dlpFindings.length;
|
|
11816
|
+
const dateRange = scan.firstDate && scan.lastDate ? `${fmtTs(scan.firstDate)} \u2013 ${fmtTs(scan.lastDate)}` : "";
|
|
11817
|
+
console.log(
|
|
11818
|
+
import_chalk3.default.bold("\u{1F6E1} Node9 Scan") + import_chalk3.default.dim(" \xB7 ") + import_chalk3.default.white(num(scan.sessions)) + import_chalk3.default.dim(" sessions \xB7 ") + import_chalk3.default.white(num(scan.totalToolCalls)) + import_chalk3.default.dim(" tool calls") + (dateRange ? import_chalk3.default.dim(" \xB7 " + dateRange) : "")
|
|
11819
|
+
);
|
|
11820
|
+
console.log("");
|
|
11821
|
+
const scoreColor = blast.score >= 80 ? import_chalk3.default.green : blast.score >= 50 ? import_chalk3.default.yellow : import_chalk3.default.red;
|
|
11822
|
+
const scoreSeverity = blast.score >= 80 ? "Good" : blast.score >= 50 ? "At Risk" : "Critical";
|
|
11823
|
+
console.log(
|
|
11824
|
+
import_chalk3.default.bold("Security Score: ") + scoreColor.bold(`${blast.score}/100`) + import_chalk3.default.dim(" \xB7 ") + scoreColor(scoreSeverity)
|
|
11825
|
+
);
|
|
11826
|
+
if (scan.totalCostUSD > 0) {
|
|
11827
|
+
console.log(
|
|
11828
|
+
import_chalk3.default.bold(fmtCost(scan.totalCostUSD)) + import_chalk3.default.dim(" AI spend \xB7 ") + import_chalk3.default.bold(`${totalRisky}`) + import_chalk3.default.dim(` risky operation${totalRisky !== 1 ? "s" : ""}`)
|
|
11829
|
+
);
|
|
11830
|
+
}
|
|
11831
|
+
console.log("");
|
|
11832
|
+
if (scan.dlpFindings.length > 0) {
|
|
11833
|
+
const patternCounts = /* @__PURE__ */ new Map();
|
|
11834
|
+
for (const f of scan.dlpFindings) {
|
|
11835
|
+
patternCounts.set(f.patternName, (patternCounts.get(f.patternName) ?? 0) + 1);
|
|
11825
11836
|
}
|
|
11837
|
+
const topPatterns = [...patternCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3).map(([name, count]) => count > 1 ? `${name} \xD7${count}` : name).join(", ");
|
|
11826
11838
|
console.log(
|
|
11827
|
-
import_chalk3.default.
|
|
11839
|
+
import_chalk3.default.red("\u{1F511} ") + import_chalk3.default.red.bold(String(scan.dlpFindings.length).padEnd(4)) + import_chalk3.default.dim("credential leak".padEnd(20)) + import_chalk3.default.dim(`(${topPatterns})`)
|
|
11828
11840
|
);
|
|
11829
|
-
|
|
11830
|
-
|
|
11831
|
-
|
|
11832
|
-
|
|
11833
|
-
|
|
11834
|
-
|
|
11841
|
+
}
|
|
11842
|
+
if (blockedCount > 0) {
|
|
11843
|
+
const blockedRules = [];
|
|
11844
|
+
for (const section of summary.sections) {
|
|
11845
|
+
for (const rule of section.rules) {
|
|
11846
|
+
if (rule.verdict === "block") {
|
|
11847
|
+
blockedRules.push({ name: rule.name, count: rule.findings.length });
|
|
11848
|
+
}
|
|
11849
|
+
}
|
|
11835
11850
|
}
|
|
11836
|
-
const
|
|
11837
|
-
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
const
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
+
const topBlocked = blockedRules.sort((a, b) => b.count - a.count).slice(0, 3).map(
|
|
11852
|
+
(r) => r.count > 1 ? `${compactRuleLabel(r.name)} \xD7${r.count}` : compactRuleLabel(r.name)
|
|
11853
|
+
).join(", ");
|
|
11854
|
+
console.log(
|
|
11855
|
+
import_chalk3.default.red("\u{1F6D1} ") + import_chalk3.default.red.bold(String(blockedCount).padEnd(4)) + import_chalk3.default.dim("would have blocked".padEnd(20)) + import_chalk3.default.dim(`(${topBlocked})`)
|
|
11856
|
+
);
|
|
11857
|
+
}
|
|
11858
|
+
if (scan.loopFindings.length > 0) {
|
|
11859
|
+
const wastedCalls = scan.loopFindings.reduce((s, l) => s + Math.max(0, l.count - 1), 0);
|
|
11860
|
+
const wastePct = scan.totalToolCalls > 0 ? Math.round(wastedCalls / scan.totalToolCalls * 100) : 0;
|
|
11861
|
+
const wasteParts = [];
|
|
11862
|
+
if (wastePct > 0) wasteParts.push(`${wastePct}% wasted`);
|
|
11863
|
+
if (summary.loopWastedUSD > 0) wasteParts.push("~" + fmtCost(summary.loopWastedUSD));
|
|
11864
|
+
const wasteSummary = wasteParts.length ? `(${wasteParts.join(" \xB7 ")})` : "";
|
|
11865
|
+
console.log(
|
|
11866
|
+
import_chalk3.default.yellow("\u{1F501} ") + import_chalk3.default.yellow.bold(String(scan.loopFindings.length).padEnd(4)) + import_chalk3.default.dim("agent loops".padEnd(20)) + import_chalk3.default.dim(wasteSummary)
|
|
11867
|
+
);
|
|
11868
|
+
}
|
|
11869
|
+
if (reviewCount > 0) {
|
|
11870
|
+
const reviewRules = [];
|
|
11871
|
+
for (const section of summary.sections) {
|
|
11872
|
+
for (const rule of section.rules) {
|
|
11873
|
+
if (rule.verdict !== "block") {
|
|
11874
|
+
reviewRules.push({ name: rule.name, count: rule.findings.length });
|
|
11875
|
+
}
|
|
11851
11876
|
}
|
|
11852
|
-
}
|
|
11853
|
-
|
|
11854
|
-
|
|
11855
|
-
|
|
11856
|
-
|
|
11857
|
-
(
|
|
11858
|
-
onLine
|
|
11877
|
+
}
|
|
11878
|
+
const topReview = reviewRules.sort((a, b) => b.count - a.count).slice(0, 3).map(
|
|
11879
|
+
(r) => r.count > 1 ? `${compactRuleLabel(r.name)} \xD7${r.count}` : compactRuleLabel(r.name)
|
|
11880
|
+
).join(", ");
|
|
11881
|
+
console.log(
|
|
11882
|
+
import_chalk3.default.yellow("\u{1F441} ") + import_chalk3.default.yellow.bold(String(reviewCount).padEnd(4)) + import_chalk3.default.dim("flagged for review".padEnd(20)) + import_chalk3.default.dim(`(${topReview})`)
|
|
11859
11883
|
);
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
|
|
11863
|
-
|
|
11884
|
+
}
|
|
11885
|
+
console.log("");
|
|
11886
|
+
if (blastExposures > 0) {
|
|
11887
|
+
const categories = /* @__PURE__ */ new Set();
|
|
11888
|
+
for (const r of blast.reachable) {
|
|
11889
|
+
const lower = r.label.toLowerCase();
|
|
11890
|
+
if (lower.includes("ssh")) categories.add("ssh");
|
|
11891
|
+
else if (lower.includes("aws")) categories.add("aws");
|
|
11892
|
+
else if (lower.includes("gcloud") || lower.includes("gcp")) categories.add("gcp");
|
|
11893
|
+
else if (lower.includes("docker")) categories.add("docker");
|
|
11894
|
+
else if (lower.includes("netrc")) categories.add("netrc");
|
|
11895
|
+
else if (lower.includes("kube")) categories.add("k8s");
|
|
11896
|
+
else if (lower.includes("npmrc")) categories.add("npm");
|
|
11897
|
+
else categories.add("other");
|
|
11898
|
+
}
|
|
11899
|
+
if (blast.envFindings.length > 0) categories.add("env");
|
|
11900
|
+
const catList = [...categories].slice(0, 6).join(" \xD7 ");
|
|
11901
|
+
console.log(
|
|
11902
|
+
import_chalk3.default.red("\u{1F52D} ") + import_chalk3.default.dim("Blast radius".padEnd(24)) + import_chalk3.default.dim(`${catList} (${blastExposures} exposure${blastExposures !== 1 ? "s" : ""})`)
|
|
11864
11903
|
);
|
|
11865
|
-
|
|
11866
|
-
|
|
11867
|
-
|
|
11868
|
-
|
|
11869
|
-
|
|
11870
|
-
|
|
11871
|
-
|
|
11872
|
-
|
|
11873
|
-
|
|
11874
|
-
|
|
11875
|
-
|
|
11876
|
-
|
|
11877
|
-
|
|
11878
|
-
|
|
11879
|
-
|
|
11880
|
-
|
|
11904
|
+
console.log("");
|
|
11905
|
+
}
|
|
11906
|
+
console.log(
|
|
11907
|
+
import_chalk3.default.dim("\u2192 ") + import_chalk3.default.cyan("npx node9-ai scan") + import_chalk3.default.dim(" run this on your machine")
|
|
11908
|
+
);
|
|
11909
|
+
console.log(import_chalk3.default.dim("\u2192 github.com/node9-ai/node9-proxy"));
|
|
11910
|
+
console.log("");
|
|
11911
|
+
}
|
|
11912
|
+
function classifyRuleSeverity(name, verdict) {
|
|
11913
|
+
const n = name.toLowerCase();
|
|
11914
|
+
const criticalPatterns = [
|
|
11915
|
+
"rm-rf",
|
|
11916
|
+
"eval-remote",
|
|
11917
|
+
"eval-curl",
|
|
11918
|
+
"read-aws",
|
|
11919
|
+
"read-ssh",
|
|
11920
|
+
"read-gcp",
|
|
11921
|
+
"read-cred",
|
|
11922
|
+
"delete-repo",
|
|
11923
|
+
"helm-uninstall",
|
|
11924
|
+
"drop-table",
|
|
11925
|
+
"drop-database",
|
|
11926
|
+
"drop-collection",
|
|
11927
|
+
"truncate",
|
|
11928
|
+
"flushall",
|
|
11929
|
+
"flushdb",
|
|
11930
|
+
"pipe-shell"
|
|
11931
|
+
];
|
|
11932
|
+
if (criticalPatterns.some((p) => n.includes(p))) return "critical";
|
|
11933
|
+
const highPatterns = [
|
|
11934
|
+
"force-push",
|
|
11935
|
+
"force_push",
|
|
11936
|
+
"git-destructive",
|
|
11937
|
+
"reset-hard",
|
|
11938
|
+
"rebase",
|
|
11939
|
+
"delete-branch",
|
|
11940
|
+
"delete-remote"
|
|
11941
|
+
];
|
|
11942
|
+
if (highPatterns.some((p) => n.includes(p))) return "high";
|
|
11943
|
+
if (verdict === "block") return "high";
|
|
11944
|
+
return "medium";
|
|
11945
|
+
}
|
|
11946
|
+
function narrativeRuleLabel(name) {
|
|
11947
|
+
const stripped = compactRuleLabel(name);
|
|
11948
|
+
const map = {
|
|
11949
|
+
"read-aws": "AWS credentials read",
|
|
11950
|
+
"read-ssh": "SSH private key read",
|
|
11951
|
+
"read-gcp": "GCP credentials read",
|
|
11952
|
+
"read-cred": "credential file read",
|
|
11953
|
+
"delete-repo": "GitHub repository deletion",
|
|
11954
|
+
"helm-uninstall": "helm uninstall",
|
|
11955
|
+
"rm-rf-home": "rm -rf on home directory",
|
|
11956
|
+
"eval-remote": "eval of remote download",
|
|
11957
|
+
"pipe-shell": "curl | bash",
|
|
11958
|
+
"drop-table": "DROP TABLE",
|
|
11959
|
+
"drop-database": "DROP DATABASE",
|
|
11960
|
+
truncate: "TRUNCATE",
|
|
11961
|
+
flushall: "Redis FLUSHALL",
|
|
11962
|
+
flushdb: "Redis FLUSHDB",
|
|
11963
|
+
"force-push": "force pushes",
|
|
11964
|
+
"git-destructive": "destructive git operations",
|
|
11965
|
+
rm: "rm calls",
|
|
11966
|
+
sudo: "sudo calls",
|
|
11967
|
+
"eval-dynamic": "dynamic eval",
|
|
11968
|
+
"config-set": "Redis CONFIG SET"
|
|
11969
|
+
};
|
|
11970
|
+
for (const [key, label] of Object.entries(map)) {
|
|
11971
|
+
if (stripped.includes(key)) return label;
|
|
11972
|
+
}
|
|
11973
|
+
return stripped;
|
|
11974
|
+
}
|
|
11975
|
+
function renderNarrativeScorecard(input) {
|
|
11976
|
+
const { scan, summary, blast, blastExposures } = input;
|
|
11977
|
+
const critical = [];
|
|
11978
|
+
const high = [];
|
|
11979
|
+
const medium = [];
|
|
11980
|
+
if (scan.dlpFindings.length > 0) {
|
|
11981
|
+
const patterns = /* @__PURE__ */ new Map();
|
|
11982
|
+
for (const f of scan.dlpFindings) {
|
|
11983
|
+
patterns.set(f.patternName, (patterns.get(f.patternName) ?? 0) + 1);
|
|
11984
|
+
}
|
|
11985
|
+
const top = [...patterns.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3).map(([name, n]) => n > 1 ? `${name} \xD7${n}` : name).join(", ");
|
|
11986
|
+
critical.push({
|
|
11987
|
+
label: `${scan.dlpFindings.length} credential leak${scan.dlpFindings.length !== 1 ? "s" : ""} (${top})`,
|
|
11988
|
+
count: scan.dlpFindings.length
|
|
11989
|
+
});
|
|
11990
|
+
}
|
|
11991
|
+
for (const section of summary.sections) {
|
|
11992
|
+
for (const rule of section.rules) {
|
|
11993
|
+
const sev = classifyRuleSeverity(rule.name, rule.verdict);
|
|
11994
|
+
const label = narrativeRuleLabel(rule.name);
|
|
11995
|
+
const count = rule.findings.length;
|
|
11996
|
+
const display = count > 1 ? `${label} \xD7${count}` : label;
|
|
11997
|
+
const entry = { label: display, count };
|
|
11998
|
+
if (sev === "critical") critical.push(entry);
|
|
11999
|
+
else if (sev === "high") high.push(entry);
|
|
12000
|
+
else medium.push(entry);
|
|
12001
|
+
}
|
|
12002
|
+
}
|
|
12003
|
+
if (blastExposures > 0) {
|
|
12004
|
+
high.push({
|
|
12005
|
+
label: `${blastExposures} credential file${blastExposures !== 1 ? "s" : ""} reachable on disk`,
|
|
12006
|
+
count: blastExposures
|
|
12007
|
+
});
|
|
12008
|
+
}
|
|
12009
|
+
if (scan.loopFindings.length > 0) {
|
|
12010
|
+
const wastedCalls = scan.loopFindings.reduce((s, l) => s + Math.max(0, l.count - 1), 0);
|
|
12011
|
+
const wastePct = scan.totalToolCalls > 0 ? Math.round(wastedCalls / scan.totalToolCalls * 100) : 0;
|
|
12012
|
+
const cost = summary.loopWastedUSD > 0 ? `, ~${fmtCost(summary.loopWastedUSD)} wasted` : "";
|
|
12013
|
+
medium.push({
|
|
12014
|
+
label: `${scan.loopFindings.length} agent loops (${wastePct}% of calls${cost})`,
|
|
12015
|
+
count: scan.loopFindings.length
|
|
12016
|
+
});
|
|
12017
|
+
}
|
|
12018
|
+
const sortByCount = (a, b) => b.count - a.count;
|
|
12019
|
+
critical.sort(sortByCount);
|
|
12020
|
+
high.sort(sortByCount);
|
|
12021
|
+
medium.sort(sortByCount);
|
|
12022
|
+
const criticalCount = critical.reduce((s, e) => s + e.count, 0);
|
|
12023
|
+
const highCount = high.reduce((s, e) => s + e.count, 0);
|
|
12024
|
+
const mediumCount = medium.reduce((s, e) => s + e.count, 0);
|
|
12025
|
+
const dateRange = scan.firstDate && scan.lastDate ? `${fmtTs(scan.firstDate)} \u2013 ${fmtTs(scan.lastDate)}` : "";
|
|
12026
|
+
console.log(
|
|
12027
|
+
import_chalk3.default.bold("\u{1F6E1} Node9 Scan") + import_chalk3.default.dim(" \xB7 ") + import_chalk3.default.white(num(scan.sessions)) + import_chalk3.default.dim(" sessions") + (scan.totalCostUSD > 0 ? import_chalk3.default.dim(" \xB7 ") + import_chalk3.default.bold(fmtCost(scan.totalCostUSD)) + import_chalk3.default.dim(" spend") : "") + (dateRange ? import_chalk3.default.dim(" \xB7 " + dateRange) : "")
|
|
12028
|
+
);
|
|
12029
|
+
console.log("");
|
|
12030
|
+
const scoreColor = blast.score >= 80 ? import_chalk3.default.green : blast.score >= 50 ? import_chalk3.default.yellow : import_chalk3.default.red;
|
|
12031
|
+
const scoreSeverity = blast.score >= 80 ? "Good" : blast.score >= 50 ? "At Risk" : "Critical";
|
|
12032
|
+
console.log(
|
|
12033
|
+
(blast.score < 50 ? import_chalk3.default.red.bold("\u26A0 ") : "") + import_chalk3.default.bold("Security Score: ") + scoreColor.bold(`${blast.score}/100`) + import_chalk3.default.dim(" \xB7 ") + scoreColor(scoreSeverity)
|
|
12034
|
+
);
|
|
12035
|
+
console.log("");
|
|
12036
|
+
if (criticalCount > 0) {
|
|
12037
|
+
console.log(
|
|
12038
|
+
import_chalk3.default.red.bold(" \u{1F534} CRITICAL ") + import_chalk3.default.red(`${criticalCount} finding${criticalCount !== 1 ? "s" : ""}`)
|
|
12039
|
+
);
|
|
12040
|
+
for (const entry of critical.slice(0, 5)) {
|
|
12041
|
+
console.log(import_chalk3.default.dim(" \u2022 ") + import_chalk3.default.red(entry.label));
|
|
12042
|
+
}
|
|
12043
|
+
if (critical.length > 5) {
|
|
12044
|
+
const remaining = critical.length - 5;
|
|
12045
|
+
console.log(import_chalk3.default.dim(` \u2022 \u2026 and ${remaining} more`));
|
|
11881
12046
|
}
|
|
11882
|
-
|
|
11883
|
-
|
|
11884
|
-
|
|
11885
|
-
if (claudeScan.sessions > 0)
|
|
11886
|
-
breakdownParts.push(import_chalk3.default.cyan(String(claudeScan.sessions)) + import_chalk3.default.dim(" Claude"));
|
|
11887
|
-
if (geminiScan.sessions > 0)
|
|
11888
|
-
breakdownParts.push(import_chalk3.default.blue(String(geminiScan.sessions)) + import_chalk3.default.dim(" Gemini"));
|
|
11889
|
-
if (codexScan.sessions > 0)
|
|
11890
|
-
breakdownParts.push(import_chalk3.default.magenta(String(codexScan.sessions)) + import_chalk3.default.dim(" Codex"));
|
|
11891
|
-
const sessionBreakdown = breakdownParts.length > 1 ? import_chalk3.default.dim("(") + breakdownParts.join(import_chalk3.default.dim(" \xB7 ")) + import_chalk3.default.dim(")") : "";
|
|
12047
|
+
console.log("");
|
|
12048
|
+
}
|
|
12049
|
+
if (highCount > 0) {
|
|
11892
12050
|
console.log(
|
|
11893
|
-
|
|
12051
|
+
import_chalk3.default.yellow.bold(" \u{1F7E1} HIGH ") + import_chalk3.default.yellow(`${highCount} finding${highCount !== 1 ? "s" : ""}`)
|
|
11894
12052
|
);
|
|
12053
|
+
for (const entry of high.slice(0, 5)) {
|
|
12054
|
+
console.log(import_chalk3.default.dim(" \u2022 ") + import_chalk3.default.yellow(entry.label));
|
|
12055
|
+
}
|
|
12056
|
+
if (high.length > 5) {
|
|
12057
|
+
const remaining = high.length - 5;
|
|
12058
|
+
console.log(import_chalk3.default.dim(` \u2022 \u2026 and ${remaining} more`));
|
|
12059
|
+
}
|
|
11895
12060
|
console.log("");
|
|
11896
|
-
|
|
11897
|
-
|
|
11898
|
-
|
|
11899
|
-
|
|
11900
|
-
|
|
11901
|
-
|
|
11902
|
-
|
|
11903
|
-
|
|
11904
|
-
|
|
11905
|
-
const
|
|
11906
|
-
|
|
11907
|
-
|
|
11908
|
-
|
|
11909
|
-
|
|
11910
|
-
|
|
11911
|
-
|
|
11912
|
-
|
|
11913
|
-
|
|
12061
|
+
}
|
|
12062
|
+
if (mediumCount > 0) {
|
|
12063
|
+
console.log(
|
|
12064
|
+
import_chalk3.default.bold(" \u{1F7E2} MEDIUM ") + import_chalk3.default.dim(`${mediumCount} finding${mediumCount !== 1 ? "s" : ""}`)
|
|
12065
|
+
);
|
|
12066
|
+
for (const entry of medium.slice(0, 5)) {
|
|
12067
|
+
console.log(import_chalk3.default.dim(" \u2022 ") + import_chalk3.default.dim(entry.label));
|
|
12068
|
+
}
|
|
12069
|
+
if (medium.length > 5) {
|
|
12070
|
+
const remaining = medium.length - 5;
|
|
12071
|
+
console.log(import_chalk3.default.dim(` \u2022 \u2026 and ${remaining} more`));
|
|
12072
|
+
}
|
|
12073
|
+
console.log("");
|
|
12074
|
+
}
|
|
12075
|
+
console.log(
|
|
12076
|
+
import_chalk3.default.dim("\u2192 ") + import_chalk3.default.cyan("npx node9-ai scan") + import_chalk3.default.dim(" run this on your machine")
|
|
12077
|
+
);
|
|
12078
|
+
console.log(import_chalk3.default.dim("\u2192 github.com/node9-ai/node9-proxy"));
|
|
12079
|
+
console.log("");
|
|
12080
|
+
}
|
|
12081
|
+
function registerScanCommand(program2) {
|
|
12082
|
+
program2.command("scan").description("Forecast: scan agent history and show what node9 would catch if installed").option("--all", "Scan all history (default: last 30 days)").option("--days <n>", "Scan last N days of history", "30").option("--top <n>", "Max findings to show per rule (default: 5)", "5").option("--drill-down", "Show all findings with full commands and session IDs").option("--compact", "Compact one-screen scorecard \u2014 for screenshots and sharing").option("--narrative", "Severity-grouped report \u2014 for video / dramatic sharing").action(
|
|
12083
|
+
async (options) => {
|
|
12084
|
+
const drillDown = options.drillDown ?? false;
|
|
12085
|
+
const topN = drillDown ? Infinity : Math.max(1, parseInt(options.top, 10) || 5);
|
|
12086
|
+
const previewWidth = 70;
|
|
12087
|
+
const startDate = options.all ? null : (() => {
|
|
12088
|
+
const d = /* @__PURE__ */ new Date();
|
|
12089
|
+
d.setDate(d.getDate() - (parseInt(options.days, 10) || 30));
|
|
12090
|
+
d.setHours(0, 0, 0, 0);
|
|
12091
|
+
return d;
|
|
12092
|
+
})();
|
|
12093
|
+
const isWired = getAgentsStatus().some((a) => a.wired);
|
|
12094
|
+
const screenshotMode = options.compact || options.narrative;
|
|
12095
|
+
if (!screenshotMode) {
|
|
12096
|
+
console.log("");
|
|
12097
|
+
if (!isWired) {
|
|
12098
|
+
console.log(
|
|
12099
|
+
import_chalk3.default.bold("\u{1F6E1} node9") + import_chalk3.default.dim(" \u2014 security layer for AI coding agents")
|
|
12100
|
+
);
|
|
12101
|
+
console.log(
|
|
12102
|
+
import_chalk3.default.dim(" Intercepts dangerous tool calls before they execute. No config needed.")
|
|
12103
|
+
);
|
|
12104
|
+
console.log("");
|
|
12105
|
+
}
|
|
11914
12106
|
console.log(
|
|
11915
|
-
|
|
12107
|
+
import_chalk3.default.cyan.bold("\u{1F50D} Scanning your AI history") + import_chalk3.default.dim(" \u2014 what would node9 have caught?")
|
|
11916
12108
|
);
|
|
12109
|
+
console.log("");
|
|
11917
12110
|
}
|
|
11918
|
-
|
|
11919
|
-
|
|
11920
|
-
|
|
11921
|
-
|
|
11922
|
-
console.log(
|
|
11923
|
-
" " + import_chalk3.default.red("\u{1F511} Credential leak") + " " + import_chalk3.default.red.bold(String(scan.dlpFindings.length).padStart(5)) + import_chalk3.default.dim(" secret detected in history or shell config") + earlyLabel
|
|
12111
|
+
const useTTY = process.stdout.isTTY === true && process.env.NODE9_WRAPPER !== "1";
|
|
12112
|
+
if (!useTTY && !screenshotMode) {
|
|
12113
|
+
process.stdout.write(
|
|
12114
|
+
" " + import_chalk3.default.dim("Scanning your history \u2014 this may take a moment...\n")
|
|
11924
12115
|
);
|
|
11925
12116
|
}
|
|
11926
|
-
|
|
12117
|
+
const totalFiles = countScanFiles();
|
|
12118
|
+
let filesScanned = 0;
|
|
12119
|
+
let linesScanned = 0;
|
|
12120
|
+
let lastRender = 0;
|
|
12121
|
+
const onProgress = (done) => {
|
|
12122
|
+
filesScanned = done;
|
|
12123
|
+
if (useTTY) renderProgressBar(filesScanned, totalFiles, linesScanned);
|
|
12124
|
+
lastRender = Date.now();
|
|
12125
|
+
};
|
|
12126
|
+
const onLine = () => {
|
|
12127
|
+
linesScanned++;
|
|
12128
|
+
const now = Date.now();
|
|
12129
|
+
if (useTTY && now - lastRender >= 80) {
|
|
12130
|
+
lastRender = now;
|
|
12131
|
+
renderProgressBar(filesScanned, totalFiles, linesScanned);
|
|
12132
|
+
}
|
|
12133
|
+
};
|
|
12134
|
+
if (useTTY) renderProgressBar(0, totalFiles, 0);
|
|
12135
|
+
const claudeScan = scanClaudeHistory(startDate, onProgress, onLine);
|
|
12136
|
+
const geminiScan = scanGeminiHistory(
|
|
12137
|
+
startDate,
|
|
12138
|
+
(done) => onProgress(claudeScan.filesScanned + done),
|
|
12139
|
+
onLine
|
|
12140
|
+
);
|
|
12141
|
+
const codexScan = scanCodexHistory(
|
|
12142
|
+
startDate,
|
|
12143
|
+
(done) => onProgress(claudeScan.filesScanned + geminiScan.filesScanned + done),
|
|
12144
|
+
onLine
|
|
12145
|
+
);
|
|
12146
|
+
const scan = mergeScans(mergeScans(claudeScan, geminiScan), codexScan);
|
|
12147
|
+
scan.dlpFindings.push(...scanShellConfig());
|
|
12148
|
+
const summary = buildScanSummary([
|
|
12149
|
+
{ id: "claude", label: "Claude", icon: "\u{1F916}", scan: claudeScan },
|
|
12150
|
+
{ id: "gemini", label: "Gemini", icon: "\u264A", scan: geminiScan },
|
|
12151
|
+
{ id: "codex", label: "Codex", icon: "\u{1F52E}", scan: codexScan }
|
|
12152
|
+
]);
|
|
12153
|
+
if (useTTY) process.stdout.write("\r" + " ".repeat(60) + "\r");
|
|
12154
|
+
if (scan.filesScanned === 0) {
|
|
12155
|
+
console.log(import_chalk3.default.yellow(" No session history found."));
|
|
11927
12156
|
console.log(
|
|
11928
|
-
|
|
12157
|
+
import_chalk3.default.gray(
|
|
12158
|
+
" Supported: Claude Code (~/.claude/projects/) \xB7 Gemini CLI (~/.gemini/tmp/)\n"
|
|
12159
|
+
)
|
|
11929
12160
|
);
|
|
12161
|
+
return;
|
|
11930
12162
|
}
|
|
11931
|
-
|
|
11932
|
-
|
|
11933
|
-
|
|
11934
|
-
|
|
11935
|
-
)
|
|
11936
|
-
|
|
12163
|
+
const rangeLabel = options.all ? import_chalk3.default.dim("all time") : import_chalk3.default.dim(`last ${options.days ?? 30} days`);
|
|
12164
|
+
const dateRange = scan.firstDate && scan.lastDate ? import_chalk3.default.dim(` ${fmtTs(scan.firstDate)} \u2013 ${fmtTs(scan.lastDate)}`) : "";
|
|
12165
|
+
const breakdownParts = [];
|
|
12166
|
+
if (claudeScan.sessions > 0)
|
|
12167
|
+
breakdownParts.push(import_chalk3.default.cyan(String(claudeScan.sessions)) + import_chalk3.default.dim(" Claude"));
|
|
12168
|
+
if (geminiScan.sessions > 0)
|
|
12169
|
+
breakdownParts.push(import_chalk3.default.blue(String(geminiScan.sessions)) + import_chalk3.default.dim(" Gemini"));
|
|
12170
|
+
if (codexScan.sessions > 0)
|
|
12171
|
+
breakdownParts.push(import_chalk3.default.magenta(String(codexScan.sessions)) + import_chalk3.default.dim(" Codex"));
|
|
12172
|
+
const sessionBreakdown = breakdownParts.length > 1 ? import_chalk3.default.dim("(") + breakdownParts.join(import_chalk3.default.dim(" \xB7 ")) + import_chalk3.default.dim(")") : "";
|
|
12173
|
+
if (!screenshotMode) {
|
|
11937
12174
|
console.log(
|
|
11938
|
-
"
|
|
12175
|
+
" " + import_chalk3.default.white(num(scan.sessions)) + import_chalk3.default.dim(" sessions ") + sessionBreakdown + (sessionBreakdown ? " " : "") + import_chalk3.default.white(num(scan.totalToolCalls)) + import_chalk3.default.dim(" tool calls ") + import_chalk3.default.white(num(scan.bashCalls)) + import_chalk3.default.dim(" bash commands ") + rangeLabel + dateRange
|
|
11939
12176
|
);
|
|
12177
|
+
console.log("");
|
|
11940
12178
|
}
|
|
11941
|
-
|
|
11942
|
-
|
|
11943
|
-
|
|
11944
|
-
|
|
12179
|
+
const totalFindings = scan.findings.length;
|
|
12180
|
+
const blockedCount = scan.findings.filter((f) => f.source.rule.verdict === "block").length;
|
|
12181
|
+
const reviewCount = totalFindings - blockedCount;
|
|
12182
|
+
const blast = runBlast();
|
|
12183
|
+
const blastExposures = blast.reachable.length + blast.envFindings.length;
|
|
12184
|
+
if (options.compact) {
|
|
12185
|
+
renderCompactScorecard({
|
|
12186
|
+
scan,
|
|
12187
|
+
summary,
|
|
12188
|
+
blast,
|
|
12189
|
+
blastExposures,
|
|
12190
|
+
blockedCount,
|
|
12191
|
+
reviewCount
|
|
12192
|
+
});
|
|
12193
|
+
return;
|
|
11945
12194
|
}
|
|
11946
|
-
|
|
11947
|
-
|
|
11948
|
-
|
|
12195
|
+
if (options.narrative) {
|
|
12196
|
+
renderNarrativeScorecard({
|
|
12197
|
+
scan,
|
|
12198
|
+
summary,
|
|
12199
|
+
blast,
|
|
12200
|
+
blastExposures,
|
|
12201
|
+
blockedCount,
|
|
12202
|
+
reviewCount
|
|
12203
|
+
});
|
|
12204
|
+
return;
|
|
12205
|
+
}
|
|
12206
|
+
if (totalFindings === 0 && scan.dlpFindings.length === 0) {
|
|
12207
|
+
console.log(import_chalk3.default.green(" \u2705 No risky operations found in your history."));
|
|
11949
12208
|
console.log(
|
|
11950
|
-
|
|
11951
|
-
|
|
12209
|
+
import_chalk3.default.dim(
|
|
12210
|
+
" node9 is still worth running \u2014 it monitors every tool call in real time.\n"
|
|
11952
12211
|
)
|
|
11953
12212
|
);
|
|
11954
|
-
|
|
11955
|
-
const
|
|
11956
|
-
const
|
|
11957
|
-
|
|
11958
|
-
|
|
11959
|
-
|
|
11960
|
-
|
|
11961
|
-
|
|
11962
|
-
|
|
11963
|
-
|
|
11964
|
-
|
|
11965
|
-
|
|
11966
|
-
|
|
11967
|
-
|
|
12213
|
+
} else {
|
|
12214
|
+
const totalRisky = totalFindings + scan.dlpFindings.length;
|
|
12215
|
+
const scoreSeverity = blast.score >= 80 ? import_chalk3.default.green("Good") : blast.score >= 50 ? import_chalk3.default.yellow("At Risk") : import_chalk3.default.red.bold("Critical");
|
|
12216
|
+
const scoreColor = blast.score >= 80 ? import_chalk3.default.green : blast.score >= 50 ? import_chalk3.default.yellow : import_chalk3.default.red;
|
|
12217
|
+
console.log(
|
|
12218
|
+
" " + (blast.score < 50 ? import_chalk3.default.red.bold("\u26A0 ") : "") + import_chalk3.default.bold("Security Score ") + scoreColor.bold(`${blast.score}/100`) + " " + scoreSeverity + import_chalk3.default.dim(" \xB7 ") + (totalRisky > 0 ? import_chalk3.default.red.bold(`${totalRisky} risky operation${totalRisky !== 1 ? "s" : ""}`) : import_chalk3.default.green("No risky operations"))
|
|
12219
|
+
);
|
|
12220
|
+
const cardParts = [];
|
|
12221
|
+
if (scan.dlpFindings.length > 0) {
|
|
12222
|
+
cardParts.push(
|
|
12223
|
+
import_chalk3.default.red("\u{1F511} ") + import_chalk3.default.red.bold(String(scan.dlpFindings.length)) + import_chalk3.default.dim(` leak${scan.dlpFindings.length !== 1 ? "s" : ""}`)
|
|
12224
|
+
);
|
|
12225
|
+
}
|
|
12226
|
+
if (blockedCount > 0) {
|
|
12227
|
+
cardParts.push(
|
|
12228
|
+
import_chalk3.default.red("\u{1F6D1} ") + import_chalk3.default.red.bold(String(blockedCount)) + import_chalk3.default.dim(" blocked")
|
|
12229
|
+
);
|
|
12230
|
+
}
|
|
12231
|
+
if (scan.loopFindings.length > 0) {
|
|
12232
|
+
const wastedCalls = scan.loopFindings.reduce((s, l) => s + Math.max(0, l.count - 1), 0);
|
|
12233
|
+
const wastePct = scan.totalToolCalls > 0 ? Math.round(wastedCalls / scan.totalToolCalls * 100) : 0;
|
|
12234
|
+
const wasteSuffix = wastePct > 0 ? import_chalk3.default.dim(` (${wastePct}% wasted)`) : "";
|
|
12235
|
+
cardParts.push(
|
|
12236
|
+
import_chalk3.default.yellow("\u{1F501} ") + import_chalk3.default.yellow.bold(String(scan.loopFindings.length)) + import_chalk3.default.dim(" loops") + wasteSuffix
|
|
12237
|
+
);
|
|
12238
|
+
}
|
|
12239
|
+
if (reviewCount > 0) {
|
|
12240
|
+
cardParts.push(
|
|
12241
|
+
import_chalk3.default.yellow("\u{1F441} ") + import_chalk3.default.yellow.bold(String(reviewCount)) + import_chalk3.default.dim(" flagged")
|
|
12242
|
+
);
|
|
12243
|
+
}
|
|
12244
|
+
if (blastExposures > 0) {
|
|
12245
|
+
cardParts.push(
|
|
12246
|
+
import_chalk3.default.red("\u{1F52D} ") + import_chalk3.default.red.bold(String(blastExposures)) + import_chalk3.default.dim(" exposures")
|
|
12247
|
+
);
|
|
12248
|
+
}
|
|
12249
|
+
if (cardParts.length > 0) {
|
|
12250
|
+
console.log(" " + cardParts.join(import_chalk3.default.dim(" ")));
|
|
12251
|
+
}
|
|
12252
|
+
if (scan.totalCostUSD > 0) {
|
|
11968
12253
|
console.log(
|
|
11969
|
-
|
|
12254
|
+
" " + import_chalk3.default.dim("AI spend ") + import_chalk3.default.bold(fmtCost(scan.totalCostUSD)) + (summary.loopWastedUSD > 0 ? import_chalk3.default.dim(" \xB7 wasted on loops ") + import_chalk3.default.yellow("~" + fmtCost(summary.loopWastedUSD)) : "")
|
|
11970
12255
|
);
|
|
11971
12256
|
}
|
|
11972
|
-
if (
|
|
12257
|
+
if (scan.dlpFindings.length > 0 && scan.sessionsWithEarlySecrets > 0) {
|
|
11973
12258
|
console.log(
|
|
11974
|
-
import_chalk3.default.dim(
|
|
11975
|
-
|
|
12259
|
+
" " + import_chalk3.default.dim(
|
|
12260
|
+
`${scan.sessionsWithEarlySecrets} session${scan.sessionsWithEarlySecrets !== 1 ? "s" : ""} loaded secrets before first edit`
|
|
11976
12261
|
)
|
|
11977
12262
|
);
|
|
11978
12263
|
}
|
|
11979
12264
|
console.log("");
|
|
11980
|
-
|
|
11981
|
-
|
|
11982
|
-
if (blockedRuleSections.length > 0) {
|
|
11983
|
-
console.log(" " + import_chalk3.default.dim("\u2500".repeat(70)));
|
|
11984
|
-
console.log(
|
|
11985
|
-
" " + import_chalk3.default.red.bold("\u{1F6D1} Blocked") + import_chalk3.default.dim(" \xB7 ") + import_chalk3.default.red(
|
|
11986
|
-
`${blockedCount} operation${blockedCount !== 1 ? "s" : ""} node9 would have stopped`
|
|
11987
|
-
)
|
|
11988
|
-
);
|
|
11989
|
-
for (const section of blockedRuleSections) {
|
|
11990
|
-
for (const rule of section.rules) {
|
|
11991
|
-
printRuleGroup(rule, topN, drillDown, previewWidth);
|
|
11992
|
-
}
|
|
11993
|
-
}
|
|
11994
|
-
console.log("");
|
|
11995
|
-
}
|
|
11996
|
-
if (scan.loopFindings.length > 0) {
|
|
11997
|
-
console.log(" " + import_chalk3.default.dim("\u2500".repeat(70)));
|
|
11998
|
-
const loopCostLabel = summary.loopWastedUSD > 0 ? import_chalk3.default.dim(" \xB7 ") + import_chalk3.default.yellow("~" + fmtCost(summary.loopWastedUSD) + " wasted") : "";
|
|
11999
|
-
console.log(
|
|
12000
|
-
" " + import_chalk3.default.yellow.bold("\u{1F501} Agent Loops") + import_chalk3.default.dim(" \xB7 ") + import_chalk3.default.yellow(
|
|
12001
|
-
`${num(scan.loopFindings.length)} repeated pattern${scan.loopFindings.length !== 1 ? "s" : ""} found`
|
|
12002
|
-
) + loopCostLabel
|
|
12003
|
-
);
|
|
12004
|
-
const shownLoops = drillDown ? scan.loopFindings : scan.loopFindings.slice(0, topN);
|
|
12005
|
-
for (const f of shownLoops) {
|
|
12006
|
-
const ts = f.timestamp ? import_chalk3.default.dim(fmtTs(f.timestamp) + " ") : "";
|
|
12007
|
-
const proj = import_chalk3.default.dim(f.project.slice(0, 22).padEnd(22) + " ");
|
|
12008
|
-
const agentBadge = f.agent === "gemini" ? import_chalk3.default.blue("[Gemini] ") : f.agent === "codex" ? import_chalk3.default.magenta("[Codex] ") : import_chalk3.default.cyan("[Claude] ");
|
|
12009
|
-
const sessionSuffix = f.sessionId ? import_chalk3.default.dim(` \u2192 ${f.sessionId.slice(0, 8)}`) : "";
|
|
12265
|
+
if (scan.dlpFindings.length > 0) {
|
|
12266
|
+
console.log(" " + import_chalk3.default.dim("\u2500".repeat(70)));
|
|
12010
12267
|
console.log(
|
|
12011
|
-
|
|
12268
|
+
" " + import_chalk3.default.red.bold("\u{1F511} Credential Leaks") + import_chalk3.default.dim(" \xB7 ") + import_chalk3.default.red(
|
|
12269
|
+
`${num(scan.dlpFindings.length)} secret${scan.dlpFindings.length !== 1 ? "s" : ""} found in plain text`
|
|
12270
|
+
)
|
|
12012
12271
|
);
|
|
12272
|
+
const sortedDlp = sortDlpFindingsByPriority(scan.dlpFindings);
|
|
12273
|
+
const recurringPatterns = buildRecurringPatternSet(scan.dlpFindings);
|
|
12274
|
+
const shownDlp = drillDown ? sortedDlp : sortedDlp.slice(0, topN);
|
|
12275
|
+
for (const f of shownDlp) {
|
|
12276
|
+
const stale = isStaleFinding(f.timestamp);
|
|
12277
|
+
const ts = f.timestamp ? import_chalk3.default.dim(fmtTs(f.timestamp) + " ") : "";
|
|
12278
|
+
const proj = import_chalk3.default.dim(f.project.slice(0, 22).padEnd(22) + " ");
|
|
12279
|
+
const agentBadge = f.agent === "gemini" ? import_chalk3.default.blue("[Gemini] ") : f.agent === "codex" ? import_chalk3.default.magenta("[Codex] ") : f.agent === "shell" ? import_chalk3.default.yellow("[Shell] ") : import_chalk3.default.cyan("[Claude] ");
|
|
12280
|
+
const sessionSuffix = f.sessionId ? import_chalk3.default.dim(` \u2192 ${f.sessionId.slice(0, 8)}`) : "";
|
|
12281
|
+
const recurringBadge = recurringPatterns.has(f.patternName) ? import_chalk3.default.red.bold(" \u26A0\uFE0F recurring ") : "";
|
|
12282
|
+
const patternDisplay = stale ? import_chalk3.default.dim(f.patternName) : import_chalk3.default.yellow(f.patternName);
|
|
12283
|
+
const sampleDisplay = stale ? import_chalk3.default.dim(f.redactedSample) : import_chalk3.default.gray(f.redactedSample);
|
|
12284
|
+
const entryBadge = import_chalk3.default.dim(` [${entryPathLabel(f.toolName)}]`);
|
|
12285
|
+
const leadIcon = stale ? import_chalk3.default.dim("\u{1F6A8}") : "\u{1F6A8}";
|
|
12286
|
+
console.log(
|
|
12287
|
+
` ${leadIcon} ${ts}${proj}${agentBadge}` + patternDisplay + recurringBadge + import_chalk3.default.dim(" ") + sampleDisplay + entryBadge + sessionSuffix
|
|
12288
|
+
);
|
|
12289
|
+
}
|
|
12290
|
+
if (!drillDown && scan.dlpFindings.length > topN) {
|
|
12291
|
+
console.log(
|
|
12292
|
+
import_chalk3.default.dim(
|
|
12293
|
+
` \u2026 and ${scan.dlpFindings.length - topN} more (--drill-down for full list)`
|
|
12294
|
+
)
|
|
12295
|
+
);
|
|
12296
|
+
}
|
|
12297
|
+
console.log("");
|
|
12013
12298
|
}
|
|
12014
|
-
|
|
12299
|
+
const blockedRuleSections = summary.sections.map((s) => ({ ...s, rules: s.rules.filter((r) => r.verdict === "block") })).filter((s) => s.rules.length > 0);
|
|
12300
|
+
if (blockedRuleSections.length > 0) {
|
|
12301
|
+
console.log(" " + import_chalk3.default.dim("\u2500".repeat(70)));
|
|
12015
12302
|
console.log(
|
|
12016
|
-
import_chalk3.default.dim(
|
|
12017
|
-
|
|
12303
|
+
" " + import_chalk3.default.red.bold("\u{1F6D1} Blocked") + import_chalk3.default.dim(" \xB7 ") + import_chalk3.default.red(
|
|
12304
|
+
`${blockedCount} operation${blockedCount !== 1 ? "s" : ""} node9 would have stopped`
|
|
12018
12305
|
)
|
|
12019
12306
|
);
|
|
12020
|
-
|
|
12021
|
-
|
|
12022
|
-
|
|
12307
|
+
for (const section of blockedRuleSections) {
|
|
12308
|
+
for (const rule of section.rules) {
|
|
12309
|
+
printRuleGroup(rule, topN, drillDown, previewWidth);
|
|
12310
|
+
}
|
|
12311
|
+
}
|
|
12023
12312
|
console.log("");
|
|
12024
|
-
|
|
12025
|
-
|
|
12313
|
+
}
|
|
12314
|
+
if (scan.loopFindings.length > 0) {
|
|
12315
|
+
console.log(" " + import_chalk3.default.dim("\u2500".repeat(70)));
|
|
12316
|
+
const loopCostLabel = summary.loopWastedUSD > 0 ? import_chalk3.default.dim(" \xB7 ") + import_chalk3.default.yellow("~" + fmtCost(summary.loopWastedUSD) + " wasted") : "";
|
|
12317
|
+
console.log(
|
|
12318
|
+
" " + import_chalk3.default.yellow.bold("\u{1F501} Agent Loops") + import_chalk3.default.dim(" \xB7 ") + import_chalk3.default.yellow(
|
|
12319
|
+
`${num(scan.loopFindings.length)} repeated pattern${scan.loopFindings.length !== 1 ? "s" : ""} found`
|
|
12320
|
+
) + loopCostLabel
|
|
12321
|
+
);
|
|
12322
|
+
const shownLoops = drillDown ? scan.loopFindings : scan.loopFindings.slice(0, topN);
|
|
12323
|
+
for (const f of shownLoops) {
|
|
12324
|
+
const ts = f.timestamp ? import_chalk3.default.dim(fmtTs(f.timestamp) + " ") : "";
|
|
12325
|
+
const proj = import_chalk3.default.dim(f.project.slice(0, 22).padEnd(22) + " ");
|
|
12326
|
+
const agentBadge = f.agent === "gemini" ? import_chalk3.default.blue("[Gemini] ") : f.agent === "codex" ? import_chalk3.default.magenta("[Codex] ") : import_chalk3.default.cyan("[Claude] ");
|
|
12327
|
+
const sessionSuffix = f.sessionId ? import_chalk3.default.dim(` \u2192 ${f.sessionId.slice(0, 8)}`) : "";
|
|
12328
|
+
console.log(
|
|
12329
|
+
` ${ts}${proj}${agentBadge}` + import_chalk3.default.yellow(f.toolName) + import_chalk3.default.dim(` \xD7${f.count} `) + import_chalk3.default.gray(f.commandPreview) + sessionSuffix
|
|
12330
|
+
);
|
|
12331
|
+
}
|
|
12332
|
+
if (!drillDown && scan.loopFindings.length > topN) {
|
|
12026
12333
|
console.log(
|
|
12027
|
-
import_chalk3.default.dim(
|
|
12334
|
+
import_chalk3.default.dim(
|
|
12335
|
+
` \u2026 and ${scan.loopFindings.length - topN} more (--drill-down for full list)`
|
|
12336
|
+
)
|
|
12028
12337
|
);
|
|
12029
12338
|
}
|
|
12339
|
+
const stuckTools = computeStuckTools(scan.loopFindings);
|
|
12340
|
+
if (stuckTools.length > 0) {
|
|
12341
|
+
console.log("");
|
|
12342
|
+
console.log(" " + import_chalk3.default.dim("Most stuck tools:"));
|
|
12343
|
+
for (const t of stuckTools) {
|
|
12344
|
+
console.log(
|
|
12345
|
+
import_chalk3.default.dim(" ") + import_chalk3.default.yellow(t.toolName.padEnd(8)) + import_chalk3.default.dim(" ") + import_chalk3.default.dim(`\xD7${t.waste} repeats`.padEnd(14)) + import_chalk3.default.dim(` (${t.pct}%)`)
|
|
12346
|
+
);
|
|
12347
|
+
}
|
|
12348
|
+
}
|
|
12349
|
+
console.log("");
|
|
12350
|
+
}
|
|
12351
|
+
for (const section of summary.sections) {
|
|
12352
|
+
const reviewRules = section.rules.filter((r) => r.verdict !== "block");
|
|
12353
|
+
if (reviewRules.length === 0) continue;
|
|
12354
|
+
const enableHint = section.shieldKey ? import_chalk3.default.dim(` \u2192 node9 shield enable ${section.shieldKey}`) : "";
|
|
12355
|
+
console.log(" " + import_chalk3.default.dim("\u2500".repeat(70)));
|
|
12356
|
+
console.log(
|
|
12357
|
+
" " + import_chalk3.default.bold(section.label) + (section.subtitle ? import_chalk3.default.dim(` \xB7 ${section.subtitle}`) : "") + " " + import_chalk3.default.yellow(`${section.reviewCount} review`) + enableHint
|
|
12358
|
+
);
|
|
12359
|
+
for (const rule of reviewRules) {
|
|
12360
|
+
printRuleGroup(rule, topN, drillDown, previewWidth);
|
|
12361
|
+
}
|
|
12362
|
+
console.log("");
|
|
12363
|
+
}
|
|
12364
|
+
const activeShieldIds = new Set(
|
|
12365
|
+
summary.sections.filter((s) => s.sourceType === "shield" && s.shieldKey).map((s) => s.shieldKey)
|
|
12366
|
+
);
|
|
12367
|
+
const emptyShields = Object.keys(SHIELDS).filter((n) => !activeShieldIds.has(n)).sort();
|
|
12368
|
+
if (emptyShields.length > 0) {
|
|
12369
|
+
console.log(" " + import_chalk3.default.dim("\u2500".repeat(70)));
|
|
12370
|
+
console.log(
|
|
12371
|
+
" " + import_chalk3.default.bold("\u{1F6E1} Inactive Shields") + import_chalk3.default.dim(" \xB7 enable for more coverage")
|
|
12372
|
+
);
|
|
12373
|
+
console.log(" " + import_chalk3.default.dim(emptyShields.join(" \xB7 ")));
|
|
12374
|
+
console.log(" " + import_chalk3.default.dim("\u2192 node9 shield enable <name> to activate"));
|
|
12375
|
+
console.log("");
|
|
12030
12376
|
}
|
|
12031
|
-
console.log("");
|
|
12032
12377
|
}
|
|
12033
|
-
|
|
12034
|
-
const reviewRules = section.rules.filter((r) => r.verdict !== "block");
|
|
12035
|
-
if (reviewRules.length === 0) continue;
|
|
12036
|
-
const enableHint = section.shieldKey ? import_chalk3.default.dim(` \u2192 node9 shield enable ${section.shieldKey}`) : "";
|
|
12378
|
+
if (blast.reachable.length > 0 || blast.envFindings.length > 0) {
|
|
12037
12379
|
console.log(" " + import_chalk3.default.dim("\u2500".repeat(70)));
|
|
12038
12380
|
console.log(
|
|
12039
|
-
" " + import_chalk3.default.bold(
|
|
12381
|
+
" " + import_chalk3.default.bold("\u{1F52D} Blast Radius") + import_chalk3.default.dim(
|
|
12382
|
+
` \xB7 ${blastExposures} exposure${blastExposures !== 1 ? "s" : ""} an AI agent can reach right now`
|
|
12383
|
+
)
|
|
12040
12384
|
);
|
|
12041
|
-
|
|
12042
|
-
|
|
12385
|
+
console.log("");
|
|
12386
|
+
if (blast.reachable.length > 0) {
|
|
12387
|
+
for (const p of blast.reachable) {
|
|
12388
|
+
console.log(
|
|
12389
|
+
" " + import_chalk3.default.red("\u2717 ") + import_chalk3.default.yellow(p.label.padEnd(38)) + import_chalk3.default.dim(p.description)
|
|
12390
|
+
);
|
|
12391
|
+
}
|
|
12392
|
+
}
|
|
12393
|
+
if (blast.envFindings.length > 0) {
|
|
12394
|
+
for (const f of blast.envFindings) {
|
|
12395
|
+
console.log(
|
|
12396
|
+
" " + import_chalk3.default.red("\u2717 ") + import_chalk3.default.yellow(f.key.padEnd(38)) + import_chalk3.default.dim(f.patternName + " in environment")
|
|
12397
|
+
);
|
|
12398
|
+
}
|
|
12043
12399
|
}
|
|
12044
12400
|
console.log("");
|
|
12045
|
-
}
|
|
12046
|
-
const activeShieldIds = new Set(
|
|
12047
|
-
summary.sections.filter((s) => s.sourceType === "shield" && s.shieldKey).map((s) => s.shieldKey)
|
|
12048
|
-
);
|
|
12049
|
-
const emptyShields = Object.keys(SHIELDS).filter((n) => !activeShieldIds.has(n)).sort();
|
|
12050
|
-
if (emptyShields.length > 0) {
|
|
12051
|
-
console.log(" " + import_chalk3.default.dim("\u2500".repeat(70)));
|
|
12052
12401
|
console.log(
|
|
12053
|
-
|
|
12402
|
+
import_chalk3.default.dim(
|
|
12403
|
+
" \u2192 Run `node9 shield enable project-jail` to block agent access to these files."
|
|
12404
|
+
)
|
|
12054
12405
|
);
|
|
12055
|
-
console.log(" " + import_chalk3.default.dim(emptyShields.join(" \xB7 ")));
|
|
12056
|
-
console.log(" " + import_chalk3.default.dim("\u2192 node9 shield enable <name> to activate"));
|
|
12057
12406
|
console.log("");
|
|
12058
12407
|
}
|
|
12059
|
-
|
|
12060
|
-
|
|
12061
|
-
|
|
12062
|
-
|
|
12063
|
-
|
|
12064
|
-
|
|
12065
|
-
);
|
|
12066
|
-
console.log("");
|
|
12067
|
-
if (blast.reachable.length > 0) {
|
|
12068
|
-
for (const p of blast.reachable) {
|
|
12408
|
+
if (isWired) {
|
|
12409
|
+
console.log(import_chalk3.default.green(" \u2705 node9 is active \u2014 your future sessions are protected."));
|
|
12410
|
+
console.log(
|
|
12411
|
+
import_chalk3.default.dim(" Run ") + import_chalk3.default.cyan("node9 report") + import_chalk3.default.dim(" to see live protection stats.")
|
|
12412
|
+
);
|
|
12413
|
+
if (drillDown) {
|
|
12069
12414
|
console.log(
|
|
12070
|
-
|
|
12415
|
+
import_chalk3.default.dim(" Run ") + import_chalk3.default.cyan("node9 sessions --detail <session-id>") + import_chalk3.default.dim(" to see the full conversation for any session above.")
|
|
12071
12416
|
);
|
|
12072
|
-
}
|
|
12073
|
-
}
|
|
12074
|
-
if (blast.envFindings.length > 0) {
|
|
12075
|
-
for (const f of blast.envFindings) {
|
|
12417
|
+
} else {
|
|
12076
12418
|
console.log(
|
|
12077
|
-
|
|
12419
|
+
import_chalk3.default.dim(" Run ") + import_chalk3.default.cyan("node9 scan --drill-down") + import_chalk3.default.dim(" to see full commands and session IDs.")
|
|
12078
12420
|
);
|
|
12079
12421
|
}
|
|
12080
|
-
}
|
|
12081
|
-
console.log("");
|
|
12082
|
-
console.log(
|
|
12083
|
-
" Security Score: " + scoreLabel(blast.score) + import_chalk3.default.dim(
|
|
12084
|
-
` (${blast.reachable.length + blast.envFindings.length} exposure${blast.reachable.length + blast.envFindings.length !== 1 ? "s" : ""})`
|
|
12085
|
-
)
|
|
12086
|
-
);
|
|
12087
|
-
console.log(
|
|
12088
|
-
import_chalk3.default.dim(
|
|
12089
|
-
"\n Run `node9 shield enable project-jail` to block agent access to these files."
|
|
12090
|
-
)
|
|
12091
|
-
);
|
|
12092
|
-
console.log("");
|
|
12093
|
-
}
|
|
12094
|
-
if (isWired) {
|
|
12095
|
-
console.log(import_chalk3.default.green(" \u2705 node9 is active \u2014 your future sessions are protected."));
|
|
12096
|
-
console.log(
|
|
12097
|
-
import_chalk3.default.dim(" Run ") + import_chalk3.default.cyan("node9 report") + import_chalk3.default.dim(" to see live protection stats.")
|
|
12098
|
-
);
|
|
12099
|
-
if (drillDown) {
|
|
12100
|
-
console.log(
|
|
12101
|
-
import_chalk3.default.dim(" Run ") + import_chalk3.default.cyan("node9 sessions --detail <session-id>") + import_chalk3.default.dim(" to see the full conversation for any session above.")
|
|
12102
|
-
);
|
|
12103
12422
|
} else {
|
|
12423
|
+
const riskySummary = totalFindings + scan.dlpFindings.length;
|
|
12424
|
+
if (riskySummary > 0) {
|
|
12425
|
+
console.log(
|
|
12426
|
+
import_chalk3.default.yellow.bold(
|
|
12427
|
+
` \u26A1 ${riskySummary} operation${riskySummary !== 1 ? "s" : ""} ran unprotected.`
|
|
12428
|
+
) + import_chalk3.default.dim(" node9 would have caught them.")
|
|
12429
|
+
);
|
|
12430
|
+
console.log("");
|
|
12431
|
+
}
|
|
12432
|
+
console.log(import_chalk3.default.bold(" Enable real-time protection:"));
|
|
12433
|
+
console.log("");
|
|
12104
12434
|
console.log(
|
|
12105
|
-
import_chalk3.default.
|
|
12435
|
+
" " + import_chalk3.default.cyan("npm install -g @node9/proxy") + import_chalk3.default.dim(" && ") + import_chalk3.default.cyan("node9 init --recommended")
|
|
12106
12436
|
);
|
|
12107
|
-
|
|
12108
|
-
} else {
|
|
12109
|
-
const riskySummary = totalFindings + scan.dlpFindings.length;
|
|
12110
|
-
if (riskySummary > 0) {
|
|
12437
|
+
console.log("");
|
|
12111
12438
|
console.log(
|
|
12112
|
-
import_chalk3.default.
|
|
12113
|
-
|
|
12114
|
-
)
|
|
12439
|
+
import_chalk3.default.dim(
|
|
12440
|
+
" Hooks into Claude Code automatically. Every tool call checked before it runs."
|
|
12441
|
+
)
|
|
12115
12442
|
);
|
|
12443
|
+
console.log(" " + import_chalk3.default.dim("\u2192 ") + import_chalk3.default.underline("https://node9.ai"));
|
|
12116
12444
|
}
|
|
12117
12445
|
console.log("");
|
|
12118
|
-
|
|
12119
|
-
|
|
12120
|
-
|
|
12121
|
-
|
|
12122
|
-
|
|
12123
|
-
|
|
12124
|
-
|
|
12125
|
-
|
|
12126
|
-
|
|
12127
|
-
|
|
12128
|
-
|
|
12129
|
-
|
|
12130
|
-
|
|
12131
|
-
|
|
12132
|
-
|
|
12133
|
-
|
|
12134
|
-
|
|
12135
|
-
|
|
12136
|
-
|
|
12137
|
-
|
|
12138
|
-
|
|
12139
|
-
|
|
12140
|
-
|
|
12141
|
-
{ id: "codex", label: "Codex", icon: "\u{1F52E}", scan: codexScan }
|
|
12142
|
-
]);
|
|
12143
|
-
await fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/scan/push`, {
|
|
12144
|
-
method: "POST",
|
|
12145
|
-
headers: {
|
|
12146
|
-
"Content-Type": "application/json",
|
|
12147
|
-
"x-node9-internal": internalToken
|
|
12148
|
-
},
|
|
12149
|
-
body: JSON.stringify({ status: "complete", summary: pushSummary }),
|
|
12150
|
-
signal: AbortSignal.timeout(3e3)
|
|
12151
|
-
});
|
|
12152
|
-
openBrowserLocal();
|
|
12153
|
-
} catch {
|
|
12446
|
+
if (!isTestingMode()) {
|
|
12447
|
+
if (isWired) {
|
|
12448
|
+
const url = `http://${DAEMON_HOST}:${DAEMON_PORT}/?openscan=1`;
|
|
12449
|
+
if (isDaemonRunning()) {
|
|
12450
|
+
const internalToken = getInternalToken();
|
|
12451
|
+
if (internalToken) {
|
|
12452
|
+
try {
|
|
12453
|
+
const pushSummary = buildScanSummary([
|
|
12454
|
+
{ id: "claude", label: "Claude", icon: "\u{1F916}", scan: claudeScan },
|
|
12455
|
+
{ id: "gemini", label: "Gemini", icon: "\u264A", scan: geminiScan },
|
|
12456
|
+
{ id: "codex", label: "Codex", icon: "\u{1F52E}", scan: codexScan }
|
|
12457
|
+
]);
|
|
12458
|
+
await fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/scan/push`, {
|
|
12459
|
+
method: "POST",
|
|
12460
|
+
headers: {
|
|
12461
|
+
"Content-Type": "application/json",
|
|
12462
|
+
"x-node9-internal": internalToken
|
|
12463
|
+
},
|
|
12464
|
+
body: JSON.stringify({ status: "complete", summary: pushSummary }),
|
|
12465
|
+
signal: AbortSignal.timeout(3e3)
|
|
12466
|
+
});
|
|
12467
|
+
} catch {
|
|
12468
|
+
}
|
|
12154
12469
|
}
|
|
12155
12470
|
}
|
|
12471
|
+
if (isDaemonRunning()) {
|
|
12472
|
+
console.log(" " + import_chalk3.default.cyan("\u{1F310} View in browser:") + " " + import_chalk3.default.underline(url));
|
|
12473
|
+
} else {
|
|
12474
|
+
console.log(
|
|
12475
|
+
" " + import_chalk3.default.dim("\u{1F4CA} To view in browser, start the daemon: ") + import_chalk3.default.cyan("node9 daemon --background")
|
|
12476
|
+
);
|
|
12477
|
+
}
|
|
12478
|
+
console.log("");
|
|
12156
12479
|
}
|
|
12157
|
-
if (isDaemonRunning()) {
|
|
12158
|
-
console.log(" " + import_chalk3.default.cyan("\u{1F310} View in browser:") + " " + import_chalk3.default.underline(url));
|
|
12159
|
-
} else {
|
|
12160
|
-
console.log(
|
|
12161
|
-
" " + import_chalk3.default.dim("\u{1F4CA} To view in browser, start the daemon: ") + import_chalk3.default.cyan("node9 daemon --background")
|
|
12162
|
-
);
|
|
12163
|
-
}
|
|
12164
|
-
console.log("");
|
|
12165
12480
|
}
|
|
12166
12481
|
}
|
|
12167
|
-
|
|
12482
|
+
);
|
|
12168
12483
|
}
|
|
12169
12484
|
var import_chalk3, import_fs15, import_path17, import_os13, CLAUDE_PRICING, GEMINI_PRICING, CODE_EXTENSIONS, TERMINAL_ESCAPE_RE, LOOP_TOOLS, LOOP_THRESHOLD, STUCK_TOOLS_MIN_WASTE, STUCK_TOOLS_LIMIT, RECURRING_SESSION_THRESHOLD, STALE_AGE_DAYS, DEFAULT_RULE_NAMES;
|
|
12170
12485
|
var init_scan = __esm({
|
|
@@ -12700,14 +13015,6 @@ function readBody(req) {
|
|
|
12700
13015
|
req.on("end", () => resolve(body));
|
|
12701
13016
|
});
|
|
12702
13017
|
}
|
|
12703
|
-
function openBrowser(url) {
|
|
12704
|
-
if (process.env.NODE9_TESTING === "1") return;
|
|
12705
|
-
try {
|
|
12706
|
-
const args = process.platform === "darwin" ? ["open", url] : process.platform === "win32" ? ["cmd", "/c", "start", "", url] : ["xdg-open", url];
|
|
12707
|
-
(0, import_child_process4.spawn)(args[0], args.slice(1), { detached: true, stdio: "ignore" }).unref();
|
|
12708
|
-
} catch {
|
|
12709
|
-
}
|
|
12710
|
-
}
|
|
12711
13018
|
function estimateToolCost(tool, args) {
|
|
12712
13019
|
const a = args ?? {};
|
|
12713
13020
|
const t = tool.toLowerCase().replace(/[^a-z_]/g, "_");
|
|
@@ -12820,6 +13127,18 @@ function startActivitySocket() {
|
|
|
12820
13127
|
});
|
|
12821
13128
|
return;
|
|
12822
13129
|
}
|
|
13130
|
+
if (data.status === "execution-completed") {
|
|
13131
|
+
broadcast("execution-result", {
|
|
13132
|
+
id: data.id,
|
|
13133
|
+
ts: data.ts,
|
|
13134
|
+
tool: data.tool,
|
|
13135
|
+
agent: data.agent,
|
|
13136
|
+
mcpServer: data.mcpServer,
|
|
13137
|
+
durationMs: data.durationMs,
|
|
13138
|
+
isError: data.isError
|
|
13139
|
+
});
|
|
13140
|
+
return;
|
|
13141
|
+
}
|
|
12823
13142
|
if (data.status === "pending") {
|
|
12824
13143
|
broadcast("activity", {
|
|
12825
13144
|
id: data.id,
|
|
@@ -12827,7 +13146,8 @@ function startActivitySocket() {
|
|
|
12827
13146
|
tool: data.tool,
|
|
12828
13147
|
args: redactArgs(data.args),
|
|
12829
13148
|
status: "pending",
|
|
12830
|
-
agent: data.agent
|
|
13149
|
+
agent: data.agent,
|
|
13150
|
+
mcpServer: data.mcpServer
|
|
12831
13151
|
});
|
|
12832
13152
|
} else {
|
|
12833
13153
|
if (data.status === "allow") {
|
|
@@ -12854,7 +13174,9 @@ function startActivitySocket() {
|
|
|
12854
13174
|
id: data.id,
|
|
12855
13175
|
status: data.status,
|
|
12856
13176
|
label: data.label,
|
|
12857
|
-
costEstimate
|
|
13177
|
+
costEstimate,
|
|
13178
|
+
agent: data.agent,
|
|
13179
|
+
mcpServer: data.mcpServer
|
|
12858
13180
|
});
|
|
12859
13181
|
}
|
|
12860
13182
|
} catch {
|
|
@@ -12871,7 +13193,7 @@ function startActivitySocket() {
|
|
|
12871
13193
|
}
|
|
12872
13194
|
});
|
|
12873
13195
|
}
|
|
12874
|
-
var import_net2, import_fs17, import_path19, import_os14,
|
|
13196
|
+
var import_net2, import_fs17, import_path19, import_os14, import_crypto6, homeDir, DAEMON_PID_FILE, DECISIONS_FILE, AUDIT_LOG_FILE, TRUST_FILE2, GLOBAL_CONFIG_FILE, CREDENTIALS_FILE, INSIGHT_COUNTS_FILE, pending, sseClients, suggestionTracker, suggestions, taintStore, insightCounts, _abandonTimer, _hadBrowserClient, _daemonServer, daemonRejectionHandlerRegistered, AUTO_DENY_MS, TRUST_DURATIONS, autoStarted, ACTIVITY_SOCKET_PATH2, ACTIVITY_RING_SIZE, activityRing, LARGE_RESPONSE_RING_SIZE, largeResponseRing, cachedScanResult, cachedScanTs, SCAN_CACHE_TTL_MS, SECRET_KEY_RE, INPUT_PRICE_PER_1M, OUTPUT_PRICE_PER_1M, BYTES_PER_TOKEN, WRITE_TOOL_NAMES;
|
|
12875
13197
|
var init_state2 = __esm({
|
|
12876
13198
|
"src/daemon/state.ts"() {
|
|
12877
13199
|
"use strict";
|
|
@@ -12879,7 +13201,6 @@ var init_state2 = __esm({
|
|
|
12879
13201
|
import_fs17 = __toESM(require("fs"));
|
|
12880
13202
|
import_path19 = __toESM(require("path"));
|
|
12881
13203
|
import_os14 = __toESM(require("os"));
|
|
12882
|
-
import_child_process4 = require("child_process");
|
|
12883
13204
|
import_crypto6 = require("crypto");
|
|
12884
13205
|
init_daemon();
|
|
12885
13206
|
init_suggestion_tracker();
|
|
@@ -13536,7 +13857,6 @@ function startDaemon() {
|
|
|
13536
13857
|
const IDLE_TIMEOUT_MS = 12 * 60 * 60 * 1e3;
|
|
13537
13858
|
const watchMode = process.env.NODE9_WATCH_MODE === "1";
|
|
13538
13859
|
let idleTimer;
|
|
13539
|
-
let browserOpened = false;
|
|
13540
13860
|
function resetIdleTimer() {
|
|
13541
13861
|
if (watchMode) return;
|
|
13542
13862
|
if (idleTimer) clearTimeout(idleTimer);
|
|
@@ -13645,12 +13965,6 @@ data: ${JSON.stringify(item.data)}
|
|
|
13645
13965
|
}
|
|
13646
13966
|
});
|
|
13647
13967
|
}
|
|
13648
|
-
if (req.method === "POST" && pathname === "/browser-opened") {
|
|
13649
|
-
if (req.headers["x-node9-internal"] !== internalToken) return res.writeHead(403).end();
|
|
13650
|
-
browserOpened = true;
|
|
13651
|
-
res.writeHead(200).end();
|
|
13652
|
-
return;
|
|
13653
|
-
}
|
|
13654
13968
|
if (req.method === "POST" && pathname === "/check") {
|
|
13655
13969
|
try {
|
|
13656
13970
|
resetIdleTimer();
|
|
@@ -13711,7 +14025,9 @@ data: ${JSON.stringify(item.data)}
|
|
|
13711
14025
|
ts: entry.timestamp,
|
|
13712
14026
|
tool: toolName,
|
|
13713
14027
|
args: redactArgs(args),
|
|
13714
|
-
status: "pending"
|
|
14028
|
+
status: "pending",
|
|
14029
|
+
agent: entry.agent,
|
|
14030
|
+
mcpServer: entry.mcpServer
|
|
13715
14031
|
});
|
|
13716
14032
|
}
|
|
13717
14033
|
const projectCwd = typeof cwd === "string" && import_path25.default.isAbsolute(cwd) ? cwd : void 0;
|
|
@@ -13734,11 +14050,6 @@ data: ${JSON.stringify(item.data)}
|
|
|
13734
14050
|
// Terminal uses this to show the 💡 insight line on the Nth consecutive approval.
|
|
13735
14051
|
allowCount: (insightCounts.get(toolName) ?? 0) + 1
|
|
13736
14052
|
});
|
|
13737
|
-
const browserAlreadyOpened = process.env.NODE9_BROWSER_OPENED === "1";
|
|
13738
|
-
if (browserEnabled && !browserOpened && !browserAlreadyOpened) {
|
|
13739
|
-
browserOpened = true;
|
|
13740
|
-
openBrowser(`http://127.0.0.1:${DAEMON_PORT}/`);
|
|
13741
|
-
}
|
|
13742
14053
|
}
|
|
13743
14054
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
13744
14055
|
res.end(JSON.stringify({ id, allowCount: (insightCounts.get(toolName) ?? 0) + 1 }));
|
|
@@ -13760,7 +14071,9 @@ data: ${JSON.stringify(item.data)}
|
|
|
13760
14071
|
broadcast("activity-result", {
|
|
13761
14072
|
id,
|
|
13762
14073
|
status: result.approved ? "allow" : result.blockedByLabel?.includes("DLP") ? "dlp" : "block",
|
|
13763
|
-
label: result.blockedByLabel
|
|
14074
|
+
label: result.blockedByLabel,
|
|
14075
|
+
agent: e.agent,
|
|
14076
|
+
mcpServer: e.mcpServer
|
|
13764
14077
|
});
|
|
13765
14078
|
clearTimeout(e.timer);
|
|
13766
14079
|
const decision = result.approved ? "allow" : "deny";
|
|
@@ -14534,7 +14847,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
14534
14847
|
}).then((res) => {
|
|
14535
14848
|
if (res.ok) {
|
|
14536
14849
|
try {
|
|
14537
|
-
const r = (0,
|
|
14850
|
+
const r = (0, import_child_process4.spawnSync)("ss", ["-Htnp", `sport = :${DAEMON_PORT}`], {
|
|
14538
14851
|
encoding: "utf8",
|
|
14539
14852
|
timeout: 1e3
|
|
14540
14853
|
});
|
|
@@ -14582,7 +14895,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
14582
14895
|
}
|
|
14583
14896
|
startActivitySocket();
|
|
14584
14897
|
}
|
|
14585
|
-
var import_http, import_fs23, import_path25, import_os20, import_crypto7,
|
|
14898
|
+
var import_http, import_fs23, import_path25, import_os20, import_crypto7, import_child_process4, import_chalk4;
|
|
14586
14899
|
var init_server = __esm({
|
|
14587
14900
|
"src/daemon/server.ts"() {
|
|
14588
14901
|
"use strict";
|
|
@@ -14591,7 +14904,7 @@ var init_server = __esm({
|
|
|
14591
14904
|
import_path25 = __toESM(require("path"));
|
|
14592
14905
|
import_os20 = __toESM(require("os"));
|
|
14593
14906
|
import_crypto7 = require("crypto");
|
|
14594
|
-
|
|
14907
|
+
import_child_process4 = require("child_process");
|
|
14595
14908
|
import_chalk4 = __toESM(require("chalk"));
|
|
14596
14909
|
init_core();
|
|
14597
14910
|
init_shields();
|
|
@@ -14620,7 +14933,7 @@ function resolveNode9Binary() {
|
|
|
14620
14933
|
}
|
|
14621
14934
|
try {
|
|
14622
14935
|
const cmd = process.platform === "win32" ? "where" : "which";
|
|
14623
|
-
const r = (0,
|
|
14936
|
+
const r = (0, import_child_process5.spawnSync)(cmd, ["node9"], { encoding: "utf8", timeout: 3e3 });
|
|
14624
14937
|
if (r.status === 0 && r.stdout.trim()) {
|
|
14625
14938
|
return r.stdout.trim().split("\n")[0].trim();
|
|
14626
14939
|
}
|
|
@@ -14674,8 +14987,8 @@ function installLaunchd(binaryPath) {
|
|
|
14674
14987
|
const dir = import_path26.default.dirname(LAUNCHD_PLIST);
|
|
14675
14988
|
if (!import_fs24.default.existsSync(dir)) import_fs24.default.mkdirSync(dir, { recursive: true });
|
|
14676
14989
|
import_fs24.default.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
|
|
14677
|
-
(0,
|
|
14678
|
-
const r = (0,
|
|
14990
|
+
(0, import_child_process5.spawnSync)("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
|
|
14991
|
+
const r = (0, import_child_process5.spawnSync)("launchctl", ["load", "-w", LAUNCHD_PLIST], {
|
|
14679
14992
|
encoding: "utf8",
|
|
14680
14993
|
timeout: 5e3
|
|
14681
14994
|
});
|
|
@@ -14685,7 +14998,7 @@ function installLaunchd(binaryPath) {
|
|
|
14685
14998
|
}
|
|
14686
14999
|
function uninstallLaunchd() {
|
|
14687
15000
|
if (import_fs24.default.existsSync(LAUNCHD_PLIST)) {
|
|
14688
|
-
(0,
|
|
15001
|
+
(0, import_child_process5.spawnSync)("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
|
|
14689
15002
|
import_fs24.default.unlinkSync(LAUNCHD_PLIST);
|
|
14690
15003
|
}
|
|
14691
15004
|
}
|
|
@@ -14715,18 +15028,18 @@ function installSystemd(binaryPath) {
|
|
|
14715
15028
|
}
|
|
14716
15029
|
import_fs24.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
|
|
14717
15030
|
try {
|
|
14718
|
-
(0,
|
|
15031
|
+
(0, import_child_process5.execFileSync)("loginctl", ["enable-linger", import_os21.default.userInfo().username], { timeout: 3e3 });
|
|
14719
15032
|
} catch {
|
|
14720
15033
|
}
|
|
14721
|
-
const reload = (0,
|
|
15034
|
+
const reload = (0, import_child_process5.spawnSync)("systemctl", ["--user", "daemon-reload"], {
|
|
14722
15035
|
encoding: "utf8",
|
|
14723
15036
|
timeout: 5e3
|
|
14724
15037
|
});
|
|
14725
15038
|
if (reload.status !== 0) {
|
|
14726
15039
|
throw new Error(`systemctl daemon-reload failed: ${reload.stderr}`);
|
|
14727
15040
|
}
|
|
14728
|
-
(0,
|
|
14729
|
-
const enable = (0,
|
|
15041
|
+
(0, import_child_process5.spawnSync)("systemctl", ["--user", "stop", "node9-daemon"], { encoding: "utf8", timeout: 3e3 });
|
|
15042
|
+
const enable = (0, import_child_process5.spawnSync)("systemctl", ["--user", "enable", "--now", "node9-daemon"], {
|
|
14730
15043
|
encoding: "utf8",
|
|
14731
15044
|
timeout: 5e3
|
|
14732
15045
|
});
|
|
@@ -14736,11 +15049,11 @@ function installSystemd(binaryPath) {
|
|
|
14736
15049
|
}
|
|
14737
15050
|
function uninstallSystemd() {
|
|
14738
15051
|
if (import_fs24.default.existsSync(SYSTEMD_UNIT)) {
|
|
14739
|
-
(0,
|
|
15052
|
+
(0, import_child_process5.spawnSync)("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
|
|
14740
15053
|
encoding: "utf8",
|
|
14741
15054
|
timeout: 5e3
|
|
14742
15055
|
});
|
|
14743
|
-
(0,
|
|
15056
|
+
(0, import_child_process5.spawnSync)("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
|
|
14744
15057
|
import_fs24.default.unlinkSync(SYSTEMD_UNIT);
|
|
14745
15058
|
}
|
|
14746
15059
|
}
|
|
@@ -14758,7 +15071,7 @@ function stopRunningDaemon() {
|
|
|
14758
15071
|
try {
|
|
14759
15072
|
process.kill(pid, "SIGTERM");
|
|
14760
15073
|
const deadline = Date.now() + 3e3;
|
|
14761
|
-
const pollStop = (0,
|
|
15074
|
+
const pollStop = (0, import_child_process5.spawnSync)(
|
|
14762
15075
|
"sh",
|
|
14763
15076
|
["-c", `while kill -0 ${pid} 2>/dev/null; do sleep 0.1; done`],
|
|
14764
15077
|
{
|
|
@@ -14790,7 +15103,7 @@ function installDaemonService() {
|
|
|
14790
15103
|
return { ok: true, platform: "launchd", alreadyInstalled };
|
|
14791
15104
|
}
|
|
14792
15105
|
if (process.platform === "linux") {
|
|
14793
|
-
const check = (0,
|
|
15106
|
+
const check = (0, import_child_process5.spawnSync)("systemctl", ["--user", "--version"], {
|
|
14794
15107
|
encoding: "utf8",
|
|
14795
15108
|
timeout: 2e3
|
|
14796
15109
|
});
|
|
@@ -14841,14 +15154,14 @@ function isDaemonServiceInstalled() {
|
|
|
14841
15154
|
if (process.platform === "linux") return isSystemdInstalled();
|
|
14842
15155
|
return false;
|
|
14843
15156
|
}
|
|
14844
|
-
var import_fs24, import_path26, import_os21,
|
|
15157
|
+
var import_fs24, import_path26, import_os21, import_child_process5, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
|
|
14845
15158
|
var init_service = __esm({
|
|
14846
15159
|
"src/daemon/service.ts"() {
|
|
14847
15160
|
"use strict";
|
|
14848
15161
|
import_fs24 = __toESM(require("fs"));
|
|
14849
15162
|
import_path26 = __toESM(require("path"));
|
|
14850
15163
|
import_os21 = __toESM(require("os"));
|
|
14851
|
-
|
|
15164
|
+
import_child_process5 = require("child_process");
|
|
14852
15165
|
LAUNCHD_LABEL = "ai.node9.daemon";
|
|
14853
15166
|
LAUNCHD_PLIST = import_path26.default.join(import_os21.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
14854
15167
|
SYSTEMD_UNIT_DIR = import_path26.default.join(import_os21.default.homedir(), ".config", "systemd", "user");
|
|
@@ -14898,7 +15211,7 @@ function daemonStatus() {
|
|
|
14898
15211
|
processStatus = import_chalk5.default.yellow("not running (stale PID file)");
|
|
14899
15212
|
}
|
|
14900
15213
|
} else {
|
|
14901
|
-
const r = (0,
|
|
15214
|
+
const r = (0, import_child_process6.spawnSync)("ss", ["-Htnp", `sport = :${DAEMON_PORT}`], {
|
|
14902
15215
|
encoding: "utf8",
|
|
14903
15216
|
timeout: 500
|
|
14904
15217
|
});
|
|
@@ -14913,13 +15226,13 @@ function daemonStatus() {
|
|
|
14913
15226
|
console.log(` Service : ${serviceLabel}
|
|
14914
15227
|
`);
|
|
14915
15228
|
}
|
|
14916
|
-
var import_fs25, import_chalk5,
|
|
15229
|
+
var import_fs25, import_chalk5, import_child_process6, MAX_PID;
|
|
14917
15230
|
var init_daemon2 = __esm({
|
|
14918
15231
|
"src/daemon/index.ts"() {
|
|
14919
15232
|
"use strict";
|
|
14920
15233
|
import_fs25 = __toESM(require("fs"));
|
|
14921
15234
|
import_chalk5 = __toESM(require("chalk"));
|
|
14922
|
-
|
|
15235
|
+
import_child_process6 = require("child_process");
|
|
14923
15236
|
init_server();
|
|
14924
15237
|
init_state2();
|
|
14925
15238
|
init_service();
|
|
@@ -15018,10 +15331,13 @@ function wrappedLineCount(text) {
|
|
|
15018
15331
|
const len = visibleLength(text);
|
|
15019
15332
|
return Math.max(1, Math.ceil(len / cols));
|
|
15020
15333
|
}
|
|
15021
|
-
function agentLabel(agent) {
|
|
15022
|
-
if (!agent || agent === "Terminal")
|
|
15334
|
+
function agentLabel(agent, mcpServer) {
|
|
15335
|
+
if (!agent || agent === "Terminal") {
|
|
15336
|
+
return mcpServer ? import_chalk27.default.dim(`[\u2192 ${mcpServer}] `) : "";
|
|
15337
|
+
}
|
|
15023
15338
|
const short = agent === "Claude Code" ? "Claude" : agent === "Gemini CLI" ? "Gemini" : agent === "Unknown Agent" ? "" : agent.split(" ")[0];
|
|
15024
|
-
|
|
15339
|
+
if (!short) return mcpServer ? import_chalk27.default.dim(`[\u2192 ${mcpServer}] `) : "";
|
|
15340
|
+
return mcpServer ? import_chalk27.default.dim(`[${short} \u2192 ${mcpServer}] `) : import_chalk27.default.dim(`[${short}] `);
|
|
15025
15341
|
}
|
|
15026
15342
|
function formatBase(activity) {
|
|
15027
15343
|
const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
|
|
@@ -15029,7 +15345,7 @@ function formatBase(activity) {
|
|
|
15029
15345
|
const toolName = activity.tool.slice(0, 16).padEnd(16);
|
|
15030
15346
|
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os37.default.homedir(), "~");
|
|
15031
15347
|
const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
|
|
15032
|
-
return `${import_chalk27.default.gray(time)} ${icon} ${agentLabel(activity.agent)}${import_chalk27.default.white.bold(toolName)} ${import_chalk27.default.dim(argsPreview)}`;
|
|
15348
|
+
return `${import_chalk27.default.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer)}${import_chalk27.default.white.bold(toolName)} ${import_chalk27.default.dim(argsPreview)}`;
|
|
15033
15349
|
}
|
|
15034
15350
|
function renderResult(activity, result) {
|
|
15035
15351
|
const base = formatBase(activity);
|
|
@@ -15083,7 +15399,7 @@ async function ensureDaemon() {
|
|
|
15083
15399
|
} catch {
|
|
15084
15400
|
}
|
|
15085
15401
|
console.log(import_chalk27.default.dim("\u{1F6E1}\uFE0F Starting Node9 daemon..."));
|
|
15086
|
-
const child = (0,
|
|
15402
|
+
const child = (0, import_child_process15.spawn)(process.execPath, [process.argv[1], "daemon"], {
|
|
15087
15403
|
detached: true,
|
|
15088
15404
|
stdio: "ignore",
|
|
15089
15405
|
env: { ...process.env, NODE9_AUTO_STARTED: "1" }
|
|
@@ -15483,22 +15799,6 @@ async function startTail(options = {}) {
|
|
|
15483
15799
|
process.stdin.on("keypress", onKeypress);
|
|
15484
15800
|
}
|
|
15485
15801
|
const dashboardUrl = `http://127.0.0.1:${port}/`;
|
|
15486
|
-
try {
|
|
15487
|
-
const browserEnabled = getConfig().settings.approvers?.browser !== false;
|
|
15488
|
-
if (browserEnabled) {
|
|
15489
|
-
if (process.platform === "darwin") (0, import_child_process16.execSync)(`open "${dashboardUrl}"`, { stdio: "ignore" });
|
|
15490
|
-
else if (process.platform === "win32")
|
|
15491
|
-
(0, import_child_process16.execSync)(`cmd /c start "" "${dashboardUrl}"`, { stdio: "ignore" });
|
|
15492
|
-
else (0, import_child_process16.execSync)(`xdg-open "${dashboardUrl}"`, { stdio: "ignore" });
|
|
15493
|
-
const intToken = getInternalToken();
|
|
15494
|
-
fetch(`http://127.0.0.1:${port}/browser-opened`, {
|
|
15495
|
-
method: "POST",
|
|
15496
|
-
headers: intToken ? { "X-Node9-Internal": intToken } : {}
|
|
15497
|
-
}).catch(() => {
|
|
15498
|
-
});
|
|
15499
|
-
}
|
|
15500
|
-
} catch {
|
|
15501
|
-
}
|
|
15502
15802
|
const auditLog = import_path43.default.join(import_os37.default.homedir(), ".node9", "audit.log");
|
|
15503
15803
|
try {
|
|
15504
15804
|
const unackedDlp = import_fs41.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
@@ -15678,6 +15978,17 @@ async function startTail(options = {}) {
|
|
|
15678
15978
|
orphanedResults.set(data.id, data);
|
|
15679
15979
|
}
|
|
15680
15980
|
}
|
|
15981
|
+
if (event === "execution-result") {
|
|
15982
|
+
const exec = data;
|
|
15983
|
+
const time = new Date(Date.now()).toLocaleTimeString([], { hour12: false });
|
|
15984
|
+
const arrow = exec.isError ? import_chalk27.default.red(" \u21B3 \u2717") : import_chalk27.default.green(" \u21B3 \u2713");
|
|
15985
|
+
const label = agentLabel(exec.agent, exec.mcpServer);
|
|
15986
|
+
const tool = (exec.tool ?? "").slice(0, 16);
|
|
15987
|
+
const duration = typeof exec.durationMs === "number" ? import_chalk27.default.dim(` (${exec.durationMs}ms)`) : "";
|
|
15988
|
+
console.log(
|
|
15989
|
+
`${import_chalk27.default.gray(time)} ${arrow} ${label}${import_chalk27.default.dim(tool)}${import_chalk27.default.dim(" completed")}${duration}`
|
|
15990
|
+
);
|
|
15991
|
+
}
|
|
15681
15992
|
}
|
|
15682
15993
|
req.on("error", (err2) => {
|
|
15683
15994
|
const msg = err2.code === "ECONNREFUSED" ? "Daemon is not running. Start it with: node9 daemon start" : err2.message;
|
|
@@ -15686,7 +15997,7 @@ async function startTail(options = {}) {
|
|
|
15686
15997
|
process.exit(1);
|
|
15687
15998
|
});
|
|
15688
15999
|
}
|
|
15689
|
-
var import_http2, import_chalk27, import_fs41, import_os37, import_path43, import_readline5,
|
|
16000
|
+
var import_http2, import_chalk27, import_fs41, import_os37, import_path43, import_readline5, import_child_process15, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
|
|
15690
16001
|
var init_tail = __esm({
|
|
15691
16002
|
"src/tui/tail.ts"() {
|
|
15692
16003
|
"use strict";
|
|
@@ -15696,10 +16007,8 @@ var init_tail = __esm({
|
|
|
15696
16007
|
import_os37 = __toESM(require("os"));
|
|
15697
16008
|
import_path43 = __toESM(require("path"));
|
|
15698
16009
|
import_readline5 = __toESM(require("readline"));
|
|
15699
|
-
|
|
16010
|
+
import_child_process15 = require("child_process");
|
|
15700
16011
|
init_daemon2();
|
|
15701
|
-
init_daemon();
|
|
15702
|
-
init_core();
|
|
15703
16012
|
PID_FILE = import_path43.default.join(import_os37.default.homedir(), ".node9", "daemon.pid");
|
|
15704
16013
|
ICONS = {
|
|
15705
16014
|
bash: "\u{1F4BB}",
|
|
@@ -16153,7 +16462,7 @@ function parseDuration(str) {
|
|
|
16153
16462
|
// src/proxy/index.ts
|
|
16154
16463
|
var import_readline = __toESM(require("readline"));
|
|
16155
16464
|
var import_chalk6 = __toESM(require("chalk"));
|
|
16156
|
-
var
|
|
16465
|
+
var import_child_process7 = require("child_process");
|
|
16157
16466
|
var import_execa = require("execa");
|
|
16158
16467
|
var import_execa2 = require("execa");
|
|
16159
16468
|
init_orchestrator();
|
|
@@ -16241,11 +16550,11 @@ async function runProxy(targetCommand) {
|
|
|
16241
16550
|
}
|
|
16242
16551
|
console.error(import_chalk6.default.green(`\u{1F680} Node9 Proxy Active: Monitoring [${targetCommand}]`));
|
|
16243
16552
|
const spawnEnv = { ...process.env, FORCE_COLOR: "1" };
|
|
16244
|
-
const child = useShell ? (0,
|
|
16553
|
+
const child = useShell ? (0, import_child_process7.spawn)("/bin/bash", ["-c", targetCommand], {
|
|
16245
16554
|
stdio: ["pipe", "pipe", "inherit"],
|
|
16246
16555
|
shell: false,
|
|
16247
16556
|
env: spawnEnv
|
|
16248
|
-
}) : (0,
|
|
16557
|
+
}) : (0, import_child_process7.spawn)(executable, args, { stdio: ["pipe", "pipe", "inherit"], shell: false, env: spawnEnv });
|
|
16249
16558
|
const agentIn = import_readline.default.createInterface({ input: process.stdin, terminal: false });
|
|
16250
16559
|
agentIn.on("line", async (line) => {
|
|
16251
16560
|
let message;
|
|
@@ -16314,7 +16623,7 @@ init_daemon_starter();
|
|
|
16314
16623
|
// src/cli/commands/check.ts
|
|
16315
16624
|
var import_chalk7 = __toESM(require("chalk"));
|
|
16316
16625
|
var import_fs28 = __toESM(require("fs"));
|
|
16317
|
-
var
|
|
16626
|
+
var import_child_process9 = require("child_process");
|
|
16318
16627
|
var import_path29 = __toESM(require("path"));
|
|
16319
16628
|
var import_os24 = __toESM(require("os"));
|
|
16320
16629
|
init_orchestrator();
|
|
@@ -16323,7 +16632,7 @@ init_config();
|
|
|
16323
16632
|
init_policy();
|
|
16324
16633
|
|
|
16325
16634
|
// src/undo.ts
|
|
16326
|
-
var
|
|
16635
|
+
var import_child_process8 = require("child_process");
|
|
16327
16636
|
var import_crypto8 = __toESM(require("crypto"));
|
|
16328
16637
|
var import_fs26 = __toESM(require("fs"));
|
|
16329
16638
|
var import_net3 = __toESM(require("net"));
|
|
@@ -16436,7 +16745,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
16436
16745
|
cleanOrphanedIndexFiles(shadowDir);
|
|
16437
16746
|
const normalizedCwd = normalizeCwdForHash(cwd);
|
|
16438
16747
|
const shadowEnvBase = { ...process.env, GIT_DIR: shadowDir, GIT_WORK_TREE: cwd };
|
|
16439
|
-
const check = (0,
|
|
16748
|
+
const check = (0, import_child_process8.spawnSync)("git", ["rev-parse", "--git-dir"], {
|
|
16440
16749
|
env: shadowEnvBase,
|
|
16441
16750
|
timeout: 3e3
|
|
16442
16751
|
});
|
|
@@ -16462,17 +16771,17 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
16462
16771
|
import_fs26.default.mkdirSync(shadowDir, { recursive: true });
|
|
16463
16772
|
} catch {
|
|
16464
16773
|
}
|
|
16465
|
-
const init = (0,
|
|
16774
|
+
const init = (0, import_child_process8.spawnSync)("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
|
|
16466
16775
|
if (init.status !== 0 || init.error) {
|
|
16467
16776
|
const reason = init.error ? init.error.message : init.stderr?.toString();
|
|
16468
16777
|
if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
|
|
16469
16778
|
return false;
|
|
16470
16779
|
}
|
|
16471
16780
|
const configFile = import_path27.default.join(shadowDir, "config");
|
|
16472
|
-
(0,
|
|
16781
|
+
(0, import_child_process8.spawnSync)("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
|
|
16473
16782
|
timeout: 3e3
|
|
16474
16783
|
});
|
|
16475
|
-
(0,
|
|
16784
|
+
(0, import_child_process8.spawnSync)("git", ["config", "--file", configFile, "core.fsmonitor", "true"], {
|
|
16476
16785
|
timeout: 3e3
|
|
16477
16786
|
});
|
|
16478
16787
|
try {
|
|
@@ -16483,7 +16792,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
16483
16792
|
}
|
|
16484
16793
|
function buildGitEnv(cwd) {
|
|
16485
16794
|
const shadowDir = getShadowRepoDir(cwd);
|
|
16486
|
-
const check = (0,
|
|
16795
|
+
const check = (0, import_child_process8.spawnSync)("git", ["rev-parse", "--git-dir"], {
|
|
16487
16796
|
env: { ...process.env, GIT_DIR: shadowDir, GIT_WORK_TREE: cwd },
|
|
16488
16797
|
timeout: 2e3
|
|
16489
16798
|
});
|
|
@@ -16508,11 +16817,11 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
16508
16817
|
GIT_WORK_TREE: cwd,
|
|
16509
16818
|
GIT_INDEX_FILE: indexFile
|
|
16510
16819
|
};
|
|
16511
|
-
(0,
|
|
16512
|
-
const treeRes = (0,
|
|
16820
|
+
(0, import_child_process8.spawnSync)("git", ["add", "-A"], { env: shadowEnv, timeout: GIT_TIMEOUT });
|
|
16821
|
+
const treeRes = (0, import_child_process8.spawnSync)("git", ["write-tree"], { env: shadowEnv, timeout: GIT_TIMEOUT });
|
|
16513
16822
|
const treeHash = treeRes.stdout?.toString().trim();
|
|
16514
16823
|
if (!treeHash || treeRes.status !== 0) return null;
|
|
16515
|
-
const commitRes = (0,
|
|
16824
|
+
const commitRes = (0, import_child_process8.spawnSync)(
|
|
16516
16825
|
"git",
|
|
16517
16826
|
["commit-tree", treeHash, "-m", `Node9 AI Snapshot: ${(/* @__PURE__ */ new Date()).toISOString()}`],
|
|
16518
16827
|
{ env: shadowEnv, timeout: GIT_TIMEOUT }
|
|
@@ -16524,7 +16833,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
16524
16833
|
let capturedFiles = [];
|
|
16525
16834
|
let capturedDiff = null;
|
|
16526
16835
|
if (prevEntry) {
|
|
16527
|
-
const filesRes = (0,
|
|
16836
|
+
const filesRes = (0, import_child_process8.spawnSync)("git", ["diff", "--name-only", prevEntry.hash, commitHash], {
|
|
16528
16837
|
env: shadowEnv,
|
|
16529
16838
|
timeout: GIT_TIMEOUT
|
|
16530
16839
|
});
|
|
@@ -16534,7 +16843,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
16534
16843
|
if (capturedFiles.length === 0) {
|
|
16535
16844
|
return prevEntry.hash;
|
|
16536
16845
|
}
|
|
16537
|
-
const diffRes = (0,
|
|
16846
|
+
const diffRes = (0, import_child_process8.spawnSync)("git", ["diff", prevEntry.hash, commitHash], {
|
|
16538
16847
|
env: shadowEnv,
|
|
16539
16848
|
timeout: GIT_TIMEOUT
|
|
16540
16849
|
});
|
|
@@ -16542,7 +16851,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
16542
16851
|
capturedDiff = diffRes.stdout?.toString() || null;
|
|
16543
16852
|
}
|
|
16544
16853
|
} else {
|
|
16545
|
-
const filesRes = (0,
|
|
16854
|
+
const filesRes = (0, import_child_process8.spawnSync)("git", ["ls-tree", "-r", "--name-only", commitHash], {
|
|
16546
16855
|
env: shadowEnv,
|
|
16547
16856
|
timeout: GIT_TIMEOUT
|
|
16548
16857
|
});
|
|
@@ -16575,7 +16884,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
16575
16884
|
notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
|
|
16576
16885
|
import_fs26.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
|
|
16577
16886
|
if (shouldGc) {
|
|
16578
|
-
(0,
|
|
16887
|
+
(0, import_child_process8.spawn)("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
|
|
16579
16888
|
}
|
|
16580
16889
|
return commitHash;
|
|
16581
16890
|
} catch (err2) {
|
|
@@ -16596,14 +16905,14 @@ function getSnapshotHistory() {
|
|
|
16596
16905
|
function computeUndoDiff(hash, cwd) {
|
|
16597
16906
|
try {
|
|
16598
16907
|
const env = buildGitEnv(cwd);
|
|
16599
|
-
const statRes = (0,
|
|
16908
|
+
const statRes = (0, import_child_process8.spawnSync)("git", ["diff", hash, "--stat", "--", "."], {
|
|
16600
16909
|
cwd,
|
|
16601
16910
|
env,
|
|
16602
16911
|
timeout: GIT_TIMEOUT
|
|
16603
16912
|
});
|
|
16604
16913
|
const stat = statRes.stdout?.toString().trim();
|
|
16605
16914
|
if (!stat || statRes.status !== 0) return null;
|
|
16606
|
-
const diffRes = (0,
|
|
16915
|
+
const diffRes = (0, import_child_process8.spawnSync)("git", ["diff", hash, "--", "."], {
|
|
16607
16916
|
cwd,
|
|
16608
16917
|
env,
|
|
16609
16918
|
timeout: GIT_TIMEOUT
|
|
@@ -16622,7 +16931,7 @@ function applyUndo(hash, cwd) {
|
|
|
16622
16931
|
try {
|
|
16623
16932
|
const dir = cwd ?? process.cwd();
|
|
16624
16933
|
const env = buildGitEnv(dir);
|
|
16625
|
-
const restore = (0,
|
|
16934
|
+
const restore = (0, import_child_process8.spawnSync)("git", ["restore", "--source", hash, "--staged", "--worktree", "."], {
|
|
16626
16935
|
cwd: dir,
|
|
16627
16936
|
env,
|
|
16628
16937
|
timeout: GIT_TIMEOUT
|
|
@@ -16634,7 +16943,7 @@ function applyUndo(hash, cwd) {
|
|
|
16634
16943
|
}
|
|
16635
16944
|
return false;
|
|
16636
16945
|
}
|
|
16637
|
-
const lsTree = (0,
|
|
16946
|
+
const lsTree = (0, import_child_process8.spawnSync)("git", ["ls-tree", "-r", "--name-only", hash], {
|
|
16638
16947
|
cwd: dir,
|
|
16639
16948
|
env,
|
|
16640
16949
|
timeout: GIT_TIMEOUT
|
|
@@ -16653,8 +16962,8 @@ function applyUndo(hash, cwd) {
|
|
|
16653
16962
|
`);
|
|
16654
16963
|
return false;
|
|
16655
16964
|
}
|
|
16656
|
-
const tracked = (0,
|
|
16657
|
-
const untracked = (0,
|
|
16965
|
+
const tracked = (0, import_child_process8.spawnSync)("git", ["ls-files"], { cwd: dir, env, timeout: GIT_TIMEOUT }).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
|
|
16966
|
+
const untracked = (0, import_child_process8.spawnSync)("git", ["ls-files", "--others", "--exclude-standard"], {
|
|
16658
16967
|
cwd: dir,
|
|
16659
16968
|
env,
|
|
16660
16969
|
timeout: GIT_TIMEOUT
|
|
@@ -16904,7 +17213,7 @@ RAW: ${raw}
|
|
|
16904
17213
|
]) {
|
|
16905
17214
|
delete safeEnv[key];
|
|
16906
17215
|
}
|
|
16907
|
-
const d = (0,
|
|
17216
|
+
const d = (0, import_child_process9.spawn)(process.execPath, [scriptPath, "daemon"], {
|
|
16908
17217
|
detached: true,
|
|
16909
17218
|
stdio: "ignore",
|
|
16910
17219
|
env: { ...safeEnv, NODE9_AUTO_STARTED: "1", NODE9_BROWSER_OPENED: "1" }
|
|
@@ -17736,7 +18045,7 @@ var import_chalk9 = __toESM(require("chalk"));
|
|
|
17736
18045
|
var import_fs30 = __toESM(require("fs"));
|
|
17737
18046
|
var import_path31 = __toESM(require("path"));
|
|
17738
18047
|
var import_os26 = __toESM(require("os"));
|
|
17739
|
-
var
|
|
18048
|
+
var import_child_process10 = require("child_process");
|
|
17740
18049
|
init_daemon();
|
|
17741
18050
|
function registerDoctorCommand(program2, version2) {
|
|
17742
18051
|
program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(() => {
|
|
@@ -17762,7 +18071,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
17762
18071
|
`));
|
|
17763
18072
|
section("Binary");
|
|
17764
18073
|
try {
|
|
17765
|
-
const which = (0,
|
|
18074
|
+
const which = (0, import_child_process10.execSync)("which node9", { encoding: "utf-8", timeout: 3e3 }).trim();
|
|
17766
18075
|
pass(`node9 found at ${which}`);
|
|
17767
18076
|
} catch {
|
|
17768
18077
|
warn(
|
|
@@ -17780,7 +18089,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
17780
18089
|
);
|
|
17781
18090
|
}
|
|
17782
18091
|
try {
|
|
17783
|
-
const gitVersion = (0,
|
|
18092
|
+
const gitVersion = (0, import_child_process10.execSync)("git --version", { encoding: "utf-8", timeout: 3e3 }).trim();
|
|
17784
18093
|
pass(gitVersion);
|
|
17785
18094
|
} catch {
|
|
17786
18095
|
warn(
|
|
@@ -18663,7 +18972,7 @@ function registerReportCommand(program2) {
|
|
|
18663
18972
|
|
|
18664
18973
|
// src/cli/commands/daemon-cmd.ts
|
|
18665
18974
|
var import_chalk12 = __toESM(require("chalk"));
|
|
18666
|
-
var
|
|
18975
|
+
var import_child_process11 = require("child_process");
|
|
18667
18976
|
init_daemon2();
|
|
18668
18977
|
init_daemon();
|
|
18669
18978
|
init_daemon_starter();
|
|
@@ -18704,7 +19013,7 @@ function registerDaemonCommand(program2) {
|
|
|
18704
19013
|
if (cmd === "restart") {
|
|
18705
19014
|
stopDaemon();
|
|
18706
19015
|
await new Promise((r) => setTimeout(r, 500));
|
|
18707
|
-
const child = (0,
|
|
19016
|
+
const child = (0, import_child_process11.spawn)(process.execPath, [process.argv[1], "daemon"], {
|
|
18708
19017
|
detached: true,
|
|
18709
19018
|
stdio: "ignore",
|
|
18710
19019
|
env: { ...process.env, NODE9_AUTO_STARTED: "1", NODE9_BROWSER_OPENED: "1" }
|
|
@@ -18738,7 +19047,7 @@ function registerDaemonCommand(program2) {
|
|
|
18738
19047
|
console.log(import_chalk12.default.green(`\u{1F310} Opened browser: http://${DAEMON_HOST}:${DAEMON_PORT}/`));
|
|
18739
19048
|
process.exit(0);
|
|
18740
19049
|
}
|
|
18741
|
-
const child = (0,
|
|
19050
|
+
const child = (0, import_child_process11.spawn)(process.execPath, [process.argv[1], "daemon"], {
|
|
18742
19051
|
detached: true,
|
|
18743
19052
|
stdio: "ignore"
|
|
18744
19053
|
});
|
|
@@ -18753,7 +19062,7 @@ function registerDaemonCommand(program2) {
|
|
|
18753
19062
|
process.exit(0);
|
|
18754
19063
|
}
|
|
18755
19064
|
if (options.background) {
|
|
18756
|
-
const child = (0,
|
|
19065
|
+
const child = (0, import_child_process11.spawn)(process.execPath, [process.argv[1], "daemon"], {
|
|
18757
19066
|
detached: true,
|
|
18758
19067
|
stdio: "ignore"
|
|
18759
19068
|
});
|
|
@@ -18961,14 +19270,18 @@ function fireTelemetryPing(agents) {
|
|
|
18961
19270
|
}
|
|
18962
19271
|
}
|
|
18963
19272
|
function registerInitCommand(program2) {
|
|
18964
|
-
program2.command("init").description("Set up Node9: create config and wire all detected AI agents").option("--force", "Overwrite existing config").option(
|
|
19273
|
+
program2.command("init").description("Set up Node9: create config and wire all detected AI agents").option("--force", "Overwrite existing config").option(
|
|
19274
|
+
"-m, --mode <mode>",
|
|
19275
|
+
"Initial security mode: standard | strict | audit | observe (logs would-block, never blocks)",
|
|
19276
|
+
"standard"
|
|
19277
|
+
).option("--skip-setup", "Only create config \u2014 do not wire AI agents").option(
|
|
18965
19278
|
"--recommended",
|
|
18966
19279
|
"Non-interactive: enable bash-safe + filesystem + project-jail shields without prompting"
|
|
18967
19280
|
).action(
|
|
18968
19281
|
async (options) => {
|
|
18969
19282
|
console.log(import_chalk14.default.cyan.bold("\n\u{1F6E1}\uFE0F Node9 Init\n"));
|
|
18970
19283
|
let chosenMode = options.mode.toLowerCase();
|
|
18971
|
-
if (!["standard", "strict", "audit"].includes(chosenMode)) {
|
|
19284
|
+
if (!["standard", "strict", "audit", "observe"].includes(chosenMode)) {
|
|
18972
19285
|
chosenMode = DEFAULT_CONFIG.settings.mode;
|
|
18973
19286
|
}
|
|
18974
19287
|
{
|
|
@@ -19409,7 +19722,7 @@ function registerUndoCommand(program2) {
|
|
|
19409
19722
|
|
|
19410
19723
|
// src/cli/commands/watch.ts
|
|
19411
19724
|
var import_chalk17 = __toESM(require("chalk"));
|
|
19412
|
-
var
|
|
19725
|
+
var import_child_process12 = require("child_process");
|
|
19413
19726
|
init_daemon();
|
|
19414
19727
|
function registerWatchCommand(program2) {
|
|
19415
19728
|
program2.command("watch").description("Run a command under Node9 watch mode (daemon stays alive for the session)").argument("<command>", "Command to run").argument("[args...]", "Arguments for the command").action(async (cmd, args) => {
|
|
@@ -19426,7 +19739,7 @@ function registerWatchCommand(program2) {
|
|
|
19426
19739
|
}
|
|
19427
19740
|
} catch {
|
|
19428
19741
|
console.error(import_chalk17.default.dim("\u{1F6E1}\uFE0F Starting Node9 daemon (watch mode)..."));
|
|
19429
|
-
const child = (0,
|
|
19742
|
+
const child = (0, import_child_process12.spawn)(process.execPath, [process.argv[1], "daemon"], {
|
|
19430
19743
|
detached: true,
|
|
19431
19744
|
stdio: "ignore",
|
|
19432
19745
|
env: { ...process.env, NODE9_AUTO_STARTED: "1", NODE9_WATCH_MODE: "1" }
|
|
@@ -19456,7 +19769,7 @@ function registerWatchCommand(program2) {
|
|
|
19456
19769
|
"\n Tip: run `node9 tail` in another terminal to review and approve AI actions.\n"
|
|
19457
19770
|
)
|
|
19458
19771
|
);
|
|
19459
|
-
const result = (0,
|
|
19772
|
+
const result = (0, import_child_process12.spawnSync)(cmd, args, {
|
|
19460
19773
|
stdio: "inherit",
|
|
19461
19774
|
env: { ...process.env, NODE9_WATCH_MODE: "1" }
|
|
19462
19775
|
});
|
|
@@ -19471,7 +19784,7 @@ function registerWatchCommand(program2) {
|
|
|
19471
19784
|
// src/mcp-gateway/index.ts
|
|
19472
19785
|
var import_readline3 = __toESM(require("readline"));
|
|
19473
19786
|
var import_chalk18 = __toESM(require("chalk"));
|
|
19474
|
-
var
|
|
19787
|
+
var import_child_process13 = require("child_process");
|
|
19475
19788
|
var import_execa3 = require("execa");
|
|
19476
19789
|
init_orchestrator();
|
|
19477
19790
|
init_provenance();
|
|
@@ -19593,6 +19906,18 @@ function extractMcpServer(toolName) {
|
|
|
19593
19906
|
const match = toolName.match(/^mcp__([^_](?:[^_]|_(?!_))*?)__/i);
|
|
19594
19907
|
return match?.[1];
|
|
19595
19908
|
}
|
|
19909
|
+
function normalizeClientName(name) {
|
|
19910
|
+
if (typeof name !== "string" || name.length === 0) return void 0;
|
|
19911
|
+
const lower = name.toLowerCase();
|
|
19912
|
+
if (lower.includes("claude")) return "Claude";
|
|
19913
|
+
if (lower.includes("cursor")) return "Cursor";
|
|
19914
|
+
if (lower.includes("codex")) return "Codex";
|
|
19915
|
+
if (lower.includes("gemini")) return "Gemini";
|
|
19916
|
+
if (lower.includes("cline")) return "Cline";
|
|
19917
|
+
if (lower.includes("continue")) return "Continue";
|
|
19918
|
+
const sanitized = sanitize4(name).slice(0, 40);
|
|
19919
|
+
return sanitized.length > 0 ? sanitized : void 0;
|
|
19920
|
+
}
|
|
19596
19921
|
function tokenize4(cmd) {
|
|
19597
19922
|
const tokens = [];
|
|
19598
19923
|
let current = "";
|
|
@@ -19665,7 +19990,7 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
19665
19990
|
const safeEnv = Object.fromEntries(
|
|
19666
19991
|
Object.entries(process.env).filter(([k]) => !UPSTREAM_INJECTOR_VARS.has(k))
|
|
19667
19992
|
);
|
|
19668
|
-
const child = (0,
|
|
19993
|
+
const child = (0, import_child_process13.spawn)(executable, cmdArgs, {
|
|
19669
19994
|
stdio: ["pipe", "pipe", "inherit"],
|
|
19670
19995
|
// control stdin/stdout; inherit stderr
|
|
19671
19996
|
shell: false,
|
|
@@ -19679,6 +20004,8 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
19679
20004
|
let pinState = "pending";
|
|
19680
20005
|
const pendingToolCalls = [];
|
|
19681
20006
|
const pendingCallNames = /* @__PURE__ */ new Map();
|
|
20007
|
+
const pendingExecutions = /* @__PURE__ */ new Map();
|
|
20008
|
+
let clientName;
|
|
19682
20009
|
const agentIn = import_readline3.default.createInterface({ input: process.stdin, terminal: false });
|
|
19683
20010
|
agentIn.on("line", async (line) => {
|
|
19684
20011
|
let message;
|
|
@@ -19701,6 +20028,13 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
19701
20028
|
child.stdin.write(line + "\n");
|
|
19702
20029
|
return;
|
|
19703
20030
|
}
|
|
20031
|
+
if (message.method === "initialize") {
|
|
20032
|
+
clientName = normalizeClientName(
|
|
20033
|
+
message.params?.clientInfo?.name
|
|
20034
|
+
);
|
|
20035
|
+
child.stdin.write(line + "\n");
|
|
20036
|
+
return;
|
|
20037
|
+
}
|
|
19704
20038
|
if (message.method === "tools/list" && message.id !== void 0 && message.id !== null) {
|
|
19705
20039
|
pendingToolsListIds.add(message.id);
|
|
19706
20040
|
}
|
|
@@ -19746,7 +20080,7 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
19746
20080
|
const toolArgs = message.params?.arguments ?? message.params?.tool_input ?? {};
|
|
19747
20081
|
const mcpServer = extractMcpServer(toolName);
|
|
19748
20082
|
const result = await authorizeHeadless(toolName, toolArgs, {
|
|
19749
|
-
agent: "MCP-Gateway",
|
|
20083
|
+
agent: clientName ?? "MCP-Gateway",
|
|
19750
20084
|
mcpServer
|
|
19751
20085
|
});
|
|
19752
20086
|
if (!result.approved) {
|
|
@@ -19776,6 +20110,12 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
19776
20110
|
}
|
|
19777
20111
|
if (message.id !== void 0 && message.id !== null) {
|
|
19778
20112
|
pendingCallNames.set(message.id, toolName);
|
|
20113
|
+
pendingExecutions.set(message.id, {
|
|
20114
|
+
ts: Date.now(),
|
|
20115
|
+
toolName,
|
|
20116
|
+
agent: clientName,
|
|
20117
|
+
mcpServer
|
|
20118
|
+
});
|
|
19779
20119
|
}
|
|
19780
20120
|
child.stdin.write(line + "\n");
|
|
19781
20121
|
} catch {
|
|
@@ -19917,6 +20257,26 @@ async function runMcpGateway(upstreamCommand) {
|
|
|
19917
20257
|
return;
|
|
19918
20258
|
}
|
|
19919
20259
|
}
|
|
20260
|
+
const respId = parsed?.id;
|
|
20261
|
+
if (respId !== void 0 && respId !== null) {
|
|
20262
|
+
const exec = pendingExecutions.get(respId);
|
|
20263
|
+
if (exec) {
|
|
20264
|
+
pendingExecutions.delete(respId);
|
|
20265
|
+
const durationMs = Date.now() - exec.ts;
|
|
20266
|
+
const isError = parsed?.error !== void 0;
|
|
20267
|
+
notifyActivitySocket({
|
|
20268
|
+
id: String(respId),
|
|
20269
|
+
ts: Date.now(),
|
|
20270
|
+
tool: exec.toolName,
|
|
20271
|
+
status: "execution-completed",
|
|
20272
|
+
durationMs,
|
|
20273
|
+
agent: exec.agent,
|
|
20274
|
+
mcpServer: exec.mcpServer,
|
|
20275
|
+
isError
|
|
20276
|
+
}).catch(() => {
|
|
20277
|
+
});
|
|
20278
|
+
}
|
|
20279
|
+
}
|
|
19920
20280
|
const LARGE_RESPONSE_THRESHOLD = 5e5;
|
|
19921
20281
|
if (parsed?.result && line.length > LARGE_RESPONSE_THRESHOLD) {
|
|
19922
20282
|
const callId = parsed.id;
|
|
@@ -19977,7 +20337,7 @@ var import_readline4 = __toESM(require("readline"));
|
|
|
19977
20337
|
var import_fs36 = __toESM(require("fs"));
|
|
19978
20338
|
var import_os32 = __toESM(require("os"));
|
|
19979
20339
|
var import_path38 = __toESM(require("path"));
|
|
19980
|
-
var
|
|
20340
|
+
var import_child_process14 = require("child_process");
|
|
19981
20341
|
init_core();
|
|
19982
20342
|
init_daemon();
|
|
19983
20343
|
init_shields();
|
|
@@ -20451,7 +20811,7 @@ function handleRuleAdd(args) {
|
|
|
20451
20811
|
return `Rule "${name}" added to ~/.node9/config.json \u2014 verdict: ${verdict} when ${field} matches "${pattern}"`;
|
|
20452
20812
|
}
|
|
20453
20813
|
function runCliCommand(subArgs) {
|
|
20454
|
-
const result = (0,
|
|
20814
|
+
const result = (0, import_child_process14.spawnSync)(process.execPath, [process.argv[1], ...subArgs], {
|
|
20455
20815
|
encoding: "utf-8",
|
|
20456
20816
|
timeout: 6e4,
|
|
20457
20817
|
// Disable colors — stdout is piped (not a TTY), chalk auto-detects, but be explicit
|