@node9/proxy 1.45.0 → 1.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +984 -792
- package/dist/cli.mjs +958 -767
- package/dist/index.js +15 -1
- package/dist/index.mjs +15 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -219,8 +219,8 @@ function sanitizeConfig(raw) {
|
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
221
|
const lines = result.error.issues.map((issue) => {
|
|
222
|
-
const
|
|
223
|
-
return ` \u2022 ${
|
|
222
|
+
const path65 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
223
|
+
return ` \u2022 ${path65}: ${issue.message}`;
|
|
224
224
|
});
|
|
225
225
|
return {
|
|
226
226
|
sanitized,
|
|
@@ -1341,9 +1341,9 @@ function matchesPattern(text, patterns) {
|
|
|
1341
1341
|
const withoutDotSlash = text.replace(/^\.\//, "");
|
|
1342
1342
|
return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
|
|
1343
1343
|
}
|
|
1344
|
-
function getNestedValue(obj,
|
|
1344
|
+
function getNestedValue(obj, path65) {
|
|
1345
1345
|
if (!obj || typeof obj !== "object") return null;
|
|
1346
|
-
const segments =
|
|
1346
|
+
const segments = path65.split(".");
|
|
1347
1347
|
for (const seg of segments) {
|
|
1348
1348
|
if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
|
|
1349
1349
|
}
|
|
@@ -1396,6 +1396,14 @@ function evaluateSmartConditions(args, rule) {
|
|
|
1396
1396
|
});
|
|
1397
1397
|
return mode === "any" ? results.some((r) => r) : results.every((r) => r);
|
|
1398
1398
|
}
|
|
1399
|
+
function resolvePinned(matches) {
|
|
1400
|
+
if (matches.length === 0) return void 0;
|
|
1401
|
+
const pinned = matches.filter((r) => r.pinned);
|
|
1402
|
+
if (pinned.length === 0) return matches[0];
|
|
1403
|
+
return pinned.reduce(
|
|
1404
|
+
(best, r) => VERDICT_RANK[r.verdict] > VERDICT_RANK[best.verdict] ? r : best
|
|
1405
|
+
);
|
|
1406
|
+
}
|
|
1399
1407
|
function tokenize2(toolName) {
|
|
1400
1408
|
return toolName.toLowerCase().split(/[_.\-\s]+/).filter(Boolean);
|
|
1401
1409
|
}
|
|
@@ -1507,9 +1515,10 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
|
|
|
1507
1515
|
}
|
|
1508
1516
|
}
|
|
1509
1517
|
if (config.policy.smartRules.length > 0) {
|
|
1510
|
-
const
|
|
1518
|
+
const matches = config.policy.smartRules.filter(
|
|
1511
1519
|
(rule) => matchesPattern(toolName, rule.tool) && !(bashCommand !== null && rule.name && AST_FS_REGEX_RULES.has(rule.name)) && evaluateSmartConditions(args, rule)
|
|
1512
1520
|
);
|
|
1521
|
+
const matchedRule = resolvePinned(matches);
|
|
1513
1522
|
if (matchedRule) {
|
|
1514
1523
|
if (matchedRule.verdict === "allow")
|
|
1515
1524
|
return { decision: "allow", ruleName: matchedRule.name ?? matchedRule.tool };
|
|
@@ -2248,7 +2257,7 @@ function* stringValues(obj, depth = 0) {
|
|
|
2248
2257
|
}
|
|
2249
2258
|
for (const v of Object.values(obj)) yield* stringValues(v, depth + 1);
|
|
2250
2259
|
}
|
|
2251
|
-
var MAX, UNTRUSTED_TOOLS, SIGNALS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, NET_BINARIES, VALUE_FLAGS, FS_OP_CACHE_MAX, fsOpCache, DEFAULT_EGRESS_ALLOWLIST, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, SQL_DML_KEYWORDS, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, LOOP_MAX_RECORDS, FINDING_TO_SIGNAL, SCAN_SIGNAL_WEIGHTS, LOOP_THRESHOLD_FOR_WASTE, COST_PER_LOOP_ITER_USD, DESTRUCTIVE_OP_RE, SENSITIVE_PATH_RE, FILE_TOOLS, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION, DEDUPE_PREVIEW_LEN, TERMINAL_ESCAPE_RE;
|
|
2260
|
+
var MAX, UNTRUSTED_TOOLS, SIGNALS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, NET_BINARIES, VALUE_FLAGS, FS_OP_CACHE_MAX, fsOpCache, DEFAULT_EGRESS_ALLOWLIST, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, VERDICT_RANK, SQL_DML_KEYWORDS, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, LOOP_MAX_RECORDS, FINDING_TO_SIGNAL, SCAN_SIGNAL_WEIGHTS, LOOP_THRESHOLD_FOR_WASTE, COST_PER_LOOP_ITER_USD, DESTRUCTIVE_OP_RE, SENSITIVE_PATH_RE, FILE_TOOLS, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION, DEDUPE_PREVIEW_LEN, TERMINAL_ESCAPE_RE, ENGINE_VERSION;
|
|
2252
2261
|
var init_dist = __esm({
|
|
2253
2262
|
"packages/policy-engine/dist/index.mjs"() {
|
|
2254
2263
|
"use strict";
|
|
@@ -3173,6 +3182,11 @@ var init_dist = __esm({
|
|
|
3173
3182
|
REGEX_CACHE_MAX = 500;
|
|
3174
3183
|
regexCache = /* @__PURE__ */ new Map();
|
|
3175
3184
|
FORBIDDEN_PATH_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
3185
|
+
VERDICT_RANK = {
|
|
3186
|
+
allow: 0,
|
|
3187
|
+
review: 1,
|
|
3188
|
+
block: 2
|
|
3189
|
+
};
|
|
3176
3190
|
SQL_DML_KEYWORDS = /* @__PURE__ */ new Set(["select", "insert", "update", "delete", "merge", "upsert"]);
|
|
3177
3191
|
aws_default = {
|
|
3178
3192
|
name: "aws",
|
|
@@ -3977,6 +3991,7 @@ var init_dist = __esm({
|
|
|
3977
3991
|
DEDUPE_PREVIEW_LEN = 120;
|
|
3978
3992
|
TERMINAL_ESCAPE_RE = // eslint-disable-next-line no-control-regex
|
|
3979
3993
|
/\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
3994
|
+
ENGINE_VERSION = "1.4.0";
|
|
3980
3995
|
}
|
|
3981
3996
|
});
|
|
3982
3997
|
|
|
@@ -9700,16 +9715,237 @@ var init_setup = __esm({
|
|
|
9700
9715
|
}
|
|
9701
9716
|
});
|
|
9702
9717
|
|
|
9703
|
-
// src/
|
|
9718
|
+
// src/agent-wiring.ts
|
|
9704
9719
|
import fs14 from "fs";
|
|
9705
9720
|
import path16 from "path";
|
|
9706
9721
|
import os13 from "os";
|
|
9722
|
+
import * as yaml2 from "yaml";
|
|
9723
|
+
import { parse as parseToml2 } from "smol-toml";
|
|
9724
|
+
function readJson2(filePath) {
|
|
9725
|
+
if (!fs14.existsSync(filePath)) return null;
|
|
9726
|
+
try {
|
|
9727
|
+
return JSON.parse(fs14.readFileSync(filePath, "utf-8"));
|
|
9728
|
+
} catch {
|
|
9729
|
+
return "invalid";
|
|
9730
|
+
}
|
|
9731
|
+
}
|
|
9732
|
+
function matchersHaveNode9Hook(matchers) {
|
|
9733
|
+
return (matchers ?? []).some((m) => (m.hooks ?? []).some((h) => isNode9Hook(h.command)));
|
|
9734
|
+
}
|
|
9735
|
+
function flatHaveNode9Hook(entries) {
|
|
9736
|
+
return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
|
|
9737
|
+
}
|
|
9738
|
+
function readHookRoot(filePath, format) {
|
|
9739
|
+
if (!fs14.existsSync(filePath)) return "absent";
|
|
9740
|
+
let raw;
|
|
9741
|
+
try {
|
|
9742
|
+
raw = fs14.readFileSync(filePath, "utf-8");
|
|
9743
|
+
} catch {
|
|
9744
|
+
return "absent";
|
|
9745
|
+
}
|
|
9746
|
+
try {
|
|
9747
|
+
const parsed = format === "yaml" ? yaml2.parse(raw) : JSON.parse(raw);
|
|
9748
|
+
return parsed?.hooks ?? {};
|
|
9749
|
+
} catch {
|
|
9750
|
+
return "invalid";
|
|
9751
|
+
}
|
|
9752
|
+
}
|
|
9753
|
+
function eventWired(root, ev, format) {
|
|
9754
|
+
const arr = root[ev.key];
|
|
9755
|
+
if (format === "matcher") return matchersHaveNode9Hook(arr);
|
|
9756
|
+
return flatHaveNode9Hook(arr);
|
|
9757
|
+
}
|
|
9758
|
+
function detectMcp(servers) {
|
|
9759
|
+
const entries = Object.entries(servers ?? {});
|
|
9760
|
+
const present = entries.some(([, s]) => s?.command === "node9");
|
|
9761
|
+
const wrapped = entries.filter(([, s]) => s?.command === "node9" && Array.isArray(s.args) && s.args.length > 0).map(([name, s]) => `${name} \u2192 ${s.args.join(" ")}`);
|
|
9762
|
+
return { wrapped, present };
|
|
9763
|
+
}
|
|
9764
|
+
function readMcp(filePath, format) {
|
|
9765
|
+
if (!fs14.existsSync(filePath)) return { wrapped: [], present: false };
|
|
9766
|
+
try {
|
|
9767
|
+
if (format === "toml") {
|
|
9768
|
+
const parsed2 = parseToml2(fs14.readFileSync(filePath, "utf-8"));
|
|
9769
|
+
return detectMcp(parsed2?.mcp_servers);
|
|
9770
|
+
}
|
|
9771
|
+
const parsed = readJson2(filePath);
|
|
9772
|
+
if (parsed === null || parsed === "invalid") return { wrapped: [], present: false };
|
|
9773
|
+
return detectMcp(parsed.mcpServers);
|
|
9774
|
+
} catch {
|
|
9775
|
+
return { wrapped: [], present: false };
|
|
9776
|
+
}
|
|
9777
|
+
}
|
|
9778
|
+
function getAgentWiring(home = os13.homedir()) {
|
|
9779
|
+
const detected = detectAgents(home);
|
|
9780
|
+
return AGENT_SPECS.map((spec) => {
|
|
9781
|
+
const present = spec.present(home);
|
|
9782
|
+
const pad = spec.labelPad ?? DEFAULT_LABEL_PAD;
|
|
9783
|
+
let hooks;
|
|
9784
|
+
let wireState;
|
|
9785
|
+
let hookLabel;
|
|
9786
|
+
let settingsPath;
|
|
9787
|
+
if (spec.shimFile) {
|
|
9788
|
+
const shimWired = exists(spec.shimFile(home));
|
|
9789
|
+
hooks = [{ label: "node9 plugin (node9 check)", wired: shimWired }];
|
|
9790
|
+
wireState = shimWired ? "wired" : present ? "unwired" : "absent";
|
|
9791
|
+
hookLabel = "node9 plugin";
|
|
9792
|
+
settingsPath = spec.shimFile(home);
|
|
9793
|
+
} else {
|
|
9794
|
+
const root = spec.hookFile ? readHookRoot(spec.hookFile(home), spec.hookFormat) : "absent";
|
|
9795
|
+
const primary = spec.hookEvents[0];
|
|
9796
|
+
const rootPresent = root !== "absent" && root !== "invalid";
|
|
9797
|
+
hooks = spec.hookEvents.map((ev) => ({
|
|
9798
|
+
label: hookLabelOf(ev, pad),
|
|
9799
|
+
wired: rootPresent && eventWired(root, ev, spec.hookFormat)
|
|
9800
|
+
}));
|
|
9801
|
+
if (root === "absent") wireState = "absent";
|
|
9802
|
+
else if (root === "invalid") wireState = "invalid";
|
|
9803
|
+
else wireState = primary && eventWired(root, primary, spec.hookFormat) ? "wired" : "unwired";
|
|
9804
|
+
hookLabel = primary ? `${primary.key} hook` : "MCP proxy";
|
|
9805
|
+
settingsPath = spec.hookFile ? spec.hookFile(home) : spec.mcpFile ? spec.mcpFile(home) : "";
|
|
9806
|
+
}
|
|
9807
|
+
const mcp = spec.mcpFile ? readMcp(spec.mcpFile(home), spec.mcpFormat ?? "json") : null;
|
|
9808
|
+
const anyHookWired = hooks.some((h) => h.wired);
|
|
9809
|
+
return {
|
|
9810
|
+
id: spec.id,
|
|
9811
|
+
label: spec.label,
|
|
9812
|
+
setupCommand: spec.setupCommand,
|
|
9813
|
+
installed: detected[spec.id],
|
|
9814
|
+
present,
|
|
9815
|
+
hooks,
|
|
9816
|
+
wireState,
|
|
9817
|
+
hookLabel,
|
|
9818
|
+
settingsPath,
|
|
9819
|
+
configFormat: spec.hookFormat === "yaml" ? "YAML" : "JSON",
|
|
9820
|
+
mcpServers: mcp ? mcp.wrapped : null,
|
|
9821
|
+
mcpProtected: mcp ? mcp.present : false,
|
|
9822
|
+
isProtected: anyHookWired || (mcp?.present ?? false)
|
|
9823
|
+
};
|
|
9824
|
+
});
|
|
9825
|
+
}
|
|
9826
|
+
var exists, ck, lg, DEFAULT_LABEL_PAD, hookLabelOf, AGENT_SPECS;
|
|
9827
|
+
var init_agent_wiring = __esm({
|
|
9828
|
+
"src/agent-wiring.ts"() {
|
|
9829
|
+
"use strict";
|
|
9830
|
+
init_setup();
|
|
9831
|
+
exists = (p) => {
|
|
9832
|
+
try {
|
|
9833
|
+
return fs14.existsSync(p);
|
|
9834
|
+
} catch {
|
|
9835
|
+
return false;
|
|
9836
|
+
}
|
|
9837
|
+
};
|
|
9838
|
+
ck = (key) => ({ key, kind: "check" });
|
|
9839
|
+
lg = (key) => ({ key, kind: "log" });
|
|
9840
|
+
DEFAULT_LABEL_PAD = 11;
|
|
9841
|
+
hookLabelOf = (ev, pad) => `${ev.key.padEnd(pad)} (node9 ${ev.kind})`;
|
|
9842
|
+
AGENT_SPECS = [
|
|
9843
|
+
{
|
|
9844
|
+
id: "claude",
|
|
9845
|
+
label: "Claude Code",
|
|
9846
|
+
setupCommand: "node9 agents add claude",
|
|
9847
|
+
hookFile: (h) => path16.join(h, ".claude", "settings.json"),
|
|
9848
|
+
hookFormat: "matcher",
|
|
9849
|
+
hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
|
|
9850
|
+
mcpFile: (h) => path16.join(h, ".claude.json"),
|
|
9851
|
+
present: (h) => exists(path16.join(h, ".claude", "settings.json")) || exists(path16.join(h, ".claude.json"))
|
|
9852
|
+
},
|
|
9853
|
+
{
|
|
9854
|
+
id: "gemini",
|
|
9855
|
+
label: "Gemini CLI",
|
|
9856
|
+
setupCommand: "node9 agents add gemini",
|
|
9857
|
+
hookFile: (h) => path16.join(h, ".gemini", "settings.json"),
|
|
9858
|
+
hookFormat: "matcher",
|
|
9859
|
+
hookEvents: [ck("BeforeTool"), lg("AfterTool")],
|
|
9860
|
+
mcpFile: (h) => path16.join(h, ".gemini", "settings.json"),
|
|
9861
|
+
present: (h) => exists(path16.join(h, ".gemini", "settings.json"))
|
|
9862
|
+
},
|
|
9863
|
+
{
|
|
9864
|
+
id: "codex",
|
|
9865
|
+
label: "Codex",
|
|
9866
|
+
setupCommand: "node9 agents add codex",
|
|
9867
|
+
hookFile: (h) => path16.join(h, ".codex", "hooks.json"),
|
|
9868
|
+
hookFormat: "matcher",
|
|
9869
|
+
hookEvents: [ck("PreToolUse"), ck("UserPromptSubmit")],
|
|
9870
|
+
mcpFile: (h) => path16.join(h, ".codex", "config.toml"),
|
|
9871
|
+
mcpFormat: "toml",
|
|
9872
|
+
present: (h) => exists(path16.join(h, ".codex"))
|
|
9873
|
+
},
|
|
9874
|
+
{
|
|
9875
|
+
id: "antigravity",
|
|
9876
|
+
label: "Antigravity",
|
|
9877
|
+
setupCommand: "node9 agents add antigravity",
|
|
9878
|
+
hookFile: (h) => path16.join(h, ".gemini", "config", "hooks.json"),
|
|
9879
|
+
hookFormat: "matcher",
|
|
9880
|
+
hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
|
|
9881
|
+
mcpFile: (h) => path16.join(h, ".gemini", "config", "mcp_config.json"),
|
|
9882
|
+
present: (h) => exists(path16.join(h, ".gemini", "config", "hooks.json")) || exists(path16.join(h, ".gemini", "antigravity-cli")) || exists(path16.join(h, ".gemini", "antigravity-ide"))
|
|
9883
|
+
},
|
|
9884
|
+
{
|
|
9885
|
+
id: "copilot",
|
|
9886
|
+
label: "GitHub Copilot",
|
|
9887
|
+
setupCommand: "node9 agents add copilot",
|
|
9888
|
+
hookFile: (h) => path16.join(h, ".copilot", "hooks", "node9.json"),
|
|
9889
|
+
hookFormat: "flat",
|
|
9890
|
+
hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
|
|
9891
|
+
mcpFile: (h) => path16.join(h, ".copilot", "mcp-config.json"),
|
|
9892
|
+
present: (h) => exists(path16.join(h, ".copilot"))
|
|
9893
|
+
},
|
|
9894
|
+
{
|
|
9895
|
+
id: "cursor",
|
|
9896
|
+
label: "Cursor",
|
|
9897
|
+
setupCommand: "node9 agents add cursor",
|
|
9898
|
+
// MCP-only — no hook file (see note above).
|
|
9899
|
+
hookFormat: "flat",
|
|
9900
|
+
hookEvents: [],
|
|
9901
|
+
mcpFile: (h) => path16.join(h, ".cursor", "mcp.json"),
|
|
9902
|
+
present: (h) => exists(path16.join(h, ".cursor", "mcp.json"))
|
|
9903
|
+
},
|
|
9904
|
+
{
|
|
9905
|
+
id: "hermes",
|
|
9906
|
+
label: "Hermes Agent",
|
|
9907
|
+
setupCommand: "node9 agents add hermes",
|
|
9908
|
+
hookFile: (h) => hermesConfigPath(h),
|
|
9909
|
+
hookFormat: "yaml",
|
|
9910
|
+
hookEvents: [ck("pre_tool_call"), lg("post_tool_call")],
|
|
9911
|
+
labelPad: 14,
|
|
9912
|
+
// 'post_tool_call' is wider than the default
|
|
9913
|
+
present: (h) => exists(hermesConfigPath(h))
|
|
9914
|
+
},
|
|
9915
|
+
{
|
|
9916
|
+
// Plugin-shim agents — protected by a node9-authored plugin/extension file
|
|
9917
|
+
// (no hooks, no MCP). hookFormat is unused for these (shimFile drives it).
|
|
9918
|
+
id: "opencode",
|
|
9919
|
+
label: "OpenCode",
|
|
9920
|
+
setupCommand: "node9 agents add opencode",
|
|
9921
|
+
hookFormat: "flat",
|
|
9922
|
+
hookEvents: [],
|
|
9923
|
+
shimFile: (h) => path16.join(h, ".config", "opencode", "plugins", "node9.js"),
|
|
9924
|
+
present: (h) => exists(path16.join(h, ".config", "opencode")) || exists(path16.join(h, ".config", "opencode", "plugins", "node9.js"))
|
|
9925
|
+
},
|
|
9926
|
+
{
|
|
9927
|
+
id: "pi",
|
|
9928
|
+
label: "Pi",
|
|
9929
|
+
setupCommand: "node9 agents add pi",
|
|
9930
|
+
hookFormat: "flat",
|
|
9931
|
+
hookEvents: [],
|
|
9932
|
+
shimFile: (h) => path16.join(h, ".pi", "agent", "extensions", "node9.js"),
|
|
9933
|
+
present: (h) => exists(path16.join(h, ".pi", "agent")) || exists(path16.join(h, ".pi", "agent", "extensions", "node9.js"))
|
|
9934
|
+
}
|
|
9935
|
+
];
|
|
9936
|
+
}
|
|
9937
|
+
});
|
|
9938
|
+
|
|
9939
|
+
// src/pricing/litellm.ts
|
|
9940
|
+
import fs15 from "fs";
|
|
9941
|
+
import path17 from "path";
|
|
9942
|
+
import os14 from "os";
|
|
9707
9943
|
function normalizeModel(raw) {
|
|
9708
9944
|
return raw.replace(/-\d{8}$/, "").toLowerCase();
|
|
9709
9945
|
}
|
|
9710
9946
|
function readCache() {
|
|
9711
9947
|
try {
|
|
9712
|
-
const raw = JSON.parse(
|
|
9948
|
+
const raw = JSON.parse(fs15.readFileSync(CACHE_FILE(), "utf-8"));
|
|
9713
9949
|
if (typeof raw.fetchedAt !== "string" || typeof raw.prices !== "object" || raw.prices === null) {
|
|
9714
9950
|
return null;
|
|
9715
9951
|
}
|
|
@@ -9723,18 +9959,18 @@ function readCache() {
|
|
|
9723
9959
|
function writeCache(prices) {
|
|
9724
9960
|
try {
|
|
9725
9961
|
const target = CACHE_FILE();
|
|
9726
|
-
const dir =
|
|
9727
|
-
if (!
|
|
9962
|
+
const dir = path17.dirname(target);
|
|
9963
|
+
if (!fs15.existsSync(dir)) fs15.mkdirSync(dir, { recursive: true });
|
|
9728
9964
|
const tmp = target + ".tmp";
|
|
9729
9965
|
const body = {
|
|
9730
9966
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9731
9967
|
prices
|
|
9732
9968
|
};
|
|
9733
|
-
|
|
9734
|
-
|
|
9969
|
+
fs15.writeFileSync(tmp, JSON.stringify(body) + "\n", "utf-8");
|
|
9970
|
+
fs15.renameSync(tmp, target);
|
|
9735
9971
|
} catch (err2) {
|
|
9736
9972
|
try {
|
|
9737
|
-
|
|
9973
|
+
fs15.appendFileSync(
|
|
9738
9974
|
HOOK_DEBUG_LOG,
|
|
9739
9975
|
`[pricing] cache write failed: ${err2.message}
|
|
9740
9976
|
`
|
|
@@ -9878,7 +10114,7 @@ var init_litellm = __esm({
|
|
|
9878
10114
|
"gemini-2.0-flash": [75e-9, 3e-7, 0, 0],
|
|
9879
10115
|
"gemini-1.5-pro": [125e-8, 5e-6, 0, 0]
|
|
9880
10116
|
};
|
|
9881
|
-
CACHE_FILE = () =>
|
|
10117
|
+
CACHE_FILE = () => path17.join(os14.homedir(), ".node9", "model-pricing.json");
|
|
9882
10118
|
TTL_MS = 24 * 60 * 60 * 1e3;
|
|
9883
10119
|
memCache = null;
|
|
9884
10120
|
memCacheAt = 0;
|
|
@@ -9888,11 +10124,11 @@ var init_litellm = __esm({
|
|
|
9888
10124
|
});
|
|
9889
10125
|
|
|
9890
10126
|
// src/cost-gemini.ts
|
|
9891
|
-
import
|
|
9892
|
-
import
|
|
9893
|
-
import
|
|
10127
|
+
import fs16 from "fs";
|
|
10128
|
+
import os15 from "os";
|
|
10129
|
+
import path18 from "path";
|
|
9894
10130
|
function geminiTmpDir() {
|
|
9895
|
-
return
|
|
10131
|
+
return path18.join(os15.homedir(), ".gemini", "tmp");
|
|
9896
10132
|
}
|
|
9897
10133
|
function geminiPriceFor(model) {
|
|
9898
10134
|
let tuple = pricingFor(model);
|
|
@@ -9907,14 +10143,14 @@ function geminiPriceFor(model) {
|
|
|
9907
10143
|
}
|
|
9908
10144
|
function safeReaddir(dir) {
|
|
9909
10145
|
try {
|
|
9910
|
-
return
|
|
10146
|
+
return fs16.readdirSync(dir);
|
|
9911
10147
|
} catch {
|
|
9912
10148
|
return [];
|
|
9913
10149
|
}
|
|
9914
10150
|
}
|
|
9915
10151
|
function isDir(p) {
|
|
9916
10152
|
try {
|
|
9917
|
-
return
|
|
10153
|
+
return fs16.statSync(p).isDirectory();
|
|
9918
10154
|
} catch {
|
|
9919
10155
|
return false;
|
|
9920
10156
|
}
|
|
@@ -9922,11 +10158,11 @@ function isDir(p) {
|
|
|
9922
10158
|
function listGeminiSessionFiles(base) {
|
|
9923
10159
|
const out = [];
|
|
9924
10160
|
for (const project of safeReaddir(base)) {
|
|
9925
|
-
const chats =
|
|
10161
|
+
const chats = path18.join(base, project, "chats");
|
|
9926
10162
|
if (!isDir(chats)) continue;
|
|
9927
10163
|
for (const f of safeReaddir(chats)) {
|
|
9928
10164
|
if (f.startsWith("session-") && f.endsWith(".jsonl")) {
|
|
9929
|
-
out.push({ file:
|
|
10165
|
+
out.push({ file: path18.join(chats, f), project });
|
|
9930
10166
|
}
|
|
9931
10167
|
}
|
|
9932
10168
|
}
|
|
@@ -9993,7 +10229,7 @@ var init_cost_gemini = __esm({
|
|
|
9993
10229
|
id: "gemini",
|
|
9994
10230
|
available() {
|
|
9995
10231
|
try {
|
|
9996
|
-
return
|
|
10232
|
+
return fs16.existsSync(geminiTmpDir());
|
|
9997
10233
|
} catch {
|
|
9998
10234
|
return false;
|
|
9999
10235
|
}
|
|
@@ -10002,13 +10238,13 @@ var init_cost_gemini = __esm({
|
|
|
10002
10238
|
const combined = /* @__PURE__ */ new Map();
|
|
10003
10239
|
for (const { file, project } of listGeminiSessionFiles(geminiTmpDir())) {
|
|
10004
10240
|
try {
|
|
10005
|
-
if (sinceMs !== void 0 &&
|
|
10241
|
+
if (sinceMs !== void 0 && fs16.statSync(file).mtimeMs < sinceMs) continue;
|
|
10006
10242
|
} catch {
|
|
10007
10243
|
continue;
|
|
10008
10244
|
}
|
|
10009
10245
|
let content;
|
|
10010
10246
|
try {
|
|
10011
|
-
content =
|
|
10247
|
+
content = fs16.readFileSync(file, "utf8");
|
|
10012
10248
|
} catch {
|
|
10013
10249
|
continue;
|
|
10014
10250
|
}
|
|
@@ -10033,11 +10269,11 @@ var init_cost_gemini = __esm({
|
|
|
10033
10269
|
});
|
|
10034
10270
|
|
|
10035
10271
|
// src/cost-codex.ts
|
|
10036
|
-
import
|
|
10037
|
-
import
|
|
10038
|
-
import
|
|
10272
|
+
import fs17 from "fs";
|
|
10273
|
+
import os16 from "os";
|
|
10274
|
+
import path19 from "path";
|
|
10039
10275
|
function codexSessionsDir() {
|
|
10040
|
-
return
|
|
10276
|
+
return path19.join(os16.homedir(), ".codex", "sessions");
|
|
10041
10277
|
}
|
|
10042
10278
|
function codexPriceFor(model) {
|
|
10043
10279
|
return pricingFor(model) ?? CODEX_FALLBACK;
|
|
@@ -10050,16 +10286,16 @@ function codexSessionCost(model, tokens) {
|
|
|
10050
10286
|
function listCodexSessionFiles(base) {
|
|
10051
10287
|
const out = [];
|
|
10052
10288
|
for (const y of safeReaddir2(base)) {
|
|
10053
|
-
const yp =
|
|
10289
|
+
const yp = path19.join(base, y);
|
|
10054
10290
|
if (!isDir2(yp)) continue;
|
|
10055
10291
|
for (const m of safeReaddir2(yp)) {
|
|
10056
|
-
const mp =
|
|
10292
|
+
const mp = path19.join(yp, m);
|
|
10057
10293
|
if (!isDir2(mp)) continue;
|
|
10058
10294
|
for (const d of safeReaddir2(mp)) {
|
|
10059
|
-
const dp =
|
|
10295
|
+
const dp = path19.join(mp, d);
|
|
10060
10296
|
if (!isDir2(dp)) continue;
|
|
10061
10297
|
for (const f of safeReaddir2(dp)) {
|
|
10062
|
-
if (f.endsWith(".jsonl")) out.push(
|
|
10298
|
+
if (f.endsWith(".jsonl")) out.push(path19.join(dp, f));
|
|
10063
10299
|
}
|
|
10064
10300
|
}
|
|
10065
10301
|
}
|
|
@@ -10068,14 +10304,14 @@ function listCodexSessionFiles(base) {
|
|
|
10068
10304
|
}
|
|
10069
10305
|
function safeReaddir2(dir) {
|
|
10070
10306
|
try {
|
|
10071
|
-
return
|
|
10307
|
+
return fs17.readdirSync(dir);
|
|
10072
10308
|
} catch {
|
|
10073
10309
|
return [];
|
|
10074
10310
|
}
|
|
10075
10311
|
}
|
|
10076
10312
|
function isDir2(p) {
|
|
10077
10313
|
try {
|
|
10078
|
-
return
|
|
10314
|
+
return fs17.statSync(p).isDirectory();
|
|
10079
10315
|
} catch {
|
|
10080
10316
|
return false;
|
|
10081
10317
|
}
|
|
@@ -10145,7 +10381,7 @@ var init_cost_codex = __esm({
|
|
|
10145
10381
|
id: "codex",
|
|
10146
10382
|
available() {
|
|
10147
10383
|
try {
|
|
10148
|
-
return
|
|
10384
|
+
return fs17.existsSync(codexSessionsDir());
|
|
10149
10385
|
} catch {
|
|
10150
10386
|
return false;
|
|
10151
10387
|
}
|
|
@@ -10155,13 +10391,13 @@ var init_cost_codex = __esm({
|
|
|
10155
10391
|
const combined = /* @__PURE__ */ new Map();
|
|
10156
10392
|
for (const file of listCodexSessionFiles(base)) {
|
|
10157
10393
|
try {
|
|
10158
|
-
if (sinceMs !== void 0 &&
|
|
10394
|
+
if (sinceMs !== void 0 && fs17.statSync(file).mtimeMs < sinceMs) continue;
|
|
10159
10395
|
} catch {
|
|
10160
10396
|
continue;
|
|
10161
10397
|
}
|
|
10162
10398
|
let content;
|
|
10163
10399
|
try {
|
|
10164
|
-
content =
|
|
10400
|
+
content = fs17.readFileSync(file, "utf8");
|
|
10165
10401
|
} catch {
|
|
10166
10402
|
continue;
|
|
10167
10403
|
}
|
|
@@ -10467,85 +10703,85 @@ var init_scan_summary = __esm({
|
|
|
10467
10703
|
|
|
10468
10704
|
// src/cli/commands/blast.ts
|
|
10469
10705
|
import chalk2 from "chalk";
|
|
10470
|
-
import
|
|
10471
|
-
import
|
|
10472
|
-
import
|
|
10706
|
+
import fs18 from "fs";
|
|
10707
|
+
import path20 from "path";
|
|
10708
|
+
import os17 from "os";
|
|
10473
10709
|
function buildSensitivePaths(home, cwd) {
|
|
10474
10710
|
return [
|
|
10475
10711
|
{
|
|
10476
|
-
full:
|
|
10712
|
+
full: path20.join(home, ".ssh", "id_rsa"),
|
|
10477
10713
|
label: "~/.ssh/id_rsa",
|
|
10478
10714
|
description: "RSA private key \u2014 grants SSH access to your servers",
|
|
10479
10715
|
score: 20
|
|
10480
10716
|
},
|
|
10481
10717
|
{
|
|
10482
|
-
full:
|
|
10718
|
+
full: path20.join(home, ".ssh", "id_ed25519"),
|
|
10483
10719
|
label: "~/.ssh/id_ed25519",
|
|
10484
10720
|
description: "Ed25519 private key \u2014 grants SSH access to your servers",
|
|
10485
10721
|
score: 20
|
|
10486
10722
|
},
|
|
10487
10723
|
{
|
|
10488
|
-
full:
|
|
10724
|
+
full: path20.join(home, ".ssh", "id_ecdsa"),
|
|
10489
10725
|
label: "~/.ssh/id_ecdsa",
|
|
10490
10726
|
description: "ECDSA private key \u2014 grants SSH access to your servers",
|
|
10491
10727
|
score: 20
|
|
10492
10728
|
},
|
|
10493
10729
|
{
|
|
10494
|
-
full:
|
|
10730
|
+
full: path20.join(home, ".aws", "credentials"),
|
|
10495
10731
|
label: "~/.aws/credentials",
|
|
10496
10732
|
description: "AWS access keys \u2014 full cloud account access",
|
|
10497
10733
|
score: 20
|
|
10498
10734
|
},
|
|
10499
10735
|
{
|
|
10500
|
-
full:
|
|
10736
|
+
full: path20.join(home, ".aws", "config"),
|
|
10501
10737
|
label: "~/.aws/config",
|
|
10502
10738
|
description: "AWS configuration \u2014 account and region settings",
|
|
10503
10739
|
score: 5
|
|
10504
10740
|
},
|
|
10505
10741
|
{
|
|
10506
|
-
full:
|
|
10742
|
+
full: path20.join(home, ".config", "gcloud", "credentials.db"),
|
|
10507
10743
|
label: "~/.config/gcloud/credentials.db",
|
|
10508
10744
|
description: "Google Cloud credentials",
|
|
10509
10745
|
score: 15
|
|
10510
10746
|
},
|
|
10511
10747
|
{
|
|
10512
|
-
full:
|
|
10748
|
+
full: path20.join(home, ".docker", "config.json"),
|
|
10513
10749
|
label: "~/.docker/config.json",
|
|
10514
10750
|
description: "Docker registry auth tokens",
|
|
10515
10751
|
score: 10
|
|
10516
10752
|
},
|
|
10517
10753
|
{
|
|
10518
|
-
full:
|
|
10754
|
+
full: path20.join(home, ".netrc"),
|
|
10519
10755
|
label: "~/.netrc",
|
|
10520
10756
|
description: "FTP/HTTP credentials in plain text",
|
|
10521
10757
|
score: 15
|
|
10522
10758
|
},
|
|
10523
10759
|
{
|
|
10524
|
-
full:
|
|
10760
|
+
full: path20.join(home, ".npmrc"),
|
|
10525
10761
|
label: "~/.npmrc",
|
|
10526
10762
|
description: "npm auth token \u2014 can publish packages as you",
|
|
10527
10763
|
score: 10
|
|
10528
10764
|
},
|
|
10529
10765
|
{
|
|
10530
|
-
full:
|
|
10766
|
+
full: path20.join(home, ".node9", "credentials.json"),
|
|
10531
10767
|
label: "~/.node9/credentials.json",
|
|
10532
10768
|
description: "Node9 cloud API key",
|
|
10533
10769
|
score: 10
|
|
10534
10770
|
},
|
|
10535
10771
|
{
|
|
10536
|
-
full:
|
|
10772
|
+
full: path20.join(cwd, ".env"),
|
|
10537
10773
|
label: ".env (current folder)",
|
|
10538
10774
|
description: "App secrets \u2014 database passwords, API keys",
|
|
10539
10775
|
score: 20
|
|
10540
10776
|
},
|
|
10541
10777
|
{
|
|
10542
|
-
full:
|
|
10778
|
+
full: path20.join(cwd, ".env.local"),
|
|
10543
10779
|
label: ".env.local (current folder)",
|
|
10544
10780
|
description: "Local overrides \u2014 often contains real credentials",
|
|
10545
10781
|
score: 15
|
|
10546
10782
|
},
|
|
10547
10783
|
{
|
|
10548
|
-
full:
|
|
10784
|
+
full: path20.join(cwd, ".env.production"),
|
|
10549
10785
|
label: ".env.production (current folder)",
|
|
10550
10786
|
description: "Production secrets",
|
|
10551
10787
|
score: 20
|
|
@@ -10554,7 +10790,7 @@ function buildSensitivePaths(home, cwd) {
|
|
|
10554
10790
|
}
|
|
10555
10791
|
function isReadable(filePath) {
|
|
10556
10792
|
try {
|
|
10557
|
-
|
|
10793
|
+
fs18.accessSync(filePath, fs18.constants.R_OK);
|
|
10558
10794
|
return true;
|
|
10559
10795
|
} catch {
|
|
10560
10796
|
return false;
|
|
@@ -10567,13 +10803,13 @@ function scoreLabel(score) {
|
|
|
10567
10803
|
return chalk2.red.bold(`${score}/100 Critical`);
|
|
10568
10804
|
}
|
|
10569
10805
|
function runBlast() {
|
|
10570
|
-
const home =
|
|
10806
|
+
const home = os17.homedir();
|
|
10571
10807
|
const cwd = process.cwd();
|
|
10572
10808
|
const paths = buildSensitivePaths(home, cwd);
|
|
10573
10809
|
let scoreDeduction = 0;
|
|
10574
10810
|
const reachable = [];
|
|
10575
10811
|
for (const p of paths) {
|
|
10576
|
-
if (
|
|
10812
|
+
if (fs18.existsSync(p.full) && isReadable(p.full)) {
|
|
10577
10813
|
reachable.push(p);
|
|
10578
10814
|
scoreDeduction += p.score;
|
|
10579
10815
|
}
|
|
@@ -10591,7 +10827,7 @@ function runBlast() {
|
|
|
10591
10827
|
}
|
|
10592
10828
|
function registerBlastCommand(program2) {
|
|
10593
10829
|
program2.command("blast").description("Map what an AI agent can currently reach on this machine").action(() => {
|
|
10594
|
-
const home =
|
|
10830
|
+
const home = os17.homedir();
|
|
10595
10831
|
const cwd = process.cwd();
|
|
10596
10832
|
const { reachable, envFindings, score } = runBlast();
|
|
10597
10833
|
console.log("");
|
|
@@ -10767,17 +11003,17 @@ var init_scan_json = __esm({
|
|
|
10767
11003
|
});
|
|
10768
11004
|
|
|
10769
11005
|
// src/cli/render/scan-history.ts
|
|
10770
|
-
import
|
|
10771
|
-
import
|
|
10772
|
-
import
|
|
11006
|
+
import fs19 from "fs";
|
|
11007
|
+
import path21 from "path";
|
|
11008
|
+
import os18 from "os";
|
|
10773
11009
|
function defaultHistoryPath() {
|
|
10774
|
-
return
|
|
11010
|
+
return path21.join(os18.homedir(), ".node9", "scan-history.json");
|
|
10775
11011
|
}
|
|
10776
11012
|
function readPreviousScan(opts = {}) {
|
|
10777
11013
|
const filePath = opts.path ?? defaultHistoryPath();
|
|
10778
11014
|
try {
|
|
10779
|
-
if (!
|
|
10780
|
-
const raw =
|
|
11015
|
+
if (!fs19.existsSync(filePath)) return null;
|
|
11016
|
+
const raw = fs19.readFileSync(filePath, "utf8");
|
|
10781
11017
|
const parsed = JSON.parse(raw);
|
|
10782
11018
|
if (!Array.isArray(parsed) || parsed.length === 0) return null;
|
|
10783
11019
|
const last = parsed[parsed.length - 1];
|
|
@@ -10791,11 +11027,11 @@ function appendScanHistory(record, opts = {}) {
|
|
|
10791
11027
|
const filePath = opts.path ?? defaultHistoryPath();
|
|
10792
11028
|
const cap = opts.cap ?? SCAN_HISTORY_CAP;
|
|
10793
11029
|
try {
|
|
10794
|
-
|
|
11030
|
+
fs19.mkdirSync(path21.dirname(filePath), { recursive: true });
|
|
10795
11031
|
let history = [];
|
|
10796
|
-
if (
|
|
11032
|
+
if (fs19.existsSync(filePath)) {
|
|
10797
11033
|
try {
|
|
10798
|
-
const parsed = JSON.parse(
|
|
11034
|
+
const parsed = JSON.parse(fs19.readFileSync(filePath, "utf8"));
|
|
10799
11035
|
if (Array.isArray(parsed)) {
|
|
10800
11036
|
history = parsed.filter(isValidRecord);
|
|
10801
11037
|
}
|
|
@@ -10806,7 +11042,7 @@ function appendScanHistory(record, opts = {}) {
|
|
|
10806
11042
|
if (history.length > cap) {
|
|
10807
11043
|
history = history.slice(history.length - cap);
|
|
10808
11044
|
}
|
|
10809
|
-
|
|
11045
|
+
fs19.writeFileSync(filePath, JSON.stringify(history, null, 2));
|
|
10810
11046
|
} catch (err2) {
|
|
10811
11047
|
process.stderr.write(
|
|
10812
11048
|
`[node9] Warning: could not write scan-history.json: ${err2.message}
|
|
@@ -10837,15 +11073,15 @@ var init_scan_history = __esm({
|
|
|
10837
11073
|
});
|
|
10838
11074
|
|
|
10839
11075
|
// src/cost-copilot.ts
|
|
10840
|
-
import
|
|
10841
|
-
import
|
|
10842
|
-
import
|
|
11076
|
+
import fs20 from "fs";
|
|
11077
|
+
import os19 from "os";
|
|
11078
|
+
import path22 from "path";
|
|
10843
11079
|
function copilotSessionsDir() {
|
|
10844
|
-
return
|
|
11080
|
+
return path22.join(os19.homedir(), ".copilot", "session-state");
|
|
10845
11081
|
}
|
|
10846
11082
|
function safeReaddir3(dir) {
|
|
10847
11083
|
try {
|
|
10848
|
-
return
|
|
11084
|
+
return fs20.readdirSync(dir);
|
|
10849
11085
|
} catch {
|
|
10850
11086
|
return [];
|
|
10851
11087
|
}
|
|
@@ -10921,7 +11157,7 @@ var init_cost_copilot = __esm({
|
|
|
10921
11157
|
id: "copilot",
|
|
10922
11158
|
available() {
|
|
10923
11159
|
try {
|
|
10924
|
-
return
|
|
11160
|
+
return fs20.existsSync(copilotSessionsDir());
|
|
10925
11161
|
} catch {
|
|
10926
11162
|
return false;
|
|
10927
11163
|
}
|
|
@@ -10930,15 +11166,15 @@ var init_cost_copilot = __esm({
|
|
|
10930
11166
|
const base = copilotSessionsDir();
|
|
10931
11167
|
const combined = /* @__PURE__ */ new Map();
|
|
10932
11168
|
for (const sid of safeReaddir3(base)) {
|
|
10933
|
-
const file =
|
|
11169
|
+
const file = path22.join(base, sid, "events.jsonl");
|
|
10934
11170
|
try {
|
|
10935
|
-
if (sinceMs !== void 0 &&
|
|
11171
|
+
if (sinceMs !== void 0 && fs20.statSync(file).mtimeMs < sinceMs) continue;
|
|
10936
11172
|
} catch {
|
|
10937
11173
|
continue;
|
|
10938
11174
|
}
|
|
10939
11175
|
let content;
|
|
10940
11176
|
try {
|
|
10941
|
-
content =
|
|
11177
|
+
content = fs20.readFileSync(file, "utf8");
|
|
10942
11178
|
} catch {
|
|
10943
11179
|
continue;
|
|
10944
11180
|
}
|
|
@@ -10963,17 +11199,17 @@ var init_cost_copilot = __esm({
|
|
|
10963
11199
|
});
|
|
10964
11200
|
|
|
10965
11201
|
// src/costSync.ts
|
|
10966
|
-
import
|
|
10967
|
-
import
|
|
10968
|
-
import
|
|
11202
|
+
import fs21 from "fs";
|
|
11203
|
+
import path23 from "path";
|
|
11204
|
+
import os20 from "os";
|
|
10969
11205
|
function decodeProjectDirName(dirName) {
|
|
10970
11206
|
return dirName.replace(/-/g, "/");
|
|
10971
11207
|
}
|
|
10972
11208
|
function parseJSONLFile(filePath, fallbackWorkingDir) {
|
|
10973
|
-
const runId =
|
|
11209
|
+
const runId = path23.basename(filePath, ".jsonl");
|
|
10974
11210
|
let content;
|
|
10975
11211
|
try {
|
|
10976
|
-
content =
|
|
11212
|
+
content = fs21.readFileSync(filePath, "utf8");
|
|
10977
11213
|
} catch {
|
|
10978
11214
|
return /* @__PURE__ */ new Map();
|
|
10979
11215
|
}
|
|
@@ -11073,7 +11309,7 @@ async function postCostBatches(apiUrl, apiKey, machineId, entries) {
|
|
|
11073
11309
|
signal: AbortSignal.timeout(15e3)
|
|
11074
11310
|
});
|
|
11075
11311
|
if (!res.ok) {
|
|
11076
|
-
|
|
11312
|
+
fs21.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
|
|
11077
11313
|
`);
|
|
11078
11314
|
} else {
|
|
11079
11315
|
let stored;
|
|
@@ -11083,7 +11319,7 @@ async function postCostBatches(apiUrl, apiKey, machineId, entries) {
|
|
|
11083
11319
|
} catch {
|
|
11084
11320
|
}
|
|
11085
11321
|
if (typeof stored === "number" && stored < batch.length) {
|
|
11086
|
-
|
|
11322
|
+
fs21.appendFileSync(
|
|
11087
11323
|
HOOK_DEBUG_LOG,
|
|
11088
11324
|
`[cost-sync] dropped ${batch.length - stored} of ${batch.length} rows
|
|
11089
11325
|
`
|
|
@@ -11091,7 +11327,7 @@ async function postCostBatches(apiUrl, apiKey, machineId, entries) {
|
|
|
11091
11327
|
}
|
|
11092
11328
|
}
|
|
11093
11329
|
} catch (err2) {
|
|
11094
|
-
|
|
11330
|
+
fs21.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
|
|
11095
11331
|
`);
|
|
11096
11332
|
}
|
|
11097
11333
|
}
|
|
@@ -11104,10 +11340,10 @@ async function syncCost() {
|
|
|
11104
11340
|
if (entries.length === 0) return;
|
|
11105
11341
|
let username = "unknown";
|
|
11106
11342
|
try {
|
|
11107
|
-
username =
|
|
11343
|
+
username = os20.userInfo().username;
|
|
11108
11344
|
} catch {
|
|
11109
11345
|
}
|
|
11110
|
-
const machineId = `${
|
|
11346
|
+
const machineId = `${os20.hostname()}:${username}`;
|
|
11111
11347
|
await postCostBatches(creds.apiUrl, creds.apiKey, machineId, entries);
|
|
11112
11348
|
}
|
|
11113
11349
|
function startCostSync() {
|
|
@@ -11133,37 +11369,37 @@ var init_costSync = __esm({
|
|
|
11133
11369
|
claudeSource = {
|
|
11134
11370
|
id: "claude",
|
|
11135
11371
|
available() {
|
|
11136
|
-
return
|
|
11372
|
+
return fs21.existsSync(path23.join(os20.homedir(), ".claude", "projects"));
|
|
11137
11373
|
},
|
|
11138
11374
|
collect(sinceMs) {
|
|
11139
|
-
const projectsDir =
|
|
11140
|
-
if (!
|
|
11375
|
+
const projectsDir = path23.join(os20.homedir(), ".claude", "projects");
|
|
11376
|
+
if (!fs21.existsSync(projectsDir)) return [];
|
|
11141
11377
|
const combined = /* @__PURE__ */ new Map();
|
|
11142
11378
|
let dirs;
|
|
11143
11379
|
try {
|
|
11144
|
-
dirs =
|
|
11380
|
+
dirs = fs21.readdirSync(projectsDir);
|
|
11145
11381
|
} catch {
|
|
11146
11382
|
return [];
|
|
11147
11383
|
}
|
|
11148
11384
|
for (const dir of dirs) {
|
|
11149
|
-
const dirPath =
|
|
11385
|
+
const dirPath = path23.join(projectsDir, dir);
|
|
11150
11386
|
try {
|
|
11151
|
-
if (!
|
|
11387
|
+
if (!fs21.statSync(dirPath).isDirectory()) continue;
|
|
11152
11388
|
} catch {
|
|
11153
11389
|
continue;
|
|
11154
11390
|
}
|
|
11155
11391
|
let files;
|
|
11156
11392
|
try {
|
|
11157
|
-
files =
|
|
11393
|
+
files = fs21.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
11158
11394
|
} catch {
|
|
11159
11395
|
continue;
|
|
11160
11396
|
}
|
|
11161
11397
|
const fallbackWorkingDir = decodeProjectDirName(dir);
|
|
11162
11398
|
for (const file of files) {
|
|
11163
|
-
const filePath =
|
|
11399
|
+
const filePath = path23.join(dirPath, file);
|
|
11164
11400
|
if (sinceMs !== void 0) {
|
|
11165
11401
|
try {
|
|
11166
|
-
if (
|
|
11402
|
+
if (fs21.statSync(filePath).mtimeMs < sinceMs) continue;
|
|
11167
11403
|
} catch {
|
|
11168
11404
|
continue;
|
|
11169
11405
|
}
|
|
@@ -11203,9 +11439,9 @@ __export(scan_watermark_exports, {
|
|
|
11203
11439
|
tickForensicBroadcast: () => tickForensicBroadcast,
|
|
11204
11440
|
tickScanWatcher: () => tickScanWatcher
|
|
11205
11441
|
});
|
|
11206
|
-
import
|
|
11207
|
-
import
|
|
11208
|
-
import
|
|
11442
|
+
import fs22 from "fs";
|
|
11443
|
+
import os21 from "os";
|
|
11444
|
+
import path24 from "path";
|
|
11209
11445
|
import readline from "readline";
|
|
11210
11446
|
function freshWatermark() {
|
|
11211
11447
|
return {
|
|
@@ -11218,7 +11454,7 @@ function freshWatermark() {
|
|
|
11218
11454
|
function loadWatermark() {
|
|
11219
11455
|
let raw;
|
|
11220
11456
|
try {
|
|
11221
|
-
raw =
|
|
11457
|
+
raw = fs22.readFileSync(WATERMARK_FILE(), "utf-8");
|
|
11222
11458
|
} catch {
|
|
11223
11459
|
return { status: "fresh", wm: freshWatermark() };
|
|
11224
11460
|
}
|
|
@@ -11270,28 +11506,28 @@ function loadWatermark() {
|
|
|
11270
11506
|
function saveWatermark(wm) {
|
|
11271
11507
|
if (wm.schemaVersion > WATERMARK_SCHEMA_VERSION) return;
|
|
11272
11508
|
const target = WATERMARK_FILE();
|
|
11273
|
-
const dir =
|
|
11274
|
-
if (!
|
|
11509
|
+
const dir = path24.dirname(target);
|
|
11510
|
+
if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
|
|
11275
11511
|
const tmp = target + ".tmp";
|
|
11276
|
-
|
|
11277
|
-
|
|
11512
|
+
fs22.writeFileSync(tmp, JSON.stringify(wm, null, 2) + "\n", "utf-8");
|
|
11513
|
+
fs22.renameSync(tmp, target);
|
|
11278
11514
|
}
|
|
11279
11515
|
function listJsonlFiles() {
|
|
11280
11516
|
const root = PROJECTS_DIR();
|
|
11281
|
-
if (!
|
|
11517
|
+
if (!fs22.existsSync(root)) return [];
|
|
11282
11518
|
const out = [];
|
|
11283
|
-
for (const entry of
|
|
11519
|
+
for (const entry of fs22.readdirSync(root, { withFileTypes: true })) {
|
|
11284
11520
|
if (!entry.isDirectory()) continue;
|
|
11285
|
-
const projectDir =
|
|
11521
|
+
const projectDir = path24.join(root, entry.name);
|
|
11286
11522
|
let inner;
|
|
11287
11523
|
try {
|
|
11288
|
-
inner =
|
|
11524
|
+
inner = fs22.readdirSync(projectDir, { withFileTypes: true });
|
|
11289
11525
|
} catch {
|
|
11290
11526
|
continue;
|
|
11291
11527
|
}
|
|
11292
11528
|
for (const file of inner) {
|
|
11293
11529
|
if (file.isFile() && file.name.endsWith(".jsonl")) {
|
|
11294
|
-
out.push(
|
|
11530
|
+
out.push(path24.join(projectDir, file.name));
|
|
11295
11531
|
}
|
|
11296
11532
|
}
|
|
11297
11533
|
}
|
|
@@ -11299,7 +11535,7 @@ function listJsonlFiles() {
|
|
|
11299
11535
|
}
|
|
11300
11536
|
function fileSize(p) {
|
|
11301
11537
|
try {
|
|
11302
|
-
return
|
|
11538
|
+
return fs22.statSync(p).size;
|
|
11303
11539
|
} catch {
|
|
11304
11540
|
return 0;
|
|
11305
11541
|
}
|
|
@@ -11307,7 +11543,7 @@ function fileSize(p) {
|
|
|
11307
11543
|
async function scanDelta(filePath, fromByte, onLine) {
|
|
11308
11544
|
const size = fileSize(filePath);
|
|
11309
11545
|
if (size <= fromByte) return fromByte;
|
|
11310
|
-
const stream =
|
|
11546
|
+
const stream = fs22.createReadStream(filePath, {
|
|
11311
11547
|
start: fromByte,
|
|
11312
11548
|
end: size - 1,
|
|
11313
11549
|
highWaterMark: 64 * 1024
|
|
@@ -11419,7 +11655,7 @@ async function tickForensicBroadcast(offsets) {
|
|
|
11419
11655
|
continue;
|
|
11420
11656
|
}
|
|
11421
11657
|
if (size <= offset) continue;
|
|
11422
|
-
const sessionId =
|
|
11658
|
+
const sessionId = path24.basename(file, ".jsonl");
|
|
11423
11659
|
const newOffset = await scanDelta(file, offset, (obj, lineIndex) => {
|
|
11424
11660
|
out.push(...extractFindingsFromLine(obj, sessionId, lineIndex));
|
|
11425
11661
|
});
|
|
@@ -11478,7 +11714,7 @@ function emptyTick(uploadAs) {
|
|
|
11478
11714
|
function readRawWatermarkPreservingOffsets() {
|
|
11479
11715
|
let raw;
|
|
11480
11716
|
try {
|
|
11481
|
-
raw =
|
|
11717
|
+
raw = fs22.readFileSync(WATERMARK_FILE(), "utf-8");
|
|
11482
11718
|
} catch {
|
|
11483
11719
|
return null;
|
|
11484
11720
|
}
|
|
@@ -11512,13 +11748,13 @@ async function runActualTick(wm) {
|
|
|
11512
11748
|
if (!known) {
|
|
11513
11749
|
let mtimeMs = 0;
|
|
11514
11750
|
try {
|
|
11515
|
-
mtimeMs =
|
|
11751
|
+
mtimeMs = fs22.statSync(filePath).mtime.getTime();
|
|
11516
11752
|
} catch {
|
|
11517
11753
|
continue;
|
|
11518
11754
|
}
|
|
11519
11755
|
if (mtimeMs >= watermarkCreatedAt) {
|
|
11520
11756
|
filesNew++;
|
|
11521
|
-
const sessionId2 =
|
|
11757
|
+
const sessionId2 = path24.basename(filePath, ".jsonl");
|
|
11522
11758
|
const newScannedTo2 = await scanDelta(filePath, 0, (obj, lineIndex) => {
|
|
11523
11759
|
totalToolCalls++;
|
|
11524
11760
|
toolCallsBySession[sessionId2] = (toolCallsBySession[sessionId2] ?? 0) + 1;
|
|
@@ -11536,7 +11772,7 @@ async function runActualTick(wm) {
|
|
|
11536
11772
|
filesSkipped++;
|
|
11537
11773
|
continue;
|
|
11538
11774
|
}
|
|
11539
|
-
const sessionId =
|
|
11775
|
+
const sessionId = path24.basename(filePath, ".jsonl");
|
|
11540
11776
|
const newScannedTo = await scanDelta(filePath, known.scannedTo, (obj, lineIndex) => {
|
|
11541
11777
|
totalToolCalls++;
|
|
11542
11778
|
toolCallsBySession[sessionId] = (toolCallsBySession[sessionId] ?? 0) + 1;
|
|
@@ -11564,8 +11800,8 @@ var init_scan_watermark = __esm({
|
|
|
11564
11800
|
"use strict";
|
|
11565
11801
|
init_dlp();
|
|
11566
11802
|
init_dist();
|
|
11567
|
-
PROJECTS_DIR = () =>
|
|
11568
|
-
WATERMARK_FILE = () =>
|
|
11803
|
+
PROJECTS_DIR = () => path24.join(os21.homedir(), ".claude", "projects");
|
|
11804
|
+
WATERMARK_FILE = () => path24.join(os21.homedir(), ".node9", "scan-watermark.json");
|
|
11569
11805
|
MAX_LINE_BYTES = 2 * 1024 * 1024;
|
|
11570
11806
|
WATERMARK_SCHEMA_VERSION = 2;
|
|
11571
11807
|
LONG_OUTPUT_THRESHOLD_BYTES2 = LONG_OUTPUT_THRESHOLD_BYTES;
|
|
@@ -11581,10 +11817,10 @@ __export(scan_upload_history_exports, {
|
|
|
11581
11817
|
parseSinceCutoff: () => parseSinceCutoff,
|
|
11582
11818
|
runUploadHistory: () => runUploadHistory
|
|
11583
11819
|
});
|
|
11584
|
-
import
|
|
11820
|
+
import fs23 from "fs";
|
|
11585
11821
|
import https from "https";
|
|
11586
|
-
import
|
|
11587
|
-
import
|
|
11822
|
+
import os22 from "os";
|
|
11823
|
+
import path25 from "path";
|
|
11588
11824
|
import chalk4 from "chalk";
|
|
11589
11825
|
function emptySignals2() {
|
|
11590
11826
|
return {
|
|
@@ -11619,40 +11855,40 @@ function parseSinceCutoff(raw, now = /* @__PURE__ */ new Date()) {
|
|
|
11619
11855
|
return now.getTime() - 90 * 864e5;
|
|
11620
11856
|
}
|
|
11621
11857
|
function* iterateJsonlFiles(cutoffMs) {
|
|
11622
|
-
const projectsDir =
|
|
11858
|
+
const projectsDir = path25.join(os22.homedir(), ".claude", "projects");
|
|
11623
11859
|
let dirs;
|
|
11624
11860
|
try {
|
|
11625
|
-
dirs =
|
|
11861
|
+
dirs = fs23.readdirSync(projectsDir);
|
|
11626
11862
|
} catch {
|
|
11627
11863
|
return;
|
|
11628
11864
|
}
|
|
11629
11865
|
for (const dir of dirs) {
|
|
11630
|
-
const dirPath =
|
|
11866
|
+
const dirPath = path25.join(projectsDir, dir);
|
|
11631
11867
|
let stats;
|
|
11632
11868
|
try {
|
|
11633
|
-
stats =
|
|
11869
|
+
stats = fs23.statSync(dirPath);
|
|
11634
11870
|
} catch {
|
|
11635
11871
|
continue;
|
|
11636
11872
|
}
|
|
11637
11873
|
if (!stats.isDirectory()) continue;
|
|
11638
11874
|
let files;
|
|
11639
11875
|
try {
|
|
11640
|
-
files =
|
|
11876
|
+
files = fs23.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
11641
11877
|
} catch {
|
|
11642
11878
|
continue;
|
|
11643
11879
|
}
|
|
11644
11880
|
for (const file of files) {
|
|
11645
|
-
const filePath =
|
|
11881
|
+
const filePath = path25.join(dirPath, file);
|
|
11646
11882
|
let mtime = 0;
|
|
11647
11883
|
try {
|
|
11648
|
-
mtime =
|
|
11884
|
+
mtime = fs23.statSync(filePath).mtimeMs;
|
|
11649
11885
|
} catch {
|
|
11650
11886
|
continue;
|
|
11651
11887
|
}
|
|
11652
11888
|
if (mtime < cutoffMs) continue;
|
|
11653
11889
|
yield {
|
|
11654
11890
|
filePath,
|
|
11655
|
-
sessionId:
|
|
11891
|
+
sessionId: path25.basename(file, ".jsonl"),
|
|
11656
11892
|
projectDir: dir
|
|
11657
11893
|
};
|
|
11658
11894
|
}
|
|
@@ -11720,7 +11956,7 @@ async function runUploadHistory(opts) {
|
|
|
11720
11956
|
filesScanned++;
|
|
11721
11957
|
let content;
|
|
11722
11958
|
try {
|
|
11723
|
-
content =
|
|
11959
|
+
content = fs23.readFileSync(filePath, "utf8");
|
|
11724
11960
|
} catch {
|
|
11725
11961
|
continue;
|
|
11726
11962
|
}
|
|
@@ -11794,10 +12030,10 @@ async function runUploadHistory(opts) {
|
|
|
11794
12030
|
const costUrl = creds.apiUrl.endsWith("/policies/sync") ? creds.apiUrl.replace(/\/policies\/sync$/, "/cost-sync") : `${creds.apiUrl.replace(/\/$/, "")}/cost-sync`;
|
|
11795
12031
|
let username = "unknown";
|
|
11796
12032
|
try {
|
|
11797
|
-
username =
|
|
12033
|
+
username = os22.userInfo().username;
|
|
11798
12034
|
} catch {
|
|
11799
12035
|
}
|
|
11800
|
-
const machineId = `${
|
|
12036
|
+
const machineId = `${os22.hostname()}:${username}`;
|
|
11801
12037
|
await postJson(costUrl, creds.apiKey, {
|
|
11802
12038
|
machineId,
|
|
11803
12039
|
entries: dailyEntries
|
|
@@ -11871,9 +12107,9 @@ var init_scan_upload_history = __esm({
|
|
|
11871
12107
|
|
|
11872
12108
|
// src/cli/commands/scan.ts
|
|
11873
12109
|
import chalk5 from "chalk";
|
|
11874
|
-
import
|
|
11875
|
-
import
|
|
11876
|
-
import
|
|
12110
|
+
import fs24 from "fs";
|
|
12111
|
+
import path26 from "path";
|
|
12112
|
+
import os23 from "os";
|
|
11877
12113
|
import stringWidth2 from "string-width";
|
|
11878
12114
|
function claudeModelPrice(model) {
|
|
11879
12115
|
const t = pricingFor(model);
|
|
@@ -12096,14 +12332,14 @@ function buildRuleSources() {
|
|
|
12096
12332
|
}
|
|
12097
12333
|
function countScanFiles() {
|
|
12098
12334
|
let total = 0;
|
|
12099
|
-
const claudeDir =
|
|
12100
|
-
if (
|
|
12335
|
+
const claudeDir = path26.join(os23.homedir(), ".claude", "projects");
|
|
12336
|
+
if (fs24.existsSync(claudeDir)) {
|
|
12101
12337
|
try {
|
|
12102
|
-
for (const proj of
|
|
12103
|
-
const p =
|
|
12338
|
+
for (const proj of fs24.readdirSync(claudeDir)) {
|
|
12339
|
+
const p = path26.join(claudeDir, proj);
|
|
12104
12340
|
try {
|
|
12105
|
-
if (!
|
|
12106
|
-
total +=
|
|
12341
|
+
if (!fs24.statSync(p).isDirectory()) continue;
|
|
12342
|
+
total += fs24.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
|
|
12107
12343
|
} catch {
|
|
12108
12344
|
continue;
|
|
12109
12345
|
}
|
|
@@ -12111,17 +12347,17 @@ function countScanFiles() {
|
|
|
12111
12347
|
} catch {
|
|
12112
12348
|
}
|
|
12113
12349
|
}
|
|
12114
|
-
const geminiDir =
|
|
12115
|
-
if (
|
|
12350
|
+
const geminiDir = path26.join(os23.homedir(), ".gemini", "tmp");
|
|
12351
|
+
if (fs24.existsSync(geminiDir)) {
|
|
12116
12352
|
try {
|
|
12117
|
-
for (const slug2 of
|
|
12118
|
-
const p =
|
|
12353
|
+
for (const slug2 of fs24.readdirSync(geminiDir)) {
|
|
12354
|
+
const p = path26.join(geminiDir, slug2);
|
|
12119
12355
|
try {
|
|
12120
|
-
if (!
|
|
12121
|
-
const chatsDir =
|
|
12122
|
-
if (
|
|
12356
|
+
if (!fs24.statSync(p).isDirectory()) continue;
|
|
12357
|
+
const chatsDir = path26.join(p, "chats");
|
|
12358
|
+
if (fs24.existsSync(chatsDir)) {
|
|
12123
12359
|
try {
|
|
12124
|
-
total +=
|
|
12360
|
+
total += fs24.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
|
|
12125
12361
|
} catch {
|
|
12126
12362
|
}
|
|
12127
12363
|
}
|
|
@@ -12133,15 +12369,15 @@ function countScanFiles() {
|
|
|
12133
12369
|
}
|
|
12134
12370
|
}
|
|
12135
12371
|
for (const surface of ["antigravity-cli", "antigravity-ide"]) {
|
|
12136
|
-
const brainDir =
|
|
12137
|
-
if (!
|
|
12372
|
+
const brainDir = path26.join(os23.homedir(), ".gemini", surface, "brain");
|
|
12373
|
+
if (!fs24.existsSync(brainDir)) continue;
|
|
12138
12374
|
try {
|
|
12139
|
-
for (const conv of
|
|
12140
|
-
const convPath =
|
|
12375
|
+
for (const conv of fs24.readdirSync(brainDir)) {
|
|
12376
|
+
const convPath = path26.join(brainDir, conv);
|
|
12141
12377
|
try {
|
|
12142
|
-
if (!
|
|
12143
|
-
const logsDir =
|
|
12144
|
-
if (
|
|
12378
|
+
if (!fs24.statSync(convPath).isDirectory()) continue;
|
|
12379
|
+
const logsDir = path26.join(convPath, ".system_generated", "logs");
|
|
12380
|
+
if (fs24.existsSync(path26.join(logsDir, "transcript_full.jsonl")) || fs24.existsSync(path26.join(logsDir, "transcript.jsonl"))) {
|
|
12145
12381
|
total += 1;
|
|
12146
12382
|
}
|
|
12147
12383
|
} catch {
|
|
@@ -12151,31 +12387,31 @@ function countScanFiles() {
|
|
|
12151
12387
|
} catch {
|
|
12152
12388
|
}
|
|
12153
12389
|
}
|
|
12154
|
-
const copilotDir =
|
|
12155
|
-
if (
|
|
12390
|
+
const copilotDir = path26.join(os23.homedir(), ".copilot", "session-state");
|
|
12391
|
+
if (fs24.existsSync(copilotDir)) {
|
|
12156
12392
|
try {
|
|
12157
|
-
for (const sid of
|
|
12158
|
-
if (
|
|
12393
|
+
for (const sid of fs24.readdirSync(copilotDir)) {
|
|
12394
|
+
if (fs24.existsSync(path26.join(copilotDir, sid, "events.jsonl"))) total += 1;
|
|
12159
12395
|
}
|
|
12160
12396
|
} catch {
|
|
12161
12397
|
}
|
|
12162
12398
|
}
|
|
12163
|
-
const codexDir =
|
|
12164
|
-
if (
|
|
12399
|
+
const codexDir = path26.join(os23.homedir(), ".codex", "sessions");
|
|
12400
|
+
if (fs24.existsSync(codexDir)) {
|
|
12165
12401
|
try {
|
|
12166
|
-
for (const year of
|
|
12167
|
-
const yp =
|
|
12402
|
+
for (const year of fs24.readdirSync(codexDir)) {
|
|
12403
|
+
const yp = path26.join(codexDir, year);
|
|
12168
12404
|
try {
|
|
12169
|
-
if (!
|
|
12170
|
-
for (const month of
|
|
12171
|
-
const mp =
|
|
12405
|
+
if (!fs24.statSync(yp).isDirectory()) continue;
|
|
12406
|
+
for (const month of fs24.readdirSync(yp)) {
|
|
12407
|
+
const mp = path26.join(yp, month);
|
|
12172
12408
|
try {
|
|
12173
|
-
if (!
|
|
12174
|
-
for (const day of
|
|
12175
|
-
const dp =
|
|
12409
|
+
if (!fs24.statSync(mp).isDirectory()) continue;
|
|
12410
|
+
for (const day of fs24.readdirSync(mp)) {
|
|
12411
|
+
const dp = path26.join(mp, day);
|
|
12176
12412
|
try {
|
|
12177
|
-
if (!
|
|
12178
|
-
total +=
|
|
12413
|
+
if (!fs24.statSync(dp).isDirectory()) continue;
|
|
12414
|
+
total += fs24.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
|
|
12179
12415
|
} catch {
|
|
12180
12416
|
continue;
|
|
12181
12417
|
}
|
|
@@ -12211,7 +12447,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
12211
12447
|
const sessionId = file.replace(/\.jsonl$/, "");
|
|
12212
12448
|
let raw;
|
|
12213
12449
|
try {
|
|
12214
|
-
raw =
|
|
12450
|
+
raw = fs24.readFileSync(path26.join(projPath, file), "utf-8");
|
|
12215
12451
|
} catch {
|
|
12216
12452
|
return;
|
|
12217
12453
|
}
|
|
@@ -12263,7 +12499,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
12263
12499
|
if (block.type !== "tool_result") continue;
|
|
12264
12500
|
const filePath = block.tool_use_id ? toolUseFilePaths.get(block.tool_use_id) : void 0;
|
|
12265
12501
|
if (filePath) {
|
|
12266
|
-
const ext =
|
|
12502
|
+
const ext = path26.extname(filePath).toLowerCase();
|
|
12267
12503
|
if (CODE_EXTENSIONS.has(ext)) continue;
|
|
12268
12504
|
}
|
|
12269
12505
|
const resultText = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => c.text ?? "").join("\n") : null;
|
|
@@ -12320,7 +12556,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
12320
12556
|
const rawCmd = String(input.command ?? "").trimStart();
|
|
12321
12557
|
if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd)) continue;
|
|
12322
12558
|
const inputFilePath = typeof input.file_path === "string" ? input.file_path : "";
|
|
12323
|
-
const inputFileExt = inputFilePath ?
|
|
12559
|
+
const inputFileExt = inputFilePath ? path26.extname(inputFilePath).toLowerCase() : "";
|
|
12324
12560
|
if (CODE_EXTENSIONS.has(inputFileExt)) continue;
|
|
12325
12561
|
const dlpMatch = scanArgs(input);
|
|
12326
12562
|
if (dlpMatch) {
|
|
@@ -12417,19 +12653,19 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
12417
12653
|
}
|
|
12418
12654
|
}
|
|
12419
12655
|
function processClaudeProject(proj, projectsDir, ruleSources, startDate, result, dedup, onProgress, onLine) {
|
|
12420
|
-
const projPath =
|
|
12656
|
+
const projPath = path26.join(projectsDir, proj);
|
|
12421
12657
|
try {
|
|
12422
|
-
if (!
|
|
12658
|
+
if (!fs24.statSync(projPath).isDirectory()) return;
|
|
12423
12659
|
} catch {
|
|
12424
12660
|
return;
|
|
12425
12661
|
}
|
|
12426
|
-
const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(
|
|
12662
|
+
const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(os23.homedir(), "~")).slice(
|
|
12427
12663
|
0,
|
|
12428
12664
|
40
|
|
12429
12665
|
);
|
|
12430
12666
|
let files;
|
|
12431
12667
|
try {
|
|
12432
|
-
files =
|
|
12668
|
+
files = fs24.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
12433
12669
|
} catch {
|
|
12434
12670
|
return;
|
|
12435
12671
|
}
|
|
@@ -12463,12 +12699,12 @@ function emptyClaudeScan() {
|
|
|
12463
12699
|
};
|
|
12464
12700
|
}
|
|
12465
12701
|
function scanClaudeHistory(startDate, onProgress, onLine) {
|
|
12466
|
-
const projectsDir =
|
|
12702
|
+
const projectsDir = path26.join(os23.homedir(), ".claude", "projects");
|
|
12467
12703
|
const result = emptyClaudeScan();
|
|
12468
|
-
if (!
|
|
12704
|
+
if (!fs24.existsSync(projectsDir)) return result;
|
|
12469
12705
|
let projDirs;
|
|
12470
12706
|
try {
|
|
12471
|
-
projDirs =
|
|
12707
|
+
projDirs = fs24.readdirSync(projectsDir);
|
|
12472
12708
|
} catch {
|
|
12473
12709
|
return result;
|
|
12474
12710
|
}
|
|
@@ -12489,7 +12725,7 @@ function scanClaudeHistory(startDate, onProgress, onLine) {
|
|
|
12489
12725
|
return result;
|
|
12490
12726
|
}
|
|
12491
12727
|
function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
12492
|
-
const tmpDir =
|
|
12728
|
+
const tmpDir = path26.join(os23.homedir(), ".gemini", "tmp");
|
|
12493
12729
|
const result = {
|
|
12494
12730
|
filesScanned: 0,
|
|
12495
12731
|
sessions: 0,
|
|
@@ -12504,33 +12740,33 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
12504
12740
|
sessionsWithEarlySecrets: 0
|
|
12505
12741
|
};
|
|
12506
12742
|
const dedup = emptyScanDedup();
|
|
12507
|
-
if (!
|
|
12743
|
+
if (!fs24.existsSync(tmpDir)) return result;
|
|
12508
12744
|
let slugDirs;
|
|
12509
12745
|
try {
|
|
12510
|
-
slugDirs =
|
|
12746
|
+
slugDirs = fs24.readdirSync(tmpDir);
|
|
12511
12747
|
} catch {
|
|
12512
12748
|
return result;
|
|
12513
12749
|
}
|
|
12514
12750
|
const ruleSources = buildRuleSources();
|
|
12515
12751
|
for (const slug2 of slugDirs) {
|
|
12516
|
-
const slugPath =
|
|
12752
|
+
const slugPath = path26.join(tmpDir, slug2);
|
|
12517
12753
|
try {
|
|
12518
|
-
if (!
|
|
12754
|
+
if (!fs24.statSync(slugPath).isDirectory()) continue;
|
|
12519
12755
|
} catch {
|
|
12520
12756
|
continue;
|
|
12521
12757
|
}
|
|
12522
12758
|
let projLabel = stripTerminalEscapes(slug2).slice(0, 40);
|
|
12523
12759
|
try {
|
|
12524
12760
|
projLabel = stripTerminalEscapes(
|
|
12525
|
-
|
|
12526
|
-
).replace(
|
|
12761
|
+
fs24.readFileSync(path26.join(slugPath, ".project_root"), "utf-8").trim()
|
|
12762
|
+
).replace(os23.homedir(), "~").slice(0, 40);
|
|
12527
12763
|
} catch {
|
|
12528
12764
|
}
|
|
12529
|
-
const chatsDir =
|
|
12530
|
-
if (!
|
|
12765
|
+
const chatsDir = path26.join(slugPath, "chats");
|
|
12766
|
+
if (!fs24.existsSync(chatsDir)) continue;
|
|
12531
12767
|
let chatFiles;
|
|
12532
12768
|
try {
|
|
12533
|
-
chatFiles =
|
|
12769
|
+
chatFiles = fs24.readdirSync(chatsDir).filter((f) => f.endsWith(".json") || f.endsWith(".jsonl")).sort((a, b) => Number(b.endsWith(".jsonl")) - Number(a.endsWith(".jsonl")));
|
|
12534
12770
|
} catch {
|
|
12535
12771
|
continue;
|
|
12536
12772
|
}
|
|
@@ -12543,7 +12779,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
12543
12779
|
onProgress?.(result.filesScanned);
|
|
12544
12780
|
let raw;
|
|
12545
12781
|
try {
|
|
12546
|
-
raw =
|
|
12782
|
+
raw = fs24.readFileSync(path26.join(chatsDir, chatFile), "utf-8");
|
|
12547
12783
|
} catch {
|
|
12548
12784
|
continue;
|
|
12549
12785
|
}
|
|
@@ -12716,13 +12952,13 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
12716
12952
|
return result;
|
|
12717
12953
|
}
|
|
12718
12954
|
function antigravityBrainDirs() {
|
|
12719
|
-
return ["antigravity-cli", "antigravity-ide"].map((surface) =>
|
|
12955
|
+
return ["antigravity-cli", "antigravity-ide"].map((surface) => path26.join(os23.homedir(), ".gemini", surface, "brain")).filter((p) => fs24.existsSync(p));
|
|
12720
12956
|
}
|
|
12721
12957
|
function antigravityTranscriptPath(convPath) {
|
|
12722
|
-
const logsDir =
|
|
12958
|
+
const logsDir = path26.join(convPath, ".system_generated", "logs");
|
|
12723
12959
|
for (const name of ["transcript_full.jsonl", "transcript.jsonl"]) {
|
|
12724
|
-
const p =
|
|
12725
|
-
if (
|
|
12960
|
+
const p = path26.join(logsDir, name);
|
|
12961
|
+
if (fs24.existsSync(p)) return p;
|
|
12726
12962
|
}
|
|
12727
12963
|
return null;
|
|
12728
12964
|
}
|
|
@@ -12748,14 +12984,14 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
|
|
|
12748
12984
|
for (const brainDir of brainDirs) {
|
|
12749
12985
|
let convDirs;
|
|
12750
12986
|
try {
|
|
12751
|
-
convDirs =
|
|
12987
|
+
convDirs = fs24.readdirSync(brainDir);
|
|
12752
12988
|
} catch {
|
|
12753
12989
|
continue;
|
|
12754
12990
|
}
|
|
12755
12991
|
for (const conv of convDirs) {
|
|
12756
|
-
const convPath =
|
|
12992
|
+
const convPath = path26.join(brainDir, conv);
|
|
12757
12993
|
try {
|
|
12758
|
-
if (!
|
|
12994
|
+
if (!fs24.statSync(convPath).isDirectory()) continue;
|
|
12759
12995
|
} catch {
|
|
12760
12996
|
continue;
|
|
12761
12997
|
}
|
|
@@ -12765,7 +13001,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
|
|
|
12765
13001
|
onProgress?.(result.filesScanned);
|
|
12766
13002
|
let raw;
|
|
12767
13003
|
try {
|
|
12768
|
-
raw =
|
|
13004
|
+
raw = fs24.readFileSync(transcriptFile, "utf-8");
|
|
12769
13005
|
} catch {
|
|
12770
13006
|
continue;
|
|
12771
13007
|
}
|
|
@@ -12822,7 +13058,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
|
|
|
12822
13058
|
result.bashCalls++;
|
|
12823
13059
|
const cwd = String(input.cwd ?? "");
|
|
12824
13060
|
if (cwd && projLabel === conv.slice(0, 8)) {
|
|
12825
|
-
projLabel = stripTerminalEscapes(cwd).replace(
|
|
13061
|
+
projLabel = stripTerminalEscapes(cwd).replace(os23.homedir(), "~").slice(0, 40);
|
|
12826
13062
|
}
|
|
12827
13063
|
}
|
|
12828
13064
|
const rawCmd = String(input.command ?? "").trimStart();
|
|
@@ -12922,7 +13158,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
|
|
|
12922
13158
|
return result;
|
|
12923
13159
|
}
|
|
12924
13160
|
function scanCopilotHistory(startDate, onProgress, onLine) {
|
|
12925
|
-
const sessionDir =
|
|
13161
|
+
const sessionDir = path26.join(os23.homedir(), ".copilot", "session-state");
|
|
12926
13162
|
const result = {
|
|
12927
13163
|
filesScanned: 0,
|
|
12928
13164
|
sessions: 0,
|
|
@@ -12938,22 +13174,22 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
|
|
|
12938
13174
|
sessionsWithEarlySecrets: 0
|
|
12939
13175
|
};
|
|
12940
13176
|
const dedup = emptyScanDedup();
|
|
12941
|
-
if (!
|
|
13177
|
+
if (!fs24.existsSync(sessionDir)) return result;
|
|
12942
13178
|
let sessionIds;
|
|
12943
13179
|
try {
|
|
12944
|
-
sessionIds =
|
|
13180
|
+
sessionIds = fs24.readdirSync(sessionDir);
|
|
12945
13181
|
} catch {
|
|
12946
13182
|
return result;
|
|
12947
13183
|
}
|
|
12948
13184
|
const ruleSources = buildRuleSources();
|
|
12949
13185
|
for (const sessionId of sessionIds) {
|
|
12950
|
-
const eventsPath =
|
|
12951
|
-
if (!
|
|
13186
|
+
const eventsPath = path26.join(sessionDir, sessionId, "events.jsonl");
|
|
13187
|
+
if (!fs24.existsSync(eventsPath)) continue;
|
|
12952
13188
|
result.filesScanned++;
|
|
12953
13189
|
onProgress?.(result.filesScanned);
|
|
12954
13190
|
let raw;
|
|
12955
13191
|
try {
|
|
12956
|
-
raw =
|
|
13192
|
+
raw = fs24.readFileSync(eventsPath, "utf-8");
|
|
12957
13193
|
} catch {
|
|
12958
13194
|
continue;
|
|
12959
13195
|
}
|
|
@@ -12973,7 +13209,7 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
|
|
|
12973
13209
|
if (ev.type === "session.start") {
|
|
12974
13210
|
const cwd = ev.data?.context?.cwd;
|
|
12975
13211
|
if (typeof cwd === "string" && cwd) {
|
|
12976
|
-
projLabel = stripTerminalEscapes(cwd).replace(
|
|
13212
|
+
projLabel = stripTerminalEscapes(cwd).replace(os23.homedir(), "~").slice(0, 40);
|
|
12977
13213
|
}
|
|
12978
13214
|
continue;
|
|
12979
13215
|
}
|
|
@@ -13105,7 +13341,7 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
|
|
|
13105
13341
|
return result;
|
|
13106
13342
|
}
|
|
13107
13343
|
function scanCodexHistory(startDate, onProgress, onLine) {
|
|
13108
|
-
const sessionsBase =
|
|
13344
|
+
const sessionsBase = path26.join(os23.homedir(), ".codex", "sessions");
|
|
13109
13345
|
const result = {
|
|
13110
13346
|
filesScanned: 0,
|
|
13111
13347
|
sessions: 0,
|
|
@@ -13120,32 +13356,32 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
13120
13356
|
sessionsWithEarlySecrets: 0
|
|
13121
13357
|
};
|
|
13122
13358
|
const dedup = emptyScanDedup();
|
|
13123
|
-
if (!
|
|
13359
|
+
if (!fs24.existsSync(sessionsBase)) return result;
|
|
13124
13360
|
const jsonlFiles = [];
|
|
13125
13361
|
try {
|
|
13126
|
-
for (const year of
|
|
13127
|
-
const yearPath =
|
|
13362
|
+
for (const year of fs24.readdirSync(sessionsBase)) {
|
|
13363
|
+
const yearPath = path26.join(sessionsBase, year);
|
|
13128
13364
|
try {
|
|
13129
|
-
if (!
|
|
13365
|
+
if (!fs24.statSync(yearPath).isDirectory()) continue;
|
|
13130
13366
|
} catch {
|
|
13131
13367
|
continue;
|
|
13132
13368
|
}
|
|
13133
|
-
for (const month of
|
|
13134
|
-
const monthPath =
|
|
13369
|
+
for (const month of fs24.readdirSync(yearPath)) {
|
|
13370
|
+
const monthPath = path26.join(yearPath, month);
|
|
13135
13371
|
try {
|
|
13136
|
-
if (!
|
|
13372
|
+
if (!fs24.statSync(monthPath).isDirectory()) continue;
|
|
13137
13373
|
} catch {
|
|
13138
13374
|
continue;
|
|
13139
13375
|
}
|
|
13140
|
-
for (const day of
|
|
13141
|
-
const dayPath =
|
|
13376
|
+
for (const day of fs24.readdirSync(monthPath)) {
|
|
13377
|
+
const dayPath = path26.join(monthPath, day);
|
|
13142
13378
|
try {
|
|
13143
|
-
if (!
|
|
13379
|
+
if (!fs24.statSync(dayPath).isDirectory()) continue;
|
|
13144
13380
|
} catch {
|
|
13145
13381
|
continue;
|
|
13146
13382
|
}
|
|
13147
|
-
for (const file of
|
|
13148
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
13383
|
+
for (const file of fs24.readdirSync(dayPath)) {
|
|
13384
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(path26.join(dayPath, file));
|
|
13149
13385
|
}
|
|
13150
13386
|
}
|
|
13151
13387
|
}
|
|
@@ -13159,7 +13395,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
13159
13395
|
onProgress?.(result.filesScanned);
|
|
13160
13396
|
let lines;
|
|
13161
13397
|
try {
|
|
13162
|
-
lines =
|
|
13398
|
+
lines = fs24.readFileSync(filePath, "utf-8").split("\n");
|
|
13163
13399
|
} catch {
|
|
13164
13400
|
continue;
|
|
13165
13401
|
}
|
|
@@ -13186,7 +13422,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
13186
13422
|
sessionId = String(payload["id"] ?? filePath);
|
|
13187
13423
|
startTime = String(payload["timestamp"] ?? "");
|
|
13188
13424
|
const cwd = String(payload["cwd"] ?? "");
|
|
13189
|
-
projLabel = stripTerminalEscapes(cwd.replace(
|
|
13425
|
+
projLabel = stripTerminalEscapes(cwd.replace(os23.homedir(), "~")).slice(0, 40);
|
|
13190
13426
|
continue;
|
|
13191
13427
|
}
|
|
13192
13428
|
if (entry.type === "turn_context" && typeof payload["model"] === "string") {
|
|
@@ -13346,17 +13582,17 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
13346
13582
|
return result;
|
|
13347
13583
|
}
|
|
13348
13584
|
function scanShellConfig() {
|
|
13349
|
-
const home =
|
|
13585
|
+
const home = os23.homedir();
|
|
13350
13586
|
const configFiles = [".zshrc", ".bashrc", ".bash_profile", ".profile"].map(
|
|
13351
|
-
(f) =>
|
|
13587
|
+
(f) => path26.join(home, f)
|
|
13352
13588
|
);
|
|
13353
13589
|
const findings = [];
|
|
13354
13590
|
const seen = /* @__PURE__ */ new Set();
|
|
13355
13591
|
for (const filePath of configFiles) {
|
|
13356
|
-
if (!
|
|
13592
|
+
if (!fs24.existsSync(filePath)) continue;
|
|
13357
13593
|
let lines;
|
|
13358
13594
|
try {
|
|
13359
|
-
lines =
|
|
13595
|
+
lines = fs24.readFileSync(filePath, "utf-8").split("\n");
|
|
13360
13596
|
} catch {
|
|
13361
13597
|
continue;
|
|
13362
13598
|
}
|
|
@@ -14162,7 +14398,7 @@ function registerScanCommand(program2) {
|
|
|
14162
14398
|
if (!drillDown) {
|
|
14163
14399
|
const useInk2 = !options.classic;
|
|
14164
14400
|
if (useInk2) {
|
|
14165
|
-
const scanInkPath =
|
|
14401
|
+
const scanInkPath = path26.join(__dirname, "scan-ink.mjs");
|
|
14166
14402
|
const dynamicImport = new Function("id", "return import(id)");
|
|
14167
14403
|
const mod = await dynamicImport(`file://${scanInkPath}`);
|
|
14168
14404
|
const rangeLabel2 = options.all ? "all time" : `last ${options.days ?? 90} days`;
|
|
@@ -14573,8 +14809,8 @@ var init_suggestion_tracker = __esm({
|
|
|
14573
14809
|
});
|
|
14574
14810
|
|
|
14575
14811
|
// src/daemon/taint-store.ts
|
|
14576
|
-
import
|
|
14577
|
-
import
|
|
14812
|
+
import fs25 from "fs";
|
|
14813
|
+
import path27 from "path";
|
|
14578
14814
|
var DEFAULT_TTL_MS, TaintStore, SESSION_TAINT_TTL_MS, SessionTaintStore;
|
|
14579
14815
|
var init_taint_store = __esm({
|
|
14580
14816
|
"src/daemon/taint-store.ts"() {
|
|
@@ -14644,9 +14880,9 @@ var init_taint_store = __esm({
|
|
|
14644
14880
|
/** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
|
|
14645
14881
|
_resolve(filePath) {
|
|
14646
14882
|
try {
|
|
14647
|
-
return
|
|
14883
|
+
return fs25.realpathSync.native(path27.resolve(filePath));
|
|
14648
14884
|
} catch {
|
|
14649
|
-
return
|
|
14885
|
+
return path27.resolve(filePath);
|
|
14650
14886
|
}
|
|
14651
14887
|
}
|
|
14652
14888
|
};
|
|
@@ -14811,14 +15047,14 @@ var init_session_history = __esm({
|
|
|
14811
15047
|
|
|
14812
15048
|
// src/daemon/state.ts
|
|
14813
15049
|
import net2 from "net";
|
|
14814
|
-
import
|
|
14815
|
-
import
|
|
14816
|
-
import
|
|
15050
|
+
import fs26 from "fs";
|
|
15051
|
+
import path28 from "path";
|
|
15052
|
+
import os24 from "os";
|
|
14817
15053
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
14818
15054
|
function loadInsightCounts() {
|
|
14819
15055
|
try {
|
|
14820
|
-
if (!
|
|
14821
|
-
const data = JSON.parse(
|
|
15056
|
+
if (!fs26.existsSync(INSIGHT_COUNTS_FILE)) return;
|
|
15057
|
+
const data = JSON.parse(fs26.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
|
|
14822
15058
|
for (const [tool, count] of Object.entries(data)) {
|
|
14823
15059
|
if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
|
|
14824
15060
|
}
|
|
@@ -14857,23 +15093,23 @@ function markRejectionHandlerRegistered() {
|
|
|
14857
15093
|
daemonRejectionHandlerRegistered = true;
|
|
14858
15094
|
}
|
|
14859
15095
|
function atomicWriteSync2(filePath, data, options) {
|
|
14860
|
-
const dir =
|
|
14861
|
-
if (!
|
|
15096
|
+
const dir = path28.dirname(filePath);
|
|
15097
|
+
if (!fs26.existsSync(dir)) fs26.mkdirSync(dir, { recursive: true });
|
|
14862
15098
|
const tmpPath = `${filePath}.${randomUUID3()}.tmp`;
|
|
14863
15099
|
try {
|
|
14864
|
-
|
|
15100
|
+
fs26.writeFileSync(tmpPath, data, options);
|
|
14865
15101
|
} catch (err2) {
|
|
14866
15102
|
try {
|
|
14867
|
-
|
|
15103
|
+
fs26.unlinkSync(tmpPath);
|
|
14868
15104
|
} catch {
|
|
14869
15105
|
}
|
|
14870
15106
|
throw err2;
|
|
14871
15107
|
}
|
|
14872
15108
|
try {
|
|
14873
|
-
|
|
15109
|
+
fs26.renameSync(tmpPath, filePath);
|
|
14874
15110
|
} catch (err2) {
|
|
14875
15111
|
try {
|
|
14876
|
-
|
|
15112
|
+
fs26.unlinkSync(tmpPath);
|
|
14877
15113
|
} catch {
|
|
14878
15114
|
}
|
|
14879
15115
|
throw err2;
|
|
@@ -14897,16 +15133,16 @@ function appendAuditLog(data) {
|
|
|
14897
15133
|
decision: data.decision,
|
|
14898
15134
|
source: "daemon"
|
|
14899
15135
|
};
|
|
14900
|
-
const dir =
|
|
14901
|
-
if (!
|
|
14902
|
-
|
|
15136
|
+
const dir = path28.dirname(AUDIT_LOG_FILE);
|
|
15137
|
+
if (!fs26.existsSync(dir)) fs26.mkdirSync(dir, { recursive: true });
|
|
15138
|
+
fs26.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
14903
15139
|
} catch {
|
|
14904
15140
|
}
|
|
14905
15141
|
}
|
|
14906
15142
|
function getAuditHistory(limit = 20) {
|
|
14907
15143
|
try {
|
|
14908
|
-
if (!
|
|
14909
|
-
const lines =
|
|
15144
|
+
if (!fs26.existsSync(AUDIT_LOG_FILE)) return [];
|
|
15145
|
+
const lines = fs26.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
|
|
14910
15146
|
if (lines.length === 1 && lines[0] === "") return [];
|
|
14911
15147
|
return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
|
|
14912
15148
|
} catch {
|
|
@@ -14915,7 +15151,7 @@ function getAuditHistory(limit = 20) {
|
|
|
14915
15151
|
}
|
|
14916
15152
|
function getOrgName() {
|
|
14917
15153
|
try {
|
|
14918
|
-
if (
|
|
15154
|
+
if (fs26.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
|
|
14919
15155
|
} catch {
|
|
14920
15156
|
}
|
|
14921
15157
|
return null;
|
|
@@ -14923,8 +15159,8 @@ function getOrgName() {
|
|
|
14923
15159
|
function writeGlobalSetting(key, value) {
|
|
14924
15160
|
let config = {};
|
|
14925
15161
|
try {
|
|
14926
|
-
if (
|
|
14927
|
-
config = JSON.parse(
|
|
15162
|
+
if (fs26.existsSync(GLOBAL_CONFIG_FILE)) {
|
|
15163
|
+
config = JSON.parse(fs26.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
|
|
14928
15164
|
}
|
|
14929
15165
|
} catch {
|
|
14930
15166
|
}
|
|
@@ -14936,8 +15172,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
14936
15172
|
try {
|
|
14937
15173
|
let trust = { entries: [] };
|
|
14938
15174
|
try {
|
|
14939
|
-
if (
|
|
14940
|
-
trust = JSON.parse(
|
|
15175
|
+
if (fs26.existsSync(TRUST_FILE2))
|
|
15176
|
+
trust = JSON.parse(fs26.readFileSync(TRUST_FILE2, "utf-8"));
|
|
14941
15177
|
} catch {
|
|
14942
15178
|
}
|
|
14943
15179
|
trust.entries = trust.entries.filter(
|
|
@@ -14954,8 +15190,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
14954
15190
|
}
|
|
14955
15191
|
function readPersistentDecisions() {
|
|
14956
15192
|
try {
|
|
14957
|
-
if (
|
|
14958
|
-
return JSON.parse(
|
|
15193
|
+
if (fs26.existsSync(DECISIONS_FILE)) {
|
|
15194
|
+
return JSON.parse(fs26.readFileSync(DECISIONS_FILE, "utf-8"));
|
|
14959
15195
|
}
|
|
14960
15196
|
} catch {
|
|
14961
15197
|
}
|
|
@@ -14983,7 +15219,7 @@ function estimateToolCost(tool, args) {
|
|
|
14983
15219
|
const filePath = a.file_path ?? a.path;
|
|
14984
15220
|
if (filePath) {
|
|
14985
15221
|
try {
|
|
14986
|
-
const bytes =
|
|
15222
|
+
const bytes = fs26.statSync(filePath).size;
|
|
14987
15223
|
return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
|
|
14988
15224
|
} catch {
|
|
14989
15225
|
}
|
|
@@ -15054,7 +15290,7 @@ function abandonPending() {
|
|
|
15054
15290
|
});
|
|
15055
15291
|
if (autoStarted) {
|
|
15056
15292
|
try {
|
|
15057
|
-
|
|
15293
|
+
fs26.unlinkSync(DAEMON_PID_FILE);
|
|
15058
15294
|
} catch {
|
|
15059
15295
|
}
|
|
15060
15296
|
setTimeout(() => {
|
|
@@ -15065,8 +15301,8 @@ function abandonPending() {
|
|
|
15065
15301
|
}
|
|
15066
15302
|
function logActivitySocket(msg) {
|
|
15067
15303
|
try {
|
|
15068
|
-
|
|
15069
|
-
|
|
15304
|
+
fs26.appendFileSync(
|
|
15305
|
+
path28.join(homeDir, ".node9", "hook-debug.log"),
|
|
15070
15306
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] [activity-socket] ${msg}
|
|
15071
15307
|
`
|
|
15072
15308
|
);
|
|
@@ -15088,13 +15324,13 @@ function shouldRebind(now = Date.now()) {
|
|
|
15088
15324
|
function startActivitySocket() {
|
|
15089
15325
|
bindActivitySocket();
|
|
15090
15326
|
activityHealthInterval = setInterval(() => {
|
|
15091
|
-
if (!
|
|
15327
|
+
if (!fs26.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
|
|
15092
15328
|
}, ACTIVITY_HEALTH_PROBE_MS);
|
|
15093
15329
|
activityHealthInterval.unref();
|
|
15094
15330
|
process.on("exit", () => {
|
|
15095
15331
|
if (activityHealthInterval) clearInterval(activityHealthInterval);
|
|
15096
15332
|
try {
|
|
15097
|
-
|
|
15333
|
+
fs26.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
15098
15334
|
} catch {
|
|
15099
15335
|
}
|
|
15100
15336
|
});
|
|
@@ -15122,7 +15358,7 @@ function attemptRebind(reason) {
|
|
|
15122
15358
|
}
|
|
15123
15359
|
function bindActivitySocket() {
|
|
15124
15360
|
try {
|
|
15125
|
-
|
|
15361
|
+
fs26.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
15126
15362
|
} catch {
|
|
15127
15363
|
}
|
|
15128
15364
|
const ACTIVITY_MAX_BYTES = 1024 * 1024;
|
|
@@ -15217,305 +15453,84 @@ function bindActivitySocket() {
|
|
|
15217
15453
|
});
|
|
15218
15454
|
socket.on("error", () => {
|
|
15219
15455
|
});
|
|
15220
|
-
});
|
|
15221
|
-
unixServer.on("error", (err2) => {
|
|
15222
|
-
logActivitySocket(`server error: ${err2.message}`);
|
|
15223
|
-
});
|
|
15224
|
-
unixServer.listen(ACTIVITY_SOCKET_PATH2, () => {
|
|
15225
|
-
logActivitySocket(`bound to ${ACTIVITY_SOCKET_PATH2}`);
|
|
15226
|
-
});
|
|
15227
|
-
activitySocketServer = unixServer;
|
|
15228
|
-
}
|
|
15229
|
-
var homeDir, DAEMON_PID_FILE, DECISIONS_FILE, AUDIT_LOG_FILE, TRUST_FILE2, GLOBAL_CONFIG_FILE, CREDENTIALS_FILE, INSIGHT_COUNTS_FILE, pending, sseClients, suggestionTracker, taintStore, sessionTaintStore, 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, CRITICAL_FORENSIC_CATEGORIES, WRITE_TOOL_NAMES, ACTIVITY_REBIND_MAX_ATTEMPTS, ACTIVITY_REBIND_WINDOW_MS, ACTIVITY_HEALTH_PROBE_MS, activitySocketServer, activityHealthInterval, activityRebindAttempts, activityCircuitTripped;
|
|
15230
|
-
var init_state2 = __esm({
|
|
15231
|
-
"src/daemon/state.ts"() {
|
|
15232
|
-
"use strict";
|
|
15233
|
-
init_daemon();
|
|
15234
|
-
init_suggestion_tracker();
|
|
15235
|
-
init_taint_store();
|
|
15236
|
-
init_session_counters();
|
|
15237
|
-
init_session_history();
|
|
15238
|
-
homeDir =
|
|
15239
|
-
DAEMON_PID_FILE =
|
|
15240
|
-
DECISIONS_FILE =
|
|
15241
|
-
AUDIT_LOG_FILE =
|
|
15242
|
-
TRUST_FILE2 =
|
|
15243
|
-
GLOBAL_CONFIG_FILE =
|
|
15244
|
-
CREDENTIALS_FILE =
|
|
15245
|
-
INSIGHT_COUNTS_FILE =
|
|
15246
|
-
pending = /* @__PURE__ */ new Map();
|
|
15247
|
-
sseClients = /* @__PURE__ */ new Set();
|
|
15248
|
-
suggestionTracker = new SuggestionTracker(3);
|
|
15249
|
-
taintStore = new TaintStore();
|
|
15250
|
-
sessionTaintStore = new SessionTaintStore();
|
|
15251
|
-
insightCounts = /* @__PURE__ */ new Map();
|
|
15252
|
-
_abandonTimer = null;
|
|
15253
|
-
_hadBrowserClient = false;
|
|
15254
|
-
_daemonServer = null;
|
|
15255
|
-
daemonRejectionHandlerRegistered = false;
|
|
15256
|
-
AUTO_DENY_MS = 12e4;
|
|
15257
|
-
TRUST_DURATIONS = {
|
|
15258
|
-
"30m": 30 * 6e4,
|
|
15259
|
-
"1h": 60 * 6e4,
|
|
15260
|
-
"2h": 2 * 60 * 6e4
|
|
15261
|
-
};
|
|
15262
|
-
autoStarted = process.env.NODE9_AUTO_STARTED === "1";
|
|
15263
|
-
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
15264
|
-
ACTIVITY_RING_SIZE = 100;
|
|
15265
|
-
activityRing = [];
|
|
15266
|
-
LARGE_RESPONSE_RING_SIZE = 20;
|
|
15267
|
-
largeResponseRing = [];
|
|
15268
|
-
cachedScanResult = null;
|
|
15269
|
-
cachedScanTs = 0;
|
|
15270
|
-
SCAN_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
15271
|
-
SECRET_KEY_RE = /password|secret|token|key|apikey|credential|auth/i;
|
|
15272
|
-
INPUT_PRICE_PER_1M = 3;
|
|
15273
|
-
OUTPUT_PRICE_PER_1M = 15;
|
|
15274
|
-
BYTES_PER_TOKEN = 4;
|
|
15275
|
-
CRITICAL_FORENSIC_CATEGORIES = /* @__PURE__ */ new Set([
|
|
15276
|
-
"privilege-escalation",
|
|
15277
|
-
"destructive-op",
|
|
15278
|
-
"eval-of-remote"
|
|
15279
|
-
]);
|
|
15280
|
-
WRITE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
15281
|
-
"write",
|
|
15282
|
-
"write_file",
|
|
15283
|
-
"create_file",
|
|
15284
|
-
"edit",
|
|
15285
|
-
"multiedit",
|
|
15286
|
-
"str_replace_based_edit_tool",
|
|
15287
|
-
"replace",
|
|
15288
|
-
"notebook_edit",
|
|
15289
|
-
"notebookedit"
|
|
15290
|
-
]);
|
|
15291
|
-
ACTIVITY_REBIND_MAX_ATTEMPTS = 5;
|
|
15292
|
-
ACTIVITY_REBIND_WINDOW_MS = 6e4;
|
|
15293
|
-
ACTIVITY_HEALTH_PROBE_MS = 2e3;
|
|
15294
|
-
activitySocketServer = null;
|
|
15295
|
-
activityHealthInterval = null;
|
|
15296
|
-
activityRebindAttempts = [];
|
|
15297
|
-
activityCircuitTripped = false;
|
|
15298
|
-
}
|
|
15299
|
-
});
|
|
15300
|
-
|
|
15301
|
-
// src/agent-wiring.ts
|
|
15302
|
-
import fs26 from "fs";
|
|
15303
|
-
import path28 from "path";
|
|
15304
|
-
import os24 from "os";
|
|
15305
|
-
import * as yaml2 from "yaml";
|
|
15306
|
-
import { parse as parseToml2 } from "smol-toml";
|
|
15307
|
-
function readJson2(filePath) {
|
|
15308
|
-
if (!fs26.existsSync(filePath)) return null;
|
|
15309
|
-
try {
|
|
15310
|
-
return JSON.parse(fs26.readFileSync(filePath, "utf-8"));
|
|
15311
|
-
} catch {
|
|
15312
|
-
return "invalid";
|
|
15313
|
-
}
|
|
15314
|
-
}
|
|
15315
|
-
function matchersHaveNode9Hook(matchers) {
|
|
15316
|
-
return (matchers ?? []).some((m) => (m.hooks ?? []).some((h) => isNode9Hook(h.command)));
|
|
15317
|
-
}
|
|
15318
|
-
function flatHaveNode9Hook(entries) {
|
|
15319
|
-
return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
|
|
15320
|
-
}
|
|
15321
|
-
function readHookRoot(filePath, format) {
|
|
15322
|
-
if (!fs26.existsSync(filePath)) return "absent";
|
|
15323
|
-
let raw;
|
|
15324
|
-
try {
|
|
15325
|
-
raw = fs26.readFileSync(filePath, "utf-8");
|
|
15326
|
-
} catch {
|
|
15327
|
-
return "absent";
|
|
15328
|
-
}
|
|
15329
|
-
try {
|
|
15330
|
-
const parsed = format === "yaml" ? yaml2.parse(raw) : JSON.parse(raw);
|
|
15331
|
-
return parsed?.hooks ?? {};
|
|
15332
|
-
} catch {
|
|
15333
|
-
return "invalid";
|
|
15334
|
-
}
|
|
15335
|
-
}
|
|
15336
|
-
function eventWired(root, ev, format) {
|
|
15337
|
-
const arr = root[ev.key];
|
|
15338
|
-
if (format === "matcher") return matchersHaveNode9Hook(arr);
|
|
15339
|
-
return flatHaveNode9Hook(arr);
|
|
15340
|
-
}
|
|
15341
|
-
function detectMcp(servers) {
|
|
15342
|
-
const entries = Object.entries(servers ?? {});
|
|
15343
|
-
const present = entries.some(([, s]) => s?.command === "node9");
|
|
15344
|
-
const wrapped = entries.filter(([, s]) => s?.command === "node9" && Array.isArray(s.args) && s.args.length > 0).map(([name, s]) => `${name} \u2192 ${s.args.join(" ")}`);
|
|
15345
|
-
return { wrapped, present };
|
|
15346
|
-
}
|
|
15347
|
-
function readMcp(filePath, format) {
|
|
15348
|
-
if (!fs26.existsSync(filePath)) return { wrapped: [], present: false };
|
|
15349
|
-
try {
|
|
15350
|
-
if (format === "toml") {
|
|
15351
|
-
const parsed2 = parseToml2(fs26.readFileSync(filePath, "utf-8"));
|
|
15352
|
-
return detectMcp(parsed2?.mcp_servers);
|
|
15353
|
-
}
|
|
15354
|
-
const parsed = readJson2(filePath);
|
|
15355
|
-
if (parsed === null || parsed === "invalid") return { wrapped: [], present: false };
|
|
15356
|
-
return detectMcp(parsed.mcpServers);
|
|
15357
|
-
} catch {
|
|
15358
|
-
return { wrapped: [], present: false };
|
|
15359
|
-
}
|
|
15360
|
-
}
|
|
15361
|
-
function getAgentWiring(home = os24.homedir()) {
|
|
15362
|
-
const detected = detectAgents(home);
|
|
15363
|
-
return AGENT_SPECS.map((spec) => {
|
|
15364
|
-
const present = spec.present(home);
|
|
15365
|
-
const pad = spec.labelPad ?? DEFAULT_LABEL_PAD;
|
|
15366
|
-
let hooks;
|
|
15367
|
-
let wireState;
|
|
15368
|
-
let hookLabel;
|
|
15369
|
-
let settingsPath;
|
|
15370
|
-
if (spec.shimFile) {
|
|
15371
|
-
const shimWired = exists(spec.shimFile(home));
|
|
15372
|
-
hooks = [{ label: "node9 plugin (node9 check)", wired: shimWired }];
|
|
15373
|
-
wireState = shimWired ? "wired" : present ? "unwired" : "absent";
|
|
15374
|
-
hookLabel = "node9 plugin";
|
|
15375
|
-
settingsPath = spec.shimFile(home);
|
|
15376
|
-
} else {
|
|
15377
|
-
const root = spec.hookFile ? readHookRoot(spec.hookFile(home), spec.hookFormat) : "absent";
|
|
15378
|
-
const primary = spec.hookEvents[0];
|
|
15379
|
-
const rootPresent = root !== "absent" && root !== "invalid";
|
|
15380
|
-
hooks = spec.hookEvents.map((ev) => ({
|
|
15381
|
-
label: hookLabelOf(ev, pad),
|
|
15382
|
-
wired: rootPresent && eventWired(root, ev, spec.hookFormat)
|
|
15383
|
-
}));
|
|
15384
|
-
if (root === "absent") wireState = "absent";
|
|
15385
|
-
else if (root === "invalid") wireState = "invalid";
|
|
15386
|
-
else wireState = primary && eventWired(root, primary, spec.hookFormat) ? "wired" : "unwired";
|
|
15387
|
-
hookLabel = primary ? `${primary.key} hook` : "MCP proxy";
|
|
15388
|
-
settingsPath = spec.hookFile ? spec.hookFile(home) : spec.mcpFile ? spec.mcpFile(home) : "";
|
|
15389
|
-
}
|
|
15390
|
-
const mcp = spec.mcpFile ? readMcp(spec.mcpFile(home), spec.mcpFormat ?? "json") : null;
|
|
15391
|
-
const anyHookWired = hooks.some((h) => h.wired);
|
|
15392
|
-
return {
|
|
15393
|
-
id: spec.id,
|
|
15394
|
-
label: spec.label,
|
|
15395
|
-
setupCommand: spec.setupCommand,
|
|
15396
|
-
installed: detected[spec.id],
|
|
15397
|
-
present,
|
|
15398
|
-
hooks,
|
|
15399
|
-
wireState,
|
|
15400
|
-
hookLabel,
|
|
15401
|
-
settingsPath,
|
|
15402
|
-
configFormat: spec.hookFormat === "yaml" ? "YAML" : "JSON",
|
|
15403
|
-
mcpServers: mcp ? mcp.wrapped : null,
|
|
15404
|
-
mcpProtected: mcp ? mcp.present : false,
|
|
15405
|
-
isProtected: anyHookWired || (mcp?.present ?? false)
|
|
15406
|
-
};
|
|
15407
|
-
});
|
|
15408
|
-
}
|
|
15409
|
-
var exists, ck, lg, DEFAULT_LABEL_PAD, hookLabelOf, AGENT_SPECS;
|
|
15410
|
-
var init_agent_wiring = __esm({
|
|
15411
|
-
"src/agent-wiring.ts"() {
|
|
15412
|
-
"use strict";
|
|
15413
|
-
init_setup();
|
|
15414
|
-
exists = (p) => {
|
|
15415
|
-
try {
|
|
15416
|
-
return fs26.existsSync(p);
|
|
15417
|
-
} catch {
|
|
15418
|
-
return false;
|
|
15419
|
-
}
|
|
15420
|
-
};
|
|
15421
|
-
ck = (key) => ({ key, kind: "check" });
|
|
15422
|
-
lg = (key) => ({ key, kind: "log" });
|
|
15423
|
-
DEFAULT_LABEL_PAD = 11;
|
|
15424
|
-
hookLabelOf = (ev, pad) => `${ev.key.padEnd(pad)} (node9 ${ev.kind})`;
|
|
15425
|
-
AGENT_SPECS = [
|
|
15426
|
-
{
|
|
15427
|
-
id: "claude",
|
|
15428
|
-
label: "Claude Code",
|
|
15429
|
-
setupCommand: "node9 agents add claude",
|
|
15430
|
-
hookFile: (h) => path28.join(h, ".claude", "settings.json"),
|
|
15431
|
-
hookFormat: "matcher",
|
|
15432
|
-
hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
|
|
15433
|
-
mcpFile: (h) => path28.join(h, ".claude.json"),
|
|
15434
|
-
present: (h) => exists(path28.join(h, ".claude", "settings.json")) || exists(path28.join(h, ".claude.json"))
|
|
15435
|
-
},
|
|
15436
|
-
{
|
|
15437
|
-
id: "gemini",
|
|
15438
|
-
label: "Gemini CLI",
|
|
15439
|
-
setupCommand: "node9 agents add gemini",
|
|
15440
|
-
hookFile: (h) => path28.join(h, ".gemini", "settings.json"),
|
|
15441
|
-
hookFormat: "matcher",
|
|
15442
|
-
hookEvents: [ck("BeforeTool"), lg("AfterTool")],
|
|
15443
|
-
mcpFile: (h) => path28.join(h, ".gemini", "settings.json"),
|
|
15444
|
-
present: (h) => exists(path28.join(h, ".gemini", "settings.json"))
|
|
15445
|
-
},
|
|
15446
|
-
{
|
|
15447
|
-
id: "codex",
|
|
15448
|
-
label: "Codex",
|
|
15449
|
-
setupCommand: "node9 agents add codex",
|
|
15450
|
-
hookFile: (h) => path28.join(h, ".codex", "hooks.json"),
|
|
15451
|
-
hookFormat: "matcher",
|
|
15452
|
-
hookEvents: [ck("PreToolUse"), ck("UserPromptSubmit")],
|
|
15453
|
-
mcpFile: (h) => path28.join(h, ".codex", "config.toml"),
|
|
15454
|
-
mcpFormat: "toml",
|
|
15455
|
-
present: (h) => exists(path28.join(h, ".codex"))
|
|
15456
|
-
},
|
|
15457
|
-
{
|
|
15458
|
-
id: "antigravity",
|
|
15459
|
-
label: "Antigravity",
|
|
15460
|
-
setupCommand: "node9 agents add antigravity",
|
|
15461
|
-
hookFile: (h) => path28.join(h, ".gemini", "config", "hooks.json"),
|
|
15462
|
-
hookFormat: "matcher",
|
|
15463
|
-
hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
|
|
15464
|
-
mcpFile: (h) => path28.join(h, ".gemini", "config", "mcp_config.json"),
|
|
15465
|
-
present: (h) => exists(path28.join(h, ".gemini", "config", "hooks.json")) || exists(path28.join(h, ".gemini", "antigravity-cli")) || exists(path28.join(h, ".gemini", "antigravity-ide"))
|
|
15466
|
-
},
|
|
15467
|
-
{
|
|
15468
|
-
id: "copilot",
|
|
15469
|
-
label: "GitHub Copilot",
|
|
15470
|
-
setupCommand: "node9 agents add copilot",
|
|
15471
|
-
hookFile: (h) => path28.join(h, ".copilot", "hooks", "node9.json"),
|
|
15472
|
-
hookFormat: "flat",
|
|
15473
|
-
hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
|
|
15474
|
-
mcpFile: (h) => path28.join(h, ".copilot", "mcp-config.json"),
|
|
15475
|
-
present: (h) => exists(path28.join(h, ".copilot"))
|
|
15476
|
-
},
|
|
15477
|
-
{
|
|
15478
|
-
id: "cursor",
|
|
15479
|
-
label: "Cursor",
|
|
15480
|
-
setupCommand: "node9 agents add cursor",
|
|
15481
|
-
// MCP-only — no hook file (see note above).
|
|
15482
|
-
hookFormat: "flat",
|
|
15483
|
-
hookEvents: [],
|
|
15484
|
-
mcpFile: (h) => path28.join(h, ".cursor", "mcp.json"),
|
|
15485
|
-
present: (h) => exists(path28.join(h, ".cursor", "mcp.json"))
|
|
15486
|
-
},
|
|
15487
|
-
{
|
|
15488
|
-
id: "hermes",
|
|
15489
|
-
label: "Hermes Agent",
|
|
15490
|
-
setupCommand: "node9 agents add hermes",
|
|
15491
|
-
hookFile: (h) => hermesConfigPath(h),
|
|
15492
|
-
hookFormat: "yaml",
|
|
15493
|
-
hookEvents: [ck("pre_tool_call"), lg("post_tool_call")],
|
|
15494
|
-
labelPad: 14,
|
|
15495
|
-
// 'post_tool_call' is wider than the default
|
|
15496
|
-
present: (h) => exists(hermesConfigPath(h))
|
|
15497
|
-
},
|
|
15498
|
-
{
|
|
15499
|
-
// Plugin-shim agents — protected by a node9-authored plugin/extension file
|
|
15500
|
-
// (no hooks, no MCP). hookFormat is unused for these (shimFile drives it).
|
|
15501
|
-
id: "opencode",
|
|
15502
|
-
label: "OpenCode",
|
|
15503
|
-
setupCommand: "node9 agents add opencode",
|
|
15504
|
-
hookFormat: "flat",
|
|
15505
|
-
hookEvents: [],
|
|
15506
|
-
shimFile: (h) => path28.join(h, ".config", "opencode", "plugins", "node9.js"),
|
|
15507
|
-
present: (h) => exists(path28.join(h, ".config", "opencode")) || exists(path28.join(h, ".config", "opencode", "plugins", "node9.js"))
|
|
15508
|
-
},
|
|
15509
|
-
{
|
|
15510
|
-
id: "pi",
|
|
15511
|
-
label: "Pi",
|
|
15512
|
-
setupCommand: "node9 agents add pi",
|
|
15513
|
-
hookFormat: "flat",
|
|
15514
|
-
hookEvents: [],
|
|
15515
|
-
shimFile: (h) => path28.join(h, ".pi", "agent", "extensions", "node9.js"),
|
|
15516
|
-
present: (h) => exists(path28.join(h, ".pi", "agent")) || exists(path28.join(h, ".pi", "agent", "extensions", "node9.js"))
|
|
15517
|
-
}
|
|
15518
|
-
];
|
|
15456
|
+
});
|
|
15457
|
+
unixServer.on("error", (err2) => {
|
|
15458
|
+
logActivitySocket(`server error: ${err2.message}`);
|
|
15459
|
+
});
|
|
15460
|
+
unixServer.listen(ACTIVITY_SOCKET_PATH2, () => {
|
|
15461
|
+
logActivitySocket(`bound to ${ACTIVITY_SOCKET_PATH2}`);
|
|
15462
|
+
});
|
|
15463
|
+
activitySocketServer = unixServer;
|
|
15464
|
+
}
|
|
15465
|
+
var homeDir, DAEMON_PID_FILE, DECISIONS_FILE, AUDIT_LOG_FILE, TRUST_FILE2, GLOBAL_CONFIG_FILE, CREDENTIALS_FILE, INSIGHT_COUNTS_FILE, pending, sseClients, suggestionTracker, taintStore, sessionTaintStore, 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, CRITICAL_FORENSIC_CATEGORIES, WRITE_TOOL_NAMES, ACTIVITY_REBIND_MAX_ATTEMPTS, ACTIVITY_REBIND_WINDOW_MS, ACTIVITY_HEALTH_PROBE_MS, activitySocketServer, activityHealthInterval, activityRebindAttempts, activityCircuitTripped;
|
|
15466
|
+
var init_state2 = __esm({
|
|
15467
|
+
"src/daemon/state.ts"() {
|
|
15468
|
+
"use strict";
|
|
15469
|
+
init_daemon();
|
|
15470
|
+
init_suggestion_tracker();
|
|
15471
|
+
init_taint_store();
|
|
15472
|
+
init_session_counters();
|
|
15473
|
+
init_session_history();
|
|
15474
|
+
homeDir = os24.homedir();
|
|
15475
|
+
DAEMON_PID_FILE = path28.join(homeDir, ".node9", "daemon.pid");
|
|
15476
|
+
DECISIONS_FILE = path28.join(homeDir, ".node9", "decisions.json");
|
|
15477
|
+
AUDIT_LOG_FILE = path28.join(homeDir, ".node9", "audit.log");
|
|
15478
|
+
TRUST_FILE2 = path28.join(homeDir, ".node9", "trust.json");
|
|
15479
|
+
GLOBAL_CONFIG_FILE = path28.join(homeDir, ".node9", "config.json");
|
|
15480
|
+
CREDENTIALS_FILE = path28.join(homeDir, ".node9", "credentials.json");
|
|
15481
|
+
INSIGHT_COUNTS_FILE = path28.join(homeDir, ".node9", "insight-counts.json");
|
|
15482
|
+
pending = /* @__PURE__ */ new Map();
|
|
15483
|
+
sseClients = /* @__PURE__ */ new Set();
|
|
15484
|
+
suggestionTracker = new SuggestionTracker(3);
|
|
15485
|
+
taintStore = new TaintStore();
|
|
15486
|
+
sessionTaintStore = new SessionTaintStore();
|
|
15487
|
+
insightCounts = /* @__PURE__ */ new Map();
|
|
15488
|
+
_abandonTimer = null;
|
|
15489
|
+
_hadBrowserClient = false;
|
|
15490
|
+
_daemonServer = null;
|
|
15491
|
+
daemonRejectionHandlerRegistered = false;
|
|
15492
|
+
AUTO_DENY_MS = 12e4;
|
|
15493
|
+
TRUST_DURATIONS = {
|
|
15494
|
+
"30m": 30 * 6e4,
|
|
15495
|
+
"1h": 60 * 6e4,
|
|
15496
|
+
"2h": 2 * 60 * 6e4
|
|
15497
|
+
};
|
|
15498
|
+
autoStarted = process.env.NODE9_AUTO_STARTED === "1";
|
|
15499
|
+
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path28.join(os24.tmpdir(), "node9-activity.sock");
|
|
15500
|
+
ACTIVITY_RING_SIZE = 100;
|
|
15501
|
+
activityRing = [];
|
|
15502
|
+
LARGE_RESPONSE_RING_SIZE = 20;
|
|
15503
|
+
largeResponseRing = [];
|
|
15504
|
+
cachedScanResult = null;
|
|
15505
|
+
cachedScanTs = 0;
|
|
15506
|
+
SCAN_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
15507
|
+
SECRET_KEY_RE = /password|secret|token|key|apikey|credential|auth/i;
|
|
15508
|
+
INPUT_PRICE_PER_1M = 3;
|
|
15509
|
+
OUTPUT_PRICE_PER_1M = 15;
|
|
15510
|
+
BYTES_PER_TOKEN = 4;
|
|
15511
|
+
CRITICAL_FORENSIC_CATEGORIES = /* @__PURE__ */ new Set([
|
|
15512
|
+
"privilege-escalation",
|
|
15513
|
+
"destructive-op",
|
|
15514
|
+
"eval-of-remote"
|
|
15515
|
+
]);
|
|
15516
|
+
WRITE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
15517
|
+
"write",
|
|
15518
|
+
"write_file",
|
|
15519
|
+
"create_file",
|
|
15520
|
+
"edit",
|
|
15521
|
+
"multiedit",
|
|
15522
|
+
"str_replace_based_edit_tool",
|
|
15523
|
+
"replace",
|
|
15524
|
+
"notebook_edit",
|
|
15525
|
+
"notebookedit"
|
|
15526
|
+
]);
|
|
15527
|
+
ACTIVITY_REBIND_MAX_ATTEMPTS = 5;
|
|
15528
|
+
ACTIVITY_REBIND_WINDOW_MS = 6e4;
|
|
15529
|
+
ACTIVITY_HEALTH_PROBE_MS = 2e3;
|
|
15530
|
+
activitySocketServer = null;
|
|
15531
|
+
activityHealthInterval = null;
|
|
15532
|
+
activityRebindAttempts = [];
|
|
15533
|
+
activityCircuitTripped = false;
|
|
15519
15534
|
}
|
|
15520
15535
|
});
|
|
15521
15536
|
|
|
@@ -16614,9 +16629,95 @@ var init_ship = __esm({
|
|
|
16614
16629
|
}
|
|
16615
16630
|
});
|
|
16616
16631
|
|
|
16632
|
+
// src/policy-snapshot/build.ts
|
|
16633
|
+
function buildPolicySnapshot(config, activeShields, overrides) {
|
|
16634
|
+
const p = config.policy;
|
|
16635
|
+
return {
|
|
16636
|
+
mode: config.settings.mode,
|
|
16637
|
+
panicMode: config.settings.panicMode === true,
|
|
16638
|
+
// The proxy expresses shadow/observe as mode === 'observe' (cloud shadowMode
|
|
16639
|
+
// forces it); there's no separate settings flag.
|
|
16640
|
+
shadowMode: config.settings.mode === "observe",
|
|
16641
|
+
activeShields,
|
|
16642
|
+
shieldOverrides: overrides,
|
|
16643
|
+
smartRuleCount: p.smartRules.length,
|
|
16644
|
+
smartRules: p.smartRules.slice(0, MAX_RULES).map((r) => ({
|
|
16645
|
+
name: r.name,
|
|
16646
|
+
tool: r.tool,
|
|
16647
|
+
verdict: r.verdict,
|
|
16648
|
+
reason: r.reason
|
|
16649
|
+
})),
|
|
16650
|
+
egress: {
|
|
16651
|
+
enabled: p.egress.enabled,
|
|
16652
|
+
mode: p.egress.mode,
|
|
16653
|
+
allow: p.egress.allow.slice(0, MAX_EGRESS)
|
|
16654
|
+
},
|
|
16655
|
+
dlpEnabled: p.dlp.enabled,
|
|
16656
|
+
engineVersion: ENGINE_VERSION
|
|
16657
|
+
};
|
|
16658
|
+
}
|
|
16659
|
+
var MAX_RULES, MAX_EGRESS;
|
|
16660
|
+
var init_build = __esm({
|
|
16661
|
+
"src/policy-snapshot/build.ts"() {
|
|
16662
|
+
"use strict";
|
|
16663
|
+
init_dist();
|
|
16664
|
+
MAX_RULES = 500;
|
|
16665
|
+
MAX_EGRESS = 200;
|
|
16666
|
+
}
|
|
16667
|
+
});
|
|
16668
|
+
|
|
16669
|
+
// src/policy-snapshot/ship.ts
|
|
16670
|
+
import http2 from "http";
|
|
16671
|
+
import https3 from "https";
|
|
16672
|
+
import { URL as URL3 } from "url";
|
|
16673
|
+
function policySnapshotUrlFrom(apiUrl) {
|
|
16674
|
+
return apiUrl.endsWith("/policies/sync") ? apiUrl.replace(/\/policies\/sync$/, "/policy/snapshot") : null;
|
|
16675
|
+
}
|
|
16676
|
+
async function shipPolicySnapshot(body, creds) {
|
|
16677
|
+
const url = policySnapshotUrlFrom(creds.apiUrl);
|
|
16678
|
+
if (!url) return false;
|
|
16679
|
+
const payload = JSON.stringify(body);
|
|
16680
|
+
const parsed = new URL3(url);
|
|
16681
|
+
const transport = parsed.protocol === "http:" ? http2 : https3;
|
|
16682
|
+
return new Promise((resolve) => {
|
|
16683
|
+
const req = transport.request(
|
|
16684
|
+
{
|
|
16685
|
+
hostname: parsed.hostname,
|
|
16686
|
+
port: parsed.port ? parseInt(parsed.port, 10) : void 0,
|
|
16687
|
+
path: parsed.pathname + parsed.search,
|
|
16688
|
+
method: "POST",
|
|
16689
|
+
headers: {
|
|
16690
|
+
"Content-Type": "application/json",
|
|
16691
|
+
"Content-Length": Buffer.byteLength(payload),
|
|
16692
|
+
Authorization: `Bearer ${creds.apiKey}`
|
|
16693
|
+
},
|
|
16694
|
+
timeout: 1e4
|
|
16695
|
+
},
|
|
16696
|
+
(res) => {
|
|
16697
|
+
const ok2 = !!res.statusCode && res.statusCode >= 200 && res.statusCode < 300;
|
|
16698
|
+
res.resume();
|
|
16699
|
+
res.on("end", () => resolve(ok2));
|
|
16700
|
+
res.on("error", () => resolve(false));
|
|
16701
|
+
}
|
|
16702
|
+
);
|
|
16703
|
+
req.on("error", () => resolve(false));
|
|
16704
|
+
req.on("timeout", () => {
|
|
16705
|
+
req.destroy();
|
|
16706
|
+
resolve(false);
|
|
16707
|
+
});
|
|
16708
|
+
req.write(payload);
|
|
16709
|
+
req.end();
|
|
16710
|
+
});
|
|
16711
|
+
}
|
|
16712
|
+
var init_ship2 = __esm({
|
|
16713
|
+
"src/policy-snapshot/ship.ts"() {
|
|
16714
|
+
"use strict";
|
|
16715
|
+
}
|
|
16716
|
+
});
|
|
16717
|
+
|
|
16617
16718
|
// src/daemon/sync.ts
|
|
16618
16719
|
import fs32 from "fs";
|
|
16619
|
-
import
|
|
16720
|
+
import https4 from "https";
|
|
16620
16721
|
import os29 from "os";
|
|
16621
16722
|
import path31 from "path";
|
|
16622
16723
|
function emptySignals3() {
|
|
@@ -16699,7 +16800,7 @@ function fetchCloudPolicy(apiKey, apiUrl, ifNoneMatch) {
|
|
|
16699
16800
|
};
|
|
16700
16801
|
if (ifNoneMatch) headers["If-None-Match"] = `"${ifNoneMatch}"`;
|
|
16701
16802
|
return new Promise((resolve, reject) => {
|
|
16702
|
-
const req =
|
|
16803
|
+
const req = https4.request(
|
|
16703
16804
|
{
|
|
16704
16805
|
hostname: parsed.hostname,
|
|
16705
16806
|
port: parsed.port ? parseInt(parsed.port, 10) : void 0,
|
|
@@ -16779,6 +16880,9 @@ async function syncOnce() {
|
|
|
16779
16880
|
if (process.env.NODE9_POSTURE_DISABLE !== "1") {
|
|
16780
16881
|
void pushPostureSnapshot(creds);
|
|
16781
16882
|
}
|
|
16883
|
+
if (process.env.NODE9_POLICY_MIRROR_DISABLE !== "1") {
|
|
16884
|
+
void pushPolicySnapshot(creds);
|
|
16885
|
+
}
|
|
16782
16886
|
}
|
|
16783
16887
|
async function pushBlastSnapshot(creds) {
|
|
16784
16888
|
try {
|
|
@@ -16788,7 +16892,7 @@ async function pushBlastSnapshot(creds) {
|
|
|
16788
16892
|
if (!blastUrl) return;
|
|
16789
16893
|
const parsed = new URL(blastUrl);
|
|
16790
16894
|
await new Promise((resolve) => {
|
|
16791
|
-
const req =
|
|
16895
|
+
const req = https4.request(
|
|
16792
16896
|
{
|
|
16793
16897
|
hostname: parsed.hostname,
|
|
16794
16898
|
port: parsed.port ? parseInt(parsed.port, 10) : void 0,
|
|
@@ -16825,6 +16929,29 @@ async function pushPostureSnapshot(creds) {
|
|
|
16825
16929
|
} catch {
|
|
16826
16930
|
}
|
|
16827
16931
|
}
|
|
16932
|
+
async function pushPolicySnapshot(creds) {
|
|
16933
|
+
try {
|
|
16934
|
+
const body = buildPolicySnapshot(getConfig(), readActiveShields(), readShieldOverrides());
|
|
16935
|
+
await shipPolicySnapshot(body, creds);
|
|
16936
|
+
} catch {
|
|
16937
|
+
}
|
|
16938
|
+
}
|
|
16939
|
+
async function runPolicyPush() {
|
|
16940
|
+
const creds = readCredentials();
|
|
16941
|
+
if (!creds) {
|
|
16942
|
+
return {
|
|
16943
|
+
ok: false,
|
|
16944
|
+
reason: "No API key configured. Add credentials with: node9 login"
|
|
16945
|
+
};
|
|
16946
|
+
}
|
|
16947
|
+
try {
|
|
16948
|
+
const body = buildPolicySnapshot(getConfig(), readActiveShields(), readShieldOverrides());
|
|
16949
|
+
const sent = await shipPolicySnapshot(body, creds);
|
|
16950
|
+
return sent ? { ok: true } : { ok: false, reason: "Push failed (network or server error)" };
|
|
16951
|
+
} catch (e) {
|
|
16952
|
+
return { ok: false, reason: e instanceof Error ? e.message : String(e) };
|
|
16953
|
+
}
|
|
16954
|
+
}
|
|
16828
16955
|
async function pushScanSnapshot(creds) {
|
|
16829
16956
|
try {
|
|
16830
16957
|
const tick = await tickScanWatcher();
|
|
@@ -16842,7 +16969,7 @@ async function pushScanSnapshot(creds) {
|
|
|
16842
16969
|
const parsed = new URL(scanUrl);
|
|
16843
16970
|
let posted = false;
|
|
16844
16971
|
await new Promise((resolve) => {
|
|
16845
|
-
const req =
|
|
16972
|
+
const req = https4.request(
|
|
16846
16973
|
{
|
|
16847
16974
|
hostname: parsed.hostname,
|
|
16848
16975
|
port: parsed.port ? parseInt(parsed.port, 10) : void 0,
|
|
@@ -16892,6 +17019,9 @@ async function runCloudSync() {
|
|
|
16892
17019
|
if (process.env.NODE9_POSTURE_DISABLE !== "1") {
|
|
16893
17020
|
void pushPostureSnapshot(creds);
|
|
16894
17021
|
}
|
|
17022
|
+
if (process.env.NODE9_POLICY_MIRROR_DISABLE !== "1") {
|
|
17023
|
+
void pushPolicySnapshot(creds);
|
|
17024
|
+
}
|
|
16895
17025
|
};
|
|
16896
17026
|
try {
|
|
16897
17027
|
const result = await fetchCloudPolicy(creds.apiKey, creds.apiUrl, readCachedEtag());
|
|
@@ -16978,6 +17108,9 @@ var init_sync = __esm({
|
|
|
16978
17108
|
init_blast();
|
|
16979
17109
|
init_posture();
|
|
16980
17110
|
init_ship();
|
|
17111
|
+
init_build();
|
|
17112
|
+
init_ship2();
|
|
17113
|
+
init_shields();
|
|
16981
17114
|
init_dist();
|
|
16982
17115
|
init_scan_watermark();
|
|
16983
17116
|
init_state2();
|
|
@@ -17451,7 +17584,7 @@ var init_mcp_tools = __esm({
|
|
|
17451
17584
|
});
|
|
17452
17585
|
|
|
17453
17586
|
// src/daemon/server.ts
|
|
17454
|
-
import
|
|
17587
|
+
import http3 from "http";
|
|
17455
17588
|
import fs36 from "fs";
|
|
17456
17589
|
import path35 from "path";
|
|
17457
17590
|
import os33 from "os";
|
|
@@ -17486,7 +17619,7 @@ function startDaemon() {
|
|
|
17486
17619
|
}
|
|
17487
17620
|
resetIdleTimer();
|
|
17488
17621
|
const allowedHosts = /* @__PURE__ */ new Set([`127.0.0.1:${DAEMON_PORT}`, `localhost:${DAEMON_PORT}`]);
|
|
17489
|
-
const server =
|
|
17622
|
+
const server = http3.createServer(async (req, res) => {
|
|
17490
17623
|
const host = req.headers.host ?? "";
|
|
17491
17624
|
if (!allowedHosts.has(host)) {
|
|
17492
17625
|
res.writeHead(421, { "Content-Type": "text/plain" });
|
|
@@ -18720,11 +18853,11 @@ __export(tail_exports, {
|
|
|
18720
18853
|
shortenPathSummary: () => shortenPathSummary,
|
|
18721
18854
|
startTail: () => startTail
|
|
18722
18855
|
});
|
|
18723
|
-
import
|
|
18856
|
+
import http4 from "http";
|
|
18724
18857
|
import chalk35 from "chalk";
|
|
18725
18858
|
import fs64 from "fs";
|
|
18726
|
-
import
|
|
18727
|
-
import
|
|
18859
|
+
import os55 from "os";
|
|
18860
|
+
import path62 from "path";
|
|
18728
18861
|
import readline6 from "readline";
|
|
18729
18862
|
import { spawn as spawn8 } from "child_process";
|
|
18730
18863
|
function shortenPathSummary(s) {
|
|
@@ -18748,18 +18881,18 @@ function getModelContextLimit(model) {
|
|
|
18748
18881
|
return 2e5;
|
|
18749
18882
|
}
|
|
18750
18883
|
function readSessionUsage() {
|
|
18751
|
-
const projectsDir =
|
|
18884
|
+
const projectsDir = path62.join(os55.homedir(), ".claude", "projects");
|
|
18752
18885
|
if (!fs64.existsSync(projectsDir)) return null;
|
|
18753
18886
|
let latestFile = null;
|
|
18754
18887
|
let latestMtime = 0;
|
|
18755
18888
|
try {
|
|
18756
18889
|
for (const dir of fs64.readdirSync(projectsDir)) {
|
|
18757
|
-
const dirPath =
|
|
18890
|
+
const dirPath = path62.join(projectsDir, dir);
|
|
18758
18891
|
try {
|
|
18759
18892
|
if (!fs64.statSync(dirPath).isDirectory()) continue;
|
|
18760
18893
|
for (const file of fs64.readdirSync(dirPath)) {
|
|
18761
18894
|
if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
|
|
18762
|
-
const filePath =
|
|
18895
|
+
const filePath = path62.join(dirPath, file);
|
|
18763
18896
|
try {
|
|
18764
18897
|
const mtime = fs64.statSync(filePath).mtimeMs;
|
|
18765
18898
|
if (mtime > latestMtime) {
|
|
@@ -18837,7 +18970,7 @@ function formatBase(activity) {
|
|
|
18837
18970
|
const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
|
|
18838
18971
|
const icon = getIcon(activity.tool);
|
|
18839
18972
|
const toolName = activity.tool.slice(0, 16).padEnd(16);
|
|
18840
|
-
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(
|
|
18973
|
+
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(os55.homedir(), "~");
|
|
18841
18974
|
const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
|
|
18842
18975
|
return `${chalk35.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${chalk35.white.bold(toolName)} ${chalk35.dim(argsPreview)}`;
|
|
18843
18976
|
}
|
|
@@ -18919,7 +19052,7 @@ function postDecisionHttp(id, decision, authToken, port, opts) {
|
|
|
18919
19052
|
if (opts?.trustDuration) bodyObj.trustDuration = opts.trustDuration;
|
|
18920
19053
|
if (opts?.reason) bodyObj.reason = opts.reason;
|
|
18921
19054
|
const body = JSON.stringify(bodyObj);
|
|
18922
|
-
const req =
|
|
19055
|
+
const req = http4.request(
|
|
18923
19056
|
{
|
|
18924
19057
|
hostname: "127.0.0.1",
|
|
18925
19058
|
port,
|
|
@@ -19034,7 +19167,7 @@ function buildRecoveryCardLines(req) {
|
|
|
19034
19167
|
];
|
|
19035
19168
|
}
|
|
19036
19169
|
function readApproversFromDisk() {
|
|
19037
|
-
const configPath =
|
|
19170
|
+
const configPath = path62.join(os55.homedir(), ".node9", "config.json");
|
|
19038
19171
|
try {
|
|
19039
19172
|
const raw = JSON.parse(fs64.readFileSync(configPath, "utf-8"));
|
|
19040
19173
|
const settings = raw.settings ?? {};
|
|
@@ -19052,7 +19185,7 @@ function approverStatusLine() {
|
|
|
19052
19185
|
return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
|
|
19053
19186
|
}
|
|
19054
19187
|
function toggleApprover(channel) {
|
|
19055
|
-
const configPath =
|
|
19188
|
+
const configPath = path62.join(os55.homedir(), ".node9", "config.json");
|
|
19056
19189
|
try {
|
|
19057
19190
|
const raw = JSON.parse(fs64.readFileSync(configPath, "utf-8"));
|
|
19058
19191
|
const settings = raw.settings ?? {};
|
|
@@ -19070,7 +19203,7 @@ async function startTail(options = {}) {
|
|
|
19070
19203
|
const port = await ensureDaemon();
|
|
19071
19204
|
if (options.clear) {
|
|
19072
19205
|
const result = await new Promise((resolve) => {
|
|
19073
|
-
const req2 =
|
|
19206
|
+
const req2 = http4.request(
|
|
19074
19207
|
{ method: "POST", hostname: "127.0.0.1", port, path: "/events/clear" },
|
|
19075
19208
|
(res) => {
|
|
19076
19209
|
const status = res.statusCode ?? 0;
|
|
@@ -19233,7 +19366,7 @@ async function startTail(options = {}) {
|
|
|
19233
19366
|
postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
|
|
19234
19367
|
try {
|
|
19235
19368
|
fs64.appendFileSync(
|
|
19236
|
-
|
|
19369
|
+
path62.join(os55.homedir(), ".node9", "hook-debug.log"),
|
|
19237
19370
|
`[tail] POST /decision failed: ${String(err2)}
|
|
19238
19371
|
`
|
|
19239
19372
|
);
|
|
@@ -19297,7 +19430,7 @@ async function startTail(options = {}) {
|
|
|
19297
19430
|
};
|
|
19298
19431
|
process.stdin.on("keypress", onKeypress);
|
|
19299
19432
|
}
|
|
19300
|
-
const auditLog =
|
|
19433
|
+
const auditLog = path62.join(os55.homedir(), ".node9", "audit.log");
|
|
19301
19434
|
try {
|
|
19302
19435
|
const unackedDlp = fs64.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
19303
19436
|
if (unackedDlp > 0) {
|
|
@@ -19353,7 +19486,7 @@ async function startTail(options = {}) {
|
|
|
19353
19486
|
}, STALL_THRESHOLD_MS / 2);
|
|
19354
19487
|
stallWatchdog.unref();
|
|
19355
19488
|
const sseUrl = `http://127.0.0.1:${port}/events?capabilities=input`;
|
|
19356
|
-
const req =
|
|
19489
|
+
const req = http4.get(
|
|
19357
19490
|
sseUrl,
|
|
19358
19491
|
{
|
|
19359
19492
|
headers: authToken ? { "X-Node9-Internal": authToken } : {}
|
|
@@ -19530,7 +19663,7 @@ var init_tail = __esm({
|
|
|
19530
19663
|
"use strict";
|
|
19531
19664
|
init_daemon2();
|
|
19532
19665
|
init_daemon();
|
|
19533
|
-
PID_FILE =
|
|
19666
|
+
PID_FILE = path62.join(os55.homedir(), ".node9", "daemon.pid");
|
|
19534
19667
|
ICONS = {
|
|
19535
19668
|
bash: "\u{1F4BB}",
|
|
19536
19669
|
shell: "\u{1F4BB}",
|
|
@@ -19579,9 +19712,9 @@ __export(hud_exports, {
|
|
|
19579
19712
|
renderEnvironmentLine: () => renderEnvironmentLine
|
|
19580
19713
|
});
|
|
19581
19714
|
import fs65 from "fs";
|
|
19582
|
-
import
|
|
19583
|
-
import
|
|
19584
|
-
import
|
|
19715
|
+
import path63 from "path";
|
|
19716
|
+
import os56 from "os";
|
|
19717
|
+
import http5 from "http";
|
|
19585
19718
|
async function readStdin() {
|
|
19586
19719
|
const chunks = [];
|
|
19587
19720
|
for await (const chunk2 of process.stdin) {
|
|
@@ -19599,7 +19732,7 @@ function queryDaemon() {
|
|
|
19599
19732
|
return new Promise((resolve) => {
|
|
19600
19733
|
const timeout = setTimeout(() => resolve(null), 50);
|
|
19601
19734
|
try {
|
|
19602
|
-
const req =
|
|
19735
|
+
const req = http5.get(
|
|
19603
19736
|
`http://${DAEMON_HOST}:${DAEMON_PORT}/status`,
|
|
19604
19737
|
{ timeout: 50 },
|
|
19605
19738
|
(res) => {
|
|
@@ -19684,7 +19817,7 @@ function countRulesInDir(rulesDir) {
|
|
|
19684
19817
|
try {
|
|
19685
19818
|
for (const entry of fs65.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
19686
19819
|
if (entry.isDirectory()) {
|
|
19687
|
-
count += countRulesInDir(
|
|
19820
|
+
count += countRulesInDir(path63.join(rulesDir, entry.name));
|
|
19688
19821
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
19689
19822
|
count++;
|
|
19690
19823
|
}
|
|
@@ -19695,46 +19828,46 @@ function countRulesInDir(rulesDir) {
|
|
|
19695
19828
|
}
|
|
19696
19829
|
function isSamePath(a, b) {
|
|
19697
19830
|
try {
|
|
19698
|
-
return
|
|
19831
|
+
return path63.resolve(a) === path63.resolve(b);
|
|
19699
19832
|
} catch {
|
|
19700
19833
|
return false;
|
|
19701
19834
|
}
|
|
19702
19835
|
}
|
|
19703
19836
|
function countConfigs(cwd) {
|
|
19704
|
-
const homeDir2 =
|
|
19705
|
-
const claudeDir =
|
|
19837
|
+
const homeDir2 = os56.homedir();
|
|
19838
|
+
const claudeDir = path63.join(homeDir2, ".claude");
|
|
19706
19839
|
let claudeMdCount = 0;
|
|
19707
19840
|
let rulesCount = 0;
|
|
19708
19841
|
let hooksCount = 0;
|
|
19709
19842
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
19710
19843
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
19711
|
-
if (fs65.existsSync(
|
|
19712
|
-
rulesCount += countRulesInDir(
|
|
19713
|
-
const userSettings =
|
|
19844
|
+
if (fs65.existsSync(path63.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
19845
|
+
rulesCount += countRulesInDir(path63.join(claudeDir, "rules"));
|
|
19846
|
+
const userSettings = path63.join(claudeDir, "settings.json");
|
|
19714
19847
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
19715
19848
|
hooksCount += countHooksInFile(userSettings);
|
|
19716
|
-
const userClaudeJson =
|
|
19849
|
+
const userClaudeJson = path63.join(homeDir2, ".claude.json");
|
|
19717
19850
|
for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
|
|
19718
19851
|
for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
|
|
19719
19852
|
userMcpServers.delete(name);
|
|
19720
19853
|
}
|
|
19721
19854
|
if (cwd) {
|
|
19722
|
-
if (fs65.existsSync(
|
|
19723
|
-
if (fs65.existsSync(
|
|
19724
|
-
const projectClaudeDir =
|
|
19855
|
+
if (fs65.existsSync(path63.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
19856
|
+
if (fs65.existsSync(path63.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
19857
|
+
const projectClaudeDir = path63.join(cwd, ".claude");
|
|
19725
19858
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
19726
19859
|
if (!overlapsUserScope) {
|
|
19727
|
-
if (fs65.existsSync(
|
|
19728
|
-
rulesCount += countRulesInDir(
|
|
19729
|
-
const projSettings =
|
|
19860
|
+
if (fs65.existsSync(path63.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
19861
|
+
rulesCount += countRulesInDir(path63.join(projectClaudeDir, "rules"));
|
|
19862
|
+
const projSettings = path63.join(projectClaudeDir, "settings.json");
|
|
19730
19863
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
19731
19864
|
hooksCount += countHooksInFile(projSettings);
|
|
19732
19865
|
}
|
|
19733
|
-
if (fs65.existsSync(
|
|
19734
|
-
const localSettings =
|
|
19866
|
+
if (fs65.existsSync(path63.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
19867
|
+
const localSettings = path63.join(projectClaudeDir, "settings.local.json");
|
|
19735
19868
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
19736
19869
|
hooksCount += countHooksInFile(localSettings);
|
|
19737
|
-
const mcpJsonServers = getMcpServerNames(
|
|
19870
|
+
const mcpJsonServers = getMcpServerNames(path63.join(cwd, ".mcp.json"));
|
|
19738
19871
|
const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
|
|
19739
19872
|
for (const name of disabledMcpJson) mcpJsonServers.delete(name);
|
|
19740
19873
|
for (const name of mcpJsonServers) projectMcpServers.add(name);
|
|
@@ -19767,7 +19900,7 @@ function readActiveShieldsHud() {
|
|
|
19767
19900
|
return shieldsCache.value;
|
|
19768
19901
|
}
|
|
19769
19902
|
try {
|
|
19770
|
-
const shieldsPath =
|
|
19903
|
+
const shieldsPath = path63.join(os56.homedir(), ".node9", "shields.json");
|
|
19771
19904
|
if (!fs65.existsSync(shieldsPath)) {
|
|
19772
19905
|
shieldsCache = { value: [], ts: now };
|
|
19773
19906
|
return [];
|
|
@@ -19874,9 +20007,9 @@ function renderContextLine(stdin) {
|
|
|
19874
20007
|
async function main() {
|
|
19875
20008
|
try {
|
|
19876
20009
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
19877
|
-
if (fs65.existsSync(
|
|
20010
|
+
if (fs65.existsSync(path63.join(os56.homedir(), ".node9", "hud-debug"))) {
|
|
19878
20011
|
try {
|
|
19879
|
-
const logPath =
|
|
20012
|
+
const logPath = path63.join(os56.homedir(), ".node9", "hud-debug.log");
|
|
19880
20013
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
19881
20014
|
let size = 0;
|
|
19882
20015
|
try {
|
|
@@ -19905,8 +20038,8 @@ async function main() {
|
|
|
19905
20038
|
try {
|
|
19906
20039
|
const cwd = stdin.cwd ?? process.cwd();
|
|
19907
20040
|
for (const configPath of [
|
|
19908
|
-
|
|
19909
|
-
|
|
20041
|
+
path63.join(cwd, "node9.config.json"),
|
|
20042
|
+
path63.join(os56.homedir(), ".node9", "config.json")
|
|
19910
20043
|
]) {
|
|
19911
20044
|
if (!fs65.existsSync(configPath)) continue;
|
|
19912
20045
|
const cfg = JSON.parse(fs65.readFileSync(configPath, "utf-8"));
|
|
@@ -19953,12 +20086,45 @@ var init_hud = __esm({
|
|
|
19953
20086
|
// src/cli.ts
|
|
19954
20087
|
init_core();
|
|
19955
20088
|
init_setup();
|
|
19956
|
-
init_daemon2();
|
|
19957
20089
|
import { Command } from "commander";
|
|
20090
|
+
|
|
20091
|
+
// src/agent-teardowns.ts
|
|
20092
|
+
init_setup();
|
|
20093
|
+
var AGENT_TEARDOWNS = [
|
|
20094
|
+
{ id: "claude", label: "Claude", fn: teardownClaude },
|
|
20095
|
+
{ id: "gemini", label: "Gemini", fn: teardownGemini },
|
|
20096
|
+
{ id: "codex", label: "Codex", fn: teardownCodex },
|
|
20097
|
+
{ id: "cursor", label: "Cursor", fn: teardownCursor },
|
|
20098
|
+
{ id: "windsurf", label: "Windsurf", fn: teardownWindsurf },
|
|
20099
|
+
{ id: "vscode", label: "VSCode", fn: teardownVSCode },
|
|
20100
|
+
{ id: "hermes", label: "Hermes", fn: teardownHermes },
|
|
20101
|
+
{ id: "antigravity", label: "Antigravity", fn: teardownAntigravity, aliases: ["agy"] },
|
|
20102
|
+
{ id: "copilot", label: "Copilot", fn: teardownCopilot },
|
|
20103
|
+
{ id: "hud", label: "HUD", fn: teardownHud },
|
|
20104
|
+
{
|
|
20105
|
+
id: "claudedesktop",
|
|
20106
|
+
label: "Claude Desktop",
|
|
20107
|
+
fn: teardownClaudeDesktop,
|
|
20108
|
+
aliases: ["claude-desktop"]
|
|
20109
|
+
},
|
|
20110
|
+
{ id: "opencode", label: "OpenCode", fn: teardownOpencode },
|
|
20111
|
+
{ id: "pi", label: "Pi", fn: teardownPi }
|
|
20112
|
+
];
|
|
20113
|
+
function resolveAgentTeardown(target) {
|
|
20114
|
+
const t = target.trim().toLowerCase();
|
|
20115
|
+
return AGENT_TEARDOWNS.find((a) => a.id === t || a.aliases?.includes(t));
|
|
20116
|
+
}
|
|
20117
|
+
function agentTeardownTargets() {
|
|
20118
|
+
return AGENT_TEARDOWNS.flatMap((a) => [a.id, ...a.aliases ?? []]);
|
|
20119
|
+
}
|
|
20120
|
+
|
|
20121
|
+
// src/cli.ts
|
|
20122
|
+
init_agent_wiring();
|
|
20123
|
+
init_daemon2();
|
|
19958
20124
|
import chalk36 from "chalk";
|
|
19959
20125
|
import fs66 from "fs";
|
|
19960
|
-
import
|
|
19961
|
-
import
|
|
20126
|
+
import path64 from "path";
|
|
20127
|
+
import os57 from "os";
|
|
19962
20128
|
import { spawn as spawn9 } from "child_process";
|
|
19963
20129
|
import { confirm as confirm2 } from "@inquirer/prompts";
|
|
19964
20130
|
|
|
@@ -21589,6 +21755,8 @@ function registerLogCommand(program2) {
|
|
|
21589
21755
|
init_shields();
|
|
21590
21756
|
import chalk10 from "chalk";
|
|
21591
21757
|
import fs46 from "fs";
|
|
21758
|
+
import path44 from "path";
|
|
21759
|
+
import os40 from "os";
|
|
21592
21760
|
|
|
21593
21761
|
// src/shields/build.ts
|
|
21594
21762
|
function escapeRegex(s) {
|
|
@@ -21718,10 +21886,10 @@ init_audit();
|
|
|
21718
21886
|
init_config();
|
|
21719
21887
|
|
|
21720
21888
|
// src/utils/https-fetch.ts
|
|
21721
|
-
import
|
|
21889
|
+
import https5 from "https";
|
|
21722
21890
|
function httpsFetch(url) {
|
|
21723
21891
|
return new Promise((resolve, reject) => {
|
|
21724
|
-
|
|
21892
|
+
https5.get(url, (res) => {
|
|
21725
21893
|
if (res.statusCode !== 200) {
|
|
21726
21894
|
reject(new Error(`HTTP ${String(res.statusCode)} for ${url}`));
|
|
21727
21895
|
res.resume();
|
|
@@ -21737,6 +21905,22 @@ function httpsFetch(url) {
|
|
|
21737
21905
|
|
|
21738
21906
|
// src/cli/commands/shield.ts
|
|
21739
21907
|
var COMMUNITY_INDEX_URL = "https://raw.githubusercontent.com/node9ai/node9-proxy/main/shields/community/index.json";
|
|
21908
|
+
function readCloudShields() {
|
|
21909
|
+
const out = /* @__PURE__ */ new Set();
|
|
21910
|
+
try {
|
|
21911
|
+
const file = path44.join(os40.homedir(), ".node9", "rules-cache.json");
|
|
21912
|
+
const raw = JSON.parse(fs46.readFileSync(file, "utf-8"));
|
|
21913
|
+
for (const r of raw.rules ?? []) {
|
|
21914
|
+
const rule = r;
|
|
21915
|
+
const fromSource = rule.source?.startsWith("SHIELD:") ? rule.source.slice("SHIELD:".length).toLowerCase() : void 0;
|
|
21916
|
+
const fromDesc = !fromSource && rule.description ? /\b([a-z0-9-]+)\s+shield/i.exec(rule.description)?.[1]?.toLowerCase() : void 0;
|
|
21917
|
+
const name = fromSource ?? fromDesc;
|
|
21918
|
+
if (name) out.add(name);
|
|
21919
|
+
}
|
|
21920
|
+
} catch {
|
|
21921
|
+
}
|
|
21922
|
+
return out;
|
|
21923
|
+
}
|
|
21740
21924
|
function registerShieldCommand(program2) {
|
|
21741
21925
|
const shieldCmd = program2.command("shield").description("Manage pre-packaged security shield templates");
|
|
21742
21926
|
shieldCmd.command("enable <service>").description("Enable a security shield for a specific service").action((service) => {
|
|
@@ -21823,10 +22007,17 @@ function registerShieldCommand(program2) {
|
|
|
21823
22007
|
return;
|
|
21824
22008
|
}
|
|
21825
22009
|
const active = new Set(readActiveShields());
|
|
22010
|
+
const cloud = readCloudShields();
|
|
21826
22011
|
console.log(chalk10.bold("\n\u{1F6E1}\uFE0F Available Shields\n"));
|
|
22012
|
+
console.log(chalk10.gray(" \u25CF local \xB7 \u2601 cloud\n"));
|
|
21827
22013
|
for (const shield of listShields()) {
|
|
21828
|
-
const
|
|
21829
|
-
|
|
22014
|
+
const isLocal = active.has(shield.name);
|
|
22015
|
+
const isCloud = cloud.has(shield.name);
|
|
22016
|
+
const status = isLocal && isCloud ? chalk10.green("\u25CF\u2601 enabled ") : isLocal ? chalk10.green("\u25CF enabled ") : isCloud ? chalk10.cyan("\u2601 cloud ") : chalk10.gray("\u25CB disabled");
|
|
22017
|
+
const via = isCloud && !isLocal ? chalk10.gray(" (via dashboard)") : "";
|
|
22018
|
+
console.log(
|
|
22019
|
+
` ${status} ${chalk10.cyan(shield.name.padEnd(12))} ${shield.description}${via}`
|
|
22020
|
+
);
|
|
21830
22021
|
if (shield.aliases.length > 0)
|
|
21831
22022
|
console.log(chalk10.gray(` aliases: ${shield.aliases.join(", ")}`));
|
|
21832
22023
|
}
|
|
@@ -22159,12 +22350,12 @@ init_config();
|
|
|
22159
22350
|
init_agent_wiring();
|
|
22160
22351
|
import chalk11 from "chalk";
|
|
22161
22352
|
import fs47 from "fs";
|
|
22162
|
-
import
|
|
22163
|
-
import
|
|
22353
|
+
import path45 from "path";
|
|
22354
|
+
import os41 from "os";
|
|
22164
22355
|
import { execSync } from "child_process";
|
|
22165
22356
|
function registerDoctorCommand(program2, version2) {
|
|
22166
22357
|
program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
|
|
22167
|
-
const homeDir2 =
|
|
22358
|
+
const homeDir2 = os41.homedir();
|
|
22168
22359
|
let failures = 0;
|
|
22169
22360
|
function pass(msg) {
|
|
22170
22361
|
console.log(chalk11.green(" \u2705 ") + msg);
|
|
@@ -22210,7 +22401,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
22210
22401
|
);
|
|
22211
22402
|
}
|
|
22212
22403
|
section("Configuration");
|
|
22213
|
-
const globalConfigPath =
|
|
22404
|
+
const globalConfigPath = path45.join(homeDir2, ".node9", "config.json");
|
|
22214
22405
|
if (fs47.existsSync(globalConfigPath)) {
|
|
22215
22406
|
try {
|
|
22216
22407
|
JSON.parse(fs47.readFileSync(globalConfigPath, "utf-8"));
|
|
@@ -22221,7 +22412,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
22221
22412
|
} else {
|
|
22222
22413
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
22223
22414
|
}
|
|
22224
|
-
const projectConfigPath =
|
|
22415
|
+
const projectConfigPath = path45.join(process.cwd(), "node9.config.json");
|
|
22225
22416
|
if (fs47.existsSync(projectConfigPath)) {
|
|
22226
22417
|
try {
|
|
22227
22418
|
JSON.parse(fs47.readFileSync(projectConfigPath, "utf-8"));
|
|
@@ -22233,7 +22424,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
22233
22424
|
);
|
|
22234
22425
|
}
|
|
22235
22426
|
}
|
|
22236
|
-
const credsPath =
|
|
22427
|
+
const credsPath = path45.join(homeDir2, ".node9", "credentials.json");
|
|
22237
22428
|
if (fs47.existsSync(credsPath)) {
|
|
22238
22429
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
22239
22430
|
} else {
|
|
@@ -22278,7 +22469,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
22278
22469
|
try {
|
|
22279
22470
|
const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
|
|
22280
22471
|
const cfg = getConfig();
|
|
22281
|
-
const creds = fs47.existsSync(
|
|
22472
|
+
const creds = fs47.existsSync(path45.join(os41.homedir(), ".node9", "credentials.json"));
|
|
22282
22473
|
if (!creds) {
|
|
22283
22474
|
warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
|
|
22284
22475
|
} else if (!cfg.settings.approvers.cloud) {
|
|
@@ -22329,8 +22520,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
22329
22520
|
// src/cli/commands/audit.ts
|
|
22330
22521
|
import chalk12 from "chalk";
|
|
22331
22522
|
import fs48 from "fs";
|
|
22332
|
-
import
|
|
22333
|
-
import
|
|
22523
|
+
import path46 from "path";
|
|
22524
|
+
import os42 from "os";
|
|
22334
22525
|
function formatRelativeTime(timestamp) {
|
|
22335
22526
|
const diff = Date.now() - new Date(timestamp).getTime();
|
|
22336
22527
|
const sec = Math.floor(diff / 1e3);
|
|
@@ -22343,7 +22534,7 @@ function formatRelativeTime(timestamp) {
|
|
|
22343
22534
|
}
|
|
22344
22535
|
function registerAuditCommand(program2) {
|
|
22345
22536
|
program2.command("audit").description("View local execution audit log").option("--tail <n>", "Number of entries to show", "20").option("--tool <pattern>", "Filter by tool name (substring match)").option("--deny", "Show only denied actions").option("--json", "Output raw JSON").action((options) => {
|
|
22346
|
-
const logPath =
|
|
22537
|
+
const logPath = path46.join(os42.homedir(), ".node9", "audit.log");
|
|
22347
22538
|
if (!fs48.existsSync(logPath)) {
|
|
22348
22539
|
console.log(
|
|
22349
22540
|
chalk12.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
@@ -22410,8 +22601,8 @@ init_costSync();
|
|
|
22410
22601
|
init_litellm();
|
|
22411
22602
|
init_cost_codex();
|
|
22412
22603
|
import fs49 from "fs";
|
|
22413
|
-
import
|
|
22414
|
-
import
|
|
22604
|
+
import os43 from "os";
|
|
22605
|
+
import path47 from "path";
|
|
22415
22606
|
var TEST_COMMAND_RE3 = /(?:^|\s)(npm\s+(?:run\s+)?test|npx\s+(?:vitest|jest|mocha)|yarn\s+(?:run\s+)?test|pnpm\s+(?:run\s+)?test|vitest|jest|mocha|pytest|py\.test|cargo\s+test|go\s+test|bundle\s+exec\s+rspec|rspec|phpunit|dotnet\s+test)\b/i;
|
|
22416
22607
|
function buildTestTimestamps(allEntries) {
|
|
22417
22608
|
const testTs = /* @__PURE__ */ new Set();
|
|
@@ -22539,7 +22730,7 @@ function freezeClaudeCost(acc) {
|
|
|
22539
22730
|
};
|
|
22540
22731
|
}
|
|
22541
22732
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
22542
|
-
const projPath =
|
|
22733
|
+
const projPath = path47.join(projectsDir, proj);
|
|
22543
22734
|
let files;
|
|
22544
22735
|
try {
|
|
22545
22736
|
const stat = fs49.statSync(projPath);
|
|
@@ -22550,7 +22741,7 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
22550
22741
|
}
|
|
22551
22742
|
const startMs = start.getTime();
|
|
22552
22743
|
for (const file of files) {
|
|
22553
|
-
const filePath =
|
|
22744
|
+
const filePath = path47.join(projPath, file);
|
|
22554
22745
|
try {
|
|
22555
22746
|
if (fs49.statSync(filePath).mtimeMs < startMs) continue;
|
|
22556
22747
|
} catch {
|
|
@@ -22680,28 +22871,28 @@ function listCodexSessionFiles2(sessionsBase) {
|
|
|
22680
22871
|
if (!fs49.existsSync(sessionsBase)) return jsonlFiles;
|
|
22681
22872
|
try {
|
|
22682
22873
|
for (const year of fs49.readdirSync(sessionsBase)) {
|
|
22683
|
-
const yearPath =
|
|
22874
|
+
const yearPath = path47.join(sessionsBase, year);
|
|
22684
22875
|
try {
|
|
22685
22876
|
if (!fs49.statSync(yearPath).isDirectory()) continue;
|
|
22686
22877
|
} catch {
|
|
22687
22878
|
continue;
|
|
22688
22879
|
}
|
|
22689
22880
|
for (const month of fs49.readdirSync(yearPath)) {
|
|
22690
|
-
const monthPath =
|
|
22881
|
+
const monthPath = path47.join(yearPath, month);
|
|
22691
22882
|
try {
|
|
22692
22883
|
if (!fs49.statSync(monthPath).isDirectory()) continue;
|
|
22693
22884
|
} catch {
|
|
22694
22885
|
continue;
|
|
22695
22886
|
}
|
|
22696
22887
|
for (const day of fs49.readdirSync(monthPath)) {
|
|
22697
|
-
const dayPath =
|
|
22888
|
+
const dayPath = path47.join(monthPath, day);
|
|
22698
22889
|
try {
|
|
22699
22890
|
if (!fs49.statSync(dayPath).isDirectory()) continue;
|
|
22700
22891
|
} catch {
|
|
22701
22892
|
continue;
|
|
22702
22893
|
}
|
|
22703
22894
|
for (const file of fs49.readdirSync(dayPath)) {
|
|
22704
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
22895
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(path47.join(dayPath, file));
|
|
22705
22896
|
}
|
|
22706
22897
|
}
|
|
22707
22898
|
}
|
|
@@ -22827,7 +23018,7 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
|
|
|
22827
23018
|
return out;
|
|
22828
23019
|
}
|
|
22829
23020
|
for (const proj of dirs) {
|
|
22830
|
-
const chatsDir =
|
|
23021
|
+
const chatsDir = path47.join(geminiTmpDir2, proj, "chats");
|
|
22831
23022
|
let files;
|
|
22832
23023
|
try {
|
|
22833
23024
|
if (!fs49.statSync(chatsDir).isDirectory()) continue;
|
|
@@ -22837,7 +23028,7 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
|
|
|
22837
23028
|
}
|
|
22838
23029
|
for (const f of files) {
|
|
22839
23030
|
if (!f.endsWith(".jsonl")) continue;
|
|
22840
|
-
out.push({ projectKey: proj, file:
|
|
23031
|
+
out.push({ projectKey: proj, file: path47.join(chatsDir, f) });
|
|
22841
23032
|
}
|
|
22842
23033
|
}
|
|
22843
23034
|
return out;
|
|
@@ -22852,10 +23043,10 @@ function loadGeminiCost(start, end, geminiTmpDir2) {
|
|
|
22852
23043
|
}
|
|
22853
23044
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
22854
23045
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
22855
|
-
const auditLogPath = opts.auditLogPath ??
|
|
22856
|
-
const claudeProjectsDir = opts.claudeProjectsDir ??
|
|
22857
|
-
const codexSessionsDir2 = opts.codexSessionsDir ??
|
|
22858
|
-
const geminiTmpDir2 = opts.geminiTmpDir ??
|
|
23046
|
+
const auditLogPath = opts.auditLogPath ?? path47.join(os43.homedir(), ".node9", "audit.log");
|
|
23047
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? path47.join(os43.homedir(), ".claude", "projects");
|
|
23048
|
+
const codexSessionsDir2 = opts.codexSessionsDir ?? path47.join(os43.homedir(), ".codex", "sessions");
|
|
23049
|
+
const geminiTmpDir2 = opts.geminiTmpDir ?? path47.join(os43.homedir(), ".gemini", "tmp");
|
|
22859
23050
|
const hasAuditFile = fs49.existsSync(auditLogPath);
|
|
22860
23051
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
|
|
22861
23052
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
@@ -23556,8 +23747,8 @@ init_daemon();
|
|
|
23556
23747
|
init_agent_wiring();
|
|
23557
23748
|
import chalk15 from "chalk";
|
|
23558
23749
|
import fs50 from "fs";
|
|
23559
|
-
import
|
|
23560
|
-
import
|
|
23750
|
+
import path48 from "path";
|
|
23751
|
+
import os44 from "os";
|
|
23561
23752
|
function printAgentSection(label2, hookPairs, wrapped) {
|
|
23562
23753
|
console.log(chalk15.bold(` ${label2}`));
|
|
23563
23754
|
for (const { name, present } of hookPairs) {
|
|
@@ -23611,8 +23802,8 @@ function registerStatusCommand(program2) {
|
|
|
23611
23802
|
console.log("");
|
|
23612
23803
|
const modeLabel = settings.mode === "audit" ? chalk15.blue("audit") : settings.mode === "strict" ? chalk15.red("strict") : chalk15.white("standard");
|
|
23613
23804
|
console.log(` Mode: ${modeLabel}`);
|
|
23614
|
-
const projectConfig =
|
|
23615
|
-
const globalConfig =
|
|
23805
|
+
const projectConfig = path48.join(process.cwd(), "node9.config.json");
|
|
23806
|
+
const globalConfig = path48.join(os44.homedir(), ".node9", "config.json");
|
|
23616
23807
|
console.log(
|
|
23617
23808
|
` Local: ${fs50.existsSync(projectConfig) ? chalk15.green("Active (node9.config.json)") : chalk15.gray("Not present")}`
|
|
23618
23809
|
);
|
|
@@ -23624,7 +23815,7 @@ function registerStatusCommand(program2) {
|
|
|
23624
23815
|
` Sandbox: ${chalk15.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
|
|
23625
23816
|
);
|
|
23626
23817
|
}
|
|
23627
|
-
const wiring = getAgentWiring(
|
|
23818
|
+
const wiring = getAgentWiring(os44.homedir()).filter((a) => a.present);
|
|
23628
23819
|
if (wiring.length > 0) {
|
|
23629
23820
|
console.log("");
|
|
23630
23821
|
console.log(chalk15.bold(" Agent Wiring:"));
|
|
@@ -23664,9 +23855,9 @@ init_shields();
|
|
|
23664
23855
|
init_service();
|
|
23665
23856
|
import chalk16 from "chalk";
|
|
23666
23857
|
import fs51 from "fs";
|
|
23667
|
-
import
|
|
23668
|
-
import
|
|
23669
|
-
import
|
|
23858
|
+
import path49 from "path";
|
|
23859
|
+
import os45 from "os";
|
|
23860
|
+
import https6 from "https";
|
|
23670
23861
|
var DEFAULT_SHIELDS = ["bash-safe", "filesystem", "project-jail"];
|
|
23671
23862
|
function buildTelemetryPayload(agents, firstInstall) {
|
|
23672
23863
|
return {
|
|
@@ -23680,7 +23871,7 @@ function buildTelemetryPayload(agents, firstInstall) {
|
|
|
23680
23871
|
function fireTelemetryPing(agents, firstInstall) {
|
|
23681
23872
|
try {
|
|
23682
23873
|
const body = JSON.stringify(buildTelemetryPayload(agents, firstInstall));
|
|
23683
|
-
const req =
|
|
23874
|
+
const req = https6.request(
|
|
23684
23875
|
{
|
|
23685
23876
|
hostname: "api.node9.ai",
|
|
23686
23877
|
path: "/api/v1/telemetry",
|
|
@@ -23751,7 +23942,7 @@ function registerInitCommand(program2) {
|
|
|
23751
23942
|
}
|
|
23752
23943
|
console.log("");
|
|
23753
23944
|
}
|
|
23754
|
-
const configPath =
|
|
23945
|
+
const configPath = path49.join(os45.homedir(), ".node9", "config.json");
|
|
23755
23946
|
const isFirstInstall = !fs51.existsSync(configPath);
|
|
23756
23947
|
if (fs51.existsSync(configPath) && !options.force) {
|
|
23757
23948
|
try {
|
|
@@ -23773,7 +23964,7 @@ function registerInitCommand(program2) {
|
|
|
23773
23964
|
...DEFAULT_CONFIG,
|
|
23774
23965
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
23775
23966
|
};
|
|
23776
|
-
const dir =
|
|
23967
|
+
const dir = path49.dirname(configPath);
|
|
23777
23968
|
if (!fs51.existsSync(dir)) fs51.mkdirSync(dir, { recursive: true });
|
|
23778
23969
|
fs51.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
|
|
23779
23970
|
console.log(chalk16.green(`\u2705 Config created: ${configPath}`));
|
|
@@ -23880,7 +24071,7 @@ function registerInitCommand(program2) {
|
|
|
23880
24071
|
}
|
|
23881
24072
|
|
|
23882
24073
|
// src/cli/commands/undo.ts
|
|
23883
|
-
import
|
|
24074
|
+
import path50 from "path";
|
|
23884
24075
|
import chalk18 from "chalk";
|
|
23885
24076
|
|
|
23886
24077
|
// src/tui/undo-navigator.ts
|
|
@@ -24039,7 +24230,7 @@ function findMatchingCwd(startDir, history) {
|
|
|
24039
24230
|
let dir = startDir;
|
|
24040
24231
|
while (true) {
|
|
24041
24232
|
if (cwds.has(dir)) return dir;
|
|
24042
|
-
const parent =
|
|
24233
|
+
const parent = path50.dirname(dir);
|
|
24043
24234
|
if (parent === dir) return null;
|
|
24044
24235
|
dir = parent;
|
|
24045
24236
|
}
|
|
@@ -24675,8 +24866,8 @@ function registerMcpGatewayCommand(program2) {
|
|
|
24675
24866
|
// src/mcp-server/index.ts
|
|
24676
24867
|
import readline5 from "readline";
|
|
24677
24868
|
import fs53 from "fs";
|
|
24678
|
-
import
|
|
24679
|
-
import
|
|
24869
|
+
import os47 from "os";
|
|
24870
|
+
import path52 from "path";
|
|
24680
24871
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
24681
24872
|
init_core();
|
|
24682
24873
|
init_daemon();
|
|
@@ -24684,8 +24875,8 @@ init_shields();
|
|
|
24684
24875
|
|
|
24685
24876
|
// src/auth/egress-config.ts
|
|
24686
24877
|
import fs52 from "fs";
|
|
24687
|
-
import
|
|
24688
|
-
import
|
|
24878
|
+
import os46 from "os";
|
|
24879
|
+
import path51 from "path";
|
|
24689
24880
|
var DEFAULT_EGRESS = {
|
|
24690
24881
|
enabled: false,
|
|
24691
24882
|
mode: "review",
|
|
@@ -24694,7 +24885,7 @@ var DEFAULT_EGRESS = {
|
|
|
24694
24885
|
allowPrivate: true
|
|
24695
24886
|
};
|
|
24696
24887
|
function egressConfigPath() {
|
|
24697
|
-
return
|
|
24888
|
+
return path51.join(os46.homedir(), ".node9", "config.json");
|
|
24698
24889
|
}
|
|
24699
24890
|
function readEgressRawConfig() {
|
|
24700
24891
|
let text;
|
|
@@ -24714,7 +24905,7 @@ function readEgressRawConfig() {
|
|
|
24714
24905
|
}
|
|
24715
24906
|
function writeEgressRawConfig(config) {
|
|
24716
24907
|
const p = egressConfigPath();
|
|
24717
|
-
fs52.mkdirSync(
|
|
24908
|
+
fs52.mkdirSync(path51.dirname(p), { recursive: true });
|
|
24718
24909
|
fs52.writeFileSync(p, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
24719
24910
|
}
|
|
24720
24911
|
function applyEgress(config, change) {
|
|
@@ -25100,8 +25291,8 @@ function handleStatus() {
|
|
|
25100
25291
|
lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
|
|
25101
25292
|
lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
|
|
25102
25293
|
lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
|
|
25103
|
-
const projectConfig =
|
|
25104
|
-
const globalConfig =
|
|
25294
|
+
const projectConfig = path52.join(process.cwd(), "node9.config.json");
|
|
25295
|
+
const globalConfig = path52.join(os47.homedir(), ".node9", "config.json");
|
|
25105
25296
|
lines.push(
|
|
25106
25297
|
`Project config (node9.config.json): ${fs53.existsSync(projectConfig) ? "present" : "not found"}`
|
|
25107
25298
|
);
|
|
@@ -25212,7 +25403,7 @@ function handleEgressDeny(args) {
|
|
|
25212
25403
|
addEgressHost("deny", host);
|
|
25213
25404
|
return `Denied egress to ${host} (deny always wins over allow).`;
|
|
25214
25405
|
}
|
|
25215
|
-
var GLOBAL_CONFIG_PATH =
|
|
25406
|
+
var GLOBAL_CONFIG_PATH = path52.join(os47.homedir(), ".node9", "config.json");
|
|
25216
25407
|
var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
|
|
25217
25408
|
function readGlobalConfigRaw() {
|
|
25218
25409
|
try {
|
|
@@ -25224,7 +25415,7 @@ function readGlobalConfigRaw() {
|
|
|
25224
25415
|
return {};
|
|
25225
25416
|
}
|
|
25226
25417
|
function writeGlobalConfigRaw(data) {
|
|
25227
|
-
const dir =
|
|
25418
|
+
const dir = path52.dirname(GLOBAL_CONFIG_PATH);
|
|
25228
25419
|
if (!fs53.existsSync(dir)) fs53.mkdirSync(dir, { recursive: true });
|
|
25229
25420
|
fs53.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
|
|
25230
25421
|
}
|
|
@@ -25270,7 +25461,7 @@ function handleApproverSet(args) {
|
|
|
25270
25461
|
function handleAuditGet(args) {
|
|
25271
25462
|
const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
|
|
25272
25463
|
const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
|
|
25273
|
-
const auditPath =
|
|
25464
|
+
const auditPath = path52.join(os47.homedir(), ".node9", "audit.log");
|
|
25274
25465
|
if (!fs53.existsSync(auditPath)) return "No audit log found.";
|
|
25275
25466
|
const rawLines = fs53.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
|
|
25276
25467
|
const parsed = [];
|
|
@@ -25778,6 +25969,17 @@ init_sync();
|
|
|
25778
25969
|
import chalk22 from "chalk";
|
|
25779
25970
|
function registerSyncCommand(program2) {
|
|
25780
25971
|
const policy = program2.command("policy").description("Manage cloud policy rules");
|
|
25972
|
+
policy.command("push").description("Push this machine's effective policy to the node9 dashboard").action(async () => {
|
|
25973
|
+
process.stdout.write(chalk22.cyan("Pushing policy to the dashboard\u2026"));
|
|
25974
|
+
const result = await runPolicyPush();
|
|
25975
|
+
process.stdout.write("\n");
|
|
25976
|
+
if (!result.ok) {
|
|
25977
|
+
console.error(chalk22.red(`\u2717 ${result.reason}`));
|
|
25978
|
+
process.exit(1);
|
|
25979
|
+
}
|
|
25980
|
+
console.log(chalk22.green("\u2713 Policy mirrored to the dashboard"));
|
|
25981
|
+
console.log(chalk22.gray(" See it under Security Policy \u2192 Machines"));
|
|
25982
|
+
});
|
|
25781
25983
|
policy.command("sync").description("Sync cloud policy rules to local cache (~/.node9/rules-cache.json)").action(async () => {
|
|
25782
25984
|
process.stdout.write(chalk22.cyan("Syncing cloud policy rules\u2026"));
|
|
25783
25985
|
const result = await runCloudSync();
|
|
@@ -26226,12 +26428,12 @@ import chalk27 from "chalk";
|
|
|
26226
26428
|
|
|
26227
26429
|
// src/shields/jail.ts
|
|
26228
26430
|
import fs55 from "fs";
|
|
26229
|
-
import
|
|
26230
|
-
import
|
|
26431
|
+
import os48 from "os";
|
|
26432
|
+
import path53 from "path";
|
|
26231
26433
|
init_shields();
|
|
26232
26434
|
var USER_JAIL_SHIELD = "user-jail";
|
|
26233
26435
|
function jailStorePath() {
|
|
26234
|
-
return
|
|
26436
|
+
return path53.join(os48.homedir(), ".node9", "jail-paths.json");
|
|
26235
26437
|
}
|
|
26236
26438
|
function readJailPaths() {
|
|
26237
26439
|
let text;
|
|
@@ -26254,7 +26456,7 @@ function readJailPaths() {
|
|
|
26254
26456
|
}
|
|
26255
26457
|
function writeJailPaths(paths) {
|
|
26256
26458
|
const p = jailStorePath();
|
|
26257
|
-
fs55.mkdirSync(
|
|
26459
|
+
fs55.mkdirSync(path53.dirname(p), { recursive: true });
|
|
26258
26460
|
fs55.writeFileSync(p, JSON.stringify({ paths }, null, 2) + "\n", { mode: 384 });
|
|
26259
26461
|
}
|
|
26260
26462
|
function addJailPath(rawPath, verdict) {
|
|
@@ -26277,7 +26479,7 @@ function removeJailPath(rawPath) {
|
|
|
26277
26479
|
return { removed, paths: after };
|
|
26278
26480
|
}
|
|
26279
26481
|
function regenerateUserJail(paths) {
|
|
26280
|
-
const file =
|
|
26482
|
+
const file = path53.join(USER_SHIELDS_DIR_PATH, `${USER_JAIL_SHIELD}.json`);
|
|
26281
26483
|
if (paths.length === 0) {
|
|
26282
26484
|
const active2 = readActiveShields();
|
|
26283
26485
|
if (active2.includes(USER_JAIL_SHIELD)) {
|
|
@@ -26400,12 +26602,12 @@ function registerJailCommand(program2) {
|
|
|
26400
26602
|
init_config();
|
|
26401
26603
|
import chalk28 from "chalk";
|
|
26402
26604
|
import fs58 from "fs";
|
|
26403
|
-
import
|
|
26605
|
+
import path56 from "path";
|
|
26404
26606
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
26405
26607
|
|
|
26406
26608
|
// src/sandbox/config.ts
|
|
26407
26609
|
import fs56 from "fs";
|
|
26408
|
-
import
|
|
26610
|
+
import path54 from "path";
|
|
26409
26611
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
26410
26612
|
var SANDBOX_CONFIG_FILE = "node9.sandbox.yaml";
|
|
26411
26613
|
var FORBIDDEN_ENV = /* @__PURE__ */ new Set(["NODE9_API_KEY", "NODE9_API_URL"]);
|
|
@@ -26478,7 +26680,7 @@ function scaffoldSandboxYaml(agent) {
|
|
|
26478
26680
|
return header + stringifyYaml(defaultSandboxConfig(agent));
|
|
26479
26681
|
}
|
|
26480
26682
|
function sandboxConfigPath(cwd = process.cwd()) {
|
|
26481
|
-
return
|
|
26683
|
+
return path54.join(cwd, SANDBOX_CONFIG_FILE);
|
|
26482
26684
|
}
|
|
26483
26685
|
function loadSandboxConfig(cwd = process.cwd(), fallbackAgent = "claude") {
|
|
26484
26686
|
const p = sandboxConfigPath(cwd);
|
|
@@ -26547,12 +26749,12 @@ init_templates();
|
|
|
26547
26749
|
// src/sandbox/runtime.ts
|
|
26548
26750
|
init_templates();
|
|
26549
26751
|
import fs57 from "fs";
|
|
26550
|
-
import
|
|
26551
|
-
import
|
|
26752
|
+
import os49 from "os";
|
|
26753
|
+
import path55 from "path";
|
|
26552
26754
|
import crypto8 from "crypto";
|
|
26553
26755
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
26554
26756
|
function sandboxDataDir(cwd = process.cwd()) {
|
|
26555
|
-
return
|
|
26757
|
+
return path55.join(cwd, ".node9", "sandbox", "data");
|
|
26556
26758
|
}
|
|
26557
26759
|
function detectEngine(engine) {
|
|
26558
26760
|
const r = spawnSync5(engine, ["--version"], { encoding: "utf-8" });
|
|
@@ -26563,7 +26765,7 @@ function detectEngine(engine) {
|
|
|
26563
26765
|
}
|
|
26564
26766
|
function agentCredentialsMount(agent) {
|
|
26565
26767
|
const rel = agent === "codex" ? ".codex/auth.json" : ".claude/.credentials.json";
|
|
26566
|
-
return { hostPath:
|
|
26768
|
+
return { hostPath: path55.join(os49.homedir(), rel), target: `/home/${RUN_AS_USER}/${rel}` };
|
|
26567
26769
|
}
|
|
26568
26770
|
function buildRunArgs(opts) {
|
|
26569
26771
|
const { config, workspaceHostPath, dataHostPath, allowlistHostPath, agentArgs } = opts;
|
|
@@ -26591,30 +26793,30 @@ function imageContentHash(dockerfile, entrypoint) {
|
|
|
26591
26793
|
return crypto8.createHash("sha256").update(dockerfile).update("\0").update(entrypoint).digest("hex").slice(0, 16);
|
|
26592
26794
|
}
|
|
26593
26795
|
function sandboxBuildDir(cwd = process.cwd()) {
|
|
26594
|
-
return
|
|
26796
|
+
return path55.join(cwd, ".node9", "sandbox", "build");
|
|
26595
26797
|
}
|
|
26596
26798
|
function writeBuildContext(cwd, dockerfile, entrypoint) {
|
|
26597
26799
|
const dir = sandboxBuildDir(cwd);
|
|
26598
26800
|
fs57.mkdirSync(dir, { recursive: true });
|
|
26599
|
-
fs57.writeFileSync(
|
|
26600
|
-
fs57.writeFileSync(
|
|
26801
|
+
fs57.writeFileSync(path55.join(dir, "Dockerfile"), dockerfile);
|
|
26802
|
+
fs57.writeFileSync(path55.join(dir, "entrypoint.sh"), entrypoint);
|
|
26601
26803
|
return dir;
|
|
26602
26804
|
}
|
|
26603
26805
|
function writeAllowlist(cwd, hosts) {
|
|
26604
|
-
const dir =
|
|
26806
|
+
const dir = path55.join(cwd, ".node9", "sandbox");
|
|
26605
26807
|
fs57.mkdirSync(dir, { recursive: true });
|
|
26606
|
-
const p =
|
|
26808
|
+
const p = path55.join(dir, "allowed-domains.txt");
|
|
26607
26809
|
fs57.writeFileSync(p, hosts.join("\n") + "\n");
|
|
26608
26810
|
return p;
|
|
26609
26811
|
}
|
|
26610
26812
|
function resolveHomePath(p) {
|
|
26611
|
-
return p.startsWith("~") ?
|
|
26813
|
+
return p.startsWith("~") ? path55.join(os49.homedir(), p.slice(1)) : path55.resolve(p);
|
|
26612
26814
|
}
|
|
26613
26815
|
|
|
26614
26816
|
// src/cli/commands/sandbox.ts
|
|
26615
26817
|
function seedDataDirConfig(dataDir, sandbox) {
|
|
26616
26818
|
fs58.mkdirSync(dataDir, { recursive: true });
|
|
26617
|
-
const configPath =
|
|
26819
|
+
const configPath = path56.join(dataDir, "config.json");
|
|
26618
26820
|
const seed = {
|
|
26619
26821
|
settings: {
|
|
26620
26822
|
approvers: {
|
|
@@ -26679,7 +26881,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
26679
26881
|
const buildDir = writeBuildContext(cwd, dockerfile, entrypoint);
|
|
26680
26882
|
const hash = imageContentHash(dockerfile, entrypoint);
|
|
26681
26883
|
const image = sandbox.runtime.image;
|
|
26682
|
-
const hashFile =
|
|
26884
|
+
const hashFile = path56.join(sandboxBuildDir(cwd), ".image-hash");
|
|
26683
26885
|
const lastHash = fs58.existsSync(hashFile) ? fs58.readFileSync(hashFile, "utf-8").trim() : "";
|
|
26684
26886
|
const imageExists = spawnSync6(sandbox.runtime.engine, ["image", "inspect", image], { stdio: "ignore" }).status === 0;
|
|
26685
26887
|
const needBuild = sandbox.runtime.rebuild === "always" || !imageExists || sandbox.runtime.rebuild !== "never" && lastHash !== hash;
|
|
@@ -26722,7 +26924,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
26722
26924
|
process.exit(r.status ?? 0);
|
|
26723
26925
|
});
|
|
26724
26926
|
cmd.command("tail").description("Stream the sandbox's audit log (host-side)").action(() => {
|
|
26725
|
-
const auditPath =
|
|
26927
|
+
const auditPath = path56.join(sandboxDataDir(), "audit.log");
|
|
26726
26928
|
if (!fs58.existsSync(auditPath)) {
|
|
26727
26929
|
console.log(chalk28.dim(" no sandbox audit yet."));
|
|
26728
26930
|
return;
|
|
@@ -26730,7 +26932,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
26730
26932
|
spawnSync6("tail", ["-f", auditPath], { stdio: "inherit" });
|
|
26731
26933
|
});
|
|
26732
26934
|
cmd.command("logs").description("Dump the sandbox's audit log").action(() => {
|
|
26733
|
-
const auditPath =
|
|
26935
|
+
const auditPath = path56.join(sandboxDataDir(), "audit.log");
|
|
26734
26936
|
if (!fs58.existsSync(auditPath)) {
|
|
26735
26937
|
console.log(chalk28.dim(" no sandbox audit yet."));
|
|
26736
26938
|
return;
|
|
@@ -26749,7 +26951,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
26749
26951
|
stdio: "ignore"
|
|
26750
26952
|
});
|
|
26751
26953
|
}
|
|
26752
|
-
fs58.rmSync(
|
|
26954
|
+
fs58.rmSync(path56.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
|
|
26753
26955
|
console.log(chalk28.green(" \u2713 sandbox image + build + data removed."));
|
|
26754
26956
|
});
|
|
26755
26957
|
}
|
|
@@ -26761,8 +26963,8 @@ init_cost_gemini();
|
|
|
26761
26963
|
init_cost_codex();
|
|
26762
26964
|
import chalk29 from "chalk";
|
|
26763
26965
|
import fs59 from "fs";
|
|
26764
|
-
import
|
|
26765
|
-
import
|
|
26966
|
+
import path57 from "path";
|
|
26967
|
+
import os50 from "os";
|
|
26766
26968
|
function modelPrice(model) {
|
|
26767
26969
|
const t = pricingFor(model);
|
|
26768
26970
|
if (!t) return null;
|
|
@@ -26779,10 +26981,10 @@ function encodeProjectPath(projectPath) {
|
|
|
26779
26981
|
}
|
|
26780
26982
|
function sessionJsonlPath(projectPath, sessionId) {
|
|
26781
26983
|
const encoded = encodeProjectPath(projectPath);
|
|
26782
|
-
return
|
|
26984
|
+
return path57.join(os50.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
|
|
26783
26985
|
}
|
|
26784
26986
|
function projectLabel(projectPath) {
|
|
26785
|
-
return projectPath.replace(
|
|
26987
|
+
return projectPath.replace(os50.homedir(), "~");
|
|
26786
26988
|
}
|
|
26787
26989
|
function parseHistoryLines(lines) {
|
|
26788
26990
|
const entries = [];
|
|
@@ -26851,7 +27053,7 @@ function parseSessionLines(lines) {
|
|
|
26851
27053
|
return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
|
|
26852
27054
|
}
|
|
26853
27055
|
function loadAuditEntries(auditPath) {
|
|
26854
|
-
const aPath = auditPath ??
|
|
27056
|
+
const aPath = auditPath ?? path57.join(os50.homedir(), ".node9", "audit.log");
|
|
26855
27057
|
let raw;
|
|
26856
27058
|
try {
|
|
26857
27059
|
raw = fs59.readFileSync(aPath, "utf-8");
|
|
@@ -26890,7 +27092,7 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
26890
27092
|
return result;
|
|
26891
27093
|
}
|
|
26892
27094
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
26893
|
-
const tmpDir =
|
|
27095
|
+
const tmpDir = path57.join(os50.homedir(), ".gemini", "tmp");
|
|
26894
27096
|
if (!fs59.existsSync(tmpDir)) return [];
|
|
26895
27097
|
const cutoff = days !== null ? (() => {
|
|
26896
27098
|
const d = /* @__PURE__ */ new Date();
|
|
@@ -26906,18 +27108,18 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
26906
27108
|
}
|
|
26907
27109
|
const summaries = [];
|
|
26908
27110
|
for (const slug2 of slugDirs) {
|
|
26909
|
-
const slugPath =
|
|
27111
|
+
const slugPath = path57.join(tmpDir, slug2);
|
|
26910
27112
|
try {
|
|
26911
27113
|
if (!fs59.statSync(slugPath).isDirectory()) continue;
|
|
26912
27114
|
} catch {
|
|
26913
27115
|
continue;
|
|
26914
27116
|
}
|
|
26915
|
-
let projectRoot =
|
|
27117
|
+
let projectRoot = path57.join(os50.homedir(), slug2);
|
|
26916
27118
|
try {
|
|
26917
|
-
projectRoot = fs59.readFileSync(
|
|
27119
|
+
projectRoot = fs59.readFileSync(path57.join(slugPath, ".project_root"), "utf-8").trim();
|
|
26918
27120
|
} catch {
|
|
26919
27121
|
}
|
|
26920
|
-
const chatsDir =
|
|
27122
|
+
const chatsDir = path57.join(slugPath, "chats");
|
|
26921
27123
|
if (!fs59.existsSync(chatsDir)) continue;
|
|
26922
27124
|
let chatFiles;
|
|
26923
27125
|
try {
|
|
@@ -26928,7 +27130,7 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
26928
27130
|
for (const chatFile of chatFiles) {
|
|
26929
27131
|
let raw;
|
|
26930
27132
|
try {
|
|
26931
|
-
raw = fs59.readFileSync(
|
|
27133
|
+
raw = fs59.readFileSync(path57.join(chatsDir, chatFile), "utf-8");
|
|
26932
27134
|
} catch {
|
|
26933
27135
|
continue;
|
|
26934
27136
|
}
|
|
@@ -27008,7 +27210,7 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
27008
27210
|
return summaries;
|
|
27009
27211
|
}
|
|
27010
27212
|
function buildCodexSessions(days, allAuditEntries) {
|
|
27011
|
-
const sessionsBase =
|
|
27213
|
+
const sessionsBase = path57.join(os50.homedir(), ".codex", "sessions");
|
|
27012
27214
|
if (!fs59.existsSync(sessionsBase)) return [];
|
|
27013
27215
|
const cutoff = days !== null ? (() => {
|
|
27014
27216
|
const d = /* @__PURE__ */ new Date();
|
|
@@ -27019,28 +27221,28 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
27019
27221
|
const jsonlFiles = [];
|
|
27020
27222
|
try {
|
|
27021
27223
|
for (const year of fs59.readdirSync(sessionsBase)) {
|
|
27022
|
-
const yearPath =
|
|
27224
|
+
const yearPath = path57.join(sessionsBase, year);
|
|
27023
27225
|
try {
|
|
27024
27226
|
if (!fs59.statSync(yearPath).isDirectory()) continue;
|
|
27025
27227
|
} catch {
|
|
27026
27228
|
continue;
|
|
27027
27229
|
}
|
|
27028
27230
|
for (const month of fs59.readdirSync(yearPath)) {
|
|
27029
|
-
const monthPath =
|
|
27231
|
+
const monthPath = path57.join(yearPath, month);
|
|
27030
27232
|
try {
|
|
27031
27233
|
if (!fs59.statSync(monthPath).isDirectory()) continue;
|
|
27032
27234
|
} catch {
|
|
27033
27235
|
continue;
|
|
27034
27236
|
}
|
|
27035
27237
|
for (const day of fs59.readdirSync(monthPath)) {
|
|
27036
|
-
const dayPath =
|
|
27238
|
+
const dayPath = path57.join(monthPath, day);
|
|
27037
27239
|
try {
|
|
27038
27240
|
if (!fs59.statSync(dayPath).isDirectory()) continue;
|
|
27039
27241
|
} catch {
|
|
27040
27242
|
continue;
|
|
27041
27243
|
}
|
|
27042
27244
|
for (const file of fs59.readdirSync(dayPath)) {
|
|
27043
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
27245
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(path57.join(dayPath, file));
|
|
27044
27246
|
}
|
|
27045
27247
|
}
|
|
27046
27248
|
}
|
|
@@ -27138,7 +27340,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
27138
27340
|
return summaries;
|
|
27139
27341
|
}
|
|
27140
27342
|
function buildSessions(days, historyPath) {
|
|
27141
|
-
const hPath = historyPath ??
|
|
27343
|
+
const hPath = historyPath ?? path57.join(os50.homedir(), ".claude", "history.jsonl");
|
|
27142
27344
|
let historyRaw = "";
|
|
27143
27345
|
try {
|
|
27144
27346
|
historyRaw = fs59.readFileSync(hPath, "utf-8");
|
|
@@ -27560,11 +27762,11 @@ function registerSessionTaintCommand(program2) {
|
|
|
27560
27762
|
// src/cli/commands/skill-pin.ts
|
|
27561
27763
|
import chalk31 from "chalk";
|
|
27562
27764
|
import fs60 from "fs";
|
|
27563
|
-
import
|
|
27564
|
-
import
|
|
27765
|
+
import os51 from "os";
|
|
27766
|
+
import path58 from "path";
|
|
27565
27767
|
function wipeSkillSessions() {
|
|
27566
27768
|
try {
|
|
27567
|
-
fs60.rmSync(
|
|
27769
|
+
fs60.rmSync(path58.join(os51.homedir(), ".node9", "skill-sessions"), {
|
|
27568
27770
|
recursive: true,
|
|
27569
27771
|
force: true
|
|
27570
27772
|
});
|
|
@@ -27647,10 +27849,10 @@ function registerSkillPinCommand(program2) {
|
|
|
27647
27849
|
|
|
27648
27850
|
// src/cli/commands/decisions.ts
|
|
27649
27851
|
import fs61 from "fs";
|
|
27650
|
-
import
|
|
27651
|
-
import
|
|
27852
|
+
import os52 from "os";
|
|
27853
|
+
import path59 from "path";
|
|
27652
27854
|
import chalk32 from "chalk";
|
|
27653
|
-
var DECISIONS_FILE2 =
|
|
27855
|
+
var DECISIONS_FILE2 = path59.join(os52.homedir(), ".node9", "decisions.json");
|
|
27654
27856
|
function readDecisions() {
|
|
27655
27857
|
try {
|
|
27656
27858
|
if (!fs61.existsSync(DECISIONS_FILE2)) return {};
|
|
@@ -27666,7 +27868,7 @@ function readDecisions() {
|
|
|
27666
27868
|
}
|
|
27667
27869
|
}
|
|
27668
27870
|
function writeDecisions(d) {
|
|
27669
|
-
const dir =
|
|
27871
|
+
const dir = path59.dirname(DECISIONS_FILE2);
|
|
27670
27872
|
if (!fs61.existsSync(dir)) fs61.mkdirSync(dir, { recursive: true });
|
|
27671
27873
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
27672
27874
|
fs61.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
@@ -27728,10 +27930,10 @@ Persistent decisions (${entries.length})
|
|
|
27728
27930
|
// src/cli/commands/dlp.ts
|
|
27729
27931
|
import chalk33 from "chalk";
|
|
27730
27932
|
import fs62 from "fs";
|
|
27731
|
-
import
|
|
27732
|
-
import
|
|
27733
|
-
var AUDIT_LOG =
|
|
27734
|
-
var RESOLVED_FILE =
|
|
27933
|
+
import path60 from "path";
|
|
27934
|
+
import os53 from "os";
|
|
27935
|
+
var AUDIT_LOG = path60.join(os53.homedir(), ".node9", "audit.log");
|
|
27936
|
+
var RESOLVED_FILE = path60.join(os53.homedir(), ".node9", "dlp-resolved.json");
|
|
27735
27937
|
var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
|
|
27736
27938
|
function stripAnsi(s) {
|
|
27737
27939
|
return s.replace(ANSI_RE, "");
|
|
@@ -27852,13 +28054,13 @@ function registerDlpCommand(program2) {
|
|
|
27852
28054
|
init_dlp();
|
|
27853
28055
|
import chalk34 from "chalk";
|
|
27854
28056
|
import fs63 from "fs";
|
|
27855
|
-
import
|
|
27856
|
-
import
|
|
28057
|
+
import path61 from "path";
|
|
28058
|
+
import os54 from "os";
|
|
27857
28059
|
function findJsonlFiles(dir) {
|
|
27858
28060
|
const results = [];
|
|
27859
28061
|
if (!fs63.existsSync(dir)) return results;
|
|
27860
28062
|
for (const entry of fs63.readdirSync(dir, { withFileTypes: true })) {
|
|
27861
|
-
const full =
|
|
28063
|
+
const full = path61.join(dir, entry.name);
|
|
27862
28064
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
27863
28065
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
27864
28066
|
}
|
|
@@ -27961,7 +28163,7 @@ function findJsonFiles(dir) {
|
|
|
27961
28163
|
const results = [];
|
|
27962
28164
|
if (!fs63.existsSync(dir)) return results;
|
|
27963
28165
|
for (const entry of fs63.readdirSync(dir, { withFileTypes: true })) {
|
|
27964
|
-
const full =
|
|
28166
|
+
const full = path61.join(dir, entry.name);
|
|
27965
28167
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
27966
28168
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
27967
28169
|
}
|
|
@@ -27970,9 +28172,9 @@ function findJsonFiles(dir) {
|
|
|
27970
28172
|
function registerMaskCommand(program2) {
|
|
27971
28173
|
program2.command("mask").description("Redact plaintext secrets from local AI session history files").option("--dry-run", "show what would be redacted without making changes").option("--all", "scan all history (default: last 30 days)").action(async (options) => {
|
|
27972
28174
|
const dryRun = !!options.dryRun;
|
|
27973
|
-
const home =
|
|
27974
|
-
const claudeDir =
|
|
27975
|
-
const geminiDir =
|
|
28175
|
+
const home = os54.homedir();
|
|
28176
|
+
const claudeDir = path61.join(home, ".claude", "projects");
|
|
28177
|
+
const geminiDir = path61.join(home, ".gemini", "tmp");
|
|
27976
28178
|
const allFiles = [
|
|
27977
28179
|
...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
|
|
27978
28180
|
...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
|
|
@@ -28036,15 +28238,15 @@ function registerMaskCommand(program2) {
|
|
|
28036
28238
|
// src/cli.ts
|
|
28037
28239
|
init_blast();
|
|
28038
28240
|
var { version } = JSON.parse(
|
|
28039
|
-
fs66.readFileSync(
|
|
28241
|
+
fs66.readFileSync(path64.join(__dirname, "../package.json"), "utf-8")
|
|
28040
28242
|
);
|
|
28041
28243
|
var program = new Command();
|
|
28042
28244
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
28043
28245
|
program.command("login").argument("<apiKey>").option("--local", "Save key for audit/logging only \u2014 local config still controls all decisions").option("--profile <name>", 'Save as a named profile (default: "default")').action((apiKey, options) => {
|
|
28044
28246
|
const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
|
|
28045
|
-
const credPath =
|
|
28046
|
-
if (!fs66.existsSync(
|
|
28047
|
-
fs66.mkdirSync(
|
|
28247
|
+
const credPath = path64.join(os57.homedir(), ".node9", "credentials.json");
|
|
28248
|
+
if (!fs66.existsSync(path64.dirname(credPath)))
|
|
28249
|
+
fs66.mkdirSync(path64.dirname(credPath), { recursive: true });
|
|
28048
28250
|
const profileName = options.profile || "default";
|
|
28049
28251
|
let existingCreds = {};
|
|
28050
28252
|
try {
|
|
@@ -28064,7 +28266,7 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
28064
28266
|
fs66.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
|
|
28065
28267
|
let effectiveCloud = null;
|
|
28066
28268
|
if (profileName === "default") {
|
|
28067
|
-
const configPath =
|
|
28269
|
+
const configPath = path64.join(os57.homedir(), ".node9", "config.json");
|
|
28068
28270
|
let config = {};
|
|
28069
28271
|
try {
|
|
28070
28272
|
if (fs66.existsSync(configPath))
|
|
@@ -28083,8 +28285,8 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
28083
28285
|
approvers.cloud = false;
|
|
28084
28286
|
}
|
|
28085
28287
|
s.approvers = approvers;
|
|
28086
|
-
if (!fs66.existsSync(
|
|
28087
|
-
fs66.mkdirSync(
|
|
28288
|
+
if (!fs66.existsSync(path64.dirname(configPath)))
|
|
28289
|
+
fs66.mkdirSync(path64.dirname(configPath), { recursive: true });
|
|
28088
28290
|
fs66.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
28089
28291
|
effectiveCloud = approvers.cloud === true;
|
|
28090
28292
|
}
|
|
@@ -28194,37 +28396,21 @@ program.command("setup", { hidden: true }).description('Alias for "addto" \u2014
|
|
|
28194
28396
|
);
|
|
28195
28397
|
process.exit(1);
|
|
28196
28398
|
});
|
|
28197
|
-
program.command("removefrom", { hidden: true }).description("Remove Node9 hooks from an AI agent configuration").addHelpText(
|
|
28198
|
-
"
|
|
28199
|
-
|
|
28200
|
-
)
|
|
28201
|
-
"<target>",
|
|
28202
|
-
"The agent to remove from: claude | antigravity | copilot | gemini | cursor | codex | windsurf | vscode | hud"
|
|
28203
|
-
).action((target) => {
|
|
28204
|
-
let fn;
|
|
28205
|
-
if (target === "claude") fn = teardownClaude;
|
|
28206
|
-
else if (target === "gemini") fn = teardownGemini;
|
|
28207
|
-
else if (target === "antigravity" || target === "agy") fn = teardownAntigravity;
|
|
28208
|
-
else if (target === "copilot") fn = teardownCopilot;
|
|
28209
|
-
else if (target === "cursor") fn = teardownCursor;
|
|
28210
|
-
else if (target === "codex") fn = teardownCodex;
|
|
28211
|
-
else if (target === "windsurf") fn = teardownWindsurf;
|
|
28212
|
-
else if (target === "vscode") fn = teardownVSCode;
|
|
28213
|
-
else if (target === "hermes") fn = teardownHermes;
|
|
28214
|
-
else if (target === "hud") fn = teardownHud;
|
|
28215
|
-
else {
|
|
28399
|
+
program.command("removefrom", { hidden: true }).description("Remove Node9 hooks from an AI agent configuration").addHelpText("after", `
|
|
28400
|
+
Supported targets: ${agentTeardownTargets().join(" ")}`).argument("<target>", `The agent to remove from: ${agentTeardownTargets().join(" | ")}`).action((target) => {
|
|
28401
|
+
const agent = resolveAgentTeardown(target);
|
|
28402
|
+
if (!agent) {
|
|
28216
28403
|
console.error(
|
|
28217
|
-
chalk36.red(
|
|
28218
|
-
`Unknown target: "${target}". Supported: claude, antigravity, copilot, gemini, cursor, codex, windsurf, vscode, hermes, hud`
|
|
28219
|
-
)
|
|
28404
|
+
chalk36.red(`Unknown target: "${target}". Supported: ${agentTeardownTargets().join(", ")}`)
|
|
28220
28405
|
);
|
|
28221
28406
|
process.exit(1);
|
|
28407
|
+
return;
|
|
28222
28408
|
}
|
|
28223
28409
|
console.log(chalk36.cyan(`
|
|
28224
|
-
\u{1F6E1}\uFE0F Node9: removing hooks from ${
|
|
28410
|
+
\u{1F6E1}\uFE0F Node9: removing hooks from ${agent.label}...
|
|
28225
28411
|
`));
|
|
28226
28412
|
try {
|
|
28227
|
-
fn();
|
|
28413
|
+
agent.fn();
|
|
28228
28414
|
} catch (err2) {
|
|
28229
28415
|
console.error(chalk36.red(` \u26A0\uFE0F Failed: ${err2 instanceof Error ? err2.message : String(err2)}`));
|
|
28230
28416
|
process.exit(1);
|
|
@@ -28242,15 +28428,7 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
28242
28428
|
}
|
|
28243
28429
|
console.log(chalk36.bold("\nRemoving hooks..."));
|
|
28244
28430
|
let teardownFailed = false;
|
|
28245
|
-
for (const
|
|
28246
|
-
["Claude", teardownClaude],
|
|
28247
|
-
["Gemini", teardownGemini],
|
|
28248
|
-
["Cursor", teardownCursor],
|
|
28249
|
-
["Codex", teardownCodex],
|
|
28250
|
-
["Windsurf", teardownWindsurf],
|
|
28251
|
-
["VSCode", teardownVSCode],
|
|
28252
|
-
["Hermes", teardownHermes]
|
|
28253
|
-
]) {
|
|
28431
|
+
for (const { label: label2, fn } of AGENT_TEARDOWNS) {
|
|
28254
28432
|
try {
|
|
28255
28433
|
fn();
|
|
28256
28434
|
} catch (err2) {
|
|
@@ -28262,8 +28440,21 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
28262
28440
|
);
|
|
28263
28441
|
}
|
|
28264
28442
|
}
|
|
28443
|
+
try {
|
|
28444
|
+
const residual = getAgentWiring().filter((a) => a.wireState === "wired");
|
|
28445
|
+
if (residual.length === 0) {
|
|
28446
|
+
console.log(chalk36.green(" \u2705 Verified \u2014 no node9 hooks or plugin shims remain"));
|
|
28447
|
+
} else {
|
|
28448
|
+
teardownFailed = true;
|
|
28449
|
+
console.error(chalk36.red(" \u26A0\uFE0F Still wired after teardown:"));
|
|
28450
|
+
for (const a of residual) {
|
|
28451
|
+
console.error(chalk36.red(` \u2022 ${a.label} \u2014 ${a.settingsPath}`));
|
|
28452
|
+
}
|
|
28453
|
+
}
|
|
28454
|
+
} catch {
|
|
28455
|
+
}
|
|
28265
28456
|
if (options.purge) {
|
|
28266
|
-
const node9Dir =
|
|
28457
|
+
const node9Dir = path64.join(os57.homedir(), ".node9");
|
|
28267
28458
|
if (fs66.existsSync(node9Dir)) {
|
|
28268
28459
|
const confirmed = await confirm2({
|
|
28269
28460
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
@@ -28394,7 +28585,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
|
|
|
28394
28585
|
});
|
|
28395
28586
|
program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
|
|
28396
28587
|
try {
|
|
28397
|
-
const dashboardPath =
|
|
28588
|
+
const dashboardPath = path64.join(__dirname, "dashboard.mjs");
|
|
28398
28589
|
const dynamicImport = new Function("id", "return import(id)");
|
|
28399
28590
|
const mod = await dynamicImport(`file://${dashboardPath}`);
|
|
28400
28591
|
await mod.startMonitor();
|
|
@@ -28432,9 +28623,9 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
|
|
|
28432
28623
|
Run "node9 addto claude" to register it as the statusLine.`
|
|
28433
28624
|
).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
|
|
28434
28625
|
if (subcommand === "debug") {
|
|
28435
|
-
const flagFile =
|
|
28626
|
+
const flagFile = path64.join(os57.homedir(), ".node9", "hud-debug");
|
|
28436
28627
|
if (state === "on") {
|
|
28437
|
-
fs66.mkdirSync(
|
|
28628
|
+
fs66.mkdirSync(path64.dirname(flagFile), { recursive: true });
|
|
28438
28629
|
fs66.writeFileSync(flagFile, "");
|
|
28439
28630
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
28440
28631
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
@@ -28561,7 +28752,7 @@ if (process.argv[2] !== "daemon") {
|
|
|
28561
28752
|
const isCheckHook = process.argv[2] === "check";
|
|
28562
28753
|
if (isCheckHook) {
|
|
28563
28754
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
28564
|
-
const logPath =
|
|
28755
|
+
const logPath = path64.join(os57.homedir(), ".node9", "hook-debug.log");
|
|
28565
28756
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
28566
28757
|
fs66.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
28567
28758
|
`);
|