@node9/proxy 1.45.0 → 1.47.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 +996 -795
- package/dist/cli.mjs +971 -771
- package/dist/dashboard.mjs +5 -0
- package/dist/index.js +20 -1
- package/dist/index.mjs +20 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -240,8 +240,8 @@ function sanitizeConfig(raw) {
|
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
242
|
const lines = result.error.issues.map((issue) => {
|
|
243
|
-
const
|
|
244
|
-
return ` \u2022 ${
|
|
243
|
+
const path65 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
244
|
+
return ` \u2022 ${path65}: ${issue.message}`;
|
|
245
245
|
});
|
|
246
246
|
return {
|
|
247
247
|
sanitized,
|
|
@@ -337,6 +337,11 @@ var init_config_schema = __esm({
|
|
|
337
337
|
// must run them from the CLI. node9's threat model is the agent itself.
|
|
338
338
|
mcpAllowWeakening: import_zod.z.boolean().optional(),
|
|
339
339
|
cloudSyncIntervalHours: import_zod.z.number().positive().optional(),
|
|
340
|
+
// Seconds-granular override for the cloud policy sync cadence. Wins over
|
|
341
|
+
// cloudSyncIntervalHours when set. Lets you opt into fast apply (e.g. 20)
|
|
342
|
+
// for an incident; clamped to a 15s floor so it can't hammer the API.
|
|
343
|
+
// Unset → falls back to hours, then the 5h default.
|
|
344
|
+
cloudSyncIntervalSeconds: import_zod.z.number().positive().optional(),
|
|
340
345
|
// Outbox shipper (audit.log → SaaS batch ingest). enabled defaults
|
|
341
346
|
// to true; set false to fall back to local-only auditing.
|
|
342
347
|
shipper: import_zod.z.object({
|
|
@@ -1357,9 +1362,9 @@ function matchesPattern(text, patterns) {
|
|
|
1357
1362
|
const withoutDotSlash = text.replace(/^\.\//, "");
|
|
1358
1363
|
return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
|
|
1359
1364
|
}
|
|
1360
|
-
function getNestedValue(obj,
|
|
1365
|
+
function getNestedValue(obj, path65) {
|
|
1361
1366
|
if (!obj || typeof obj !== "object") return null;
|
|
1362
|
-
const segments =
|
|
1367
|
+
const segments = path65.split(".");
|
|
1363
1368
|
for (const seg of segments) {
|
|
1364
1369
|
if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
|
|
1365
1370
|
}
|
|
@@ -1412,6 +1417,14 @@ function evaluateSmartConditions(args, rule) {
|
|
|
1412
1417
|
});
|
|
1413
1418
|
return mode === "any" ? results.some((r) => r) : results.every((r) => r);
|
|
1414
1419
|
}
|
|
1420
|
+
function resolvePinned(matches) {
|
|
1421
|
+
if (matches.length === 0) return void 0;
|
|
1422
|
+
const pinned = matches.filter((r) => r.pinned);
|
|
1423
|
+
if (pinned.length === 0) return matches[0];
|
|
1424
|
+
return pinned.reduce(
|
|
1425
|
+
(best, r) => VERDICT_RANK[r.verdict] > VERDICT_RANK[best.verdict] ? r : best
|
|
1426
|
+
);
|
|
1427
|
+
}
|
|
1415
1428
|
function tokenize2(toolName) {
|
|
1416
1429
|
return toolName.toLowerCase().split(/[_.\-\s]+/).filter(Boolean);
|
|
1417
1430
|
}
|
|
@@ -1523,9 +1536,10 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
|
|
|
1523
1536
|
}
|
|
1524
1537
|
}
|
|
1525
1538
|
if (config.policy.smartRules.length > 0) {
|
|
1526
|
-
const
|
|
1539
|
+
const matches = config.policy.smartRules.filter(
|
|
1527
1540
|
(rule) => matchesPattern(toolName, rule.tool) && !(bashCommand !== null && rule.name && AST_FS_REGEX_RULES.has(rule.name)) && evaluateSmartConditions(args, rule)
|
|
1528
1541
|
);
|
|
1542
|
+
const matchedRule = resolvePinned(matches);
|
|
1529
1543
|
if (matchedRule) {
|
|
1530
1544
|
if (matchedRule.verdict === "allow")
|
|
1531
1545
|
return { decision: "allow", ruleName: matchedRule.name ?? matchedRule.tool };
|
|
@@ -2264,7 +2278,7 @@ function* stringValues(obj, depth = 0) {
|
|
|
2264
2278
|
}
|
|
2265
2279
|
for (const v of Object.values(obj)) yield* stringValues(v, depth + 1);
|
|
2266
2280
|
}
|
|
2267
|
-
var import_safe_regex2, import_mvdan_sh, import_picomatch, import_safe_regex22, import_safe_regex23, import_crypto3, 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;
|
|
2281
|
+
var import_safe_regex2, import_mvdan_sh, import_picomatch, import_safe_regex22, import_safe_regex23, import_crypto3, 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;
|
|
2268
2282
|
var init_dist = __esm({
|
|
2269
2283
|
"packages/policy-engine/dist/index.mjs"() {
|
|
2270
2284
|
"use strict";
|
|
@@ -3195,6 +3209,11 @@ var init_dist = __esm({
|
|
|
3195
3209
|
REGEX_CACHE_MAX = 500;
|
|
3196
3210
|
regexCache = /* @__PURE__ */ new Map();
|
|
3197
3211
|
FORBIDDEN_PATH_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
3212
|
+
VERDICT_RANK = {
|
|
3213
|
+
allow: 0,
|
|
3214
|
+
review: 1,
|
|
3215
|
+
block: 2
|
|
3216
|
+
};
|
|
3198
3217
|
SQL_DML_KEYWORDS = /* @__PURE__ */ new Set(["select", "insert", "update", "delete", "merge", "upsert"]);
|
|
3199
3218
|
aws_default = {
|
|
3200
3219
|
name: "aws",
|
|
@@ -3999,6 +4018,7 @@ var init_dist = __esm({
|
|
|
3999
4018
|
DEDUPE_PREVIEW_LEN = 120;
|
|
4000
4019
|
TERMINAL_ESCAPE_RE = // eslint-disable-next-line no-control-regex
|
|
4001
4020
|
/\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
4021
|
+
ENGINE_VERSION = "1.4.0";
|
|
4002
4022
|
}
|
|
4003
4023
|
});
|
|
4004
4024
|
|
|
@@ -9725,13 +9745,234 @@ var init_setup = __esm({
|
|
|
9725
9745
|
}
|
|
9726
9746
|
});
|
|
9727
9747
|
|
|
9748
|
+
// src/agent-wiring.ts
|
|
9749
|
+
function readJson2(filePath) {
|
|
9750
|
+
if (!import_fs14.default.existsSync(filePath)) return null;
|
|
9751
|
+
try {
|
|
9752
|
+
return JSON.parse(import_fs14.default.readFileSync(filePath, "utf-8"));
|
|
9753
|
+
} catch {
|
|
9754
|
+
return "invalid";
|
|
9755
|
+
}
|
|
9756
|
+
}
|
|
9757
|
+
function matchersHaveNode9Hook(matchers) {
|
|
9758
|
+
return (matchers ?? []).some((m) => (m.hooks ?? []).some((h) => isNode9Hook(h.command)));
|
|
9759
|
+
}
|
|
9760
|
+
function flatHaveNode9Hook(entries) {
|
|
9761
|
+
return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
|
|
9762
|
+
}
|
|
9763
|
+
function readHookRoot(filePath, format) {
|
|
9764
|
+
if (!import_fs14.default.existsSync(filePath)) return "absent";
|
|
9765
|
+
let raw;
|
|
9766
|
+
try {
|
|
9767
|
+
raw = import_fs14.default.readFileSync(filePath, "utf-8");
|
|
9768
|
+
} catch {
|
|
9769
|
+
return "absent";
|
|
9770
|
+
}
|
|
9771
|
+
try {
|
|
9772
|
+
const parsed = format === "yaml" ? yaml2.parse(raw) : JSON.parse(raw);
|
|
9773
|
+
return parsed?.hooks ?? {};
|
|
9774
|
+
} catch {
|
|
9775
|
+
return "invalid";
|
|
9776
|
+
}
|
|
9777
|
+
}
|
|
9778
|
+
function eventWired(root, ev, format) {
|
|
9779
|
+
const arr = root[ev.key];
|
|
9780
|
+
if (format === "matcher") return matchersHaveNode9Hook(arr);
|
|
9781
|
+
return flatHaveNode9Hook(arr);
|
|
9782
|
+
}
|
|
9783
|
+
function detectMcp(servers) {
|
|
9784
|
+
const entries = Object.entries(servers ?? {});
|
|
9785
|
+
const present = entries.some(([, s]) => s?.command === "node9");
|
|
9786
|
+
const wrapped = entries.filter(([, s]) => s?.command === "node9" && Array.isArray(s.args) && s.args.length > 0).map(([name, s]) => `${name} \u2192 ${s.args.join(" ")}`);
|
|
9787
|
+
return { wrapped, present };
|
|
9788
|
+
}
|
|
9789
|
+
function readMcp(filePath, format) {
|
|
9790
|
+
if (!import_fs14.default.existsSync(filePath)) return { wrapped: [], present: false };
|
|
9791
|
+
try {
|
|
9792
|
+
if (format === "toml") {
|
|
9793
|
+
const parsed2 = (0, import_smol_toml2.parse)(import_fs14.default.readFileSync(filePath, "utf-8"));
|
|
9794
|
+
return detectMcp(parsed2?.mcp_servers);
|
|
9795
|
+
}
|
|
9796
|
+
const parsed = readJson2(filePath);
|
|
9797
|
+
if (parsed === null || parsed === "invalid") return { wrapped: [], present: false };
|
|
9798
|
+
return detectMcp(parsed.mcpServers);
|
|
9799
|
+
} catch {
|
|
9800
|
+
return { wrapped: [], present: false };
|
|
9801
|
+
}
|
|
9802
|
+
}
|
|
9803
|
+
function getAgentWiring(home = import_os13.default.homedir()) {
|
|
9804
|
+
const detected = detectAgents(home);
|
|
9805
|
+
return AGENT_SPECS.map((spec) => {
|
|
9806
|
+
const present = spec.present(home);
|
|
9807
|
+
const pad = spec.labelPad ?? DEFAULT_LABEL_PAD;
|
|
9808
|
+
let hooks;
|
|
9809
|
+
let wireState;
|
|
9810
|
+
let hookLabel;
|
|
9811
|
+
let settingsPath;
|
|
9812
|
+
if (spec.shimFile) {
|
|
9813
|
+
const shimWired = exists(spec.shimFile(home));
|
|
9814
|
+
hooks = [{ label: "node9 plugin (node9 check)", wired: shimWired }];
|
|
9815
|
+
wireState = shimWired ? "wired" : present ? "unwired" : "absent";
|
|
9816
|
+
hookLabel = "node9 plugin";
|
|
9817
|
+
settingsPath = spec.shimFile(home);
|
|
9818
|
+
} else {
|
|
9819
|
+
const root = spec.hookFile ? readHookRoot(spec.hookFile(home), spec.hookFormat) : "absent";
|
|
9820
|
+
const primary = spec.hookEvents[0];
|
|
9821
|
+
const rootPresent = root !== "absent" && root !== "invalid";
|
|
9822
|
+
hooks = spec.hookEvents.map((ev) => ({
|
|
9823
|
+
label: hookLabelOf(ev, pad),
|
|
9824
|
+
wired: rootPresent && eventWired(root, ev, spec.hookFormat)
|
|
9825
|
+
}));
|
|
9826
|
+
if (root === "absent") wireState = "absent";
|
|
9827
|
+
else if (root === "invalid") wireState = "invalid";
|
|
9828
|
+
else wireState = primary && eventWired(root, primary, spec.hookFormat) ? "wired" : "unwired";
|
|
9829
|
+
hookLabel = primary ? `${primary.key} hook` : "MCP proxy";
|
|
9830
|
+
settingsPath = spec.hookFile ? spec.hookFile(home) : spec.mcpFile ? spec.mcpFile(home) : "";
|
|
9831
|
+
}
|
|
9832
|
+
const mcp = spec.mcpFile ? readMcp(spec.mcpFile(home), spec.mcpFormat ?? "json") : null;
|
|
9833
|
+
const anyHookWired = hooks.some((h) => h.wired);
|
|
9834
|
+
return {
|
|
9835
|
+
id: spec.id,
|
|
9836
|
+
label: spec.label,
|
|
9837
|
+
setupCommand: spec.setupCommand,
|
|
9838
|
+
installed: detected[spec.id],
|
|
9839
|
+
present,
|
|
9840
|
+
hooks,
|
|
9841
|
+
wireState,
|
|
9842
|
+
hookLabel,
|
|
9843
|
+
settingsPath,
|
|
9844
|
+
configFormat: spec.hookFormat === "yaml" ? "YAML" : "JSON",
|
|
9845
|
+
mcpServers: mcp ? mcp.wrapped : null,
|
|
9846
|
+
mcpProtected: mcp ? mcp.present : false,
|
|
9847
|
+
isProtected: anyHookWired || (mcp?.present ?? false)
|
|
9848
|
+
};
|
|
9849
|
+
});
|
|
9850
|
+
}
|
|
9851
|
+
var import_fs14, import_path16, import_os13, yaml2, import_smol_toml2, exists, ck, lg, DEFAULT_LABEL_PAD, hookLabelOf, AGENT_SPECS;
|
|
9852
|
+
var init_agent_wiring = __esm({
|
|
9853
|
+
"src/agent-wiring.ts"() {
|
|
9854
|
+
"use strict";
|
|
9855
|
+
import_fs14 = __toESM(require("fs"));
|
|
9856
|
+
import_path16 = __toESM(require("path"));
|
|
9857
|
+
import_os13 = __toESM(require("os"));
|
|
9858
|
+
yaml2 = __toESM(require("yaml"));
|
|
9859
|
+
import_smol_toml2 = require("smol-toml");
|
|
9860
|
+
init_setup();
|
|
9861
|
+
exists = (p) => {
|
|
9862
|
+
try {
|
|
9863
|
+
return import_fs14.default.existsSync(p);
|
|
9864
|
+
} catch {
|
|
9865
|
+
return false;
|
|
9866
|
+
}
|
|
9867
|
+
};
|
|
9868
|
+
ck = (key) => ({ key, kind: "check" });
|
|
9869
|
+
lg = (key) => ({ key, kind: "log" });
|
|
9870
|
+
DEFAULT_LABEL_PAD = 11;
|
|
9871
|
+
hookLabelOf = (ev, pad) => `${ev.key.padEnd(pad)} (node9 ${ev.kind})`;
|
|
9872
|
+
AGENT_SPECS = [
|
|
9873
|
+
{
|
|
9874
|
+
id: "claude",
|
|
9875
|
+
label: "Claude Code",
|
|
9876
|
+
setupCommand: "node9 agents add claude",
|
|
9877
|
+
hookFile: (h) => import_path16.default.join(h, ".claude", "settings.json"),
|
|
9878
|
+
hookFormat: "matcher",
|
|
9879
|
+
hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
|
|
9880
|
+
mcpFile: (h) => import_path16.default.join(h, ".claude.json"),
|
|
9881
|
+
present: (h) => exists(import_path16.default.join(h, ".claude", "settings.json")) || exists(import_path16.default.join(h, ".claude.json"))
|
|
9882
|
+
},
|
|
9883
|
+
{
|
|
9884
|
+
id: "gemini",
|
|
9885
|
+
label: "Gemini CLI",
|
|
9886
|
+
setupCommand: "node9 agents add gemini",
|
|
9887
|
+
hookFile: (h) => import_path16.default.join(h, ".gemini", "settings.json"),
|
|
9888
|
+
hookFormat: "matcher",
|
|
9889
|
+
hookEvents: [ck("BeforeTool"), lg("AfterTool")],
|
|
9890
|
+
mcpFile: (h) => import_path16.default.join(h, ".gemini", "settings.json"),
|
|
9891
|
+
present: (h) => exists(import_path16.default.join(h, ".gemini", "settings.json"))
|
|
9892
|
+
},
|
|
9893
|
+
{
|
|
9894
|
+
id: "codex",
|
|
9895
|
+
label: "Codex",
|
|
9896
|
+
setupCommand: "node9 agents add codex",
|
|
9897
|
+
hookFile: (h) => import_path16.default.join(h, ".codex", "hooks.json"),
|
|
9898
|
+
hookFormat: "matcher",
|
|
9899
|
+
hookEvents: [ck("PreToolUse"), ck("UserPromptSubmit")],
|
|
9900
|
+
mcpFile: (h) => import_path16.default.join(h, ".codex", "config.toml"),
|
|
9901
|
+
mcpFormat: "toml",
|
|
9902
|
+
present: (h) => exists(import_path16.default.join(h, ".codex"))
|
|
9903
|
+
},
|
|
9904
|
+
{
|
|
9905
|
+
id: "antigravity",
|
|
9906
|
+
label: "Antigravity",
|
|
9907
|
+
setupCommand: "node9 agents add antigravity",
|
|
9908
|
+
hookFile: (h) => import_path16.default.join(h, ".gemini", "config", "hooks.json"),
|
|
9909
|
+
hookFormat: "matcher",
|
|
9910
|
+
hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
|
|
9911
|
+
mcpFile: (h) => import_path16.default.join(h, ".gemini", "config", "mcp_config.json"),
|
|
9912
|
+
present: (h) => exists(import_path16.default.join(h, ".gemini", "config", "hooks.json")) || exists(import_path16.default.join(h, ".gemini", "antigravity-cli")) || exists(import_path16.default.join(h, ".gemini", "antigravity-ide"))
|
|
9913
|
+
},
|
|
9914
|
+
{
|
|
9915
|
+
id: "copilot",
|
|
9916
|
+
label: "GitHub Copilot",
|
|
9917
|
+
setupCommand: "node9 agents add copilot",
|
|
9918
|
+
hookFile: (h) => import_path16.default.join(h, ".copilot", "hooks", "node9.json"),
|
|
9919
|
+
hookFormat: "flat",
|
|
9920
|
+
hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
|
|
9921
|
+
mcpFile: (h) => import_path16.default.join(h, ".copilot", "mcp-config.json"),
|
|
9922
|
+
present: (h) => exists(import_path16.default.join(h, ".copilot"))
|
|
9923
|
+
},
|
|
9924
|
+
{
|
|
9925
|
+
id: "cursor",
|
|
9926
|
+
label: "Cursor",
|
|
9927
|
+
setupCommand: "node9 agents add cursor",
|
|
9928
|
+
// MCP-only — no hook file (see note above).
|
|
9929
|
+
hookFormat: "flat",
|
|
9930
|
+
hookEvents: [],
|
|
9931
|
+
mcpFile: (h) => import_path16.default.join(h, ".cursor", "mcp.json"),
|
|
9932
|
+
present: (h) => exists(import_path16.default.join(h, ".cursor", "mcp.json"))
|
|
9933
|
+
},
|
|
9934
|
+
{
|
|
9935
|
+
id: "hermes",
|
|
9936
|
+
label: "Hermes Agent",
|
|
9937
|
+
setupCommand: "node9 agents add hermes",
|
|
9938
|
+
hookFile: (h) => hermesConfigPath(h),
|
|
9939
|
+
hookFormat: "yaml",
|
|
9940
|
+
hookEvents: [ck("pre_tool_call"), lg("post_tool_call")],
|
|
9941
|
+
labelPad: 14,
|
|
9942
|
+
// 'post_tool_call' is wider than the default
|
|
9943
|
+
present: (h) => exists(hermesConfigPath(h))
|
|
9944
|
+
},
|
|
9945
|
+
{
|
|
9946
|
+
// Plugin-shim agents — protected by a node9-authored plugin/extension file
|
|
9947
|
+
// (no hooks, no MCP). hookFormat is unused for these (shimFile drives it).
|
|
9948
|
+
id: "opencode",
|
|
9949
|
+
label: "OpenCode",
|
|
9950
|
+
setupCommand: "node9 agents add opencode",
|
|
9951
|
+
hookFormat: "flat",
|
|
9952
|
+
hookEvents: [],
|
|
9953
|
+
shimFile: (h) => import_path16.default.join(h, ".config", "opencode", "plugins", "node9.js"),
|
|
9954
|
+
present: (h) => exists(import_path16.default.join(h, ".config", "opencode")) || exists(import_path16.default.join(h, ".config", "opencode", "plugins", "node9.js"))
|
|
9955
|
+
},
|
|
9956
|
+
{
|
|
9957
|
+
id: "pi",
|
|
9958
|
+
label: "Pi",
|
|
9959
|
+
setupCommand: "node9 agents add pi",
|
|
9960
|
+
hookFormat: "flat",
|
|
9961
|
+
hookEvents: [],
|
|
9962
|
+
shimFile: (h) => import_path16.default.join(h, ".pi", "agent", "extensions", "node9.js"),
|
|
9963
|
+
present: (h) => exists(import_path16.default.join(h, ".pi", "agent")) || exists(import_path16.default.join(h, ".pi", "agent", "extensions", "node9.js"))
|
|
9964
|
+
}
|
|
9965
|
+
];
|
|
9966
|
+
}
|
|
9967
|
+
});
|
|
9968
|
+
|
|
9728
9969
|
// src/pricing/litellm.ts
|
|
9729
9970
|
function normalizeModel(raw) {
|
|
9730
9971
|
return raw.replace(/-\d{8}$/, "").toLowerCase();
|
|
9731
9972
|
}
|
|
9732
9973
|
function readCache() {
|
|
9733
9974
|
try {
|
|
9734
|
-
const raw = JSON.parse(
|
|
9975
|
+
const raw = JSON.parse(import_fs15.default.readFileSync(CACHE_FILE(), "utf-8"));
|
|
9735
9976
|
if (typeof raw.fetchedAt !== "string" || typeof raw.prices !== "object" || raw.prices === null) {
|
|
9736
9977
|
return null;
|
|
9737
9978
|
}
|
|
@@ -9745,18 +9986,18 @@ function readCache() {
|
|
|
9745
9986
|
function writeCache(prices) {
|
|
9746
9987
|
try {
|
|
9747
9988
|
const target = CACHE_FILE();
|
|
9748
|
-
const dir =
|
|
9749
|
-
if (!
|
|
9989
|
+
const dir = import_path17.default.dirname(target);
|
|
9990
|
+
if (!import_fs15.default.existsSync(dir)) import_fs15.default.mkdirSync(dir, { recursive: true });
|
|
9750
9991
|
const tmp = target + ".tmp";
|
|
9751
9992
|
const body = {
|
|
9752
9993
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9753
9994
|
prices
|
|
9754
9995
|
};
|
|
9755
|
-
|
|
9756
|
-
|
|
9996
|
+
import_fs15.default.writeFileSync(tmp, JSON.stringify(body) + "\n", "utf-8");
|
|
9997
|
+
import_fs15.default.renameSync(tmp, target);
|
|
9757
9998
|
} catch (err2) {
|
|
9758
9999
|
try {
|
|
9759
|
-
|
|
10000
|
+
import_fs15.default.appendFileSync(
|
|
9760
10001
|
HOOK_DEBUG_LOG,
|
|
9761
10002
|
`[pricing] cache write failed: ${err2.message}
|
|
9762
10003
|
`
|
|
@@ -9857,13 +10098,13 @@ function pricingFor(model) {
|
|
|
9857
10098
|
lookupCache.set(norm, resolved);
|
|
9858
10099
|
return resolved;
|
|
9859
10100
|
}
|
|
9860
|
-
var
|
|
10101
|
+
var import_fs15, import_path17, import_os14, LITELLM_URL, BUNDLED_PRICING, CACHE_FILE, TTL_MS, memCache, memCacheAt, diskChecked, lookupCache;
|
|
9861
10102
|
var init_litellm = __esm({
|
|
9862
10103
|
"src/pricing/litellm.ts"() {
|
|
9863
10104
|
"use strict";
|
|
9864
|
-
|
|
9865
|
-
|
|
9866
|
-
|
|
10105
|
+
import_fs15 = __toESM(require("fs"));
|
|
10106
|
+
import_path17 = __toESM(require("path"));
|
|
10107
|
+
import_os14 = __toESM(require("os"));
|
|
9867
10108
|
init_audit();
|
|
9868
10109
|
LITELLM_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json";
|
|
9869
10110
|
BUNDLED_PRICING = {
|
|
@@ -9903,7 +10144,7 @@ var init_litellm = __esm({
|
|
|
9903
10144
|
"gemini-2.0-flash": [75e-9, 3e-7, 0, 0],
|
|
9904
10145
|
"gemini-1.5-pro": [125e-8, 5e-6, 0, 0]
|
|
9905
10146
|
};
|
|
9906
|
-
CACHE_FILE = () =>
|
|
10147
|
+
CACHE_FILE = () => import_path17.default.join(import_os14.default.homedir(), ".node9", "model-pricing.json");
|
|
9907
10148
|
TTL_MS = 24 * 60 * 60 * 1e3;
|
|
9908
10149
|
memCache = null;
|
|
9909
10150
|
memCacheAt = 0;
|
|
@@ -9914,7 +10155,7 @@ var init_litellm = __esm({
|
|
|
9914
10155
|
|
|
9915
10156
|
// src/cost-gemini.ts
|
|
9916
10157
|
function geminiTmpDir() {
|
|
9917
|
-
return
|
|
10158
|
+
return import_path18.default.join(import_os15.default.homedir(), ".gemini", "tmp");
|
|
9918
10159
|
}
|
|
9919
10160
|
function geminiPriceFor(model) {
|
|
9920
10161
|
let tuple = pricingFor(model);
|
|
@@ -9929,14 +10170,14 @@ function geminiPriceFor(model) {
|
|
|
9929
10170
|
}
|
|
9930
10171
|
function safeReaddir(dir) {
|
|
9931
10172
|
try {
|
|
9932
|
-
return
|
|
10173
|
+
return import_fs16.default.readdirSync(dir);
|
|
9933
10174
|
} catch {
|
|
9934
10175
|
return [];
|
|
9935
10176
|
}
|
|
9936
10177
|
}
|
|
9937
10178
|
function isDir(p) {
|
|
9938
10179
|
try {
|
|
9939
|
-
return
|
|
10180
|
+
return import_fs16.default.statSync(p).isDirectory();
|
|
9940
10181
|
} catch {
|
|
9941
10182
|
return false;
|
|
9942
10183
|
}
|
|
@@ -9944,11 +10185,11 @@ function isDir(p) {
|
|
|
9944
10185
|
function listGeminiSessionFiles(base) {
|
|
9945
10186
|
const out = [];
|
|
9946
10187
|
for (const project of safeReaddir(base)) {
|
|
9947
|
-
const chats =
|
|
10188
|
+
const chats = import_path18.default.join(base, project, "chats");
|
|
9948
10189
|
if (!isDir(chats)) continue;
|
|
9949
10190
|
for (const f of safeReaddir(chats)) {
|
|
9950
10191
|
if (f.startsWith("session-") && f.endsWith(".jsonl")) {
|
|
9951
|
-
out.push({ file:
|
|
10192
|
+
out.push({ file: import_path18.default.join(chats, f), project });
|
|
9952
10193
|
}
|
|
9953
10194
|
}
|
|
9954
10195
|
}
|
|
@@ -10005,20 +10246,20 @@ function parseGeminiSession(lines, project) {
|
|
|
10005
10246
|
if (runId) for (const e of byKey.values()) e.runId = runId;
|
|
10006
10247
|
return [...byKey.values()];
|
|
10007
10248
|
}
|
|
10008
|
-
var
|
|
10249
|
+
var import_fs16, import_os15, import_path18, GEMINI_FALLBACK_MODELS, geminiSource;
|
|
10009
10250
|
var init_cost_gemini = __esm({
|
|
10010
10251
|
"src/cost-gemini.ts"() {
|
|
10011
10252
|
"use strict";
|
|
10012
|
-
|
|
10013
|
-
|
|
10014
|
-
|
|
10253
|
+
import_fs16 = __toESM(require("fs"));
|
|
10254
|
+
import_os15 = __toESM(require("os"));
|
|
10255
|
+
import_path18 = __toESM(require("path"));
|
|
10015
10256
|
init_litellm();
|
|
10016
10257
|
GEMINI_FALLBACK_MODELS = ["gemini-2.5-flash", "gemini-2.0-flash"];
|
|
10017
10258
|
geminiSource = {
|
|
10018
10259
|
id: "gemini",
|
|
10019
10260
|
available() {
|
|
10020
10261
|
try {
|
|
10021
|
-
return
|
|
10262
|
+
return import_fs16.default.existsSync(geminiTmpDir());
|
|
10022
10263
|
} catch {
|
|
10023
10264
|
return false;
|
|
10024
10265
|
}
|
|
@@ -10027,13 +10268,13 @@ var init_cost_gemini = __esm({
|
|
|
10027
10268
|
const combined = /* @__PURE__ */ new Map();
|
|
10028
10269
|
for (const { file, project } of listGeminiSessionFiles(geminiTmpDir())) {
|
|
10029
10270
|
try {
|
|
10030
|
-
if (sinceMs !== void 0 &&
|
|
10271
|
+
if (sinceMs !== void 0 && import_fs16.default.statSync(file).mtimeMs < sinceMs) continue;
|
|
10031
10272
|
} catch {
|
|
10032
10273
|
continue;
|
|
10033
10274
|
}
|
|
10034
10275
|
let content;
|
|
10035
10276
|
try {
|
|
10036
|
-
content =
|
|
10277
|
+
content = import_fs16.default.readFileSync(file, "utf8");
|
|
10037
10278
|
} catch {
|
|
10038
10279
|
continue;
|
|
10039
10280
|
}
|
|
@@ -10059,7 +10300,7 @@ var init_cost_gemini = __esm({
|
|
|
10059
10300
|
|
|
10060
10301
|
// src/cost-codex.ts
|
|
10061
10302
|
function codexSessionsDir() {
|
|
10062
|
-
return
|
|
10303
|
+
return import_path19.default.join(import_os16.default.homedir(), ".codex", "sessions");
|
|
10063
10304
|
}
|
|
10064
10305
|
function codexPriceFor(model) {
|
|
10065
10306
|
return pricingFor(model) ?? CODEX_FALLBACK;
|
|
@@ -10072,16 +10313,16 @@ function codexSessionCost(model, tokens) {
|
|
|
10072
10313
|
function listCodexSessionFiles(base) {
|
|
10073
10314
|
const out = [];
|
|
10074
10315
|
for (const y of safeReaddir2(base)) {
|
|
10075
|
-
const yp =
|
|
10316
|
+
const yp = import_path19.default.join(base, y);
|
|
10076
10317
|
if (!isDir2(yp)) continue;
|
|
10077
10318
|
for (const m of safeReaddir2(yp)) {
|
|
10078
|
-
const mp =
|
|
10319
|
+
const mp = import_path19.default.join(yp, m);
|
|
10079
10320
|
if (!isDir2(mp)) continue;
|
|
10080
10321
|
for (const d of safeReaddir2(mp)) {
|
|
10081
|
-
const dp =
|
|
10322
|
+
const dp = import_path19.default.join(mp, d);
|
|
10082
10323
|
if (!isDir2(dp)) continue;
|
|
10083
10324
|
for (const f of safeReaddir2(dp)) {
|
|
10084
|
-
if (f.endsWith(".jsonl")) out.push(
|
|
10325
|
+
if (f.endsWith(".jsonl")) out.push(import_path19.default.join(dp, f));
|
|
10085
10326
|
}
|
|
10086
10327
|
}
|
|
10087
10328
|
}
|
|
@@ -10090,14 +10331,14 @@ function listCodexSessionFiles(base) {
|
|
|
10090
10331
|
}
|
|
10091
10332
|
function safeReaddir2(dir) {
|
|
10092
10333
|
try {
|
|
10093
|
-
return
|
|
10334
|
+
return import_fs17.default.readdirSync(dir);
|
|
10094
10335
|
} catch {
|
|
10095
10336
|
return [];
|
|
10096
10337
|
}
|
|
10097
10338
|
}
|
|
10098
10339
|
function isDir2(p) {
|
|
10099
10340
|
try {
|
|
10100
|
-
return
|
|
10341
|
+
return import_fs17.default.statSync(p).isDirectory();
|
|
10101
10342
|
} catch {
|
|
10102
10343
|
return false;
|
|
10103
10344
|
}
|
|
@@ -10157,20 +10398,20 @@ function parseCodexSession(lines) {
|
|
|
10157
10398
|
cacheWriteTokens: 0
|
|
10158
10399
|
};
|
|
10159
10400
|
}
|
|
10160
|
-
var
|
|
10401
|
+
var import_fs17, import_os16, import_path19, CODEX_FALLBACK, codexSource;
|
|
10161
10402
|
var init_cost_codex = __esm({
|
|
10162
10403
|
"src/cost-codex.ts"() {
|
|
10163
10404
|
"use strict";
|
|
10164
|
-
|
|
10165
|
-
|
|
10166
|
-
|
|
10405
|
+
import_fs17 = __toESM(require("fs"));
|
|
10406
|
+
import_os16 = __toESM(require("os"));
|
|
10407
|
+
import_path19 = __toESM(require("path"));
|
|
10167
10408
|
init_litellm();
|
|
10168
10409
|
CODEX_FALLBACK = [5e-6, 15e-6, 0, 25e-7];
|
|
10169
10410
|
codexSource = {
|
|
10170
10411
|
id: "codex",
|
|
10171
10412
|
available() {
|
|
10172
10413
|
try {
|
|
10173
|
-
return
|
|
10414
|
+
return import_fs17.default.existsSync(codexSessionsDir());
|
|
10174
10415
|
} catch {
|
|
10175
10416
|
return false;
|
|
10176
10417
|
}
|
|
@@ -10180,13 +10421,13 @@ var init_cost_codex = __esm({
|
|
|
10180
10421
|
const combined = /* @__PURE__ */ new Map();
|
|
10181
10422
|
for (const file of listCodexSessionFiles(base)) {
|
|
10182
10423
|
try {
|
|
10183
|
-
if (sinceMs !== void 0 &&
|
|
10424
|
+
if (sinceMs !== void 0 && import_fs17.default.statSync(file).mtimeMs < sinceMs) continue;
|
|
10184
10425
|
} catch {
|
|
10185
10426
|
continue;
|
|
10186
10427
|
}
|
|
10187
10428
|
let content;
|
|
10188
10429
|
try {
|
|
10189
|
-
content =
|
|
10430
|
+
content = import_fs17.default.readFileSync(file, "utf8");
|
|
10190
10431
|
} catch {
|
|
10191
10432
|
continue;
|
|
10192
10433
|
}
|
|
@@ -10494,79 +10735,79 @@ var init_scan_summary = __esm({
|
|
|
10494
10735
|
function buildSensitivePaths(home, cwd) {
|
|
10495
10736
|
return [
|
|
10496
10737
|
{
|
|
10497
|
-
full:
|
|
10738
|
+
full: import_path20.default.join(home, ".ssh", "id_rsa"),
|
|
10498
10739
|
label: "~/.ssh/id_rsa",
|
|
10499
10740
|
description: "RSA private key \u2014 grants SSH access to your servers",
|
|
10500
10741
|
score: 20
|
|
10501
10742
|
},
|
|
10502
10743
|
{
|
|
10503
|
-
full:
|
|
10744
|
+
full: import_path20.default.join(home, ".ssh", "id_ed25519"),
|
|
10504
10745
|
label: "~/.ssh/id_ed25519",
|
|
10505
10746
|
description: "Ed25519 private key \u2014 grants SSH access to your servers",
|
|
10506
10747
|
score: 20
|
|
10507
10748
|
},
|
|
10508
10749
|
{
|
|
10509
|
-
full:
|
|
10750
|
+
full: import_path20.default.join(home, ".ssh", "id_ecdsa"),
|
|
10510
10751
|
label: "~/.ssh/id_ecdsa",
|
|
10511
10752
|
description: "ECDSA private key \u2014 grants SSH access to your servers",
|
|
10512
10753
|
score: 20
|
|
10513
10754
|
},
|
|
10514
10755
|
{
|
|
10515
|
-
full:
|
|
10756
|
+
full: import_path20.default.join(home, ".aws", "credentials"),
|
|
10516
10757
|
label: "~/.aws/credentials",
|
|
10517
10758
|
description: "AWS access keys \u2014 full cloud account access",
|
|
10518
10759
|
score: 20
|
|
10519
10760
|
},
|
|
10520
10761
|
{
|
|
10521
|
-
full:
|
|
10762
|
+
full: import_path20.default.join(home, ".aws", "config"),
|
|
10522
10763
|
label: "~/.aws/config",
|
|
10523
10764
|
description: "AWS configuration \u2014 account and region settings",
|
|
10524
10765
|
score: 5
|
|
10525
10766
|
},
|
|
10526
10767
|
{
|
|
10527
|
-
full:
|
|
10768
|
+
full: import_path20.default.join(home, ".config", "gcloud", "credentials.db"),
|
|
10528
10769
|
label: "~/.config/gcloud/credentials.db",
|
|
10529
10770
|
description: "Google Cloud credentials",
|
|
10530
10771
|
score: 15
|
|
10531
10772
|
},
|
|
10532
10773
|
{
|
|
10533
|
-
full:
|
|
10774
|
+
full: import_path20.default.join(home, ".docker", "config.json"),
|
|
10534
10775
|
label: "~/.docker/config.json",
|
|
10535
10776
|
description: "Docker registry auth tokens",
|
|
10536
10777
|
score: 10
|
|
10537
10778
|
},
|
|
10538
10779
|
{
|
|
10539
|
-
full:
|
|
10780
|
+
full: import_path20.default.join(home, ".netrc"),
|
|
10540
10781
|
label: "~/.netrc",
|
|
10541
10782
|
description: "FTP/HTTP credentials in plain text",
|
|
10542
10783
|
score: 15
|
|
10543
10784
|
},
|
|
10544
10785
|
{
|
|
10545
|
-
full:
|
|
10786
|
+
full: import_path20.default.join(home, ".npmrc"),
|
|
10546
10787
|
label: "~/.npmrc",
|
|
10547
10788
|
description: "npm auth token \u2014 can publish packages as you",
|
|
10548
10789
|
score: 10
|
|
10549
10790
|
},
|
|
10550
10791
|
{
|
|
10551
|
-
full:
|
|
10792
|
+
full: import_path20.default.join(home, ".node9", "credentials.json"),
|
|
10552
10793
|
label: "~/.node9/credentials.json",
|
|
10553
10794
|
description: "Node9 cloud API key",
|
|
10554
10795
|
score: 10
|
|
10555
10796
|
},
|
|
10556
10797
|
{
|
|
10557
|
-
full:
|
|
10798
|
+
full: import_path20.default.join(cwd, ".env"),
|
|
10558
10799
|
label: ".env (current folder)",
|
|
10559
10800
|
description: "App secrets \u2014 database passwords, API keys",
|
|
10560
10801
|
score: 20
|
|
10561
10802
|
},
|
|
10562
10803
|
{
|
|
10563
|
-
full:
|
|
10804
|
+
full: import_path20.default.join(cwd, ".env.local"),
|
|
10564
10805
|
label: ".env.local (current folder)",
|
|
10565
10806
|
description: "Local overrides \u2014 often contains real credentials",
|
|
10566
10807
|
score: 15
|
|
10567
10808
|
},
|
|
10568
10809
|
{
|
|
10569
|
-
full:
|
|
10810
|
+
full: import_path20.default.join(cwd, ".env.production"),
|
|
10570
10811
|
label: ".env.production (current folder)",
|
|
10571
10812
|
description: "Production secrets",
|
|
10572
10813
|
score: 20
|
|
@@ -10575,7 +10816,7 @@ function buildSensitivePaths(home, cwd) {
|
|
|
10575
10816
|
}
|
|
10576
10817
|
function isReadable(filePath) {
|
|
10577
10818
|
try {
|
|
10578
|
-
|
|
10819
|
+
import_fs18.default.accessSync(filePath, import_fs18.default.constants.R_OK);
|
|
10579
10820
|
return true;
|
|
10580
10821
|
} catch {
|
|
10581
10822
|
return false;
|
|
@@ -10588,13 +10829,13 @@ function scoreLabel(score) {
|
|
|
10588
10829
|
return import_chalk2.default.red.bold(`${score}/100 Critical`);
|
|
10589
10830
|
}
|
|
10590
10831
|
function runBlast() {
|
|
10591
|
-
const home =
|
|
10832
|
+
const home = import_os17.default.homedir();
|
|
10592
10833
|
const cwd = process.cwd();
|
|
10593
10834
|
const paths = buildSensitivePaths(home, cwd);
|
|
10594
10835
|
let scoreDeduction = 0;
|
|
10595
10836
|
const reachable = [];
|
|
10596
10837
|
for (const p of paths) {
|
|
10597
|
-
if (
|
|
10838
|
+
if (import_fs18.default.existsSync(p.full) && isReadable(p.full)) {
|
|
10598
10839
|
reachable.push(p);
|
|
10599
10840
|
scoreDeduction += p.score;
|
|
10600
10841
|
}
|
|
@@ -10612,7 +10853,7 @@ function runBlast() {
|
|
|
10612
10853
|
}
|
|
10613
10854
|
function registerBlastCommand(program2) {
|
|
10614
10855
|
program2.command("blast").description("Map what an AI agent can currently reach on this machine").action(() => {
|
|
10615
|
-
const home =
|
|
10856
|
+
const home = import_os17.default.homedir();
|
|
10616
10857
|
const cwd = process.cwd();
|
|
10617
10858
|
const { reachable, envFindings, score } = runBlast();
|
|
10618
10859
|
console.log("");
|
|
@@ -10659,14 +10900,14 @@ function registerBlastCommand(program2) {
|
|
|
10659
10900
|
console.log("");
|
|
10660
10901
|
});
|
|
10661
10902
|
}
|
|
10662
|
-
var import_chalk2,
|
|
10903
|
+
var import_chalk2, import_fs18, import_path20, import_os17;
|
|
10663
10904
|
var init_blast = __esm({
|
|
10664
10905
|
"src/cli/commands/blast.ts"() {
|
|
10665
10906
|
"use strict";
|
|
10666
10907
|
import_chalk2 = __toESM(require("chalk"));
|
|
10667
|
-
|
|
10668
|
-
|
|
10669
|
-
|
|
10908
|
+
import_fs18 = __toESM(require("fs"));
|
|
10909
|
+
import_path20 = __toESM(require("path"));
|
|
10910
|
+
import_os17 = __toESM(require("os"));
|
|
10670
10911
|
init_dlp();
|
|
10671
10912
|
}
|
|
10672
10913
|
});
|
|
@@ -10794,13 +11035,13 @@ var init_scan_json = __esm({
|
|
|
10794
11035
|
|
|
10795
11036
|
// src/cli/render/scan-history.ts
|
|
10796
11037
|
function defaultHistoryPath() {
|
|
10797
|
-
return
|
|
11038
|
+
return import_path21.default.join(import_os18.default.homedir(), ".node9", "scan-history.json");
|
|
10798
11039
|
}
|
|
10799
11040
|
function readPreviousScan(opts = {}) {
|
|
10800
11041
|
const filePath = opts.path ?? defaultHistoryPath();
|
|
10801
11042
|
try {
|
|
10802
|
-
if (!
|
|
10803
|
-
const raw =
|
|
11043
|
+
if (!import_fs19.default.existsSync(filePath)) return null;
|
|
11044
|
+
const raw = import_fs19.default.readFileSync(filePath, "utf8");
|
|
10804
11045
|
const parsed = JSON.parse(raw);
|
|
10805
11046
|
if (!Array.isArray(parsed) || parsed.length === 0) return null;
|
|
10806
11047
|
const last = parsed[parsed.length - 1];
|
|
@@ -10814,11 +11055,11 @@ function appendScanHistory(record, opts = {}) {
|
|
|
10814
11055
|
const filePath = opts.path ?? defaultHistoryPath();
|
|
10815
11056
|
const cap = opts.cap ?? SCAN_HISTORY_CAP;
|
|
10816
11057
|
try {
|
|
10817
|
-
|
|
11058
|
+
import_fs19.default.mkdirSync(import_path21.default.dirname(filePath), { recursive: true });
|
|
10818
11059
|
let history = [];
|
|
10819
|
-
if (
|
|
11060
|
+
if (import_fs19.default.existsSync(filePath)) {
|
|
10820
11061
|
try {
|
|
10821
|
-
const parsed = JSON.parse(
|
|
11062
|
+
const parsed = JSON.parse(import_fs19.default.readFileSync(filePath, "utf8"));
|
|
10822
11063
|
if (Array.isArray(parsed)) {
|
|
10823
11064
|
history = parsed.filter(isValidRecord);
|
|
10824
11065
|
}
|
|
@@ -10829,7 +11070,7 @@ function appendScanHistory(record, opts = {}) {
|
|
|
10829
11070
|
if (history.length > cap) {
|
|
10830
11071
|
history = history.slice(history.length - cap);
|
|
10831
11072
|
}
|
|
10832
|
-
|
|
11073
|
+
import_fs19.default.writeFileSync(filePath, JSON.stringify(history, null, 2));
|
|
10833
11074
|
} catch (err2) {
|
|
10834
11075
|
process.stderr.write(
|
|
10835
11076
|
`[node9] Warning: could not write scan-history.json: ${err2.message}
|
|
@@ -10851,24 +11092,24 @@ function isValidRecord(x) {
|
|
|
10851
11092
|
const r = x;
|
|
10852
11093
|
return typeof r.timestamp === "string" && typeof r.score === "number" && typeof r.blocked === "number" && typeof r.review === "number" && typeof r.leaks === "number" && typeof r.loops === "number" && typeof r.totalCalls === "number";
|
|
10853
11094
|
}
|
|
10854
|
-
var
|
|
11095
|
+
var import_fs19, import_path21, import_os18, SCAN_HISTORY_CAP;
|
|
10855
11096
|
var init_scan_history = __esm({
|
|
10856
11097
|
"src/cli/render/scan-history.ts"() {
|
|
10857
11098
|
"use strict";
|
|
10858
|
-
|
|
10859
|
-
|
|
10860
|
-
|
|
11099
|
+
import_fs19 = __toESM(require("fs"));
|
|
11100
|
+
import_path21 = __toESM(require("path"));
|
|
11101
|
+
import_os18 = __toESM(require("os"));
|
|
10861
11102
|
SCAN_HISTORY_CAP = 30;
|
|
10862
11103
|
}
|
|
10863
11104
|
});
|
|
10864
11105
|
|
|
10865
11106
|
// src/cost-copilot.ts
|
|
10866
11107
|
function copilotSessionsDir() {
|
|
10867
|
-
return
|
|
11108
|
+
return import_path22.default.join(import_os19.default.homedir(), ".copilot", "session-state");
|
|
10868
11109
|
}
|
|
10869
11110
|
function safeReaddir3(dir) {
|
|
10870
11111
|
try {
|
|
10871
|
-
return
|
|
11112
|
+
return import_fs20.default.readdirSync(dir);
|
|
10872
11113
|
} catch {
|
|
10873
11114
|
return [];
|
|
10874
11115
|
}
|
|
@@ -10935,19 +11176,19 @@ function parseCopilotSession(lines) {
|
|
|
10935
11176
|
}
|
|
10936
11177
|
return rows;
|
|
10937
11178
|
}
|
|
10938
|
-
var
|
|
11179
|
+
var import_fs20, import_os19, import_path22, copilotSource;
|
|
10939
11180
|
var init_cost_copilot = __esm({
|
|
10940
11181
|
"src/cost-copilot.ts"() {
|
|
10941
11182
|
"use strict";
|
|
10942
|
-
|
|
10943
|
-
|
|
10944
|
-
|
|
11183
|
+
import_fs20 = __toESM(require("fs"));
|
|
11184
|
+
import_os19 = __toESM(require("os"));
|
|
11185
|
+
import_path22 = __toESM(require("path"));
|
|
10945
11186
|
init_litellm();
|
|
10946
11187
|
copilotSource = {
|
|
10947
11188
|
id: "copilot",
|
|
10948
11189
|
available() {
|
|
10949
11190
|
try {
|
|
10950
|
-
return
|
|
11191
|
+
return import_fs20.default.existsSync(copilotSessionsDir());
|
|
10951
11192
|
} catch {
|
|
10952
11193
|
return false;
|
|
10953
11194
|
}
|
|
@@ -10956,15 +11197,15 @@ var init_cost_copilot = __esm({
|
|
|
10956
11197
|
const base = copilotSessionsDir();
|
|
10957
11198
|
const combined = /* @__PURE__ */ new Map();
|
|
10958
11199
|
for (const sid of safeReaddir3(base)) {
|
|
10959
|
-
const file =
|
|
11200
|
+
const file = import_path22.default.join(base, sid, "events.jsonl");
|
|
10960
11201
|
try {
|
|
10961
|
-
if (sinceMs !== void 0 &&
|
|
11202
|
+
if (sinceMs !== void 0 && import_fs20.default.statSync(file).mtimeMs < sinceMs) continue;
|
|
10962
11203
|
} catch {
|
|
10963
11204
|
continue;
|
|
10964
11205
|
}
|
|
10965
11206
|
let content;
|
|
10966
11207
|
try {
|
|
10967
|
-
content =
|
|
11208
|
+
content = import_fs20.default.readFileSync(file, "utf8");
|
|
10968
11209
|
} catch {
|
|
10969
11210
|
continue;
|
|
10970
11211
|
}
|
|
@@ -10993,10 +11234,10 @@ function decodeProjectDirName(dirName) {
|
|
|
10993
11234
|
return dirName.replace(/-/g, "/");
|
|
10994
11235
|
}
|
|
10995
11236
|
function parseJSONLFile(filePath, fallbackWorkingDir) {
|
|
10996
|
-
const runId =
|
|
11237
|
+
const runId = import_path23.default.basename(filePath, ".jsonl");
|
|
10997
11238
|
let content;
|
|
10998
11239
|
try {
|
|
10999
|
-
content =
|
|
11240
|
+
content = import_fs21.default.readFileSync(filePath, "utf8");
|
|
11000
11241
|
} catch {
|
|
11001
11242
|
return /* @__PURE__ */ new Map();
|
|
11002
11243
|
}
|
|
@@ -11096,7 +11337,7 @@ async function postCostBatches(apiUrl, apiKey, machineId, entries) {
|
|
|
11096
11337
|
signal: AbortSignal.timeout(15e3)
|
|
11097
11338
|
});
|
|
11098
11339
|
if (!res.ok) {
|
|
11099
|
-
|
|
11340
|
+
import_fs21.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
|
|
11100
11341
|
`);
|
|
11101
11342
|
} else {
|
|
11102
11343
|
let stored;
|
|
@@ -11106,7 +11347,7 @@ async function postCostBatches(apiUrl, apiKey, machineId, entries) {
|
|
|
11106
11347
|
} catch {
|
|
11107
11348
|
}
|
|
11108
11349
|
if (typeof stored === "number" && stored < batch.length) {
|
|
11109
|
-
|
|
11350
|
+
import_fs21.default.appendFileSync(
|
|
11110
11351
|
HOOK_DEBUG_LOG,
|
|
11111
11352
|
`[cost-sync] dropped ${batch.length - stored} of ${batch.length} rows
|
|
11112
11353
|
`
|
|
@@ -11114,7 +11355,7 @@ async function postCostBatches(apiUrl, apiKey, machineId, entries) {
|
|
|
11114
11355
|
}
|
|
11115
11356
|
}
|
|
11116
11357
|
} catch (err2) {
|
|
11117
|
-
|
|
11358
|
+
import_fs21.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
|
|
11118
11359
|
`);
|
|
11119
11360
|
}
|
|
11120
11361
|
}
|
|
@@ -11127,10 +11368,10 @@ async function syncCost() {
|
|
|
11127
11368
|
if (entries.length === 0) return;
|
|
11128
11369
|
let username = "unknown";
|
|
11129
11370
|
try {
|
|
11130
|
-
username =
|
|
11371
|
+
username = import_os20.default.userInfo().username;
|
|
11131
11372
|
} catch {
|
|
11132
11373
|
}
|
|
11133
|
-
const machineId = `${
|
|
11374
|
+
const machineId = `${import_os20.default.hostname()}:${username}`;
|
|
11134
11375
|
await postCostBatches(creds.apiUrl, creds.apiKey, machineId, entries);
|
|
11135
11376
|
}
|
|
11136
11377
|
function startCostSync() {
|
|
@@ -11142,13 +11383,13 @@ function startCostSync() {
|
|
|
11142
11383
|
}, SYNC_INTERVAL_MS);
|
|
11143
11384
|
timer.unref();
|
|
11144
11385
|
}
|
|
11145
|
-
var
|
|
11386
|
+
var import_fs21, import_path23, import_os20, SYNC_INTERVAL_MS, claudeSource, COST_SOURCES, COST_BATCH_SIZE;
|
|
11146
11387
|
var init_costSync = __esm({
|
|
11147
11388
|
"src/costSync.ts"() {
|
|
11148
11389
|
"use strict";
|
|
11149
|
-
|
|
11150
|
-
|
|
11151
|
-
|
|
11390
|
+
import_fs21 = __toESM(require("fs"));
|
|
11391
|
+
import_path23 = __toESM(require("path"));
|
|
11392
|
+
import_os20 = __toESM(require("os"));
|
|
11152
11393
|
init_config();
|
|
11153
11394
|
init_audit();
|
|
11154
11395
|
init_litellm();
|
|
@@ -11159,37 +11400,37 @@ var init_costSync = __esm({
|
|
|
11159
11400
|
claudeSource = {
|
|
11160
11401
|
id: "claude",
|
|
11161
11402
|
available() {
|
|
11162
|
-
return
|
|
11403
|
+
return import_fs21.default.existsSync(import_path23.default.join(import_os20.default.homedir(), ".claude", "projects"));
|
|
11163
11404
|
},
|
|
11164
11405
|
collect(sinceMs) {
|
|
11165
|
-
const projectsDir =
|
|
11166
|
-
if (!
|
|
11406
|
+
const projectsDir = import_path23.default.join(import_os20.default.homedir(), ".claude", "projects");
|
|
11407
|
+
if (!import_fs21.default.existsSync(projectsDir)) return [];
|
|
11167
11408
|
const combined = /* @__PURE__ */ new Map();
|
|
11168
11409
|
let dirs;
|
|
11169
11410
|
try {
|
|
11170
|
-
dirs =
|
|
11411
|
+
dirs = import_fs21.default.readdirSync(projectsDir);
|
|
11171
11412
|
} catch {
|
|
11172
11413
|
return [];
|
|
11173
11414
|
}
|
|
11174
11415
|
for (const dir of dirs) {
|
|
11175
|
-
const dirPath =
|
|
11416
|
+
const dirPath = import_path23.default.join(projectsDir, dir);
|
|
11176
11417
|
try {
|
|
11177
|
-
if (!
|
|
11418
|
+
if (!import_fs21.default.statSync(dirPath).isDirectory()) continue;
|
|
11178
11419
|
} catch {
|
|
11179
11420
|
continue;
|
|
11180
11421
|
}
|
|
11181
11422
|
let files;
|
|
11182
11423
|
try {
|
|
11183
|
-
files =
|
|
11424
|
+
files = import_fs21.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
11184
11425
|
} catch {
|
|
11185
11426
|
continue;
|
|
11186
11427
|
}
|
|
11187
11428
|
const fallbackWorkingDir = decodeProjectDirName(dir);
|
|
11188
11429
|
for (const file of files) {
|
|
11189
|
-
const filePath =
|
|
11430
|
+
const filePath = import_path23.default.join(dirPath, file);
|
|
11190
11431
|
if (sinceMs !== void 0) {
|
|
11191
11432
|
try {
|
|
11192
|
-
if (
|
|
11433
|
+
if (import_fs21.default.statSync(filePath).mtimeMs < sinceMs) continue;
|
|
11193
11434
|
} catch {
|
|
11194
11435
|
continue;
|
|
11195
11436
|
}
|
|
@@ -11240,7 +11481,7 @@ function freshWatermark() {
|
|
|
11240
11481
|
function loadWatermark() {
|
|
11241
11482
|
let raw;
|
|
11242
11483
|
try {
|
|
11243
|
-
raw =
|
|
11484
|
+
raw = import_fs22.default.readFileSync(WATERMARK_FILE(), "utf-8");
|
|
11244
11485
|
} catch {
|
|
11245
11486
|
return { status: "fresh", wm: freshWatermark() };
|
|
11246
11487
|
}
|
|
@@ -11292,28 +11533,28 @@ function loadWatermark() {
|
|
|
11292
11533
|
function saveWatermark(wm) {
|
|
11293
11534
|
if (wm.schemaVersion > WATERMARK_SCHEMA_VERSION) return;
|
|
11294
11535
|
const target = WATERMARK_FILE();
|
|
11295
|
-
const dir =
|
|
11296
|
-
if (!
|
|
11536
|
+
const dir = import_path24.default.dirname(target);
|
|
11537
|
+
if (!import_fs22.default.existsSync(dir)) import_fs22.default.mkdirSync(dir, { recursive: true });
|
|
11297
11538
|
const tmp = target + ".tmp";
|
|
11298
|
-
|
|
11299
|
-
|
|
11539
|
+
import_fs22.default.writeFileSync(tmp, JSON.stringify(wm, null, 2) + "\n", "utf-8");
|
|
11540
|
+
import_fs22.default.renameSync(tmp, target);
|
|
11300
11541
|
}
|
|
11301
11542
|
function listJsonlFiles() {
|
|
11302
11543
|
const root = PROJECTS_DIR();
|
|
11303
|
-
if (!
|
|
11544
|
+
if (!import_fs22.default.existsSync(root)) return [];
|
|
11304
11545
|
const out = [];
|
|
11305
|
-
for (const entry of
|
|
11546
|
+
for (const entry of import_fs22.default.readdirSync(root, { withFileTypes: true })) {
|
|
11306
11547
|
if (!entry.isDirectory()) continue;
|
|
11307
|
-
const projectDir =
|
|
11548
|
+
const projectDir = import_path24.default.join(root, entry.name);
|
|
11308
11549
|
let inner;
|
|
11309
11550
|
try {
|
|
11310
|
-
inner =
|
|
11551
|
+
inner = import_fs22.default.readdirSync(projectDir, { withFileTypes: true });
|
|
11311
11552
|
} catch {
|
|
11312
11553
|
continue;
|
|
11313
11554
|
}
|
|
11314
11555
|
for (const file of inner) {
|
|
11315
11556
|
if (file.isFile() && file.name.endsWith(".jsonl")) {
|
|
11316
|
-
out.push(
|
|
11557
|
+
out.push(import_path24.default.join(projectDir, file.name));
|
|
11317
11558
|
}
|
|
11318
11559
|
}
|
|
11319
11560
|
}
|
|
@@ -11321,7 +11562,7 @@ function listJsonlFiles() {
|
|
|
11321
11562
|
}
|
|
11322
11563
|
function fileSize(p) {
|
|
11323
11564
|
try {
|
|
11324
|
-
return
|
|
11565
|
+
return import_fs22.default.statSync(p).size;
|
|
11325
11566
|
} catch {
|
|
11326
11567
|
return 0;
|
|
11327
11568
|
}
|
|
@@ -11329,7 +11570,7 @@ function fileSize(p) {
|
|
|
11329
11570
|
async function scanDelta(filePath, fromByte, onLine) {
|
|
11330
11571
|
const size = fileSize(filePath);
|
|
11331
11572
|
if (size <= fromByte) return fromByte;
|
|
11332
|
-
const stream =
|
|
11573
|
+
const stream = import_fs22.default.createReadStream(filePath, {
|
|
11333
11574
|
start: fromByte,
|
|
11334
11575
|
end: size - 1,
|
|
11335
11576
|
highWaterMark: 64 * 1024
|
|
@@ -11441,7 +11682,7 @@ async function tickForensicBroadcast(offsets) {
|
|
|
11441
11682
|
continue;
|
|
11442
11683
|
}
|
|
11443
11684
|
if (size <= offset) continue;
|
|
11444
|
-
const sessionId =
|
|
11685
|
+
const sessionId = import_path24.default.basename(file, ".jsonl");
|
|
11445
11686
|
const newOffset = await scanDelta(file, offset, (obj, lineIndex) => {
|
|
11446
11687
|
out.push(...extractFindingsFromLine(obj, sessionId, lineIndex));
|
|
11447
11688
|
});
|
|
@@ -11500,7 +11741,7 @@ function emptyTick(uploadAs) {
|
|
|
11500
11741
|
function readRawWatermarkPreservingOffsets() {
|
|
11501
11742
|
let raw;
|
|
11502
11743
|
try {
|
|
11503
|
-
raw =
|
|
11744
|
+
raw = import_fs22.default.readFileSync(WATERMARK_FILE(), "utf-8");
|
|
11504
11745
|
} catch {
|
|
11505
11746
|
return null;
|
|
11506
11747
|
}
|
|
@@ -11534,13 +11775,13 @@ async function runActualTick(wm) {
|
|
|
11534
11775
|
if (!known) {
|
|
11535
11776
|
let mtimeMs = 0;
|
|
11536
11777
|
try {
|
|
11537
|
-
mtimeMs =
|
|
11778
|
+
mtimeMs = import_fs22.default.statSync(filePath).mtime.getTime();
|
|
11538
11779
|
} catch {
|
|
11539
11780
|
continue;
|
|
11540
11781
|
}
|
|
11541
11782
|
if (mtimeMs >= watermarkCreatedAt) {
|
|
11542
11783
|
filesNew++;
|
|
11543
|
-
const sessionId2 =
|
|
11784
|
+
const sessionId2 = import_path24.default.basename(filePath, ".jsonl");
|
|
11544
11785
|
const newScannedTo2 = await scanDelta(filePath, 0, (obj, lineIndex) => {
|
|
11545
11786
|
totalToolCalls++;
|
|
11546
11787
|
toolCallsBySession[sessionId2] = (toolCallsBySession[sessionId2] ?? 0) + 1;
|
|
@@ -11558,7 +11799,7 @@ async function runActualTick(wm) {
|
|
|
11558
11799
|
filesSkipped++;
|
|
11559
11800
|
continue;
|
|
11560
11801
|
}
|
|
11561
|
-
const sessionId =
|
|
11802
|
+
const sessionId = import_path24.default.basename(filePath, ".jsonl");
|
|
11562
11803
|
const newScannedTo = await scanDelta(filePath, known.scannedTo, (obj, lineIndex) => {
|
|
11563
11804
|
totalToolCalls++;
|
|
11564
11805
|
toolCallsBySession[sessionId] = (toolCallsBySession[sessionId] ?? 0) + 1;
|
|
@@ -11580,18 +11821,18 @@ async function runActualTick(wm) {
|
|
|
11580
11821
|
schemaFuture: false
|
|
11581
11822
|
};
|
|
11582
11823
|
}
|
|
11583
|
-
var
|
|
11824
|
+
var import_fs22, import_os21, import_path24, import_readline, PROJECTS_DIR, WATERMARK_FILE, MAX_LINE_BYTES, WATERMARK_SCHEMA_VERSION, LONG_OUTPUT_THRESHOLD_BYTES2;
|
|
11584
11825
|
var init_scan_watermark = __esm({
|
|
11585
11826
|
"src/daemon/scan-watermark.ts"() {
|
|
11586
11827
|
"use strict";
|
|
11587
|
-
|
|
11588
|
-
|
|
11589
|
-
|
|
11828
|
+
import_fs22 = __toESM(require("fs"));
|
|
11829
|
+
import_os21 = __toESM(require("os"));
|
|
11830
|
+
import_path24 = __toESM(require("path"));
|
|
11590
11831
|
import_readline = __toESM(require("readline"));
|
|
11591
11832
|
init_dlp();
|
|
11592
11833
|
init_dist();
|
|
11593
|
-
PROJECTS_DIR = () =>
|
|
11594
|
-
WATERMARK_FILE = () =>
|
|
11834
|
+
PROJECTS_DIR = () => import_path24.default.join(import_os21.default.homedir(), ".claude", "projects");
|
|
11835
|
+
WATERMARK_FILE = () => import_path24.default.join(import_os21.default.homedir(), ".node9", "scan-watermark.json");
|
|
11595
11836
|
MAX_LINE_BYTES = 2 * 1024 * 1024;
|
|
11596
11837
|
WATERMARK_SCHEMA_VERSION = 2;
|
|
11597
11838
|
LONG_OUTPUT_THRESHOLD_BYTES2 = LONG_OUTPUT_THRESHOLD_BYTES;
|
|
@@ -11640,40 +11881,40 @@ function parseSinceCutoff(raw, now = /* @__PURE__ */ new Date()) {
|
|
|
11640
11881
|
return now.getTime() - 90 * 864e5;
|
|
11641
11882
|
}
|
|
11642
11883
|
function* iterateJsonlFiles(cutoffMs) {
|
|
11643
|
-
const projectsDir =
|
|
11884
|
+
const projectsDir = import_path25.default.join(import_os22.default.homedir(), ".claude", "projects");
|
|
11644
11885
|
let dirs;
|
|
11645
11886
|
try {
|
|
11646
|
-
dirs =
|
|
11887
|
+
dirs = import_fs23.default.readdirSync(projectsDir);
|
|
11647
11888
|
} catch {
|
|
11648
11889
|
return;
|
|
11649
11890
|
}
|
|
11650
11891
|
for (const dir of dirs) {
|
|
11651
|
-
const dirPath =
|
|
11892
|
+
const dirPath = import_path25.default.join(projectsDir, dir);
|
|
11652
11893
|
let stats;
|
|
11653
11894
|
try {
|
|
11654
|
-
stats =
|
|
11895
|
+
stats = import_fs23.default.statSync(dirPath);
|
|
11655
11896
|
} catch {
|
|
11656
11897
|
continue;
|
|
11657
11898
|
}
|
|
11658
11899
|
if (!stats.isDirectory()) continue;
|
|
11659
11900
|
let files;
|
|
11660
11901
|
try {
|
|
11661
|
-
files =
|
|
11902
|
+
files = import_fs23.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
11662
11903
|
} catch {
|
|
11663
11904
|
continue;
|
|
11664
11905
|
}
|
|
11665
11906
|
for (const file of files) {
|
|
11666
|
-
const filePath =
|
|
11907
|
+
const filePath = import_path25.default.join(dirPath, file);
|
|
11667
11908
|
let mtime = 0;
|
|
11668
11909
|
try {
|
|
11669
|
-
mtime =
|
|
11910
|
+
mtime = import_fs23.default.statSync(filePath).mtimeMs;
|
|
11670
11911
|
} catch {
|
|
11671
11912
|
continue;
|
|
11672
11913
|
}
|
|
11673
11914
|
if (mtime < cutoffMs) continue;
|
|
11674
11915
|
yield {
|
|
11675
11916
|
filePath,
|
|
11676
|
-
sessionId:
|
|
11917
|
+
sessionId: import_path25.default.basename(file, ".jsonl"),
|
|
11677
11918
|
projectDir: dir
|
|
11678
11919
|
};
|
|
11679
11920
|
}
|
|
@@ -11741,7 +11982,7 @@ async function runUploadHistory(opts) {
|
|
|
11741
11982
|
filesScanned++;
|
|
11742
11983
|
let content;
|
|
11743
11984
|
try {
|
|
11744
|
-
content =
|
|
11985
|
+
content = import_fs23.default.readFileSync(filePath, "utf8");
|
|
11745
11986
|
} catch {
|
|
11746
11987
|
continue;
|
|
11747
11988
|
}
|
|
@@ -11815,10 +12056,10 @@ async function runUploadHistory(opts) {
|
|
|
11815
12056
|
const costUrl = creds.apiUrl.endsWith("/policies/sync") ? creds.apiUrl.replace(/\/policies\/sync$/, "/cost-sync") : `${creds.apiUrl.replace(/\/$/, "")}/cost-sync`;
|
|
11816
12057
|
let username = "unknown";
|
|
11817
12058
|
try {
|
|
11818
|
-
username =
|
|
12059
|
+
username = import_os22.default.userInfo().username;
|
|
11819
12060
|
} catch {
|
|
11820
12061
|
}
|
|
11821
|
-
const machineId = `${
|
|
12062
|
+
const machineId = `${import_os22.default.hostname()}:${username}`;
|
|
11822
12063
|
await postJson(costUrl, creds.apiKey, {
|
|
11823
12064
|
machineId,
|
|
11824
12065
|
entries: dailyEntries
|
|
@@ -11868,14 +12109,14 @@ async function postJson(url, apiKey, body) {
|
|
|
11868
12109
|
req.end();
|
|
11869
12110
|
});
|
|
11870
12111
|
}
|
|
11871
|
-
var
|
|
12112
|
+
var import_fs23, import_https, import_os22, import_path25, import_chalk4, FINDING_TO_SIGNAL2;
|
|
11872
12113
|
var init_scan_upload_history = __esm({
|
|
11873
12114
|
"src/scan-upload-history.ts"() {
|
|
11874
12115
|
"use strict";
|
|
11875
|
-
|
|
12116
|
+
import_fs23 = __toESM(require("fs"));
|
|
11876
12117
|
import_https = __toESM(require("https"));
|
|
11877
|
-
|
|
11878
|
-
|
|
12118
|
+
import_os22 = __toESM(require("os"));
|
|
12119
|
+
import_path25 = __toESM(require("path"));
|
|
11879
12120
|
import_chalk4 = __toESM(require("chalk"));
|
|
11880
12121
|
init_dist();
|
|
11881
12122
|
init_config();
|
|
@@ -12117,14 +12358,14 @@ function buildRuleSources() {
|
|
|
12117
12358
|
}
|
|
12118
12359
|
function countScanFiles() {
|
|
12119
12360
|
let total = 0;
|
|
12120
|
-
const claudeDir =
|
|
12121
|
-
if (
|
|
12361
|
+
const claudeDir = import_path26.default.join(import_os23.default.homedir(), ".claude", "projects");
|
|
12362
|
+
if (import_fs24.default.existsSync(claudeDir)) {
|
|
12122
12363
|
try {
|
|
12123
|
-
for (const proj of
|
|
12124
|
-
const p =
|
|
12364
|
+
for (const proj of import_fs24.default.readdirSync(claudeDir)) {
|
|
12365
|
+
const p = import_path26.default.join(claudeDir, proj);
|
|
12125
12366
|
try {
|
|
12126
|
-
if (!
|
|
12127
|
-
total +=
|
|
12367
|
+
if (!import_fs24.default.statSync(p).isDirectory()) continue;
|
|
12368
|
+
total += import_fs24.default.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
|
|
12128
12369
|
} catch {
|
|
12129
12370
|
continue;
|
|
12130
12371
|
}
|
|
@@ -12132,17 +12373,17 @@ function countScanFiles() {
|
|
|
12132
12373
|
} catch {
|
|
12133
12374
|
}
|
|
12134
12375
|
}
|
|
12135
|
-
const geminiDir =
|
|
12136
|
-
if (
|
|
12376
|
+
const geminiDir = import_path26.default.join(import_os23.default.homedir(), ".gemini", "tmp");
|
|
12377
|
+
if (import_fs24.default.existsSync(geminiDir)) {
|
|
12137
12378
|
try {
|
|
12138
|
-
for (const slug2 of
|
|
12139
|
-
const p =
|
|
12379
|
+
for (const slug2 of import_fs24.default.readdirSync(geminiDir)) {
|
|
12380
|
+
const p = import_path26.default.join(geminiDir, slug2);
|
|
12140
12381
|
try {
|
|
12141
|
-
if (!
|
|
12142
|
-
const chatsDir =
|
|
12143
|
-
if (
|
|
12382
|
+
if (!import_fs24.default.statSync(p).isDirectory()) continue;
|
|
12383
|
+
const chatsDir = import_path26.default.join(p, "chats");
|
|
12384
|
+
if (import_fs24.default.existsSync(chatsDir)) {
|
|
12144
12385
|
try {
|
|
12145
|
-
total +=
|
|
12386
|
+
total += import_fs24.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
|
|
12146
12387
|
} catch {
|
|
12147
12388
|
}
|
|
12148
12389
|
}
|
|
@@ -12154,15 +12395,15 @@ function countScanFiles() {
|
|
|
12154
12395
|
}
|
|
12155
12396
|
}
|
|
12156
12397
|
for (const surface of ["antigravity-cli", "antigravity-ide"]) {
|
|
12157
|
-
const brainDir =
|
|
12158
|
-
if (!
|
|
12398
|
+
const brainDir = import_path26.default.join(import_os23.default.homedir(), ".gemini", surface, "brain");
|
|
12399
|
+
if (!import_fs24.default.existsSync(brainDir)) continue;
|
|
12159
12400
|
try {
|
|
12160
|
-
for (const conv of
|
|
12161
|
-
const convPath =
|
|
12401
|
+
for (const conv of import_fs24.default.readdirSync(brainDir)) {
|
|
12402
|
+
const convPath = import_path26.default.join(brainDir, conv);
|
|
12162
12403
|
try {
|
|
12163
|
-
if (!
|
|
12164
|
-
const logsDir =
|
|
12165
|
-
if (
|
|
12404
|
+
if (!import_fs24.default.statSync(convPath).isDirectory()) continue;
|
|
12405
|
+
const logsDir = import_path26.default.join(convPath, ".system_generated", "logs");
|
|
12406
|
+
if (import_fs24.default.existsSync(import_path26.default.join(logsDir, "transcript_full.jsonl")) || import_fs24.default.existsSync(import_path26.default.join(logsDir, "transcript.jsonl"))) {
|
|
12166
12407
|
total += 1;
|
|
12167
12408
|
}
|
|
12168
12409
|
} catch {
|
|
@@ -12172,31 +12413,31 @@ function countScanFiles() {
|
|
|
12172
12413
|
} catch {
|
|
12173
12414
|
}
|
|
12174
12415
|
}
|
|
12175
|
-
const copilotDir =
|
|
12176
|
-
if (
|
|
12416
|
+
const copilotDir = import_path26.default.join(import_os23.default.homedir(), ".copilot", "session-state");
|
|
12417
|
+
if (import_fs24.default.existsSync(copilotDir)) {
|
|
12177
12418
|
try {
|
|
12178
|
-
for (const sid of
|
|
12179
|
-
if (
|
|
12419
|
+
for (const sid of import_fs24.default.readdirSync(copilotDir)) {
|
|
12420
|
+
if (import_fs24.default.existsSync(import_path26.default.join(copilotDir, sid, "events.jsonl"))) total += 1;
|
|
12180
12421
|
}
|
|
12181
12422
|
} catch {
|
|
12182
12423
|
}
|
|
12183
12424
|
}
|
|
12184
|
-
const codexDir =
|
|
12185
|
-
if (
|
|
12425
|
+
const codexDir = import_path26.default.join(import_os23.default.homedir(), ".codex", "sessions");
|
|
12426
|
+
if (import_fs24.default.existsSync(codexDir)) {
|
|
12186
12427
|
try {
|
|
12187
|
-
for (const year of
|
|
12188
|
-
const yp =
|
|
12428
|
+
for (const year of import_fs24.default.readdirSync(codexDir)) {
|
|
12429
|
+
const yp = import_path26.default.join(codexDir, year);
|
|
12189
12430
|
try {
|
|
12190
|
-
if (!
|
|
12191
|
-
for (const month of
|
|
12192
|
-
const mp =
|
|
12431
|
+
if (!import_fs24.default.statSync(yp).isDirectory()) continue;
|
|
12432
|
+
for (const month of import_fs24.default.readdirSync(yp)) {
|
|
12433
|
+
const mp = import_path26.default.join(yp, month);
|
|
12193
12434
|
try {
|
|
12194
|
-
if (!
|
|
12195
|
-
for (const day of
|
|
12196
|
-
const dp =
|
|
12435
|
+
if (!import_fs24.default.statSync(mp).isDirectory()) continue;
|
|
12436
|
+
for (const day of import_fs24.default.readdirSync(mp)) {
|
|
12437
|
+
const dp = import_path26.default.join(mp, day);
|
|
12197
12438
|
try {
|
|
12198
|
-
if (!
|
|
12199
|
-
total +=
|
|
12439
|
+
if (!import_fs24.default.statSync(dp).isDirectory()) continue;
|
|
12440
|
+
total += import_fs24.default.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
|
|
12200
12441
|
} catch {
|
|
12201
12442
|
continue;
|
|
12202
12443
|
}
|
|
@@ -12232,7 +12473,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
12232
12473
|
const sessionId = file.replace(/\.jsonl$/, "");
|
|
12233
12474
|
let raw;
|
|
12234
12475
|
try {
|
|
12235
|
-
raw =
|
|
12476
|
+
raw = import_fs24.default.readFileSync(import_path26.default.join(projPath, file), "utf-8");
|
|
12236
12477
|
} catch {
|
|
12237
12478
|
return;
|
|
12238
12479
|
}
|
|
@@ -12284,7 +12525,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
12284
12525
|
if (block.type !== "tool_result") continue;
|
|
12285
12526
|
const filePath = block.tool_use_id ? toolUseFilePaths.get(block.tool_use_id) : void 0;
|
|
12286
12527
|
if (filePath) {
|
|
12287
|
-
const ext =
|
|
12528
|
+
const ext = import_path26.default.extname(filePath).toLowerCase();
|
|
12288
12529
|
if (CODE_EXTENSIONS.has(ext)) continue;
|
|
12289
12530
|
}
|
|
12290
12531
|
const resultText = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => c.text ?? "").join("\n") : null;
|
|
@@ -12341,7 +12582,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
12341
12582
|
const rawCmd = String(input.command ?? "").trimStart();
|
|
12342
12583
|
if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd)) continue;
|
|
12343
12584
|
const inputFilePath = typeof input.file_path === "string" ? input.file_path : "";
|
|
12344
|
-
const inputFileExt = inputFilePath ?
|
|
12585
|
+
const inputFileExt = inputFilePath ? import_path26.default.extname(inputFilePath).toLowerCase() : "";
|
|
12345
12586
|
if (CODE_EXTENSIONS.has(inputFileExt)) continue;
|
|
12346
12587
|
const dlpMatch = scanArgs(input);
|
|
12347
12588
|
if (dlpMatch) {
|
|
@@ -12438,19 +12679,19 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
12438
12679
|
}
|
|
12439
12680
|
}
|
|
12440
12681
|
function processClaudeProject(proj, projectsDir, ruleSources, startDate, result, dedup, onProgress, onLine) {
|
|
12441
|
-
const projPath =
|
|
12682
|
+
const projPath = import_path26.default.join(projectsDir, proj);
|
|
12442
12683
|
try {
|
|
12443
|
-
if (!
|
|
12684
|
+
if (!import_fs24.default.statSync(projPath).isDirectory()) return;
|
|
12444
12685
|
} catch {
|
|
12445
12686
|
return;
|
|
12446
12687
|
}
|
|
12447
|
-
const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(
|
|
12688
|
+
const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(import_os23.default.homedir(), "~")).slice(
|
|
12448
12689
|
0,
|
|
12449
12690
|
40
|
|
12450
12691
|
);
|
|
12451
12692
|
let files;
|
|
12452
12693
|
try {
|
|
12453
|
-
files =
|
|
12694
|
+
files = import_fs24.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
12454
12695
|
} catch {
|
|
12455
12696
|
return;
|
|
12456
12697
|
}
|
|
@@ -12484,12 +12725,12 @@ function emptyClaudeScan() {
|
|
|
12484
12725
|
};
|
|
12485
12726
|
}
|
|
12486
12727
|
function scanClaudeHistory(startDate, onProgress, onLine) {
|
|
12487
|
-
const projectsDir =
|
|
12728
|
+
const projectsDir = import_path26.default.join(import_os23.default.homedir(), ".claude", "projects");
|
|
12488
12729
|
const result = emptyClaudeScan();
|
|
12489
|
-
if (!
|
|
12730
|
+
if (!import_fs24.default.existsSync(projectsDir)) return result;
|
|
12490
12731
|
let projDirs;
|
|
12491
12732
|
try {
|
|
12492
|
-
projDirs =
|
|
12733
|
+
projDirs = import_fs24.default.readdirSync(projectsDir);
|
|
12493
12734
|
} catch {
|
|
12494
12735
|
return result;
|
|
12495
12736
|
}
|
|
@@ -12510,7 +12751,7 @@ function scanClaudeHistory(startDate, onProgress, onLine) {
|
|
|
12510
12751
|
return result;
|
|
12511
12752
|
}
|
|
12512
12753
|
function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
12513
|
-
const tmpDir =
|
|
12754
|
+
const tmpDir = import_path26.default.join(import_os23.default.homedir(), ".gemini", "tmp");
|
|
12514
12755
|
const result = {
|
|
12515
12756
|
filesScanned: 0,
|
|
12516
12757
|
sessions: 0,
|
|
@@ -12525,33 +12766,33 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
12525
12766
|
sessionsWithEarlySecrets: 0
|
|
12526
12767
|
};
|
|
12527
12768
|
const dedup = emptyScanDedup();
|
|
12528
|
-
if (!
|
|
12769
|
+
if (!import_fs24.default.existsSync(tmpDir)) return result;
|
|
12529
12770
|
let slugDirs;
|
|
12530
12771
|
try {
|
|
12531
|
-
slugDirs =
|
|
12772
|
+
slugDirs = import_fs24.default.readdirSync(tmpDir);
|
|
12532
12773
|
} catch {
|
|
12533
12774
|
return result;
|
|
12534
12775
|
}
|
|
12535
12776
|
const ruleSources = buildRuleSources();
|
|
12536
12777
|
for (const slug2 of slugDirs) {
|
|
12537
|
-
const slugPath =
|
|
12778
|
+
const slugPath = import_path26.default.join(tmpDir, slug2);
|
|
12538
12779
|
try {
|
|
12539
|
-
if (!
|
|
12780
|
+
if (!import_fs24.default.statSync(slugPath).isDirectory()) continue;
|
|
12540
12781
|
} catch {
|
|
12541
12782
|
continue;
|
|
12542
12783
|
}
|
|
12543
12784
|
let projLabel = stripTerminalEscapes(slug2).slice(0, 40);
|
|
12544
12785
|
try {
|
|
12545
12786
|
projLabel = stripTerminalEscapes(
|
|
12546
|
-
|
|
12547
|
-
).replace(
|
|
12787
|
+
import_fs24.default.readFileSync(import_path26.default.join(slugPath, ".project_root"), "utf-8").trim()
|
|
12788
|
+
).replace(import_os23.default.homedir(), "~").slice(0, 40);
|
|
12548
12789
|
} catch {
|
|
12549
12790
|
}
|
|
12550
|
-
const chatsDir =
|
|
12551
|
-
if (!
|
|
12791
|
+
const chatsDir = import_path26.default.join(slugPath, "chats");
|
|
12792
|
+
if (!import_fs24.default.existsSync(chatsDir)) continue;
|
|
12552
12793
|
let chatFiles;
|
|
12553
12794
|
try {
|
|
12554
|
-
chatFiles =
|
|
12795
|
+
chatFiles = import_fs24.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json") || f.endsWith(".jsonl")).sort((a, b) => Number(b.endsWith(".jsonl")) - Number(a.endsWith(".jsonl")));
|
|
12555
12796
|
} catch {
|
|
12556
12797
|
continue;
|
|
12557
12798
|
}
|
|
@@ -12564,7 +12805,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
12564
12805
|
onProgress?.(result.filesScanned);
|
|
12565
12806
|
let raw;
|
|
12566
12807
|
try {
|
|
12567
|
-
raw =
|
|
12808
|
+
raw = import_fs24.default.readFileSync(import_path26.default.join(chatsDir, chatFile), "utf-8");
|
|
12568
12809
|
} catch {
|
|
12569
12810
|
continue;
|
|
12570
12811
|
}
|
|
@@ -12737,13 +12978,13 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
12737
12978
|
return result;
|
|
12738
12979
|
}
|
|
12739
12980
|
function antigravityBrainDirs() {
|
|
12740
|
-
return ["antigravity-cli", "antigravity-ide"].map((surface) =>
|
|
12981
|
+
return ["antigravity-cli", "antigravity-ide"].map((surface) => import_path26.default.join(import_os23.default.homedir(), ".gemini", surface, "brain")).filter((p) => import_fs24.default.existsSync(p));
|
|
12741
12982
|
}
|
|
12742
12983
|
function antigravityTranscriptPath(convPath) {
|
|
12743
|
-
const logsDir =
|
|
12984
|
+
const logsDir = import_path26.default.join(convPath, ".system_generated", "logs");
|
|
12744
12985
|
for (const name of ["transcript_full.jsonl", "transcript.jsonl"]) {
|
|
12745
|
-
const p =
|
|
12746
|
-
if (
|
|
12986
|
+
const p = import_path26.default.join(logsDir, name);
|
|
12987
|
+
if (import_fs24.default.existsSync(p)) return p;
|
|
12747
12988
|
}
|
|
12748
12989
|
return null;
|
|
12749
12990
|
}
|
|
@@ -12769,14 +13010,14 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
|
|
|
12769
13010
|
for (const brainDir of brainDirs) {
|
|
12770
13011
|
let convDirs;
|
|
12771
13012
|
try {
|
|
12772
|
-
convDirs =
|
|
13013
|
+
convDirs = import_fs24.default.readdirSync(brainDir);
|
|
12773
13014
|
} catch {
|
|
12774
13015
|
continue;
|
|
12775
13016
|
}
|
|
12776
13017
|
for (const conv of convDirs) {
|
|
12777
|
-
const convPath =
|
|
13018
|
+
const convPath = import_path26.default.join(brainDir, conv);
|
|
12778
13019
|
try {
|
|
12779
|
-
if (!
|
|
13020
|
+
if (!import_fs24.default.statSync(convPath).isDirectory()) continue;
|
|
12780
13021
|
} catch {
|
|
12781
13022
|
continue;
|
|
12782
13023
|
}
|
|
@@ -12786,7 +13027,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
|
|
|
12786
13027
|
onProgress?.(result.filesScanned);
|
|
12787
13028
|
let raw;
|
|
12788
13029
|
try {
|
|
12789
|
-
raw =
|
|
13030
|
+
raw = import_fs24.default.readFileSync(transcriptFile, "utf-8");
|
|
12790
13031
|
} catch {
|
|
12791
13032
|
continue;
|
|
12792
13033
|
}
|
|
@@ -12843,7 +13084,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
|
|
|
12843
13084
|
result.bashCalls++;
|
|
12844
13085
|
const cwd = String(input.cwd ?? "");
|
|
12845
13086
|
if (cwd && projLabel === conv.slice(0, 8)) {
|
|
12846
|
-
projLabel = stripTerminalEscapes(cwd).replace(
|
|
13087
|
+
projLabel = stripTerminalEscapes(cwd).replace(import_os23.default.homedir(), "~").slice(0, 40);
|
|
12847
13088
|
}
|
|
12848
13089
|
}
|
|
12849
13090
|
const rawCmd = String(input.command ?? "").trimStart();
|
|
@@ -12943,7 +13184,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
|
|
|
12943
13184
|
return result;
|
|
12944
13185
|
}
|
|
12945
13186
|
function scanCopilotHistory(startDate, onProgress, onLine) {
|
|
12946
|
-
const sessionDir =
|
|
13187
|
+
const sessionDir = import_path26.default.join(import_os23.default.homedir(), ".copilot", "session-state");
|
|
12947
13188
|
const result = {
|
|
12948
13189
|
filesScanned: 0,
|
|
12949
13190
|
sessions: 0,
|
|
@@ -12959,22 +13200,22 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
|
|
|
12959
13200
|
sessionsWithEarlySecrets: 0
|
|
12960
13201
|
};
|
|
12961
13202
|
const dedup = emptyScanDedup();
|
|
12962
|
-
if (!
|
|
13203
|
+
if (!import_fs24.default.existsSync(sessionDir)) return result;
|
|
12963
13204
|
let sessionIds;
|
|
12964
13205
|
try {
|
|
12965
|
-
sessionIds =
|
|
13206
|
+
sessionIds = import_fs24.default.readdirSync(sessionDir);
|
|
12966
13207
|
} catch {
|
|
12967
13208
|
return result;
|
|
12968
13209
|
}
|
|
12969
13210
|
const ruleSources = buildRuleSources();
|
|
12970
13211
|
for (const sessionId of sessionIds) {
|
|
12971
|
-
const eventsPath =
|
|
12972
|
-
if (!
|
|
13212
|
+
const eventsPath = import_path26.default.join(sessionDir, sessionId, "events.jsonl");
|
|
13213
|
+
if (!import_fs24.default.existsSync(eventsPath)) continue;
|
|
12973
13214
|
result.filesScanned++;
|
|
12974
13215
|
onProgress?.(result.filesScanned);
|
|
12975
13216
|
let raw;
|
|
12976
13217
|
try {
|
|
12977
|
-
raw =
|
|
13218
|
+
raw = import_fs24.default.readFileSync(eventsPath, "utf-8");
|
|
12978
13219
|
} catch {
|
|
12979
13220
|
continue;
|
|
12980
13221
|
}
|
|
@@ -12994,7 +13235,7 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
|
|
|
12994
13235
|
if (ev.type === "session.start") {
|
|
12995
13236
|
const cwd = ev.data?.context?.cwd;
|
|
12996
13237
|
if (typeof cwd === "string" && cwd) {
|
|
12997
|
-
projLabel = stripTerminalEscapes(cwd).replace(
|
|
13238
|
+
projLabel = stripTerminalEscapes(cwd).replace(import_os23.default.homedir(), "~").slice(0, 40);
|
|
12998
13239
|
}
|
|
12999
13240
|
continue;
|
|
13000
13241
|
}
|
|
@@ -13126,7 +13367,7 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
|
|
|
13126
13367
|
return result;
|
|
13127
13368
|
}
|
|
13128
13369
|
function scanCodexHistory(startDate, onProgress, onLine) {
|
|
13129
|
-
const sessionsBase =
|
|
13370
|
+
const sessionsBase = import_path26.default.join(import_os23.default.homedir(), ".codex", "sessions");
|
|
13130
13371
|
const result = {
|
|
13131
13372
|
filesScanned: 0,
|
|
13132
13373
|
sessions: 0,
|
|
@@ -13141,32 +13382,32 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
13141
13382
|
sessionsWithEarlySecrets: 0
|
|
13142
13383
|
};
|
|
13143
13384
|
const dedup = emptyScanDedup();
|
|
13144
|
-
if (!
|
|
13385
|
+
if (!import_fs24.default.existsSync(sessionsBase)) return result;
|
|
13145
13386
|
const jsonlFiles = [];
|
|
13146
13387
|
try {
|
|
13147
|
-
for (const year of
|
|
13148
|
-
const yearPath =
|
|
13388
|
+
for (const year of import_fs24.default.readdirSync(sessionsBase)) {
|
|
13389
|
+
const yearPath = import_path26.default.join(sessionsBase, year);
|
|
13149
13390
|
try {
|
|
13150
|
-
if (!
|
|
13391
|
+
if (!import_fs24.default.statSync(yearPath).isDirectory()) continue;
|
|
13151
13392
|
} catch {
|
|
13152
13393
|
continue;
|
|
13153
13394
|
}
|
|
13154
|
-
for (const month of
|
|
13155
|
-
const monthPath =
|
|
13395
|
+
for (const month of import_fs24.default.readdirSync(yearPath)) {
|
|
13396
|
+
const monthPath = import_path26.default.join(yearPath, month);
|
|
13156
13397
|
try {
|
|
13157
|
-
if (!
|
|
13398
|
+
if (!import_fs24.default.statSync(monthPath).isDirectory()) continue;
|
|
13158
13399
|
} catch {
|
|
13159
13400
|
continue;
|
|
13160
13401
|
}
|
|
13161
|
-
for (const day of
|
|
13162
|
-
const dayPath =
|
|
13402
|
+
for (const day of import_fs24.default.readdirSync(monthPath)) {
|
|
13403
|
+
const dayPath = import_path26.default.join(monthPath, day);
|
|
13163
13404
|
try {
|
|
13164
|
-
if (!
|
|
13405
|
+
if (!import_fs24.default.statSync(dayPath).isDirectory()) continue;
|
|
13165
13406
|
} catch {
|
|
13166
13407
|
continue;
|
|
13167
13408
|
}
|
|
13168
|
-
for (const file of
|
|
13169
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
13409
|
+
for (const file of import_fs24.default.readdirSync(dayPath)) {
|
|
13410
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path26.default.join(dayPath, file));
|
|
13170
13411
|
}
|
|
13171
13412
|
}
|
|
13172
13413
|
}
|
|
@@ -13180,7 +13421,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
13180
13421
|
onProgress?.(result.filesScanned);
|
|
13181
13422
|
let lines;
|
|
13182
13423
|
try {
|
|
13183
|
-
lines =
|
|
13424
|
+
lines = import_fs24.default.readFileSync(filePath, "utf-8").split("\n");
|
|
13184
13425
|
} catch {
|
|
13185
13426
|
continue;
|
|
13186
13427
|
}
|
|
@@ -13207,7 +13448,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
13207
13448
|
sessionId = String(payload["id"] ?? filePath);
|
|
13208
13449
|
startTime = String(payload["timestamp"] ?? "");
|
|
13209
13450
|
const cwd = String(payload["cwd"] ?? "");
|
|
13210
|
-
projLabel = stripTerminalEscapes(cwd.replace(
|
|
13451
|
+
projLabel = stripTerminalEscapes(cwd.replace(import_os23.default.homedir(), "~")).slice(0, 40);
|
|
13211
13452
|
continue;
|
|
13212
13453
|
}
|
|
13213
13454
|
if (entry.type === "turn_context" && typeof payload["model"] === "string") {
|
|
@@ -13367,17 +13608,17 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
13367
13608
|
return result;
|
|
13368
13609
|
}
|
|
13369
13610
|
function scanShellConfig() {
|
|
13370
|
-
const home =
|
|
13611
|
+
const home = import_os23.default.homedir();
|
|
13371
13612
|
const configFiles = [".zshrc", ".bashrc", ".bash_profile", ".profile"].map(
|
|
13372
|
-
(f) =>
|
|
13613
|
+
(f) => import_path26.default.join(home, f)
|
|
13373
13614
|
);
|
|
13374
13615
|
const findings = [];
|
|
13375
13616
|
const seen = /* @__PURE__ */ new Set();
|
|
13376
13617
|
for (const filePath of configFiles) {
|
|
13377
|
-
if (!
|
|
13618
|
+
if (!import_fs24.default.existsSync(filePath)) continue;
|
|
13378
13619
|
let lines;
|
|
13379
13620
|
try {
|
|
13380
|
-
lines =
|
|
13621
|
+
lines = import_fs24.default.readFileSync(filePath, "utf-8").split("\n");
|
|
13381
13622
|
} catch {
|
|
13382
13623
|
continue;
|
|
13383
13624
|
}
|
|
@@ -14183,7 +14424,7 @@ function registerScanCommand(program2) {
|
|
|
14183
14424
|
if (!drillDown) {
|
|
14184
14425
|
const useInk2 = !options.classic;
|
|
14185
14426
|
if (useInk2) {
|
|
14186
|
-
const scanInkPath =
|
|
14427
|
+
const scanInkPath = import_path26.default.join(__dirname, "scan-ink.mjs");
|
|
14187
14428
|
const dynamicImport = new Function("id", "return import(id)");
|
|
14188
14429
|
const mod = await dynamicImport(`file://${scanInkPath}`);
|
|
14189
14430
|
const rangeLabel2 = options.all ? "all time" : `last ${options.days ?? 90} days`;
|
|
@@ -14415,14 +14656,14 @@ function registerScanCommand(program2) {
|
|
|
14415
14656
|
}
|
|
14416
14657
|
);
|
|
14417
14658
|
}
|
|
14418
|
-
var import_chalk5,
|
|
14659
|
+
var import_chalk5, import_fs24, import_path26, import_os23, import_string_width2, CODE_EXTENSIONS, SELF_OUTPUT_MARKERS, FIXTURE_TOKEN_PATTERNS, TERMINAL_ESCAPE_RE2, LOOP_TOOLS, LOOP_THRESHOLD, LOOP_TIMESPAN_THRESHOLD_MS, STUCK_TOOLS_MIN_WASTE, STUCK_TOOLS_LIMIT, RECURRING_SESSION_THRESHOLD, STALE_AGE_DAYS, classifyRuleSeverity2, narrativeRuleLabel2;
|
|
14419
14660
|
var init_scan = __esm({
|
|
14420
14661
|
"src/cli/commands/scan.ts"() {
|
|
14421
14662
|
"use strict";
|
|
14422
14663
|
import_chalk5 = __toESM(require("chalk"));
|
|
14423
|
-
|
|
14424
|
-
|
|
14425
|
-
|
|
14664
|
+
import_fs24 = __toESM(require("fs"));
|
|
14665
|
+
import_path26 = __toESM(require("path"));
|
|
14666
|
+
import_os23 = __toESM(require("os"));
|
|
14426
14667
|
init_shields();
|
|
14427
14668
|
init_config();
|
|
14428
14669
|
init_policy();
|
|
@@ -14599,12 +14840,12 @@ var init_suggestion_tracker = __esm({
|
|
|
14599
14840
|
});
|
|
14600
14841
|
|
|
14601
14842
|
// src/daemon/taint-store.ts
|
|
14602
|
-
var
|
|
14843
|
+
var import_fs25, import_path27, DEFAULT_TTL_MS, TaintStore, SESSION_TAINT_TTL_MS, SessionTaintStore;
|
|
14603
14844
|
var init_taint_store = __esm({
|
|
14604
14845
|
"src/daemon/taint-store.ts"() {
|
|
14605
14846
|
"use strict";
|
|
14606
|
-
|
|
14607
|
-
|
|
14847
|
+
import_fs25 = __toESM(require("fs"));
|
|
14848
|
+
import_path27 = __toESM(require("path"));
|
|
14608
14849
|
DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
14609
14850
|
TaintStore = class {
|
|
14610
14851
|
records = /* @__PURE__ */ new Map();
|
|
@@ -14670,9 +14911,9 @@ var init_taint_store = __esm({
|
|
|
14670
14911
|
/** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
|
|
14671
14912
|
_resolve(filePath) {
|
|
14672
14913
|
try {
|
|
14673
|
-
return
|
|
14914
|
+
return import_fs25.default.realpathSync.native(import_path27.default.resolve(filePath));
|
|
14674
14915
|
} catch {
|
|
14675
|
-
return
|
|
14916
|
+
return import_path27.default.resolve(filePath);
|
|
14676
14917
|
}
|
|
14677
14918
|
}
|
|
14678
14919
|
};
|
|
@@ -14838,8 +15079,8 @@ var init_session_history = __esm({
|
|
|
14838
15079
|
// src/daemon/state.ts
|
|
14839
15080
|
function loadInsightCounts() {
|
|
14840
15081
|
try {
|
|
14841
|
-
if (!
|
|
14842
|
-
const data = JSON.parse(
|
|
15082
|
+
if (!import_fs26.default.existsSync(INSIGHT_COUNTS_FILE)) return;
|
|
15083
|
+
const data = JSON.parse(import_fs26.default.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
|
|
14843
15084
|
for (const [tool, count] of Object.entries(data)) {
|
|
14844
15085
|
if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
|
|
14845
15086
|
}
|
|
@@ -14878,23 +15119,23 @@ function markRejectionHandlerRegistered() {
|
|
|
14878
15119
|
daemonRejectionHandlerRegistered = true;
|
|
14879
15120
|
}
|
|
14880
15121
|
function atomicWriteSync2(filePath, data, options) {
|
|
14881
|
-
const dir =
|
|
14882
|
-
if (!
|
|
15122
|
+
const dir = import_path28.default.dirname(filePath);
|
|
15123
|
+
if (!import_fs26.default.existsSync(dir)) import_fs26.default.mkdirSync(dir, { recursive: true });
|
|
14883
15124
|
const tmpPath = `${filePath}.${(0, import_crypto8.randomUUID)()}.tmp`;
|
|
14884
15125
|
try {
|
|
14885
|
-
|
|
15126
|
+
import_fs26.default.writeFileSync(tmpPath, data, options);
|
|
14886
15127
|
} catch (err2) {
|
|
14887
15128
|
try {
|
|
14888
|
-
|
|
15129
|
+
import_fs26.default.unlinkSync(tmpPath);
|
|
14889
15130
|
} catch {
|
|
14890
15131
|
}
|
|
14891
15132
|
throw err2;
|
|
14892
15133
|
}
|
|
14893
15134
|
try {
|
|
14894
|
-
|
|
15135
|
+
import_fs26.default.renameSync(tmpPath, filePath);
|
|
14895
15136
|
} catch (err2) {
|
|
14896
15137
|
try {
|
|
14897
|
-
|
|
15138
|
+
import_fs26.default.unlinkSync(tmpPath);
|
|
14898
15139
|
} catch {
|
|
14899
15140
|
}
|
|
14900
15141
|
throw err2;
|
|
@@ -14918,16 +15159,16 @@ function appendAuditLog(data) {
|
|
|
14918
15159
|
decision: data.decision,
|
|
14919
15160
|
source: "daemon"
|
|
14920
15161
|
};
|
|
14921
|
-
const dir =
|
|
14922
|
-
if (!
|
|
14923
|
-
|
|
15162
|
+
const dir = import_path28.default.dirname(AUDIT_LOG_FILE);
|
|
15163
|
+
if (!import_fs26.default.existsSync(dir)) import_fs26.default.mkdirSync(dir, { recursive: true });
|
|
15164
|
+
import_fs26.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
14924
15165
|
} catch {
|
|
14925
15166
|
}
|
|
14926
15167
|
}
|
|
14927
15168
|
function getAuditHistory(limit = 20) {
|
|
14928
15169
|
try {
|
|
14929
|
-
if (!
|
|
14930
|
-
const lines =
|
|
15170
|
+
if (!import_fs26.default.existsSync(AUDIT_LOG_FILE)) return [];
|
|
15171
|
+
const lines = import_fs26.default.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
|
|
14931
15172
|
if (lines.length === 1 && lines[0] === "") return [];
|
|
14932
15173
|
return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
|
|
14933
15174
|
} catch {
|
|
@@ -14936,7 +15177,7 @@ function getAuditHistory(limit = 20) {
|
|
|
14936
15177
|
}
|
|
14937
15178
|
function getOrgName() {
|
|
14938
15179
|
try {
|
|
14939
|
-
if (
|
|
15180
|
+
if (import_fs26.default.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
|
|
14940
15181
|
} catch {
|
|
14941
15182
|
}
|
|
14942
15183
|
return null;
|
|
@@ -14944,8 +15185,8 @@ function getOrgName() {
|
|
|
14944
15185
|
function writeGlobalSetting(key, value) {
|
|
14945
15186
|
let config = {};
|
|
14946
15187
|
try {
|
|
14947
|
-
if (
|
|
14948
|
-
config = JSON.parse(
|
|
15188
|
+
if (import_fs26.default.existsSync(GLOBAL_CONFIG_FILE)) {
|
|
15189
|
+
config = JSON.parse(import_fs26.default.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
|
|
14949
15190
|
}
|
|
14950
15191
|
} catch {
|
|
14951
15192
|
}
|
|
@@ -14957,8 +15198,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
14957
15198
|
try {
|
|
14958
15199
|
let trust = { entries: [] };
|
|
14959
15200
|
try {
|
|
14960
|
-
if (
|
|
14961
|
-
trust = JSON.parse(
|
|
15201
|
+
if (import_fs26.default.existsSync(TRUST_FILE2))
|
|
15202
|
+
trust = JSON.parse(import_fs26.default.readFileSync(TRUST_FILE2, "utf-8"));
|
|
14962
15203
|
} catch {
|
|
14963
15204
|
}
|
|
14964
15205
|
trust.entries = trust.entries.filter(
|
|
@@ -14975,8 +15216,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
14975
15216
|
}
|
|
14976
15217
|
function readPersistentDecisions() {
|
|
14977
15218
|
try {
|
|
14978
|
-
if (
|
|
14979
|
-
return JSON.parse(
|
|
15219
|
+
if (import_fs26.default.existsSync(DECISIONS_FILE)) {
|
|
15220
|
+
return JSON.parse(import_fs26.default.readFileSync(DECISIONS_FILE, "utf-8"));
|
|
14980
15221
|
}
|
|
14981
15222
|
} catch {
|
|
14982
15223
|
}
|
|
@@ -15004,7 +15245,7 @@ function estimateToolCost(tool, args) {
|
|
|
15004
15245
|
const filePath = a.file_path ?? a.path;
|
|
15005
15246
|
if (filePath) {
|
|
15006
15247
|
try {
|
|
15007
|
-
const bytes =
|
|
15248
|
+
const bytes = import_fs26.default.statSync(filePath).size;
|
|
15008
15249
|
return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
|
|
15009
15250
|
} catch {
|
|
15010
15251
|
}
|
|
@@ -15075,7 +15316,7 @@ function abandonPending() {
|
|
|
15075
15316
|
});
|
|
15076
15317
|
if (autoStarted) {
|
|
15077
15318
|
try {
|
|
15078
|
-
|
|
15319
|
+
import_fs26.default.unlinkSync(DAEMON_PID_FILE);
|
|
15079
15320
|
} catch {
|
|
15080
15321
|
}
|
|
15081
15322
|
setTimeout(() => {
|
|
@@ -15086,8 +15327,8 @@ function abandonPending() {
|
|
|
15086
15327
|
}
|
|
15087
15328
|
function logActivitySocket(msg) {
|
|
15088
15329
|
try {
|
|
15089
|
-
|
|
15090
|
-
|
|
15330
|
+
import_fs26.default.appendFileSync(
|
|
15331
|
+
import_path28.default.join(homeDir, ".node9", "hook-debug.log"),
|
|
15091
15332
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] [activity-socket] ${msg}
|
|
15092
15333
|
`
|
|
15093
15334
|
);
|
|
@@ -15109,13 +15350,13 @@ function shouldRebind(now = Date.now()) {
|
|
|
15109
15350
|
function startActivitySocket() {
|
|
15110
15351
|
bindActivitySocket();
|
|
15111
15352
|
activityHealthInterval = setInterval(() => {
|
|
15112
|
-
if (!
|
|
15353
|
+
if (!import_fs26.default.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
|
|
15113
15354
|
}, ACTIVITY_HEALTH_PROBE_MS);
|
|
15114
15355
|
activityHealthInterval.unref();
|
|
15115
15356
|
process.on("exit", () => {
|
|
15116
15357
|
if (activityHealthInterval) clearInterval(activityHealthInterval);
|
|
15117
15358
|
try {
|
|
15118
|
-
|
|
15359
|
+
import_fs26.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
15119
15360
|
} catch {
|
|
15120
15361
|
}
|
|
15121
15362
|
});
|
|
@@ -15143,7 +15384,7 @@ function attemptRebind(reason) {
|
|
|
15143
15384
|
}
|
|
15144
15385
|
function bindActivitySocket() {
|
|
15145
15386
|
try {
|
|
15146
|
-
|
|
15387
|
+
import_fs26.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
15147
15388
|
} catch {
|
|
15148
15389
|
}
|
|
15149
15390
|
const ACTIVITY_MAX_BYTES = 1024 * 1024;
|
|
@@ -15231,317 +15472,96 @@ function bindActivitySocket() {
|
|
|
15231
15472
|
agent: data.agent,
|
|
15232
15473
|
mcpServer: data.mcpServer,
|
|
15233
15474
|
sessionId: data.sessionId
|
|
15234
|
-
});
|
|
15235
|
-
}
|
|
15236
|
-
} catch {
|
|
15237
|
-
}
|
|
15238
|
-
});
|
|
15239
|
-
socket.on("error", () => {
|
|
15240
|
-
});
|
|
15241
|
-
});
|
|
15242
|
-
unixServer.on("error", (err2) => {
|
|
15243
|
-
logActivitySocket(`server error: ${err2.message}`);
|
|
15244
|
-
});
|
|
15245
|
-
unixServer.listen(ACTIVITY_SOCKET_PATH2, () => {
|
|
15246
|
-
logActivitySocket(`bound to ${ACTIVITY_SOCKET_PATH2}`);
|
|
15247
|
-
});
|
|
15248
|
-
activitySocketServer = unixServer;
|
|
15249
|
-
}
|
|
15250
|
-
var import_net2, import_fs25, import_path27, import_os23, import_crypto8, 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;
|
|
15251
|
-
var init_state2 = __esm({
|
|
15252
|
-
"src/daemon/state.ts"() {
|
|
15253
|
-
"use strict";
|
|
15254
|
-
import_net2 = __toESM(require("net"));
|
|
15255
|
-
import_fs25 = __toESM(require("fs"));
|
|
15256
|
-
import_path27 = __toESM(require("path"));
|
|
15257
|
-
import_os23 = __toESM(require("os"));
|
|
15258
|
-
import_crypto8 = require("crypto");
|
|
15259
|
-
init_daemon();
|
|
15260
|
-
init_suggestion_tracker();
|
|
15261
|
-
init_taint_store();
|
|
15262
|
-
init_session_counters();
|
|
15263
|
-
init_session_history();
|
|
15264
|
-
homeDir = import_os23.default.homedir();
|
|
15265
|
-
DAEMON_PID_FILE = import_path27.default.join(homeDir, ".node9", "daemon.pid");
|
|
15266
|
-
DECISIONS_FILE = import_path27.default.join(homeDir, ".node9", "decisions.json");
|
|
15267
|
-
AUDIT_LOG_FILE = import_path27.default.join(homeDir, ".node9", "audit.log");
|
|
15268
|
-
TRUST_FILE2 = import_path27.default.join(homeDir, ".node9", "trust.json");
|
|
15269
|
-
GLOBAL_CONFIG_FILE = import_path27.default.join(homeDir, ".node9", "config.json");
|
|
15270
|
-
CREDENTIALS_FILE = import_path27.default.join(homeDir, ".node9", "credentials.json");
|
|
15271
|
-
INSIGHT_COUNTS_FILE = import_path27.default.join(homeDir, ".node9", "insight-counts.json");
|
|
15272
|
-
pending = /* @__PURE__ */ new Map();
|
|
15273
|
-
sseClients = /* @__PURE__ */ new Set();
|
|
15274
|
-
suggestionTracker = new SuggestionTracker(3);
|
|
15275
|
-
taintStore = new TaintStore();
|
|
15276
|
-
sessionTaintStore = new SessionTaintStore();
|
|
15277
|
-
insightCounts = /* @__PURE__ */ new Map();
|
|
15278
|
-
_abandonTimer = null;
|
|
15279
|
-
_hadBrowserClient = false;
|
|
15280
|
-
_daemonServer = null;
|
|
15281
|
-
daemonRejectionHandlerRegistered = false;
|
|
15282
|
-
AUTO_DENY_MS = 12e4;
|
|
15283
|
-
TRUST_DURATIONS = {
|
|
15284
|
-
"30m": 30 * 6e4,
|
|
15285
|
-
"1h": 60 * 6e4,
|
|
15286
|
-
"2h": 2 * 60 * 6e4
|
|
15287
|
-
};
|
|
15288
|
-
autoStarted = process.env.NODE9_AUTO_STARTED === "1";
|
|
15289
|
-
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path27.default.join(import_os23.default.tmpdir(), "node9-activity.sock");
|
|
15290
|
-
ACTIVITY_RING_SIZE = 100;
|
|
15291
|
-
activityRing = [];
|
|
15292
|
-
LARGE_RESPONSE_RING_SIZE = 20;
|
|
15293
|
-
largeResponseRing = [];
|
|
15294
|
-
cachedScanResult = null;
|
|
15295
|
-
cachedScanTs = 0;
|
|
15296
|
-
SCAN_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
15297
|
-
SECRET_KEY_RE = /password|secret|token|key|apikey|credential|auth/i;
|
|
15298
|
-
INPUT_PRICE_PER_1M = 3;
|
|
15299
|
-
OUTPUT_PRICE_PER_1M = 15;
|
|
15300
|
-
BYTES_PER_TOKEN = 4;
|
|
15301
|
-
CRITICAL_FORENSIC_CATEGORIES = /* @__PURE__ */ new Set([
|
|
15302
|
-
"privilege-escalation",
|
|
15303
|
-
"destructive-op",
|
|
15304
|
-
"eval-of-remote"
|
|
15305
|
-
]);
|
|
15306
|
-
WRITE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
15307
|
-
"write",
|
|
15308
|
-
"write_file",
|
|
15309
|
-
"create_file",
|
|
15310
|
-
"edit",
|
|
15311
|
-
"multiedit",
|
|
15312
|
-
"str_replace_based_edit_tool",
|
|
15313
|
-
"replace",
|
|
15314
|
-
"notebook_edit",
|
|
15315
|
-
"notebookedit"
|
|
15316
|
-
]);
|
|
15317
|
-
ACTIVITY_REBIND_MAX_ATTEMPTS = 5;
|
|
15318
|
-
ACTIVITY_REBIND_WINDOW_MS = 6e4;
|
|
15319
|
-
ACTIVITY_HEALTH_PROBE_MS = 2e3;
|
|
15320
|
-
activitySocketServer = null;
|
|
15321
|
-
activityHealthInterval = null;
|
|
15322
|
-
activityRebindAttempts = [];
|
|
15323
|
-
activityCircuitTripped = false;
|
|
15324
|
-
}
|
|
15325
|
-
});
|
|
15326
|
-
|
|
15327
|
-
// src/agent-wiring.ts
|
|
15328
|
-
function readJson2(filePath) {
|
|
15329
|
-
if (!import_fs26.default.existsSync(filePath)) return null;
|
|
15330
|
-
try {
|
|
15331
|
-
return JSON.parse(import_fs26.default.readFileSync(filePath, "utf-8"));
|
|
15332
|
-
} catch {
|
|
15333
|
-
return "invalid";
|
|
15334
|
-
}
|
|
15335
|
-
}
|
|
15336
|
-
function matchersHaveNode9Hook(matchers) {
|
|
15337
|
-
return (matchers ?? []).some((m) => (m.hooks ?? []).some((h) => isNode9Hook(h.command)));
|
|
15338
|
-
}
|
|
15339
|
-
function flatHaveNode9Hook(entries) {
|
|
15340
|
-
return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
|
|
15341
|
-
}
|
|
15342
|
-
function readHookRoot(filePath, format) {
|
|
15343
|
-
if (!import_fs26.default.existsSync(filePath)) return "absent";
|
|
15344
|
-
let raw;
|
|
15345
|
-
try {
|
|
15346
|
-
raw = import_fs26.default.readFileSync(filePath, "utf-8");
|
|
15347
|
-
} catch {
|
|
15348
|
-
return "absent";
|
|
15349
|
-
}
|
|
15350
|
-
try {
|
|
15351
|
-
const parsed = format === "yaml" ? yaml2.parse(raw) : JSON.parse(raw);
|
|
15352
|
-
return parsed?.hooks ?? {};
|
|
15353
|
-
} catch {
|
|
15354
|
-
return "invalid";
|
|
15355
|
-
}
|
|
15356
|
-
}
|
|
15357
|
-
function eventWired(root, ev, format) {
|
|
15358
|
-
const arr = root[ev.key];
|
|
15359
|
-
if (format === "matcher") return matchersHaveNode9Hook(arr);
|
|
15360
|
-
return flatHaveNode9Hook(arr);
|
|
15361
|
-
}
|
|
15362
|
-
function detectMcp(servers) {
|
|
15363
|
-
const entries = Object.entries(servers ?? {});
|
|
15364
|
-
const present = entries.some(([, s]) => s?.command === "node9");
|
|
15365
|
-
const wrapped = entries.filter(([, s]) => s?.command === "node9" && Array.isArray(s.args) && s.args.length > 0).map(([name, s]) => `${name} \u2192 ${s.args.join(" ")}`);
|
|
15366
|
-
return { wrapped, present };
|
|
15367
|
-
}
|
|
15368
|
-
function readMcp(filePath, format) {
|
|
15369
|
-
if (!import_fs26.default.existsSync(filePath)) return { wrapped: [], present: false };
|
|
15370
|
-
try {
|
|
15371
|
-
if (format === "toml") {
|
|
15372
|
-
const parsed2 = (0, import_smol_toml2.parse)(import_fs26.default.readFileSync(filePath, "utf-8"));
|
|
15373
|
-
return detectMcp(parsed2?.mcp_servers);
|
|
15374
|
-
}
|
|
15375
|
-
const parsed = readJson2(filePath);
|
|
15376
|
-
if (parsed === null || parsed === "invalid") return { wrapped: [], present: false };
|
|
15377
|
-
return detectMcp(parsed.mcpServers);
|
|
15378
|
-
} catch {
|
|
15379
|
-
return { wrapped: [], present: false };
|
|
15380
|
-
}
|
|
15381
|
-
}
|
|
15382
|
-
function getAgentWiring(home = import_os24.default.homedir()) {
|
|
15383
|
-
const detected = detectAgents(home);
|
|
15384
|
-
return AGENT_SPECS.map((spec) => {
|
|
15385
|
-
const present = spec.present(home);
|
|
15386
|
-
const pad = spec.labelPad ?? DEFAULT_LABEL_PAD;
|
|
15387
|
-
let hooks;
|
|
15388
|
-
let wireState;
|
|
15389
|
-
let hookLabel;
|
|
15390
|
-
let settingsPath;
|
|
15391
|
-
if (spec.shimFile) {
|
|
15392
|
-
const shimWired = exists(spec.shimFile(home));
|
|
15393
|
-
hooks = [{ label: "node9 plugin (node9 check)", wired: shimWired }];
|
|
15394
|
-
wireState = shimWired ? "wired" : present ? "unwired" : "absent";
|
|
15395
|
-
hookLabel = "node9 plugin";
|
|
15396
|
-
settingsPath = spec.shimFile(home);
|
|
15397
|
-
} else {
|
|
15398
|
-
const root = spec.hookFile ? readHookRoot(spec.hookFile(home), spec.hookFormat) : "absent";
|
|
15399
|
-
const primary = spec.hookEvents[0];
|
|
15400
|
-
const rootPresent = root !== "absent" && root !== "invalid";
|
|
15401
|
-
hooks = spec.hookEvents.map((ev) => ({
|
|
15402
|
-
label: hookLabelOf(ev, pad),
|
|
15403
|
-
wired: rootPresent && eventWired(root, ev, spec.hookFormat)
|
|
15404
|
-
}));
|
|
15405
|
-
if (root === "absent") wireState = "absent";
|
|
15406
|
-
else if (root === "invalid") wireState = "invalid";
|
|
15407
|
-
else wireState = primary && eventWired(root, primary, spec.hookFormat) ? "wired" : "unwired";
|
|
15408
|
-
hookLabel = primary ? `${primary.key} hook` : "MCP proxy";
|
|
15409
|
-
settingsPath = spec.hookFile ? spec.hookFile(home) : spec.mcpFile ? spec.mcpFile(home) : "";
|
|
15410
|
-
}
|
|
15411
|
-
const mcp = spec.mcpFile ? readMcp(spec.mcpFile(home), spec.mcpFormat ?? "json") : null;
|
|
15412
|
-
const anyHookWired = hooks.some((h) => h.wired);
|
|
15413
|
-
return {
|
|
15414
|
-
id: spec.id,
|
|
15415
|
-
label: spec.label,
|
|
15416
|
-
setupCommand: spec.setupCommand,
|
|
15417
|
-
installed: detected[spec.id],
|
|
15418
|
-
present,
|
|
15419
|
-
hooks,
|
|
15420
|
-
wireState,
|
|
15421
|
-
hookLabel,
|
|
15422
|
-
settingsPath,
|
|
15423
|
-
configFormat: spec.hookFormat === "yaml" ? "YAML" : "JSON",
|
|
15424
|
-
mcpServers: mcp ? mcp.wrapped : null,
|
|
15425
|
-
mcpProtected: mcp ? mcp.present : false,
|
|
15426
|
-
isProtected: anyHookWired || (mcp?.present ?? false)
|
|
15427
|
-
};
|
|
15428
|
-
});
|
|
15429
|
-
}
|
|
15430
|
-
var import_fs26, import_path28, import_os24, yaml2, import_smol_toml2, exists, ck, lg, DEFAULT_LABEL_PAD, hookLabelOf, AGENT_SPECS;
|
|
15431
|
-
var init_agent_wiring = __esm({
|
|
15432
|
-
"src/agent-wiring.ts"() {
|
|
15433
|
-
"use strict";
|
|
15434
|
-
import_fs26 = __toESM(require("fs"));
|
|
15435
|
-
import_path28 = __toESM(require("path"));
|
|
15436
|
-
import_os24 = __toESM(require("os"));
|
|
15437
|
-
yaml2 = __toESM(require("yaml"));
|
|
15438
|
-
import_smol_toml2 = require("smol-toml");
|
|
15439
|
-
init_setup();
|
|
15440
|
-
exists = (p) => {
|
|
15441
|
-
try {
|
|
15442
|
-
return import_fs26.default.existsSync(p);
|
|
15443
|
-
} catch {
|
|
15444
|
-
return false;
|
|
15445
|
-
}
|
|
15446
|
-
};
|
|
15447
|
-
ck = (key) => ({ key, kind: "check" });
|
|
15448
|
-
lg = (key) => ({ key, kind: "log" });
|
|
15449
|
-
DEFAULT_LABEL_PAD = 11;
|
|
15450
|
-
hookLabelOf = (ev, pad) => `${ev.key.padEnd(pad)} (node9 ${ev.kind})`;
|
|
15451
|
-
AGENT_SPECS = [
|
|
15452
|
-
{
|
|
15453
|
-
id: "claude",
|
|
15454
|
-
label: "Claude Code",
|
|
15455
|
-
setupCommand: "node9 agents add claude",
|
|
15456
|
-
hookFile: (h) => import_path28.default.join(h, ".claude", "settings.json"),
|
|
15457
|
-
hookFormat: "matcher",
|
|
15458
|
-
hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
|
|
15459
|
-
mcpFile: (h) => import_path28.default.join(h, ".claude.json"),
|
|
15460
|
-
present: (h) => exists(import_path28.default.join(h, ".claude", "settings.json")) || exists(import_path28.default.join(h, ".claude.json"))
|
|
15461
|
-
},
|
|
15462
|
-
{
|
|
15463
|
-
id: "gemini",
|
|
15464
|
-
label: "Gemini CLI",
|
|
15465
|
-
setupCommand: "node9 agents add gemini",
|
|
15466
|
-
hookFile: (h) => import_path28.default.join(h, ".gemini", "settings.json"),
|
|
15467
|
-
hookFormat: "matcher",
|
|
15468
|
-
hookEvents: [ck("BeforeTool"), lg("AfterTool")],
|
|
15469
|
-
mcpFile: (h) => import_path28.default.join(h, ".gemini", "settings.json"),
|
|
15470
|
-
present: (h) => exists(import_path28.default.join(h, ".gemini", "settings.json"))
|
|
15471
|
-
},
|
|
15472
|
-
{
|
|
15473
|
-
id: "codex",
|
|
15474
|
-
label: "Codex",
|
|
15475
|
-
setupCommand: "node9 agents add codex",
|
|
15476
|
-
hookFile: (h) => import_path28.default.join(h, ".codex", "hooks.json"),
|
|
15477
|
-
hookFormat: "matcher",
|
|
15478
|
-
hookEvents: [ck("PreToolUse"), ck("UserPromptSubmit")],
|
|
15479
|
-
mcpFile: (h) => import_path28.default.join(h, ".codex", "config.toml"),
|
|
15480
|
-
mcpFormat: "toml",
|
|
15481
|
-
present: (h) => exists(import_path28.default.join(h, ".codex"))
|
|
15482
|
-
},
|
|
15483
|
-
{
|
|
15484
|
-
id: "antigravity",
|
|
15485
|
-
label: "Antigravity",
|
|
15486
|
-
setupCommand: "node9 agents add antigravity",
|
|
15487
|
-
hookFile: (h) => import_path28.default.join(h, ".gemini", "config", "hooks.json"),
|
|
15488
|
-
hookFormat: "matcher",
|
|
15489
|
-
hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
|
|
15490
|
-
mcpFile: (h) => import_path28.default.join(h, ".gemini", "config", "mcp_config.json"),
|
|
15491
|
-
present: (h) => exists(import_path28.default.join(h, ".gemini", "config", "hooks.json")) || exists(import_path28.default.join(h, ".gemini", "antigravity-cli")) || exists(import_path28.default.join(h, ".gemini", "antigravity-ide"))
|
|
15492
|
-
},
|
|
15493
|
-
{
|
|
15494
|
-
id: "copilot",
|
|
15495
|
-
label: "GitHub Copilot",
|
|
15496
|
-
setupCommand: "node9 agents add copilot",
|
|
15497
|
-
hookFile: (h) => import_path28.default.join(h, ".copilot", "hooks", "node9.json"),
|
|
15498
|
-
hookFormat: "flat",
|
|
15499
|
-
hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
|
|
15500
|
-
mcpFile: (h) => import_path28.default.join(h, ".copilot", "mcp-config.json"),
|
|
15501
|
-
present: (h) => exists(import_path28.default.join(h, ".copilot"))
|
|
15502
|
-
},
|
|
15503
|
-
{
|
|
15504
|
-
id: "cursor",
|
|
15505
|
-
label: "Cursor",
|
|
15506
|
-
setupCommand: "node9 agents add cursor",
|
|
15507
|
-
// MCP-only — no hook file (see note above).
|
|
15508
|
-
hookFormat: "flat",
|
|
15509
|
-
hookEvents: [],
|
|
15510
|
-
mcpFile: (h) => import_path28.default.join(h, ".cursor", "mcp.json"),
|
|
15511
|
-
present: (h) => exists(import_path28.default.join(h, ".cursor", "mcp.json"))
|
|
15512
|
-
},
|
|
15513
|
-
{
|
|
15514
|
-
id: "hermes",
|
|
15515
|
-
label: "Hermes Agent",
|
|
15516
|
-
setupCommand: "node9 agents add hermes",
|
|
15517
|
-
hookFile: (h) => hermesConfigPath(h),
|
|
15518
|
-
hookFormat: "yaml",
|
|
15519
|
-
hookEvents: [ck("pre_tool_call"), lg("post_tool_call")],
|
|
15520
|
-
labelPad: 14,
|
|
15521
|
-
// 'post_tool_call' is wider than the default
|
|
15522
|
-
present: (h) => exists(hermesConfigPath(h))
|
|
15523
|
-
},
|
|
15524
|
-
{
|
|
15525
|
-
// Plugin-shim agents — protected by a node9-authored plugin/extension file
|
|
15526
|
-
// (no hooks, no MCP). hookFormat is unused for these (shimFile drives it).
|
|
15527
|
-
id: "opencode",
|
|
15528
|
-
label: "OpenCode",
|
|
15529
|
-
setupCommand: "node9 agents add opencode",
|
|
15530
|
-
hookFormat: "flat",
|
|
15531
|
-
hookEvents: [],
|
|
15532
|
-
shimFile: (h) => import_path28.default.join(h, ".config", "opencode", "plugins", "node9.js"),
|
|
15533
|
-
present: (h) => exists(import_path28.default.join(h, ".config", "opencode")) || exists(import_path28.default.join(h, ".config", "opencode", "plugins", "node9.js"))
|
|
15534
|
-
},
|
|
15535
|
-
{
|
|
15536
|
-
id: "pi",
|
|
15537
|
-
label: "Pi",
|
|
15538
|
-
setupCommand: "node9 agents add pi",
|
|
15539
|
-
hookFormat: "flat",
|
|
15540
|
-
hookEvents: [],
|
|
15541
|
-
shimFile: (h) => import_path28.default.join(h, ".pi", "agent", "extensions", "node9.js"),
|
|
15542
|
-
present: (h) => exists(import_path28.default.join(h, ".pi", "agent")) || exists(import_path28.default.join(h, ".pi", "agent", "extensions", "node9.js"))
|
|
15475
|
+
});
|
|
15476
|
+
}
|
|
15477
|
+
} catch {
|
|
15543
15478
|
}
|
|
15544
|
-
|
|
15479
|
+
});
|
|
15480
|
+
socket.on("error", () => {
|
|
15481
|
+
});
|
|
15482
|
+
});
|
|
15483
|
+
unixServer.on("error", (err2) => {
|
|
15484
|
+
logActivitySocket(`server error: ${err2.message}`);
|
|
15485
|
+
});
|
|
15486
|
+
unixServer.listen(ACTIVITY_SOCKET_PATH2, () => {
|
|
15487
|
+
logActivitySocket(`bound to ${ACTIVITY_SOCKET_PATH2}`);
|
|
15488
|
+
});
|
|
15489
|
+
activitySocketServer = unixServer;
|
|
15490
|
+
}
|
|
15491
|
+
var import_net2, import_fs26, import_path28, import_os24, import_crypto8, 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;
|
|
15492
|
+
var init_state2 = __esm({
|
|
15493
|
+
"src/daemon/state.ts"() {
|
|
15494
|
+
"use strict";
|
|
15495
|
+
import_net2 = __toESM(require("net"));
|
|
15496
|
+
import_fs26 = __toESM(require("fs"));
|
|
15497
|
+
import_path28 = __toESM(require("path"));
|
|
15498
|
+
import_os24 = __toESM(require("os"));
|
|
15499
|
+
import_crypto8 = require("crypto");
|
|
15500
|
+
init_daemon();
|
|
15501
|
+
init_suggestion_tracker();
|
|
15502
|
+
init_taint_store();
|
|
15503
|
+
init_session_counters();
|
|
15504
|
+
init_session_history();
|
|
15505
|
+
homeDir = import_os24.default.homedir();
|
|
15506
|
+
DAEMON_PID_FILE = import_path28.default.join(homeDir, ".node9", "daemon.pid");
|
|
15507
|
+
DECISIONS_FILE = import_path28.default.join(homeDir, ".node9", "decisions.json");
|
|
15508
|
+
AUDIT_LOG_FILE = import_path28.default.join(homeDir, ".node9", "audit.log");
|
|
15509
|
+
TRUST_FILE2 = import_path28.default.join(homeDir, ".node9", "trust.json");
|
|
15510
|
+
GLOBAL_CONFIG_FILE = import_path28.default.join(homeDir, ".node9", "config.json");
|
|
15511
|
+
CREDENTIALS_FILE = import_path28.default.join(homeDir, ".node9", "credentials.json");
|
|
15512
|
+
INSIGHT_COUNTS_FILE = import_path28.default.join(homeDir, ".node9", "insight-counts.json");
|
|
15513
|
+
pending = /* @__PURE__ */ new Map();
|
|
15514
|
+
sseClients = /* @__PURE__ */ new Set();
|
|
15515
|
+
suggestionTracker = new SuggestionTracker(3);
|
|
15516
|
+
taintStore = new TaintStore();
|
|
15517
|
+
sessionTaintStore = new SessionTaintStore();
|
|
15518
|
+
insightCounts = /* @__PURE__ */ new Map();
|
|
15519
|
+
_abandonTimer = null;
|
|
15520
|
+
_hadBrowserClient = false;
|
|
15521
|
+
_daemonServer = null;
|
|
15522
|
+
daemonRejectionHandlerRegistered = false;
|
|
15523
|
+
AUTO_DENY_MS = 12e4;
|
|
15524
|
+
TRUST_DURATIONS = {
|
|
15525
|
+
"30m": 30 * 6e4,
|
|
15526
|
+
"1h": 60 * 6e4,
|
|
15527
|
+
"2h": 2 * 60 * 6e4
|
|
15528
|
+
};
|
|
15529
|
+
autoStarted = process.env.NODE9_AUTO_STARTED === "1";
|
|
15530
|
+
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path28.default.join(import_os24.default.tmpdir(), "node9-activity.sock");
|
|
15531
|
+
ACTIVITY_RING_SIZE = 100;
|
|
15532
|
+
activityRing = [];
|
|
15533
|
+
LARGE_RESPONSE_RING_SIZE = 20;
|
|
15534
|
+
largeResponseRing = [];
|
|
15535
|
+
cachedScanResult = null;
|
|
15536
|
+
cachedScanTs = 0;
|
|
15537
|
+
SCAN_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
15538
|
+
SECRET_KEY_RE = /password|secret|token|key|apikey|credential|auth/i;
|
|
15539
|
+
INPUT_PRICE_PER_1M = 3;
|
|
15540
|
+
OUTPUT_PRICE_PER_1M = 15;
|
|
15541
|
+
BYTES_PER_TOKEN = 4;
|
|
15542
|
+
CRITICAL_FORENSIC_CATEGORIES = /* @__PURE__ */ new Set([
|
|
15543
|
+
"privilege-escalation",
|
|
15544
|
+
"destructive-op",
|
|
15545
|
+
"eval-of-remote"
|
|
15546
|
+
]);
|
|
15547
|
+
WRITE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
15548
|
+
"write",
|
|
15549
|
+
"write_file",
|
|
15550
|
+
"create_file",
|
|
15551
|
+
"edit",
|
|
15552
|
+
"multiedit",
|
|
15553
|
+
"str_replace_based_edit_tool",
|
|
15554
|
+
"replace",
|
|
15555
|
+
"notebook_edit",
|
|
15556
|
+
"notebookedit"
|
|
15557
|
+
]);
|
|
15558
|
+
ACTIVITY_REBIND_MAX_ATTEMPTS = 5;
|
|
15559
|
+
ACTIVITY_REBIND_WINDOW_MS = 6e4;
|
|
15560
|
+
ACTIVITY_HEALTH_PROBE_MS = 2e3;
|
|
15561
|
+
activitySocketServer = null;
|
|
15562
|
+
activityHealthInterval = null;
|
|
15563
|
+
activityRebindAttempts = [];
|
|
15564
|
+
activityCircuitTripped = false;
|
|
15545
15565
|
}
|
|
15546
15566
|
});
|
|
15547
15567
|
|
|
@@ -16643,6 +16663,93 @@ var init_ship = __esm({
|
|
|
16643
16663
|
}
|
|
16644
16664
|
});
|
|
16645
16665
|
|
|
16666
|
+
// src/policy-snapshot/build.ts
|
|
16667
|
+
function buildPolicySnapshot(config, activeShields, overrides) {
|
|
16668
|
+
const p = config.policy;
|
|
16669
|
+
return {
|
|
16670
|
+
mode: config.settings.mode,
|
|
16671
|
+
panicMode: config.settings.panicMode === true,
|
|
16672
|
+
// The proxy expresses shadow/observe as mode === 'observe' (cloud shadowMode
|
|
16673
|
+
// forces it); there's no separate settings flag.
|
|
16674
|
+
shadowMode: config.settings.mode === "observe",
|
|
16675
|
+
activeShields,
|
|
16676
|
+
shieldOverrides: overrides,
|
|
16677
|
+
smartRuleCount: p.smartRules.length,
|
|
16678
|
+
smartRules: p.smartRules.slice(0, MAX_RULES).map((r) => ({
|
|
16679
|
+
name: r.name,
|
|
16680
|
+
tool: r.tool,
|
|
16681
|
+
verdict: r.verdict,
|
|
16682
|
+
reason: r.reason
|
|
16683
|
+
})),
|
|
16684
|
+
egress: {
|
|
16685
|
+
enabled: p.egress.enabled,
|
|
16686
|
+
mode: p.egress.mode,
|
|
16687
|
+
allow: p.egress.allow.slice(0, MAX_EGRESS)
|
|
16688
|
+
},
|
|
16689
|
+
dlpEnabled: p.dlp.enabled,
|
|
16690
|
+
engineVersion: ENGINE_VERSION
|
|
16691
|
+
};
|
|
16692
|
+
}
|
|
16693
|
+
var MAX_RULES, MAX_EGRESS;
|
|
16694
|
+
var init_build = __esm({
|
|
16695
|
+
"src/policy-snapshot/build.ts"() {
|
|
16696
|
+
"use strict";
|
|
16697
|
+
init_dist();
|
|
16698
|
+
MAX_RULES = 500;
|
|
16699
|
+
MAX_EGRESS = 200;
|
|
16700
|
+
}
|
|
16701
|
+
});
|
|
16702
|
+
|
|
16703
|
+
// src/policy-snapshot/ship.ts
|
|
16704
|
+
function policySnapshotUrlFrom(apiUrl) {
|
|
16705
|
+
return apiUrl.endsWith("/policies/sync") ? apiUrl.replace(/\/policies\/sync$/, "/policy/snapshot") : null;
|
|
16706
|
+
}
|
|
16707
|
+
async function shipPolicySnapshot(body, creds) {
|
|
16708
|
+
const url = policySnapshotUrlFrom(creds.apiUrl);
|
|
16709
|
+
if (!url) return false;
|
|
16710
|
+
const payload = JSON.stringify(body);
|
|
16711
|
+
const parsed = new import_url2.URL(url);
|
|
16712
|
+
const transport = parsed.protocol === "http:" ? import_http2.default : import_https3.default;
|
|
16713
|
+
return new Promise((resolve) => {
|
|
16714
|
+
const req = transport.request(
|
|
16715
|
+
{
|
|
16716
|
+
hostname: parsed.hostname,
|
|
16717
|
+
port: parsed.port ? parseInt(parsed.port, 10) : void 0,
|
|
16718
|
+
path: parsed.pathname + parsed.search,
|
|
16719
|
+
method: "POST",
|
|
16720
|
+
headers: {
|
|
16721
|
+
"Content-Type": "application/json",
|
|
16722
|
+
"Content-Length": Buffer.byteLength(payload),
|
|
16723
|
+
Authorization: `Bearer ${creds.apiKey}`
|
|
16724
|
+
},
|
|
16725
|
+
timeout: 1e4
|
|
16726
|
+
},
|
|
16727
|
+
(res) => {
|
|
16728
|
+
const ok2 = !!res.statusCode && res.statusCode >= 200 && res.statusCode < 300;
|
|
16729
|
+
res.resume();
|
|
16730
|
+
res.on("end", () => resolve(ok2));
|
|
16731
|
+
res.on("error", () => resolve(false));
|
|
16732
|
+
}
|
|
16733
|
+
);
|
|
16734
|
+
req.on("error", () => resolve(false));
|
|
16735
|
+
req.on("timeout", () => {
|
|
16736
|
+
req.destroy();
|
|
16737
|
+
resolve(false);
|
|
16738
|
+
});
|
|
16739
|
+
req.write(payload);
|
|
16740
|
+
req.end();
|
|
16741
|
+
});
|
|
16742
|
+
}
|
|
16743
|
+
var import_http2, import_https3, import_url2;
|
|
16744
|
+
var init_ship2 = __esm({
|
|
16745
|
+
"src/policy-snapshot/ship.ts"() {
|
|
16746
|
+
"use strict";
|
|
16747
|
+
import_http2 = __toESM(require("http"));
|
|
16748
|
+
import_https3 = __toESM(require("https"));
|
|
16749
|
+
import_url2 = require("url");
|
|
16750
|
+
}
|
|
16751
|
+
});
|
|
16752
|
+
|
|
16646
16753
|
// src/daemon/sync.ts
|
|
16647
16754
|
function emptySignals3() {
|
|
16648
16755
|
return {
|
|
@@ -16675,6 +16782,11 @@ function buildSessionDeltas(findings, toolCallsBySession) {
|
|
|
16675
16782
|
signals
|
|
16676
16783
|
}));
|
|
16677
16784
|
}
|
|
16785
|
+
function resolveSyncIntervalMs(settings) {
|
|
16786
|
+
const rawSeconds = settings.cloudSyncIntervalSeconds ?? (settings.cloudSyncIntervalHours ?? DEFAULT_INTERVAL_HOURS) * 3600;
|
|
16787
|
+
const clamped = Math.min(Math.max(rawSeconds, MIN_INTERVAL_SECONDS), MAX_INTERVAL_SECONDS);
|
|
16788
|
+
return clamped * 1e3;
|
|
16789
|
+
}
|
|
16678
16790
|
function readCredentials() {
|
|
16679
16791
|
if (process.env.NODE9_API_KEY) {
|
|
16680
16792
|
return {
|
|
@@ -16724,7 +16836,7 @@ function fetchCloudPolicy(apiKey, apiUrl, ifNoneMatch) {
|
|
|
16724
16836
|
};
|
|
16725
16837
|
if (ifNoneMatch) headers["If-None-Match"] = `"${ifNoneMatch}"`;
|
|
16726
16838
|
return new Promise((resolve, reject) => {
|
|
16727
|
-
const req =
|
|
16839
|
+
const req = import_https4.default.request(
|
|
16728
16840
|
{
|
|
16729
16841
|
hostname: parsed.hostname,
|
|
16730
16842
|
port: parsed.port ? parseInt(parsed.port, 10) : void 0,
|
|
@@ -16804,6 +16916,9 @@ async function syncOnce() {
|
|
|
16804
16916
|
if (process.env.NODE9_POSTURE_DISABLE !== "1") {
|
|
16805
16917
|
void pushPostureSnapshot(creds);
|
|
16806
16918
|
}
|
|
16919
|
+
if (process.env.NODE9_POLICY_MIRROR_DISABLE !== "1") {
|
|
16920
|
+
void pushPolicySnapshot(creds);
|
|
16921
|
+
}
|
|
16807
16922
|
}
|
|
16808
16923
|
async function pushBlastSnapshot(creds) {
|
|
16809
16924
|
try {
|
|
@@ -16813,7 +16928,7 @@ async function pushBlastSnapshot(creds) {
|
|
|
16813
16928
|
if (!blastUrl) return;
|
|
16814
16929
|
const parsed = new URL(blastUrl);
|
|
16815
16930
|
await new Promise((resolve) => {
|
|
16816
|
-
const req =
|
|
16931
|
+
const req = import_https4.default.request(
|
|
16817
16932
|
{
|
|
16818
16933
|
hostname: parsed.hostname,
|
|
16819
16934
|
port: parsed.port ? parseInt(parsed.port, 10) : void 0,
|
|
@@ -16850,6 +16965,29 @@ async function pushPostureSnapshot(creds) {
|
|
|
16850
16965
|
} catch {
|
|
16851
16966
|
}
|
|
16852
16967
|
}
|
|
16968
|
+
async function pushPolicySnapshot(creds) {
|
|
16969
|
+
try {
|
|
16970
|
+
const body = buildPolicySnapshot(getConfig(), readActiveShields(), readShieldOverrides());
|
|
16971
|
+
await shipPolicySnapshot(body, creds);
|
|
16972
|
+
} catch {
|
|
16973
|
+
}
|
|
16974
|
+
}
|
|
16975
|
+
async function runPolicyPush() {
|
|
16976
|
+
const creds = readCredentials();
|
|
16977
|
+
if (!creds) {
|
|
16978
|
+
return {
|
|
16979
|
+
ok: false,
|
|
16980
|
+
reason: "No API key configured. Add credentials with: node9 login"
|
|
16981
|
+
};
|
|
16982
|
+
}
|
|
16983
|
+
try {
|
|
16984
|
+
const body = buildPolicySnapshot(getConfig(), readActiveShields(), readShieldOverrides());
|
|
16985
|
+
const sent = await shipPolicySnapshot(body, creds);
|
|
16986
|
+
return sent ? { ok: true } : { ok: false, reason: "Push failed (network or server error)" };
|
|
16987
|
+
} catch (e) {
|
|
16988
|
+
return { ok: false, reason: e instanceof Error ? e.message : String(e) };
|
|
16989
|
+
}
|
|
16990
|
+
}
|
|
16853
16991
|
async function pushScanSnapshot(creds) {
|
|
16854
16992
|
try {
|
|
16855
16993
|
const tick = await tickScanWatcher();
|
|
@@ -16867,7 +17005,7 @@ async function pushScanSnapshot(creds) {
|
|
|
16867
17005
|
const parsed = new URL(scanUrl);
|
|
16868
17006
|
let posted = false;
|
|
16869
17007
|
await new Promise((resolve) => {
|
|
16870
|
-
const req =
|
|
17008
|
+
const req = import_https4.default.request(
|
|
16871
17009
|
{
|
|
16872
17010
|
hostname: parsed.hostname,
|
|
16873
17011
|
port: parsed.port ? parseInt(parsed.port, 10) : void 0,
|
|
@@ -16917,6 +17055,9 @@ async function runCloudSync() {
|
|
|
16917
17055
|
if (process.env.NODE9_POSTURE_DISABLE !== "1") {
|
|
16918
17056
|
void pushPostureSnapshot(creds);
|
|
16919
17057
|
}
|
|
17058
|
+
if (process.env.NODE9_POLICY_MIRROR_DISABLE !== "1") {
|
|
17059
|
+
void pushPolicySnapshot(creds);
|
|
17060
|
+
}
|
|
16920
17061
|
};
|
|
16921
17062
|
try {
|
|
16922
17063
|
const result = await fetchCloudPolicy(creds.apiKey, creds.apiUrl, readCachedEtag());
|
|
@@ -16968,9 +17109,7 @@ function getCloudRules() {
|
|
|
16968
17109
|
}
|
|
16969
17110
|
}
|
|
16970
17111
|
function startCloudSync() {
|
|
16971
|
-
const
|
|
16972
|
-
const intervalHours = Math.max(rawHours, MIN_INTERVAL_HOURS);
|
|
16973
|
-
const intervalMs = intervalHours * 60 * 60 * 1e3;
|
|
17112
|
+
const intervalMs = resolveSyncIntervalMs(getConfig().settings);
|
|
16974
17113
|
const initial = setTimeout(() => void syncOnce(), 3e4);
|
|
16975
17114
|
initial.unref();
|
|
16976
17115
|
const recurring = setInterval(() => void syncOnce(), intervalMs);
|
|
@@ -16995,18 +17134,21 @@ function startForensicBroadcast() {
|
|
|
16995
17134
|
const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
|
|
16996
17135
|
recurring.unref();
|
|
16997
17136
|
}
|
|
16998
|
-
var import_fs32,
|
|
17137
|
+
var import_fs32, import_https4, import_os29, import_path31, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_SECONDS, MAX_INTERVAL_SECONDS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
|
|
16999
17138
|
var init_sync = __esm({
|
|
17000
17139
|
"src/daemon/sync.ts"() {
|
|
17001
17140
|
"use strict";
|
|
17002
17141
|
import_fs32 = __toESM(require("fs"));
|
|
17003
|
-
|
|
17142
|
+
import_https4 = __toESM(require("https"));
|
|
17004
17143
|
import_os29 = __toESM(require("os"));
|
|
17005
17144
|
import_path31 = __toESM(require("path"));
|
|
17006
17145
|
init_config();
|
|
17007
17146
|
init_blast();
|
|
17008
17147
|
init_posture();
|
|
17009
17148
|
init_ship();
|
|
17149
|
+
init_build();
|
|
17150
|
+
init_ship2();
|
|
17151
|
+
init_shields();
|
|
17010
17152
|
init_dist();
|
|
17011
17153
|
init_scan_watermark();
|
|
17012
17154
|
init_state2();
|
|
@@ -17026,7 +17168,8 @@ var init_sync = __esm({
|
|
|
17026
17168
|
rulesCacheFile = () => import_path31.default.join(import_os29.default.homedir(), ".node9", "rules-cache.json");
|
|
17027
17169
|
DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept/policies/sync";
|
|
17028
17170
|
DEFAULT_INTERVAL_HOURS = 5;
|
|
17029
|
-
|
|
17171
|
+
MIN_INTERVAL_SECONDS = 15;
|
|
17172
|
+
MAX_INTERVAL_SECONDS = 24 * 60 * 60;
|
|
17030
17173
|
FORENSIC_BROADCAST_INTERVAL_MS = 3e4;
|
|
17031
17174
|
FORENSIC_INITIAL_DELAY_MS = 5e3;
|
|
17032
17175
|
forensicBroadcastOffsets = /* @__PURE__ */ new Map();
|
|
@@ -17509,7 +17652,7 @@ function startDaemon() {
|
|
|
17509
17652
|
}
|
|
17510
17653
|
resetIdleTimer();
|
|
17511
17654
|
const allowedHosts = /* @__PURE__ */ new Set([`127.0.0.1:${DAEMON_PORT}`, `localhost:${DAEMON_PORT}`]);
|
|
17512
|
-
const server =
|
|
17655
|
+
const server = import_http3.default.createServer(async (req, res) => {
|
|
17513
17656
|
const host = req.headers.host ?? "";
|
|
17514
17657
|
if (!allowedHosts.has(host)) {
|
|
17515
17658
|
res.writeHead(421, { "Content-Type": "text/plain" });
|
|
@@ -18411,11 +18554,11 @@ data: ${JSON.stringify(item.data)}
|
|
|
18411
18554
|
}
|
|
18412
18555
|
startActivitySocket();
|
|
18413
18556
|
}
|
|
18414
|
-
var
|
|
18557
|
+
var import_http3, import_fs36, import_path35, import_os33, import_crypto10, import_child_process2, import_chalk6;
|
|
18415
18558
|
var init_server = __esm({
|
|
18416
18559
|
"src/daemon/server.ts"() {
|
|
18417
18560
|
"use strict";
|
|
18418
|
-
|
|
18561
|
+
import_http3 = __toESM(require("http"));
|
|
18419
18562
|
import_fs36 = __toESM(require("fs"));
|
|
18420
18563
|
import_path35 = __toESM(require("path"));
|
|
18421
18564
|
import_os33 = __toESM(require("os"));
|
|
@@ -18772,18 +18915,18 @@ function getModelContextLimit(model) {
|
|
|
18772
18915
|
return 2e5;
|
|
18773
18916
|
}
|
|
18774
18917
|
function readSessionUsage() {
|
|
18775
|
-
const projectsDir =
|
|
18918
|
+
const projectsDir = import_path62.default.join(import_os55.default.homedir(), ".claude", "projects");
|
|
18776
18919
|
if (!import_fs64.default.existsSync(projectsDir)) return null;
|
|
18777
18920
|
let latestFile = null;
|
|
18778
18921
|
let latestMtime = 0;
|
|
18779
18922
|
try {
|
|
18780
18923
|
for (const dir of import_fs64.default.readdirSync(projectsDir)) {
|
|
18781
|
-
const dirPath =
|
|
18924
|
+
const dirPath = import_path62.default.join(projectsDir, dir);
|
|
18782
18925
|
try {
|
|
18783
18926
|
if (!import_fs64.default.statSync(dirPath).isDirectory()) continue;
|
|
18784
18927
|
for (const file of import_fs64.default.readdirSync(dirPath)) {
|
|
18785
18928
|
if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
|
|
18786
|
-
const filePath =
|
|
18929
|
+
const filePath = import_path62.default.join(dirPath, file);
|
|
18787
18930
|
try {
|
|
18788
18931
|
const mtime = import_fs64.default.statSync(filePath).mtimeMs;
|
|
18789
18932
|
if (mtime > latestMtime) {
|
|
@@ -18861,7 +19004,7 @@ function formatBase(activity) {
|
|
|
18861
19004
|
const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
|
|
18862
19005
|
const icon = getIcon(activity.tool);
|
|
18863
19006
|
const toolName = activity.tool.slice(0, 16).padEnd(16);
|
|
18864
|
-
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(
|
|
19007
|
+
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os55.default.homedir(), "~");
|
|
18865
19008
|
const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
|
|
18866
19009
|
return `${import_chalk35.default.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${import_chalk35.default.white.bold(toolName)} ${import_chalk35.default.dim(argsPreview)}`;
|
|
18867
19010
|
}
|
|
@@ -18943,7 +19086,7 @@ function postDecisionHttp(id, decision, authToken, port, opts) {
|
|
|
18943
19086
|
if (opts?.trustDuration) bodyObj.trustDuration = opts.trustDuration;
|
|
18944
19087
|
if (opts?.reason) bodyObj.reason = opts.reason;
|
|
18945
19088
|
const body = JSON.stringify(bodyObj);
|
|
18946
|
-
const req =
|
|
19089
|
+
const req = import_http4.default.request(
|
|
18947
19090
|
{
|
|
18948
19091
|
hostname: "127.0.0.1",
|
|
18949
19092
|
port,
|
|
@@ -19058,7 +19201,7 @@ function buildRecoveryCardLines(req) {
|
|
|
19058
19201
|
];
|
|
19059
19202
|
}
|
|
19060
19203
|
function readApproversFromDisk() {
|
|
19061
|
-
const configPath =
|
|
19204
|
+
const configPath = import_path62.default.join(import_os55.default.homedir(), ".node9", "config.json");
|
|
19062
19205
|
try {
|
|
19063
19206
|
const raw = JSON.parse(import_fs64.default.readFileSync(configPath, "utf-8"));
|
|
19064
19207
|
const settings = raw.settings ?? {};
|
|
@@ -19076,7 +19219,7 @@ function approverStatusLine() {
|
|
|
19076
19219
|
return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
|
|
19077
19220
|
}
|
|
19078
19221
|
function toggleApprover(channel) {
|
|
19079
|
-
const configPath =
|
|
19222
|
+
const configPath = import_path62.default.join(import_os55.default.homedir(), ".node9", "config.json");
|
|
19080
19223
|
try {
|
|
19081
19224
|
const raw = JSON.parse(import_fs64.default.readFileSync(configPath, "utf-8"));
|
|
19082
19225
|
const settings = raw.settings ?? {};
|
|
@@ -19094,7 +19237,7 @@ async function startTail(options = {}) {
|
|
|
19094
19237
|
const port = await ensureDaemon();
|
|
19095
19238
|
if (options.clear) {
|
|
19096
19239
|
const result = await new Promise((resolve) => {
|
|
19097
|
-
const req2 =
|
|
19240
|
+
const req2 = import_http4.default.request(
|
|
19098
19241
|
{ method: "POST", hostname: "127.0.0.1", port, path: "/events/clear" },
|
|
19099
19242
|
(res) => {
|
|
19100
19243
|
const status = res.statusCode ?? 0;
|
|
@@ -19257,7 +19400,7 @@ async function startTail(options = {}) {
|
|
|
19257
19400
|
postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
|
|
19258
19401
|
try {
|
|
19259
19402
|
import_fs64.default.appendFileSync(
|
|
19260
|
-
|
|
19403
|
+
import_path62.default.join(import_os55.default.homedir(), ".node9", "hook-debug.log"),
|
|
19261
19404
|
`[tail] POST /decision failed: ${String(err2)}
|
|
19262
19405
|
`
|
|
19263
19406
|
);
|
|
@@ -19321,7 +19464,7 @@ async function startTail(options = {}) {
|
|
|
19321
19464
|
};
|
|
19322
19465
|
process.stdin.on("keypress", onKeypress);
|
|
19323
19466
|
}
|
|
19324
|
-
const auditLog =
|
|
19467
|
+
const auditLog = import_path62.default.join(import_os55.default.homedir(), ".node9", "audit.log");
|
|
19325
19468
|
try {
|
|
19326
19469
|
const unackedDlp = import_fs64.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
19327
19470
|
if (unackedDlp > 0) {
|
|
@@ -19377,7 +19520,7 @@ async function startTail(options = {}) {
|
|
|
19377
19520
|
}, STALL_THRESHOLD_MS / 2);
|
|
19378
19521
|
stallWatchdog.unref();
|
|
19379
19522
|
const sseUrl = `http://127.0.0.1:${port}/events?capabilities=input`;
|
|
19380
|
-
const req =
|
|
19523
|
+
const req = import_http4.default.get(
|
|
19381
19524
|
sseUrl,
|
|
19382
19525
|
{
|
|
19383
19526
|
headers: authToken ? { "X-Node9-Internal": authToken } : {}
|
|
@@ -19548,20 +19691,20 @@ async function startTail(options = {}) {
|
|
|
19548
19691
|
process.exit(1);
|
|
19549
19692
|
});
|
|
19550
19693
|
}
|
|
19551
|
-
var
|
|
19694
|
+
var import_http4, import_chalk35, import_fs64, import_os55, import_path62, import_readline6, import_child_process14, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
|
|
19552
19695
|
var init_tail = __esm({
|
|
19553
19696
|
"src/tui/tail.ts"() {
|
|
19554
19697
|
"use strict";
|
|
19555
|
-
|
|
19698
|
+
import_http4 = __toESM(require("http"));
|
|
19556
19699
|
import_chalk35 = __toESM(require("chalk"));
|
|
19557
19700
|
import_fs64 = __toESM(require("fs"));
|
|
19558
|
-
|
|
19559
|
-
|
|
19701
|
+
import_os55 = __toESM(require("os"));
|
|
19702
|
+
import_path62 = __toESM(require("path"));
|
|
19560
19703
|
import_readline6 = __toESM(require("readline"));
|
|
19561
19704
|
import_child_process14 = require("child_process");
|
|
19562
19705
|
init_daemon2();
|
|
19563
19706
|
init_daemon();
|
|
19564
|
-
PID_FILE =
|
|
19707
|
+
PID_FILE = import_path62.default.join(import_os55.default.homedir(), ".node9", "daemon.pid");
|
|
19565
19708
|
ICONS = {
|
|
19566
19709
|
bash: "\u{1F4BB}",
|
|
19567
19710
|
shell: "\u{1F4BB}",
|
|
@@ -19626,7 +19769,7 @@ function queryDaemon() {
|
|
|
19626
19769
|
return new Promise((resolve) => {
|
|
19627
19770
|
const timeout = setTimeout(() => resolve(null), 50);
|
|
19628
19771
|
try {
|
|
19629
|
-
const req =
|
|
19772
|
+
const req = import_http5.default.get(
|
|
19630
19773
|
`http://${DAEMON_HOST}:${DAEMON_PORT}/status`,
|
|
19631
19774
|
{ timeout: 50 },
|
|
19632
19775
|
(res) => {
|
|
@@ -19711,7 +19854,7 @@ function countRulesInDir(rulesDir) {
|
|
|
19711
19854
|
try {
|
|
19712
19855
|
for (const entry of import_fs65.default.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
19713
19856
|
if (entry.isDirectory()) {
|
|
19714
|
-
count += countRulesInDir(
|
|
19857
|
+
count += countRulesInDir(import_path63.default.join(rulesDir, entry.name));
|
|
19715
19858
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
19716
19859
|
count++;
|
|
19717
19860
|
}
|
|
@@ -19722,46 +19865,46 @@ function countRulesInDir(rulesDir) {
|
|
|
19722
19865
|
}
|
|
19723
19866
|
function isSamePath(a, b) {
|
|
19724
19867
|
try {
|
|
19725
|
-
return
|
|
19868
|
+
return import_path63.default.resolve(a) === import_path63.default.resolve(b);
|
|
19726
19869
|
} catch {
|
|
19727
19870
|
return false;
|
|
19728
19871
|
}
|
|
19729
19872
|
}
|
|
19730
19873
|
function countConfigs(cwd) {
|
|
19731
|
-
const homeDir2 =
|
|
19732
|
-
const claudeDir =
|
|
19874
|
+
const homeDir2 = import_os56.default.homedir();
|
|
19875
|
+
const claudeDir = import_path63.default.join(homeDir2, ".claude");
|
|
19733
19876
|
let claudeMdCount = 0;
|
|
19734
19877
|
let rulesCount = 0;
|
|
19735
19878
|
let hooksCount = 0;
|
|
19736
19879
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
19737
19880
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
19738
|
-
if (import_fs65.default.existsSync(
|
|
19739
|
-
rulesCount += countRulesInDir(
|
|
19740
|
-
const userSettings =
|
|
19881
|
+
if (import_fs65.default.existsSync(import_path63.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
19882
|
+
rulesCount += countRulesInDir(import_path63.default.join(claudeDir, "rules"));
|
|
19883
|
+
const userSettings = import_path63.default.join(claudeDir, "settings.json");
|
|
19741
19884
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
19742
19885
|
hooksCount += countHooksInFile(userSettings);
|
|
19743
|
-
const userClaudeJson =
|
|
19886
|
+
const userClaudeJson = import_path63.default.join(homeDir2, ".claude.json");
|
|
19744
19887
|
for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
|
|
19745
19888
|
for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
|
|
19746
19889
|
userMcpServers.delete(name);
|
|
19747
19890
|
}
|
|
19748
19891
|
if (cwd) {
|
|
19749
|
-
if (import_fs65.default.existsSync(
|
|
19750
|
-
if (import_fs65.default.existsSync(
|
|
19751
|
-
const projectClaudeDir =
|
|
19892
|
+
if (import_fs65.default.existsSync(import_path63.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
19893
|
+
if (import_fs65.default.existsSync(import_path63.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
19894
|
+
const projectClaudeDir = import_path63.default.join(cwd, ".claude");
|
|
19752
19895
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
19753
19896
|
if (!overlapsUserScope) {
|
|
19754
|
-
if (import_fs65.default.existsSync(
|
|
19755
|
-
rulesCount += countRulesInDir(
|
|
19756
|
-
const projSettings =
|
|
19897
|
+
if (import_fs65.default.existsSync(import_path63.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
19898
|
+
rulesCount += countRulesInDir(import_path63.default.join(projectClaudeDir, "rules"));
|
|
19899
|
+
const projSettings = import_path63.default.join(projectClaudeDir, "settings.json");
|
|
19757
19900
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
19758
19901
|
hooksCount += countHooksInFile(projSettings);
|
|
19759
19902
|
}
|
|
19760
|
-
if (import_fs65.default.existsSync(
|
|
19761
|
-
const localSettings =
|
|
19903
|
+
if (import_fs65.default.existsSync(import_path63.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
19904
|
+
const localSettings = import_path63.default.join(projectClaudeDir, "settings.local.json");
|
|
19762
19905
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
19763
19906
|
hooksCount += countHooksInFile(localSettings);
|
|
19764
|
-
const mcpJsonServers = getMcpServerNames(
|
|
19907
|
+
const mcpJsonServers = getMcpServerNames(import_path63.default.join(cwd, ".mcp.json"));
|
|
19765
19908
|
const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
|
|
19766
19909
|
for (const name of disabledMcpJson) mcpJsonServers.delete(name);
|
|
19767
19910
|
for (const name of mcpJsonServers) projectMcpServers.add(name);
|
|
@@ -19794,7 +19937,7 @@ function readActiveShieldsHud() {
|
|
|
19794
19937
|
return shieldsCache.value;
|
|
19795
19938
|
}
|
|
19796
19939
|
try {
|
|
19797
|
-
const shieldsPath =
|
|
19940
|
+
const shieldsPath = import_path63.default.join(import_os56.default.homedir(), ".node9", "shields.json");
|
|
19798
19941
|
if (!import_fs65.default.existsSync(shieldsPath)) {
|
|
19799
19942
|
shieldsCache = { value: [], ts: now };
|
|
19800
19943
|
return [];
|
|
@@ -19901,9 +20044,9 @@ function renderContextLine(stdin) {
|
|
|
19901
20044
|
async function main() {
|
|
19902
20045
|
try {
|
|
19903
20046
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
19904
|
-
if (import_fs65.default.existsSync(
|
|
20047
|
+
if (import_fs65.default.existsSync(import_path63.default.join(import_os56.default.homedir(), ".node9", "hud-debug"))) {
|
|
19905
20048
|
try {
|
|
19906
|
-
const logPath =
|
|
20049
|
+
const logPath = import_path63.default.join(import_os56.default.homedir(), ".node9", "hud-debug.log");
|
|
19907
20050
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
19908
20051
|
let size = 0;
|
|
19909
20052
|
try {
|
|
@@ -19932,8 +20075,8 @@ async function main() {
|
|
|
19932
20075
|
try {
|
|
19933
20076
|
const cwd = stdin.cwd ?? process.cwd();
|
|
19934
20077
|
for (const configPath of [
|
|
19935
|
-
|
|
19936
|
-
|
|
20078
|
+
import_path63.default.join(cwd, "node9.config.json"),
|
|
20079
|
+
import_path63.default.join(import_os56.default.homedir(), ".node9", "config.json")
|
|
19937
20080
|
]) {
|
|
19938
20081
|
if (!import_fs65.default.existsSync(configPath)) continue;
|
|
19939
20082
|
const cfg = JSON.parse(import_fs65.default.readFileSync(configPath, "utf-8"));
|
|
@@ -19954,14 +20097,14 @@ async function main() {
|
|
|
19954
20097
|
renderOffline();
|
|
19955
20098
|
}
|
|
19956
20099
|
}
|
|
19957
|
-
var import_fs65,
|
|
20100
|
+
var import_fs65, import_path63, import_os56, import_http5, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
|
|
19958
20101
|
var init_hud = __esm({
|
|
19959
20102
|
"src/cli/hud.ts"() {
|
|
19960
20103
|
"use strict";
|
|
19961
20104
|
import_fs65 = __toESM(require("fs"));
|
|
19962
|
-
|
|
19963
|
-
|
|
19964
|
-
|
|
20105
|
+
import_path63 = __toESM(require("path"));
|
|
20106
|
+
import_os56 = __toESM(require("os"));
|
|
20107
|
+
import_http5 = __toESM(require("http"));
|
|
19965
20108
|
init_daemon();
|
|
19966
20109
|
RESET3 = "\x1B[0m";
|
|
19967
20110
|
BOLD3 = "\x1B[1m";
|
|
@@ -19985,11 +20128,44 @@ var init_hud = __esm({
|
|
|
19985
20128
|
var import_commander = require("commander");
|
|
19986
20129
|
init_core();
|
|
19987
20130
|
init_setup();
|
|
20131
|
+
|
|
20132
|
+
// src/agent-teardowns.ts
|
|
20133
|
+
init_setup();
|
|
20134
|
+
var AGENT_TEARDOWNS = [
|
|
20135
|
+
{ id: "claude", label: "Claude", fn: teardownClaude },
|
|
20136
|
+
{ id: "gemini", label: "Gemini", fn: teardownGemini },
|
|
20137
|
+
{ id: "codex", label: "Codex", fn: teardownCodex },
|
|
20138
|
+
{ id: "cursor", label: "Cursor", fn: teardownCursor },
|
|
20139
|
+
{ id: "windsurf", label: "Windsurf", fn: teardownWindsurf },
|
|
20140
|
+
{ id: "vscode", label: "VSCode", fn: teardownVSCode },
|
|
20141
|
+
{ id: "hermes", label: "Hermes", fn: teardownHermes },
|
|
20142
|
+
{ id: "antigravity", label: "Antigravity", fn: teardownAntigravity, aliases: ["agy"] },
|
|
20143
|
+
{ id: "copilot", label: "Copilot", fn: teardownCopilot },
|
|
20144
|
+
{ id: "hud", label: "HUD", fn: teardownHud },
|
|
20145
|
+
{
|
|
20146
|
+
id: "claudedesktop",
|
|
20147
|
+
label: "Claude Desktop",
|
|
20148
|
+
fn: teardownClaudeDesktop,
|
|
20149
|
+
aliases: ["claude-desktop"]
|
|
20150
|
+
},
|
|
20151
|
+
{ id: "opencode", label: "OpenCode", fn: teardownOpencode },
|
|
20152
|
+
{ id: "pi", label: "Pi", fn: teardownPi }
|
|
20153
|
+
];
|
|
20154
|
+
function resolveAgentTeardown(target) {
|
|
20155
|
+
const t = target.trim().toLowerCase();
|
|
20156
|
+
return AGENT_TEARDOWNS.find((a) => a.id === t || a.aliases?.includes(t));
|
|
20157
|
+
}
|
|
20158
|
+
function agentTeardownTargets() {
|
|
20159
|
+
return AGENT_TEARDOWNS.flatMap((a) => [a.id, ...a.aliases ?? []]);
|
|
20160
|
+
}
|
|
20161
|
+
|
|
20162
|
+
// src/cli.ts
|
|
20163
|
+
init_agent_wiring();
|
|
19988
20164
|
init_daemon2();
|
|
19989
20165
|
var import_chalk36 = __toESM(require("chalk"));
|
|
19990
20166
|
var import_fs66 = __toESM(require("fs"));
|
|
19991
|
-
var
|
|
19992
|
-
var
|
|
20167
|
+
var import_path64 = __toESM(require("path"));
|
|
20168
|
+
var import_os57 = __toESM(require("os"));
|
|
19993
20169
|
var import_child_process15 = require("child_process");
|
|
19994
20170
|
var import_prompts2 = require("@inquirer/prompts");
|
|
19995
20171
|
|
|
@@ -21619,6 +21795,8 @@ function registerLogCommand(program2) {
|
|
|
21619
21795
|
// src/cli/commands/shield.ts
|
|
21620
21796
|
var import_chalk10 = __toESM(require("chalk"));
|
|
21621
21797
|
var import_fs46 = __toESM(require("fs"));
|
|
21798
|
+
var import_path44 = __toESM(require("path"));
|
|
21799
|
+
var import_os40 = __toESM(require("os"));
|
|
21622
21800
|
init_shields();
|
|
21623
21801
|
|
|
21624
21802
|
// src/shields/build.ts
|
|
@@ -21749,10 +21927,10 @@ init_audit();
|
|
|
21749
21927
|
init_config();
|
|
21750
21928
|
|
|
21751
21929
|
// src/utils/https-fetch.ts
|
|
21752
|
-
var
|
|
21930
|
+
var import_https5 = __toESM(require("https"));
|
|
21753
21931
|
function httpsFetch(url) {
|
|
21754
21932
|
return new Promise((resolve, reject) => {
|
|
21755
|
-
|
|
21933
|
+
import_https5.default.get(url, (res) => {
|
|
21756
21934
|
if (res.statusCode !== 200) {
|
|
21757
21935
|
reject(new Error(`HTTP ${String(res.statusCode)} for ${url}`));
|
|
21758
21936
|
res.resume();
|
|
@@ -21768,6 +21946,22 @@ function httpsFetch(url) {
|
|
|
21768
21946
|
|
|
21769
21947
|
// src/cli/commands/shield.ts
|
|
21770
21948
|
var COMMUNITY_INDEX_URL = "https://raw.githubusercontent.com/node9ai/node9-proxy/main/shields/community/index.json";
|
|
21949
|
+
function readCloudShields() {
|
|
21950
|
+
const out = /* @__PURE__ */ new Set();
|
|
21951
|
+
try {
|
|
21952
|
+
const file = import_path44.default.join(import_os40.default.homedir(), ".node9", "rules-cache.json");
|
|
21953
|
+
const raw = JSON.parse(import_fs46.default.readFileSync(file, "utf-8"));
|
|
21954
|
+
for (const r of raw.rules ?? []) {
|
|
21955
|
+
const rule = r;
|
|
21956
|
+
const fromSource = rule.source?.startsWith("SHIELD:") ? rule.source.slice("SHIELD:".length).toLowerCase() : void 0;
|
|
21957
|
+
const fromDesc = !fromSource && rule.description ? /\b([a-z0-9-]+)\s+shield/i.exec(rule.description)?.[1]?.toLowerCase() : void 0;
|
|
21958
|
+
const name = fromSource ?? fromDesc;
|
|
21959
|
+
if (name) out.add(name);
|
|
21960
|
+
}
|
|
21961
|
+
} catch {
|
|
21962
|
+
}
|
|
21963
|
+
return out;
|
|
21964
|
+
}
|
|
21771
21965
|
function registerShieldCommand(program2) {
|
|
21772
21966
|
const shieldCmd = program2.command("shield").description("Manage pre-packaged security shield templates");
|
|
21773
21967
|
shieldCmd.command("enable <service>").description("Enable a security shield for a specific service").action((service) => {
|
|
@@ -21854,10 +22048,17 @@ function registerShieldCommand(program2) {
|
|
|
21854
22048
|
return;
|
|
21855
22049
|
}
|
|
21856
22050
|
const active = new Set(readActiveShields());
|
|
22051
|
+
const cloud = readCloudShields();
|
|
21857
22052
|
console.log(import_chalk10.default.bold("\n\u{1F6E1}\uFE0F Available Shields\n"));
|
|
22053
|
+
console.log(import_chalk10.default.gray(" \u25CF local \xB7 \u2601 cloud\n"));
|
|
21858
22054
|
for (const shield of listShields()) {
|
|
21859
|
-
const
|
|
21860
|
-
|
|
22055
|
+
const isLocal = active.has(shield.name);
|
|
22056
|
+
const isCloud = cloud.has(shield.name);
|
|
22057
|
+
const status = isLocal && isCloud ? import_chalk10.default.green("\u25CF\u2601 enabled ") : isLocal ? import_chalk10.default.green("\u25CF enabled ") : isCloud ? import_chalk10.default.cyan("\u2601 cloud ") : import_chalk10.default.gray("\u25CB disabled");
|
|
22058
|
+
const via = isCloud && !isLocal ? import_chalk10.default.gray(" (via dashboard)") : "";
|
|
22059
|
+
console.log(
|
|
22060
|
+
` ${status} ${import_chalk10.default.cyan(shield.name.padEnd(12))} ${shield.description}${via}`
|
|
22061
|
+
);
|
|
21861
22062
|
if (shield.aliases.length > 0)
|
|
21862
22063
|
console.log(import_chalk10.default.gray(` aliases: ${shield.aliases.join(", ")}`));
|
|
21863
22064
|
}
|
|
@@ -22187,15 +22388,15 @@ function registerConfigShowCommand(program2) {
|
|
|
22187
22388
|
// src/cli/commands/doctor.ts
|
|
22188
22389
|
var import_chalk11 = __toESM(require("chalk"));
|
|
22189
22390
|
var import_fs47 = __toESM(require("fs"));
|
|
22190
|
-
var
|
|
22191
|
-
var
|
|
22391
|
+
var import_path45 = __toESM(require("path"));
|
|
22392
|
+
var import_os41 = __toESM(require("os"));
|
|
22192
22393
|
var import_child_process8 = require("child_process");
|
|
22193
22394
|
init_daemon();
|
|
22194
22395
|
init_config();
|
|
22195
22396
|
init_agent_wiring();
|
|
22196
22397
|
function registerDoctorCommand(program2, version2) {
|
|
22197
22398
|
program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
|
|
22198
|
-
const homeDir2 =
|
|
22399
|
+
const homeDir2 = import_os41.default.homedir();
|
|
22199
22400
|
let failures = 0;
|
|
22200
22401
|
function pass(msg) {
|
|
22201
22402
|
console.log(import_chalk11.default.green(" \u2705 ") + msg);
|
|
@@ -22241,7 +22442,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
22241
22442
|
);
|
|
22242
22443
|
}
|
|
22243
22444
|
section("Configuration");
|
|
22244
|
-
const globalConfigPath =
|
|
22445
|
+
const globalConfigPath = import_path45.default.join(homeDir2, ".node9", "config.json");
|
|
22245
22446
|
if (import_fs47.default.existsSync(globalConfigPath)) {
|
|
22246
22447
|
try {
|
|
22247
22448
|
JSON.parse(import_fs47.default.readFileSync(globalConfigPath, "utf-8"));
|
|
@@ -22252,7 +22453,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
22252
22453
|
} else {
|
|
22253
22454
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
22254
22455
|
}
|
|
22255
|
-
const projectConfigPath =
|
|
22456
|
+
const projectConfigPath = import_path45.default.join(process.cwd(), "node9.config.json");
|
|
22256
22457
|
if (import_fs47.default.existsSync(projectConfigPath)) {
|
|
22257
22458
|
try {
|
|
22258
22459
|
JSON.parse(import_fs47.default.readFileSync(projectConfigPath, "utf-8"));
|
|
@@ -22264,7 +22465,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
22264
22465
|
);
|
|
22265
22466
|
}
|
|
22266
22467
|
}
|
|
22267
|
-
const credsPath =
|
|
22468
|
+
const credsPath = import_path45.default.join(homeDir2, ".node9", "credentials.json");
|
|
22268
22469
|
if (import_fs47.default.existsSync(credsPath)) {
|
|
22269
22470
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
22270
22471
|
} else {
|
|
@@ -22309,7 +22510,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
22309
22510
|
try {
|
|
22310
22511
|
const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
|
|
22311
22512
|
const cfg = getConfig();
|
|
22312
|
-
const creds = import_fs47.default.existsSync(
|
|
22513
|
+
const creds = import_fs47.default.existsSync(import_path45.default.join(import_os41.default.homedir(), ".node9", "credentials.json"));
|
|
22313
22514
|
if (!creds) {
|
|
22314
22515
|
warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
|
|
22315
22516
|
} else if (!cfg.settings.approvers.cloud) {
|
|
@@ -22360,8 +22561,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
22360
22561
|
// src/cli/commands/audit.ts
|
|
22361
22562
|
var import_chalk12 = __toESM(require("chalk"));
|
|
22362
22563
|
var import_fs48 = __toESM(require("fs"));
|
|
22363
|
-
var
|
|
22364
|
-
var
|
|
22564
|
+
var import_path46 = __toESM(require("path"));
|
|
22565
|
+
var import_os42 = __toESM(require("os"));
|
|
22365
22566
|
function formatRelativeTime(timestamp) {
|
|
22366
22567
|
const diff = Date.now() - new Date(timestamp).getTime();
|
|
22367
22568
|
const sec = Math.floor(diff / 1e3);
|
|
@@ -22374,7 +22575,7 @@ function formatRelativeTime(timestamp) {
|
|
|
22374
22575
|
}
|
|
22375
22576
|
function registerAuditCommand(program2) {
|
|
22376
22577
|
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) => {
|
|
22377
|
-
const logPath =
|
|
22578
|
+
const logPath = import_path46.default.join(import_os42.default.homedir(), ".node9", "audit.log");
|
|
22378
22579
|
if (!import_fs48.default.existsSync(logPath)) {
|
|
22379
22580
|
console.log(
|
|
22380
22581
|
import_chalk12.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
@@ -22438,8 +22639,8 @@ var import_chalk13 = __toESM(require("chalk"));
|
|
|
22438
22639
|
|
|
22439
22640
|
// src/cli/aggregate/report-audit.ts
|
|
22440
22641
|
var import_fs49 = __toESM(require("fs"));
|
|
22441
|
-
var
|
|
22442
|
-
var
|
|
22642
|
+
var import_os43 = __toESM(require("os"));
|
|
22643
|
+
var import_path47 = __toESM(require("path"));
|
|
22443
22644
|
init_costSync();
|
|
22444
22645
|
init_litellm();
|
|
22445
22646
|
init_cost_codex();
|
|
@@ -22570,7 +22771,7 @@ function freezeClaudeCost(acc) {
|
|
|
22570
22771
|
};
|
|
22571
22772
|
}
|
|
22572
22773
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
22573
|
-
const projPath =
|
|
22774
|
+
const projPath = import_path47.default.join(projectsDir, proj);
|
|
22574
22775
|
let files;
|
|
22575
22776
|
try {
|
|
22576
22777
|
const stat = import_fs49.default.statSync(projPath);
|
|
@@ -22581,7 +22782,7 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
22581
22782
|
}
|
|
22582
22783
|
const startMs = start.getTime();
|
|
22583
22784
|
for (const file of files) {
|
|
22584
|
-
const filePath =
|
|
22785
|
+
const filePath = import_path47.default.join(projPath, file);
|
|
22585
22786
|
try {
|
|
22586
22787
|
if (import_fs49.default.statSync(filePath).mtimeMs < startMs) continue;
|
|
22587
22788
|
} catch {
|
|
@@ -22711,28 +22912,28 @@ function listCodexSessionFiles2(sessionsBase) {
|
|
|
22711
22912
|
if (!import_fs49.default.existsSync(sessionsBase)) return jsonlFiles;
|
|
22712
22913
|
try {
|
|
22713
22914
|
for (const year of import_fs49.default.readdirSync(sessionsBase)) {
|
|
22714
|
-
const yearPath =
|
|
22915
|
+
const yearPath = import_path47.default.join(sessionsBase, year);
|
|
22715
22916
|
try {
|
|
22716
22917
|
if (!import_fs49.default.statSync(yearPath).isDirectory()) continue;
|
|
22717
22918
|
} catch {
|
|
22718
22919
|
continue;
|
|
22719
22920
|
}
|
|
22720
22921
|
for (const month of import_fs49.default.readdirSync(yearPath)) {
|
|
22721
|
-
const monthPath =
|
|
22922
|
+
const monthPath = import_path47.default.join(yearPath, month);
|
|
22722
22923
|
try {
|
|
22723
22924
|
if (!import_fs49.default.statSync(monthPath).isDirectory()) continue;
|
|
22724
22925
|
} catch {
|
|
22725
22926
|
continue;
|
|
22726
22927
|
}
|
|
22727
22928
|
for (const day of import_fs49.default.readdirSync(monthPath)) {
|
|
22728
|
-
const dayPath =
|
|
22929
|
+
const dayPath = import_path47.default.join(monthPath, day);
|
|
22729
22930
|
try {
|
|
22730
22931
|
if (!import_fs49.default.statSync(dayPath).isDirectory()) continue;
|
|
22731
22932
|
} catch {
|
|
22732
22933
|
continue;
|
|
22733
22934
|
}
|
|
22734
22935
|
for (const file of import_fs49.default.readdirSync(dayPath)) {
|
|
22735
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
22936
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path47.default.join(dayPath, file));
|
|
22736
22937
|
}
|
|
22737
22938
|
}
|
|
22738
22939
|
}
|
|
@@ -22858,7 +23059,7 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
|
|
|
22858
23059
|
return out;
|
|
22859
23060
|
}
|
|
22860
23061
|
for (const proj of dirs) {
|
|
22861
|
-
const chatsDir =
|
|
23062
|
+
const chatsDir = import_path47.default.join(geminiTmpDir2, proj, "chats");
|
|
22862
23063
|
let files;
|
|
22863
23064
|
try {
|
|
22864
23065
|
if (!import_fs49.default.statSync(chatsDir).isDirectory()) continue;
|
|
@@ -22868,7 +23069,7 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
|
|
|
22868
23069
|
}
|
|
22869
23070
|
for (const f of files) {
|
|
22870
23071
|
if (!f.endsWith(".jsonl")) continue;
|
|
22871
|
-
out.push({ projectKey: proj, file:
|
|
23072
|
+
out.push({ projectKey: proj, file: import_path47.default.join(chatsDir, f) });
|
|
22872
23073
|
}
|
|
22873
23074
|
}
|
|
22874
23075
|
return out;
|
|
@@ -22883,10 +23084,10 @@ function loadGeminiCost(start, end, geminiTmpDir2) {
|
|
|
22883
23084
|
}
|
|
22884
23085
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
22885
23086
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
22886
|
-
const auditLogPath = opts.auditLogPath ??
|
|
22887
|
-
const claudeProjectsDir = opts.claudeProjectsDir ??
|
|
22888
|
-
const codexSessionsDir2 = opts.codexSessionsDir ??
|
|
22889
|
-
const geminiTmpDir2 = opts.geminiTmpDir ??
|
|
23087
|
+
const auditLogPath = opts.auditLogPath ?? import_path47.default.join(import_os43.default.homedir(), ".node9", "audit.log");
|
|
23088
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? import_path47.default.join(import_os43.default.homedir(), ".claude", "projects");
|
|
23089
|
+
const codexSessionsDir2 = opts.codexSessionsDir ?? import_path47.default.join(import_os43.default.homedir(), ".codex", "sessions");
|
|
23090
|
+
const geminiTmpDir2 = opts.geminiTmpDir ?? import_path47.default.join(import_os43.default.homedir(), ".gemini", "tmp");
|
|
22890
23091
|
const hasAuditFile = import_fs49.default.existsSync(auditLogPath);
|
|
22891
23092
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
|
|
22892
23093
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
@@ -23584,8 +23785,8 @@ function registerDaemonCommand(program2) {
|
|
|
23584
23785
|
// src/cli/commands/status.ts
|
|
23585
23786
|
var import_chalk15 = __toESM(require("chalk"));
|
|
23586
23787
|
var import_fs50 = __toESM(require("fs"));
|
|
23587
|
-
var
|
|
23588
|
-
var
|
|
23788
|
+
var import_path48 = __toESM(require("path"));
|
|
23789
|
+
var import_os44 = __toESM(require("os"));
|
|
23589
23790
|
init_core();
|
|
23590
23791
|
init_daemon();
|
|
23591
23792
|
init_agent_wiring();
|
|
@@ -23642,8 +23843,8 @@ function registerStatusCommand(program2) {
|
|
|
23642
23843
|
console.log("");
|
|
23643
23844
|
const modeLabel = settings.mode === "audit" ? import_chalk15.default.blue("audit") : settings.mode === "strict" ? import_chalk15.default.red("strict") : import_chalk15.default.white("standard");
|
|
23644
23845
|
console.log(` Mode: ${modeLabel}`);
|
|
23645
|
-
const projectConfig =
|
|
23646
|
-
const globalConfig =
|
|
23846
|
+
const projectConfig = import_path48.default.join(process.cwd(), "node9.config.json");
|
|
23847
|
+
const globalConfig = import_path48.default.join(import_os44.default.homedir(), ".node9", "config.json");
|
|
23647
23848
|
console.log(
|
|
23648
23849
|
` Local: ${import_fs50.default.existsSync(projectConfig) ? import_chalk15.default.green("Active (node9.config.json)") : import_chalk15.default.gray("Not present")}`
|
|
23649
23850
|
);
|
|
@@ -23655,7 +23856,7 @@ function registerStatusCommand(program2) {
|
|
|
23655
23856
|
` Sandbox: ${import_chalk15.default.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
|
|
23656
23857
|
);
|
|
23657
23858
|
}
|
|
23658
|
-
const wiring = getAgentWiring(
|
|
23859
|
+
const wiring = getAgentWiring(import_os44.default.homedir()).filter((a) => a.present);
|
|
23659
23860
|
if (wiring.length > 0) {
|
|
23660
23861
|
console.log("");
|
|
23661
23862
|
console.log(import_chalk15.default.bold(" Agent Wiring:"));
|
|
@@ -23691,9 +23892,9 @@ function registerStatusCommand(program2) {
|
|
|
23691
23892
|
// src/cli/commands/init.ts
|
|
23692
23893
|
var import_chalk16 = __toESM(require("chalk"));
|
|
23693
23894
|
var import_fs51 = __toESM(require("fs"));
|
|
23694
|
-
var
|
|
23695
|
-
var
|
|
23696
|
-
var
|
|
23895
|
+
var import_path49 = __toESM(require("path"));
|
|
23896
|
+
var import_os45 = __toESM(require("os"));
|
|
23897
|
+
var import_https6 = __toESM(require("https"));
|
|
23697
23898
|
init_core();
|
|
23698
23899
|
init_setup();
|
|
23699
23900
|
init_shields();
|
|
@@ -23711,7 +23912,7 @@ function buildTelemetryPayload(agents, firstInstall) {
|
|
|
23711
23912
|
function fireTelemetryPing(agents, firstInstall) {
|
|
23712
23913
|
try {
|
|
23713
23914
|
const body = JSON.stringify(buildTelemetryPayload(agents, firstInstall));
|
|
23714
|
-
const req =
|
|
23915
|
+
const req = import_https6.default.request(
|
|
23715
23916
|
{
|
|
23716
23917
|
hostname: "api.node9.ai",
|
|
23717
23918
|
path: "/api/v1/telemetry",
|
|
@@ -23782,7 +23983,7 @@ function registerInitCommand(program2) {
|
|
|
23782
23983
|
}
|
|
23783
23984
|
console.log("");
|
|
23784
23985
|
}
|
|
23785
|
-
const configPath =
|
|
23986
|
+
const configPath = import_path49.default.join(import_os45.default.homedir(), ".node9", "config.json");
|
|
23786
23987
|
const isFirstInstall = !import_fs51.default.existsSync(configPath);
|
|
23787
23988
|
if (import_fs51.default.existsSync(configPath) && !options.force) {
|
|
23788
23989
|
try {
|
|
@@ -23804,7 +24005,7 @@ function registerInitCommand(program2) {
|
|
|
23804
24005
|
...DEFAULT_CONFIG,
|
|
23805
24006
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
23806
24007
|
};
|
|
23807
|
-
const dir =
|
|
24008
|
+
const dir = import_path49.default.dirname(configPath);
|
|
23808
24009
|
if (!import_fs51.default.existsSync(dir)) import_fs51.default.mkdirSync(dir, { recursive: true });
|
|
23809
24010
|
import_fs51.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
|
|
23810
24011
|
console.log(import_chalk16.default.green(`\u2705 Config created: ${configPath}`));
|
|
@@ -23911,7 +24112,7 @@ function registerInitCommand(program2) {
|
|
|
23911
24112
|
}
|
|
23912
24113
|
|
|
23913
24114
|
// src/cli/commands/undo.ts
|
|
23914
|
-
var
|
|
24115
|
+
var import_path50 = __toESM(require("path"));
|
|
23915
24116
|
var import_chalk18 = __toESM(require("chalk"));
|
|
23916
24117
|
|
|
23917
24118
|
// src/tui/undo-navigator.ts
|
|
@@ -24070,7 +24271,7 @@ function findMatchingCwd(startDir, history) {
|
|
|
24070
24271
|
let dir = startDir;
|
|
24071
24272
|
while (true) {
|
|
24072
24273
|
if (cwds.has(dir)) return dir;
|
|
24073
|
-
const parent =
|
|
24274
|
+
const parent = import_path50.default.dirname(dir);
|
|
24074
24275
|
if (parent === dir) return null;
|
|
24075
24276
|
dir = parent;
|
|
24076
24277
|
}
|
|
@@ -24706,8 +24907,8 @@ function registerMcpGatewayCommand(program2) {
|
|
|
24706
24907
|
// src/mcp-server/index.ts
|
|
24707
24908
|
var import_readline5 = __toESM(require("readline"));
|
|
24708
24909
|
var import_fs53 = __toESM(require("fs"));
|
|
24709
|
-
var
|
|
24710
|
-
var
|
|
24910
|
+
var import_os47 = __toESM(require("os"));
|
|
24911
|
+
var import_path52 = __toESM(require("path"));
|
|
24711
24912
|
var import_child_process11 = require("child_process");
|
|
24712
24913
|
init_core();
|
|
24713
24914
|
init_daemon();
|
|
@@ -24715,8 +24916,8 @@ init_shields();
|
|
|
24715
24916
|
|
|
24716
24917
|
// src/auth/egress-config.ts
|
|
24717
24918
|
var import_fs52 = __toESM(require("fs"));
|
|
24718
|
-
var
|
|
24719
|
-
var
|
|
24919
|
+
var import_os46 = __toESM(require("os"));
|
|
24920
|
+
var import_path51 = __toESM(require("path"));
|
|
24720
24921
|
var DEFAULT_EGRESS = {
|
|
24721
24922
|
enabled: false,
|
|
24722
24923
|
mode: "review",
|
|
@@ -24725,7 +24926,7 @@ var DEFAULT_EGRESS = {
|
|
|
24725
24926
|
allowPrivate: true
|
|
24726
24927
|
};
|
|
24727
24928
|
function egressConfigPath() {
|
|
24728
|
-
return
|
|
24929
|
+
return import_path51.default.join(import_os46.default.homedir(), ".node9", "config.json");
|
|
24729
24930
|
}
|
|
24730
24931
|
function readEgressRawConfig() {
|
|
24731
24932
|
let text;
|
|
@@ -24745,7 +24946,7 @@ function readEgressRawConfig() {
|
|
|
24745
24946
|
}
|
|
24746
24947
|
function writeEgressRawConfig(config) {
|
|
24747
24948
|
const p = egressConfigPath();
|
|
24748
|
-
import_fs52.default.mkdirSync(
|
|
24949
|
+
import_fs52.default.mkdirSync(import_path51.default.dirname(p), { recursive: true });
|
|
24749
24950
|
import_fs52.default.writeFileSync(p, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
24750
24951
|
}
|
|
24751
24952
|
function applyEgress(config, change) {
|
|
@@ -25131,8 +25332,8 @@ function handleStatus() {
|
|
|
25131
25332
|
lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
|
|
25132
25333
|
lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
|
|
25133
25334
|
lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
|
|
25134
|
-
const projectConfig =
|
|
25135
|
-
const globalConfig =
|
|
25335
|
+
const projectConfig = import_path52.default.join(process.cwd(), "node9.config.json");
|
|
25336
|
+
const globalConfig = import_path52.default.join(import_os47.default.homedir(), ".node9", "config.json");
|
|
25136
25337
|
lines.push(
|
|
25137
25338
|
`Project config (node9.config.json): ${import_fs53.default.existsSync(projectConfig) ? "present" : "not found"}`
|
|
25138
25339
|
);
|
|
@@ -25243,7 +25444,7 @@ function handleEgressDeny(args) {
|
|
|
25243
25444
|
addEgressHost("deny", host);
|
|
25244
25445
|
return `Denied egress to ${host} (deny always wins over allow).`;
|
|
25245
25446
|
}
|
|
25246
|
-
var GLOBAL_CONFIG_PATH =
|
|
25447
|
+
var GLOBAL_CONFIG_PATH = import_path52.default.join(import_os47.default.homedir(), ".node9", "config.json");
|
|
25247
25448
|
var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
|
|
25248
25449
|
function readGlobalConfigRaw() {
|
|
25249
25450
|
try {
|
|
@@ -25255,7 +25456,7 @@ function readGlobalConfigRaw() {
|
|
|
25255
25456
|
return {};
|
|
25256
25457
|
}
|
|
25257
25458
|
function writeGlobalConfigRaw(data) {
|
|
25258
|
-
const dir =
|
|
25459
|
+
const dir = import_path52.default.dirname(GLOBAL_CONFIG_PATH);
|
|
25259
25460
|
if (!import_fs53.default.existsSync(dir)) import_fs53.default.mkdirSync(dir, { recursive: true });
|
|
25260
25461
|
import_fs53.default.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
|
|
25261
25462
|
}
|
|
@@ -25301,7 +25502,7 @@ function handleApproverSet(args) {
|
|
|
25301
25502
|
function handleAuditGet(args) {
|
|
25302
25503
|
const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
|
|
25303
25504
|
const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
|
|
25304
|
-
const auditPath =
|
|
25505
|
+
const auditPath = import_path52.default.join(import_os47.default.homedir(), ".node9", "audit.log");
|
|
25305
25506
|
if (!import_fs53.default.existsSync(auditPath)) return "No audit log found.";
|
|
25306
25507
|
const rawLines = import_fs53.default.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
|
|
25307
25508
|
const parsed = [];
|
|
@@ -25809,6 +26010,17 @@ var import_chalk22 = __toESM(require("chalk"));
|
|
|
25809
26010
|
init_sync();
|
|
25810
26011
|
function registerSyncCommand(program2) {
|
|
25811
26012
|
const policy = program2.command("policy").description("Manage cloud policy rules");
|
|
26013
|
+
policy.command("push").description("Push this machine's effective policy to the node9 dashboard").action(async () => {
|
|
26014
|
+
process.stdout.write(import_chalk22.default.cyan("Pushing policy to the dashboard\u2026"));
|
|
26015
|
+
const result = await runPolicyPush();
|
|
26016
|
+
process.stdout.write("\n");
|
|
26017
|
+
if (!result.ok) {
|
|
26018
|
+
console.error(import_chalk22.default.red(`\u2717 ${result.reason}`));
|
|
26019
|
+
process.exit(1);
|
|
26020
|
+
}
|
|
26021
|
+
console.log(import_chalk22.default.green("\u2713 Policy mirrored to the dashboard"));
|
|
26022
|
+
console.log(import_chalk22.default.gray(" See it under Security Policy \u2192 Machines"));
|
|
26023
|
+
});
|
|
25812
26024
|
policy.command("sync").description("Sync cloud policy rules to local cache (~/.node9/rules-cache.json)").action(async () => {
|
|
25813
26025
|
process.stdout.write(import_chalk22.default.cyan("Syncing cloud policy rules\u2026"));
|
|
25814
26026
|
const result = await runCloudSync();
|
|
@@ -26257,12 +26469,12 @@ var import_chalk27 = __toESM(require("chalk"));
|
|
|
26257
26469
|
|
|
26258
26470
|
// src/shields/jail.ts
|
|
26259
26471
|
var import_fs55 = __toESM(require("fs"));
|
|
26260
|
-
var
|
|
26261
|
-
var
|
|
26472
|
+
var import_os48 = __toESM(require("os"));
|
|
26473
|
+
var import_path53 = __toESM(require("path"));
|
|
26262
26474
|
init_shields();
|
|
26263
26475
|
var USER_JAIL_SHIELD = "user-jail";
|
|
26264
26476
|
function jailStorePath() {
|
|
26265
|
-
return
|
|
26477
|
+
return import_path53.default.join(import_os48.default.homedir(), ".node9", "jail-paths.json");
|
|
26266
26478
|
}
|
|
26267
26479
|
function readJailPaths() {
|
|
26268
26480
|
let text;
|
|
@@ -26285,7 +26497,7 @@ function readJailPaths() {
|
|
|
26285
26497
|
}
|
|
26286
26498
|
function writeJailPaths(paths) {
|
|
26287
26499
|
const p = jailStorePath();
|
|
26288
|
-
import_fs55.default.mkdirSync(
|
|
26500
|
+
import_fs55.default.mkdirSync(import_path53.default.dirname(p), { recursive: true });
|
|
26289
26501
|
import_fs55.default.writeFileSync(p, JSON.stringify({ paths }, null, 2) + "\n", { mode: 384 });
|
|
26290
26502
|
}
|
|
26291
26503
|
function addJailPath(rawPath, verdict) {
|
|
@@ -26308,7 +26520,7 @@ function removeJailPath(rawPath) {
|
|
|
26308
26520
|
return { removed, paths: after };
|
|
26309
26521
|
}
|
|
26310
26522
|
function regenerateUserJail(paths) {
|
|
26311
|
-
const file =
|
|
26523
|
+
const file = import_path53.default.join(USER_SHIELDS_DIR_PATH, `${USER_JAIL_SHIELD}.json`);
|
|
26312
26524
|
if (paths.length === 0) {
|
|
26313
26525
|
const active2 = readActiveShields();
|
|
26314
26526
|
if (active2.includes(USER_JAIL_SHIELD)) {
|
|
@@ -26430,13 +26642,13 @@ function registerJailCommand(program2) {
|
|
|
26430
26642
|
// src/cli/commands/sandbox.ts
|
|
26431
26643
|
var import_chalk28 = __toESM(require("chalk"));
|
|
26432
26644
|
var import_fs58 = __toESM(require("fs"));
|
|
26433
|
-
var
|
|
26645
|
+
var import_path56 = __toESM(require("path"));
|
|
26434
26646
|
var import_child_process13 = require("child_process");
|
|
26435
26647
|
init_config();
|
|
26436
26648
|
|
|
26437
26649
|
// src/sandbox/config.ts
|
|
26438
26650
|
var import_fs56 = __toESM(require("fs"));
|
|
26439
|
-
var
|
|
26651
|
+
var import_path54 = __toESM(require("path"));
|
|
26440
26652
|
var import_yaml = require("yaml");
|
|
26441
26653
|
var SANDBOX_CONFIG_FILE = "node9.sandbox.yaml";
|
|
26442
26654
|
var FORBIDDEN_ENV = /* @__PURE__ */ new Set(["NODE9_API_KEY", "NODE9_API_URL"]);
|
|
@@ -26509,7 +26721,7 @@ function scaffoldSandboxYaml(agent) {
|
|
|
26509
26721
|
return header + (0, import_yaml.stringify)(defaultSandboxConfig(agent));
|
|
26510
26722
|
}
|
|
26511
26723
|
function sandboxConfigPath(cwd = process.cwd()) {
|
|
26512
|
-
return
|
|
26724
|
+
return import_path54.default.join(cwd, SANDBOX_CONFIG_FILE);
|
|
26513
26725
|
}
|
|
26514
26726
|
function loadSandboxConfig(cwd = process.cwd(), fallbackAgent = "claude") {
|
|
26515
26727
|
const p = sandboxConfigPath(cwd);
|
|
@@ -26577,13 +26789,13 @@ init_templates();
|
|
|
26577
26789
|
|
|
26578
26790
|
// src/sandbox/runtime.ts
|
|
26579
26791
|
var import_fs57 = __toESM(require("fs"));
|
|
26580
|
-
var
|
|
26581
|
-
var
|
|
26792
|
+
var import_os49 = __toESM(require("os"));
|
|
26793
|
+
var import_path55 = __toESM(require("path"));
|
|
26582
26794
|
var import_crypto13 = __toESM(require("crypto"));
|
|
26583
26795
|
var import_child_process12 = require("child_process");
|
|
26584
26796
|
init_templates();
|
|
26585
26797
|
function sandboxDataDir(cwd = process.cwd()) {
|
|
26586
|
-
return
|
|
26798
|
+
return import_path55.default.join(cwd, ".node9", "sandbox", "data");
|
|
26587
26799
|
}
|
|
26588
26800
|
function detectEngine(engine) {
|
|
26589
26801
|
const r = (0, import_child_process12.spawnSync)(engine, ["--version"], { encoding: "utf-8" });
|
|
@@ -26594,7 +26806,7 @@ function detectEngine(engine) {
|
|
|
26594
26806
|
}
|
|
26595
26807
|
function agentCredentialsMount(agent) {
|
|
26596
26808
|
const rel = agent === "codex" ? ".codex/auth.json" : ".claude/.credentials.json";
|
|
26597
|
-
return { hostPath:
|
|
26809
|
+
return { hostPath: import_path55.default.join(import_os49.default.homedir(), rel), target: `/home/${RUN_AS_USER}/${rel}` };
|
|
26598
26810
|
}
|
|
26599
26811
|
function buildRunArgs(opts) {
|
|
26600
26812
|
const { config, workspaceHostPath, dataHostPath, allowlistHostPath, agentArgs } = opts;
|
|
@@ -26622,30 +26834,30 @@ function imageContentHash(dockerfile, entrypoint) {
|
|
|
26622
26834
|
return import_crypto13.default.createHash("sha256").update(dockerfile).update("\0").update(entrypoint).digest("hex").slice(0, 16);
|
|
26623
26835
|
}
|
|
26624
26836
|
function sandboxBuildDir(cwd = process.cwd()) {
|
|
26625
|
-
return
|
|
26837
|
+
return import_path55.default.join(cwd, ".node9", "sandbox", "build");
|
|
26626
26838
|
}
|
|
26627
26839
|
function writeBuildContext(cwd, dockerfile, entrypoint) {
|
|
26628
26840
|
const dir = sandboxBuildDir(cwd);
|
|
26629
26841
|
import_fs57.default.mkdirSync(dir, { recursive: true });
|
|
26630
|
-
import_fs57.default.writeFileSync(
|
|
26631
|
-
import_fs57.default.writeFileSync(
|
|
26842
|
+
import_fs57.default.writeFileSync(import_path55.default.join(dir, "Dockerfile"), dockerfile);
|
|
26843
|
+
import_fs57.default.writeFileSync(import_path55.default.join(dir, "entrypoint.sh"), entrypoint);
|
|
26632
26844
|
return dir;
|
|
26633
26845
|
}
|
|
26634
26846
|
function writeAllowlist(cwd, hosts) {
|
|
26635
|
-
const dir =
|
|
26847
|
+
const dir = import_path55.default.join(cwd, ".node9", "sandbox");
|
|
26636
26848
|
import_fs57.default.mkdirSync(dir, { recursive: true });
|
|
26637
|
-
const p =
|
|
26849
|
+
const p = import_path55.default.join(dir, "allowed-domains.txt");
|
|
26638
26850
|
import_fs57.default.writeFileSync(p, hosts.join("\n") + "\n");
|
|
26639
26851
|
return p;
|
|
26640
26852
|
}
|
|
26641
26853
|
function resolveHomePath(p) {
|
|
26642
|
-
return p.startsWith("~") ?
|
|
26854
|
+
return p.startsWith("~") ? import_path55.default.join(import_os49.default.homedir(), p.slice(1)) : import_path55.default.resolve(p);
|
|
26643
26855
|
}
|
|
26644
26856
|
|
|
26645
26857
|
// src/cli/commands/sandbox.ts
|
|
26646
26858
|
function seedDataDirConfig(dataDir, sandbox) {
|
|
26647
26859
|
import_fs58.default.mkdirSync(dataDir, { recursive: true });
|
|
26648
|
-
const configPath =
|
|
26860
|
+
const configPath = import_path56.default.join(dataDir, "config.json");
|
|
26649
26861
|
const seed = {
|
|
26650
26862
|
settings: {
|
|
26651
26863
|
approvers: {
|
|
@@ -26710,7 +26922,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
26710
26922
|
const buildDir = writeBuildContext(cwd, dockerfile, entrypoint);
|
|
26711
26923
|
const hash = imageContentHash(dockerfile, entrypoint);
|
|
26712
26924
|
const image = sandbox.runtime.image;
|
|
26713
|
-
const hashFile =
|
|
26925
|
+
const hashFile = import_path56.default.join(sandboxBuildDir(cwd), ".image-hash");
|
|
26714
26926
|
const lastHash = import_fs58.default.existsSync(hashFile) ? import_fs58.default.readFileSync(hashFile, "utf-8").trim() : "";
|
|
26715
26927
|
const imageExists = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, ["image", "inspect", image], { stdio: "ignore" }).status === 0;
|
|
26716
26928
|
const needBuild = sandbox.runtime.rebuild === "always" || !imageExists || sandbox.runtime.rebuild !== "never" && lastHash !== hash;
|
|
@@ -26753,7 +26965,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
26753
26965
|
process.exit(r.status ?? 0);
|
|
26754
26966
|
});
|
|
26755
26967
|
cmd.command("tail").description("Stream the sandbox's audit log (host-side)").action(() => {
|
|
26756
|
-
const auditPath =
|
|
26968
|
+
const auditPath = import_path56.default.join(sandboxDataDir(), "audit.log");
|
|
26757
26969
|
if (!import_fs58.default.existsSync(auditPath)) {
|
|
26758
26970
|
console.log(import_chalk28.default.dim(" no sandbox audit yet."));
|
|
26759
26971
|
return;
|
|
@@ -26761,7 +26973,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
26761
26973
|
(0, import_child_process13.spawnSync)("tail", ["-f", auditPath], { stdio: "inherit" });
|
|
26762
26974
|
});
|
|
26763
26975
|
cmd.command("logs").description("Dump the sandbox's audit log").action(() => {
|
|
26764
|
-
const auditPath =
|
|
26976
|
+
const auditPath = import_path56.default.join(sandboxDataDir(), "audit.log");
|
|
26765
26977
|
if (!import_fs58.default.existsSync(auditPath)) {
|
|
26766
26978
|
console.log(import_chalk28.default.dim(" no sandbox audit yet."));
|
|
26767
26979
|
return;
|
|
@@ -26780,7 +26992,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
26780
26992
|
stdio: "ignore"
|
|
26781
26993
|
});
|
|
26782
26994
|
}
|
|
26783
|
-
import_fs58.default.rmSync(
|
|
26995
|
+
import_fs58.default.rmSync(import_path56.default.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
|
|
26784
26996
|
console.log(import_chalk28.default.green(" \u2713 sandbox image + build + data removed."));
|
|
26785
26997
|
});
|
|
26786
26998
|
}
|
|
@@ -26788,8 +27000,8 @@ function registerSandboxCommand(program2, version2) {
|
|
|
26788
27000
|
// src/cli/commands/sessions.ts
|
|
26789
27001
|
var import_chalk29 = __toESM(require("chalk"));
|
|
26790
27002
|
var import_fs59 = __toESM(require("fs"));
|
|
26791
|
-
var
|
|
26792
|
-
var
|
|
27003
|
+
var import_path57 = __toESM(require("path"));
|
|
27004
|
+
var import_os50 = __toESM(require("os"));
|
|
26793
27005
|
init_scan_summary();
|
|
26794
27006
|
init_litellm();
|
|
26795
27007
|
init_cost_gemini();
|
|
@@ -26810,10 +27022,10 @@ function encodeProjectPath(projectPath) {
|
|
|
26810
27022
|
}
|
|
26811
27023
|
function sessionJsonlPath(projectPath, sessionId) {
|
|
26812
27024
|
const encoded = encodeProjectPath(projectPath);
|
|
26813
|
-
return
|
|
27025
|
+
return import_path57.default.join(import_os50.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
|
|
26814
27026
|
}
|
|
26815
27027
|
function projectLabel(projectPath) {
|
|
26816
|
-
return projectPath.replace(
|
|
27028
|
+
return projectPath.replace(import_os50.default.homedir(), "~");
|
|
26817
27029
|
}
|
|
26818
27030
|
function parseHistoryLines(lines) {
|
|
26819
27031
|
const entries = [];
|
|
@@ -26882,7 +27094,7 @@ function parseSessionLines(lines) {
|
|
|
26882
27094
|
return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
|
|
26883
27095
|
}
|
|
26884
27096
|
function loadAuditEntries(auditPath) {
|
|
26885
|
-
const aPath = auditPath ??
|
|
27097
|
+
const aPath = auditPath ?? import_path57.default.join(import_os50.default.homedir(), ".node9", "audit.log");
|
|
26886
27098
|
let raw;
|
|
26887
27099
|
try {
|
|
26888
27100
|
raw = import_fs59.default.readFileSync(aPath, "utf-8");
|
|
@@ -26921,7 +27133,7 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
26921
27133
|
return result;
|
|
26922
27134
|
}
|
|
26923
27135
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
26924
|
-
const tmpDir =
|
|
27136
|
+
const tmpDir = import_path57.default.join(import_os50.default.homedir(), ".gemini", "tmp");
|
|
26925
27137
|
if (!import_fs59.default.existsSync(tmpDir)) return [];
|
|
26926
27138
|
const cutoff = days !== null ? (() => {
|
|
26927
27139
|
const d = /* @__PURE__ */ new Date();
|
|
@@ -26937,18 +27149,18 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
26937
27149
|
}
|
|
26938
27150
|
const summaries = [];
|
|
26939
27151
|
for (const slug2 of slugDirs) {
|
|
26940
|
-
const slugPath =
|
|
27152
|
+
const slugPath = import_path57.default.join(tmpDir, slug2);
|
|
26941
27153
|
try {
|
|
26942
27154
|
if (!import_fs59.default.statSync(slugPath).isDirectory()) continue;
|
|
26943
27155
|
} catch {
|
|
26944
27156
|
continue;
|
|
26945
27157
|
}
|
|
26946
|
-
let projectRoot =
|
|
27158
|
+
let projectRoot = import_path57.default.join(import_os50.default.homedir(), slug2);
|
|
26947
27159
|
try {
|
|
26948
|
-
projectRoot = import_fs59.default.readFileSync(
|
|
27160
|
+
projectRoot = import_fs59.default.readFileSync(import_path57.default.join(slugPath, ".project_root"), "utf-8").trim();
|
|
26949
27161
|
} catch {
|
|
26950
27162
|
}
|
|
26951
|
-
const chatsDir =
|
|
27163
|
+
const chatsDir = import_path57.default.join(slugPath, "chats");
|
|
26952
27164
|
if (!import_fs59.default.existsSync(chatsDir)) continue;
|
|
26953
27165
|
let chatFiles;
|
|
26954
27166
|
try {
|
|
@@ -26959,7 +27171,7 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
26959
27171
|
for (const chatFile of chatFiles) {
|
|
26960
27172
|
let raw;
|
|
26961
27173
|
try {
|
|
26962
|
-
raw = import_fs59.default.readFileSync(
|
|
27174
|
+
raw = import_fs59.default.readFileSync(import_path57.default.join(chatsDir, chatFile), "utf-8");
|
|
26963
27175
|
} catch {
|
|
26964
27176
|
continue;
|
|
26965
27177
|
}
|
|
@@ -27039,7 +27251,7 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
27039
27251
|
return summaries;
|
|
27040
27252
|
}
|
|
27041
27253
|
function buildCodexSessions(days, allAuditEntries) {
|
|
27042
|
-
const sessionsBase =
|
|
27254
|
+
const sessionsBase = import_path57.default.join(import_os50.default.homedir(), ".codex", "sessions");
|
|
27043
27255
|
if (!import_fs59.default.existsSync(sessionsBase)) return [];
|
|
27044
27256
|
const cutoff = days !== null ? (() => {
|
|
27045
27257
|
const d = /* @__PURE__ */ new Date();
|
|
@@ -27050,28 +27262,28 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
27050
27262
|
const jsonlFiles = [];
|
|
27051
27263
|
try {
|
|
27052
27264
|
for (const year of import_fs59.default.readdirSync(sessionsBase)) {
|
|
27053
|
-
const yearPath =
|
|
27265
|
+
const yearPath = import_path57.default.join(sessionsBase, year);
|
|
27054
27266
|
try {
|
|
27055
27267
|
if (!import_fs59.default.statSync(yearPath).isDirectory()) continue;
|
|
27056
27268
|
} catch {
|
|
27057
27269
|
continue;
|
|
27058
27270
|
}
|
|
27059
27271
|
for (const month of import_fs59.default.readdirSync(yearPath)) {
|
|
27060
|
-
const monthPath =
|
|
27272
|
+
const monthPath = import_path57.default.join(yearPath, month);
|
|
27061
27273
|
try {
|
|
27062
27274
|
if (!import_fs59.default.statSync(monthPath).isDirectory()) continue;
|
|
27063
27275
|
} catch {
|
|
27064
27276
|
continue;
|
|
27065
27277
|
}
|
|
27066
27278
|
for (const day of import_fs59.default.readdirSync(monthPath)) {
|
|
27067
|
-
const dayPath =
|
|
27279
|
+
const dayPath = import_path57.default.join(monthPath, day);
|
|
27068
27280
|
try {
|
|
27069
27281
|
if (!import_fs59.default.statSync(dayPath).isDirectory()) continue;
|
|
27070
27282
|
} catch {
|
|
27071
27283
|
continue;
|
|
27072
27284
|
}
|
|
27073
27285
|
for (const file of import_fs59.default.readdirSync(dayPath)) {
|
|
27074
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
27286
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path57.default.join(dayPath, file));
|
|
27075
27287
|
}
|
|
27076
27288
|
}
|
|
27077
27289
|
}
|
|
@@ -27169,7 +27381,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
27169
27381
|
return summaries;
|
|
27170
27382
|
}
|
|
27171
27383
|
function buildSessions(days, historyPath) {
|
|
27172
|
-
const hPath = historyPath ??
|
|
27384
|
+
const hPath = historyPath ?? import_path57.default.join(import_os50.default.homedir(), ".claude", "history.jsonl");
|
|
27173
27385
|
let historyRaw = "";
|
|
27174
27386
|
try {
|
|
27175
27387
|
historyRaw = import_fs59.default.readFileSync(hPath, "utf-8");
|
|
@@ -27591,11 +27803,11 @@ function registerSessionTaintCommand(program2) {
|
|
|
27591
27803
|
// src/cli/commands/skill-pin.ts
|
|
27592
27804
|
var import_chalk31 = __toESM(require("chalk"));
|
|
27593
27805
|
var import_fs60 = __toESM(require("fs"));
|
|
27594
|
-
var
|
|
27595
|
-
var
|
|
27806
|
+
var import_os51 = __toESM(require("os"));
|
|
27807
|
+
var import_path58 = __toESM(require("path"));
|
|
27596
27808
|
function wipeSkillSessions() {
|
|
27597
27809
|
try {
|
|
27598
|
-
import_fs60.default.rmSync(
|
|
27810
|
+
import_fs60.default.rmSync(import_path58.default.join(import_os51.default.homedir(), ".node9", "skill-sessions"), {
|
|
27599
27811
|
recursive: true,
|
|
27600
27812
|
force: true
|
|
27601
27813
|
});
|
|
@@ -27678,10 +27890,10 @@ function registerSkillPinCommand(program2) {
|
|
|
27678
27890
|
|
|
27679
27891
|
// src/cli/commands/decisions.ts
|
|
27680
27892
|
var import_fs61 = __toESM(require("fs"));
|
|
27681
|
-
var
|
|
27682
|
-
var
|
|
27893
|
+
var import_os52 = __toESM(require("os"));
|
|
27894
|
+
var import_path59 = __toESM(require("path"));
|
|
27683
27895
|
var import_chalk32 = __toESM(require("chalk"));
|
|
27684
|
-
var DECISIONS_FILE2 =
|
|
27896
|
+
var DECISIONS_FILE2 = import_path59.default.join(import_os52.default.homedir(), ".node9", "decisions.json");
|
|
27685
27897
|
function readDecisions() {
|
|
27686
27898
|
try {
|
|
27687
27899
|
if (!import_fs61.default.existsSync(DECISIONS_FILE2)) return {};
|
|
@@ -27697,7 +27909,7 @@ function readDecisions() {
|
|
|
27697
27909
|
}
|
|
27698
27910
|
}
|
|
27699
27911
|
function writeDecisions(d) {
|
|
27700
|
-
const dir =
|
|
27912
|
+
const dir = import_path59.default.dirname(DECISIONS_FILE2);
|
|
27701
27913
|
if (!import_fs61.default.existsSync(dir)) import_fs61.default.mkdirSync(dir, { recursive: true });
|
|
27702
27914
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
27703
27915
|
import_fs61.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
@@ -27759,10 +27971,10 @@ Persistent decisions (${entries.length})
|
|
|
27759
27971
|
// src/cli/commands/dlp.ts
|
|
27760
27972
|
var import_chalk33 = __toESM(require("chalk"));
|
|
27761
27973
|
var import_fs62 = __toESM(require("fs"));
|
|
27762
|
-
var
|
|
27763
|
-
var
|
|
27764
|
-
var AUDIT_LOG =
|
|
27765
|
-
var RESOLVED_FILE =
|
|
27974
|
+
var import_path60 = __toESM(require("path"));
|
|
27975
|
+
var import_os53 = __toESM(require("os"));
|
|
27976
|
+
var AUDIT_LOG = import_path60.default.join(import_os53.default.homedir(), ".node9", "audit.log");
|
|
27977
|
+
var RESOLVED_FILE = import_path60.default.join(import_os53.default.homedir(), ".node9", "dlp-resolved.json");
|
|
27766
27978
|
var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
|
|
27767
27979
|
function stripAnsi(s) {
|
|
27768
27980
|
return s.replace(ANSI_RE, "");
|
|
@@ -27882,14 +28094,14 @@ function registerDlpCommand(program2) {
|
|
|
27882
28094
|
// src/cli/commands/mask.ts
|
|
27883
28095
|
var import_chalk34 = __toESM(require("chalk"));
|
|
27884
28096
|
var import_fs63 = __toESM(require("fs"));
|
|
27885
|
-
var
|
|
27886
|
-
var
|
|
28097
|
+
var import_path61 = __toESM(require("path"));
|
|
28098
|
+
var import_os54 = __toESM(require("os"));
|
|
27887
28099
|
init_dlp();
|
|
27888
28100
|
function findJsonlFiles(dir) {
|
|
27889
28101
|
const results = [];
|
|
27890
28102
|
if (!import_fs63.default.existsSync(dir)) return results;
|
|
27891
28103
|
for (const entry of import_fs63.default.readdirSync(dir, { withFileTypes: true })) {
|
|
27892
|
-
const full =
|
|
28104
|
+
const full = import_path61.default.join(dir, entry.name);
|
|
27893
28105
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
27894
28106
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
27895
28107
|
}
|
|
@@ -27992,7 +28204,7 @@ function findJsonFiles(dir) {
|
|
|
27992
28204
|
const results = [];
|
|
27993
28205
|
if (!import_fs63.default.existsSync(dir)) return results;
|
|
27994
28206
|
for (const entry of import_fs63.default.readdirSync(dir, { withFileTypes: true })) {
|
|
27995
|
-
const full =
|
|
28207
|
+
const full = import_path61.default.join(dir, entry.name);
|
|
27996
28208
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
27997
28209
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
27998
28210
|
}
|
|
@@ -28001,9 +28213,9 @@ function findJsonFiles(dir) {
|
|
|
28001
28213
|
function registerMaskCommand(program2) {
|
|
28002
28214
|
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) => {
|
|
28003
28215
|
const dryRun = !!options.dryRun;
|
|
28004
|
-
const home =
|
|
28005
|
-
const claudeDir =
|
|
28006
|
-
const geminiDir =
|
|
28216
|
+
const home = import_os54.default.homedir();
|
|
28217
|
+
const claudeDir = import_path61.default.join(home, ".claude", "projects");
|
|
28218
|
+
const geminiDir = import_path61.default.join(home, ".gemini", "tmp");
|
|
28007
28219
|
const allFiles = [
|
|
28008
28220
|
...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
|
|
28009
28221
|
...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
|
|
@@ -28067,15 +28279,15 @@ function registerMaskCommand(program2) {
|
|
|
28067
28279
|
// src/cli.ts
|
|
28068
28280
|
init_blast();
|
|
28069
28281
|
var { version } = JSON.parse(
|
|
28070
|
-
import_fs66.default.readFileSync(
|
|
28282
|
+
import_fs66.default.readFileSync(import_path64.default.join(__dirname, "../package.json"), "utf-8")
|
|
28071
28283
|
);
|
|
28072
28284
|
var program = new import_commander.Command();
|
|
28073
28285
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
28074
28286
|
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) => {
|
|
28075
28287
|
const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
|
|
28076
|
-
const credPath =
|
|
28077
|
-
if (!import_fs66.default.existsSync(
|
|
28078
|
-
import_fs66.default.mkdirSync(
|
|
28288
|
+
const credPath = import_path64.default.join(import_os57.default.homedir(), ".node9", "credentials.json");
|
|
28289
|
+
if (!import_fs66.default.existsSync(import_path64.default.dirname(credPath)))
|
|
28290
|
+
import_fs66.default.mkdirSync(import_path64.default.dirname(credPath), { recursive: true });
|
|
28079
28291
|
const profileName = options.profile || "default";
|
|
28080
28292
|
let existingCreds = {};
|
|
28081
28293
|
try {
|
|
@@ -28095,7 +28307,7 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
28095
28307
|
import_fs66.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
|
|
28096
28308
|
let effectiveCloud = null;
|
|
28097
28309
|
if (profileName === "default") {
|
|
28098
|
-
const configPath =
|
|
28310
|
+
const configPath = import_path64.default.join(import_os57.default.homedir(), ".node9", "config.json");
|
|
28099
28311
|
let config = {};
|
|
28100
28312
|
try {
|
|
28101
28313
|
if (import_fs66.default.existsSync(configPath))
|
|
@@ -28114,8 +28326,8 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
28114
28326
|
approvers.cloud = false;
|
|
28115
28327
|
}
|
|
28116
28328
|
s.approvers = approvers;
|
|
28117
|
-
if (!import_fs66.default.existsSync(
|
|
28118
|
-
import_fs66.default.mkdirSync(
|
|
28329
|
+
if (!import_fs66.default.existsSync(import_path64.default.dirname(configPath)))
|
|
28330
|
+
import_fs66.default.mkdirSync(import_path64.default.dirname(configPath), { recursive: true });
|
|
28119
28331
|
import_fs66.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
28120
28332
|
effectiveCloud = approvers.cloud === true;
|
|
28121
28333
|
}
|
|
@@ -28225,37 +28437,21 @@ program.command("setup", { hidden: true }).description('Alias for "addto" \u2014
|
|
|
28225
28437
|
);
|
|
28226
28438
|
process.exit(1);
|
|
28227
28439
|
});
|
|
28228
|
-
program.command("removefrom", { hidden: true }).description("Remove Node9 hooks from an AI agent configuration").addHelpText(
|
|
28229
|
-
"
|
|
28230
|
-
|
|
28231
|
-
)
|
|
28232
|
-
"<target>",
|
|
28233
|
-
"The agent to remove from: claude | antigravity | copilot | gemini | cursor | codex | windsurf | vscode | hud"
|
|
28234
|
-
).action((target) => {
|
|
28235
|
-
let fn;
|
|
28236
|
-
if (target === "claude") fn = teardownClaude;
|
|
28237
|
-
else if (target === "gemini") fn = teardownGemini;
|
|
28238
|
-
else if (target === "antigravity" || target === "agy") fn = teardownAntigravity;
|
|
28239
|
-
else if (target === "copilot") fn = teardownCopilot;
|
|
28240
|
-
else if (target === "cursor") fn = teardownCursor;
|
|
28241
|
-
else if (target === "codex") fn = teardownCodex;
|
|
28242
|
-
else if (target === "windsurf") fn = teardownWindsurf;
|
|
28243
|
-
else if (target === "vscode") fn = teardownVSCode;
|
|
28244
|
-
else if (target === "hermes") fn = teardownHermes;
|
|
28245
|
-
else if (target === "hud") fn = teardownHud;
|
|
28246
|
-
else {
|
|
28440
|
+
program.command("removefrom", { hidden: true }).description("Remove Node9 hooks from an AI agent configuration").addHelpText("after", `
|
|
28441
|
+
Supported targets: ${agentTeardownTargets().join(" ")}`).argument("<target>", `The agent to remove from: ${agentTeardownTargets().join(" | ")}`).action((target) => {
|
|
28442
|
+
const agent = resolveAgentTeardown(target);
|
|
28443
|
+
if (!agent) {
|
|
28247
28444
|
console.error(
|
|
28248
|
-
import_chalk36.default.red(
|
|
28249
|
-
`Unknown target: "${target}". Supported: claude, antigravity, copilot, gemini, cursor, codex, windsurf, vscode, hermes, hud`
|
|
28250
|
-
)
|
|
28445
|
+
import_chalk36.default.red(`Unknown target: "${target}". Supported: ${agentTeardownTargets().join(", ")}`)
|
|
28251
28446
|
);
|
|
28252
28447
|
process.exit(1);
|
|
28448
|
+
return;
|
|
28253
28449
|
}
|
|
28254
28450
|
console.log(import_chalk36.default.cyan(`
|
|
28255
|
-
\u{1F6E1}\uFE0F Node9: removing hooks from ${
|
|
28451
|
+
\u{1F6E1}\uFE0F Node9: removing hooks from ${agent.label}...
|
|
28256
28452
|
`));
|
|
28257
28453
|
try {
|
|
28258
|
-
fn();
|
|
28454
|
+
agent.fn();
|
|
28259
28455
|
} catch (err2) {
|
|
28260
28456
|
console.error(import_chalk36.default.red(` \u26A0\uFE0F Failed: ${err2 instanceof Error ? err2.message : String(err2)}`));
|
|
28261
28457
|
process.exit(1);
|
|
@@ -28273,15 +28469,7 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
28273
28469
|
}
|
|
28274
28470
|
console.log(import_chalk36.default.bold("\nRemoving hooks..."));
|
|
28275
28471
|
let teardownFailed = false;
|
|
28276
|
-
for (const
|
|
28277
|
-
["Claude", teardownClaude],
|
|
28278
|
-
["Gemini", teardownGemini],
|
|
28279
|
-
["Cursor", teardownCursor],
|
|
28280
|
-
["Codex", teardownCodex],
|
|
28281
|
-
["Windsurf", teardownWindsurf],
|
|
28282
|
-
["VSCode", teardownVSCode],
|
|
28283
|
-
["Hermes", teardownHermes]
|
|
28284
|
-
]) {
|
|
28472
|
+
for (const { label: label2, fn } of AGENT_TEARDOWNS) {
|
|
28285
28473
|
try {
|
|
28286
28474
|
fn();
|
|
28287
28475
|
} catch (err2) {
|
|
@@ -28293,8 +28481,21 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
28293
28481
|
);
|
|
28294
28482
|
}
|
|
28295
28483
|
}
|
|
28484
|
+
try {
|
|
28485
|
+
const residual = getAgentWiring().filter((a) => a.wireState === "wired");
|
|
28486
|
+
if (residual.length === 0) {
|
|
28487
|
+
console.log(import_chalk36.default.green(" \u2705 Verified \u2014 no node9 hooks or plugin shims remain"));
|
|
28488
|
+
} else {
|
|
28489
|
+
teardownFailed = true;
|
|
28490
|
+
console.error(import_chalk36.default.red(" \u26A0\uFE0F Still wired after teardown:"));
|
|
28491
|
+
for (const a of residual) {
|
|
28492
|
+
console.error(import_chalk36.default.red(` \u2022 ${a.label} \u2014 ${a.settingsPath}`));
|
|
28493
|
+
}
|
|
28494
|
+
}
|
|
28495
|
+
} catch {
|
|
28496
|
+
}
|
|
28296
28497
|
if (options.purge) {
|
|
28297
|
-
const node9Dir =
|
|
28498
|
+
const node9Dir = import_path64.default.join(import_os57.default.homedir(), ".node9");
|
|
28298
28499
|
if (import_fs66.default.existsSync(node9Dir)) {
|
|
28299
28500
|
const confirmed = await (0, import_prompts2.confirm)({
|
|
28300
28501
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
@@ -28425,7 +28626,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
|
|
|
28425
28626
|
});
|
|
28426
28627
|
program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
|
|
28427
28628
|
try {
|
|
28428
|
-
const dashboardPath =
|
|
28629
|
+
const dashboardPath = import_path64.default.join(__dirname, "dashboard.mjs");
|
|
28429
28630
|
const dynamicImport = new Function("id", "return import(id)");
|
|
28430
28631
|
const mod = await dynamicImport(`file://${dashboardPath}`);
|
|
28431
28632
|
await mod.startMonitor();
|
|
@@ -28463,9 +28664,9 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
|
|
|
28463
28664
|
Run "node9 addto claude" to register it as the statusLine.`
|
|
28464
28665
|
).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
|
|
28465
28666
|
if (subcommand === "debug") {
|
|
28466
|
-
const flagFile =
|
|
28667
|
+
const flagFile = import_path64.default.join(import_os57.default.homedir(), ".node9", "hud-debug");
|
|
28467
28668
|
if (state === "on") {
|
|
28468
|
-
import_fs66.default.mkdirSync(
|
|
28669
|
+
import_fs66.default.mkdirSync(import_path64.default.dirname(flagFile), { recursive: true });
|
|
28469
28670
|
import_fs66.default.writeFileSync(flagFile, "");
|
|
28470
28671
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
28471
28672
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
@@ -28592,7 +28793,7 @@ if (process.argv[2] !== "daemon") {
|
|
|
28592
28793
|
const isCheckHook = process.argv[2] === "check";
|
|
28593
28794
|
if (isCheckHook) {
|
|
28594
28795
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
28595
|
-
const logPath =
|
|
28796
|
+
const logPath = import_path64.default.join(import_os57.default.homedir(), ".node9", "hook-debug.log");
|
|
28596
28797
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
28597
28798
|
import_fs66.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
28598
28799
|
`);
|