@node9/proxy 1.45.0 → 1.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -240,8 +240,8 @@ function sanitizeConfig(raw) {
240
240
  }
241
241
  }
242
242
  const lines = result.error.issues.map((issue) => {
243
- const path64 = issue.path.length > 0 ? issue.path.join(".") : "root";
244
- return ` \u2022 ${path64}: ${issue.message}`;
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,
@@ -1357,9 +1357,9 @@ function matchesPattern(text, patterns) {
1357
1357
  const withoutDotSlash = text.replace(/^\.\//, "");
1358
1358
  return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
1359
1359
  }
1360
- function getNestedValue(obj, path64) {
1360
+ function getNestedValue(obj, path65) {
1361
1361
  if (!obj || typeof obj !== "object") return null;
1362
- const segments = path64.split(".");
1362
+ const segments = path65.split(".");
1363
1363
  for (const seg of segments) {
1364
1364
  if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
1365
1365
  }
@@ -1412,6 +1412,14 @@ function evaluateSmartConditions(args, rule) {
1412
1412
  });
1413
1413
  return mode === "any" ? results.some((r) => r) : results.every((r) => r);
1414
1414
  }
1415
+ function resolvePinned(matches) {
1416
+ if (matches.length === 0) return void 0;
1417
+ const pinned = matches.filter((r) => r.pinned);
1418
+ if (pinned.length === 0) return matches[0];
1419
+ return pinned.reduce(
1420
+ (best, r) => VERDICT_RANK[r.verdict] > VERDICT_RANK[best.verdict] ? r : best
1421
+ );
1422
+ }
1415
1423
  function tokenize2(toolName) {
1416
1424
  return toolName.toLowerCase().split(/[_.\-\s]+/).filter(Boolean);
1417
1425
  }
@@ -1523,9 +1531,10 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
1523
1531
  }
1524
1532
  }
1525
1533
  if (config.policy.smartRules.length > 0) {
1526
- const matchedRule = config.policy.smartRules.find(
1534
+ const matches = config.policy.smartRules.filter(
1527
1535
  (rule) => matchesPattern(toolName, rule.tool) && !(bashCommand !== null && rule.name && AST_FS_REGEX_RULES.has(rule.name)) && evaluateSmartConditions(args, rule)
1528
1536
  );
1537
+ const matchedRule = resolvePinned(matches);
1529
1538
  if (matchedRule) {
1530
1539
  if (matchedRule.verdict === "allow")
1531
1540
  return { decision: "allow", ruleName: matchedRule.name ?? matchedRule.tool };
@@ -2264,7 +2273,7 @@ function* stringValues(obj, depth = 0) {
2264
2273
  }
2265
2274
  for (const v of Object.values(obj)) yield* stringValues(v, depth + 1);
2266
2275
  }
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;
2276
+ 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
2277
  var init_dist = __esm({
2269
2278
  "packages/policy-engine/dist/index.mjs"() {
2270
2279
  "use strict";
@@ -3195,6 +3204,11 @@ var init_dist = __esm({
3195
3204
  REGEX_CACHE_MAX = 500;
3196
3205
  regexCache = /* @__PURE__ */ new Map();
3197
3206
  FORBIDDEN_PATH_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
3207
+ VERDICT_RANK = {
3208
+ allow: 0,
3209
+ review: 1,
3210
+ block: 2
3211
+ };
3198
3212
  SQL_DML_KEYWORDS = /* @__PURE__ */ new Set(["select", "insert", "update", "delete", "merge", "upsert"]);
3199
3213
  aws_default = {
3200
3214
  name: "aws",
@@ -3999,6 +4013,7 @@ var init_dist = __esm({
3999
4013
  DEDUPE_PREVIEW_LEN = 120;
4000
4014
  TERMINAL_ESCAPE_RE = // eslint-disable-next-line no-control-regex
4001
4015
  /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
4016
+ ENGINE_VERSION = "1.4.0";
4002
4017
  }
4003
4018
  });
4004
4019
 
@@ -9725,13 +9740,234 @@ var init_setup = __esm({
9725
9740
  }
9726
9741
  });
9727
9742
 
9743
+ // src/agent-wiring.ts
9744
+ function readJson2(filePath) {
9745
+ if (!import_fs14.default.existsSync(filePath)) return null;
9746
+ try {
9747
+ return JSON.parse(import_fs14.default.readFileSync(filePath, "utf-8"));
9748
+ } catch {
9749
+ return "invalid";
9750
+ }
9751
+ }
9752
+ function matchersHaveNode9Hook(matchers) {
9753
+ return (matchers ?? []).some((m) => (m.hooks ?? []).some((h) => isNode9Hook(h.command)));
9754
+ }
9755
+ function flatHaveNode9Hook(entries) {
9756
+ return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
9757
+ }
9758
+ function readHookRoot(filePath, format) {
9759
+ if (!import_fs14.default.existsSync(filePath)) return "absent";
9760
+ let raw;
9761
+ try {
9762
+ raw = import_fs14.default.readFileSync(filePath, "utf-8");
9763
+ } catch {
9764
+ return "absent";
9765
+ }
9766
+ try {
9767
+ const parsed = format === "yaml" ? yaml2.parse(raw) : JSON.parse(raw);
9768
+ return parsed?.hooks ?? {};
9769
+ } catch {
9770
+ return "invalid";
9771
+ }
9772
+ }
9773
+ function eventWired(root, ev, format) {
9774
+ const arr = root[ev.key];
9775
+ if (format === "matcher") return matchersHaveNode9Hook(arr);
9776
+ return flatHaveNode9Hook(arr);
9777
+ }
9778
+ function detectMcp(servers) {
9779
+ const entries = Object.entries(servers ?? {});
9780
+ const present = entries.some(([, s]) => s?.command === "node9");
9781
+ const wrapped = entries.filter(([, s]) => s?.command === "node9" && Array.isArray(s.args) && s.args.length > 0).map(([name, s]) => `${name} \u2192 ${s.args.join(" ")}`);
9782
+ return { wrapped, present };
9783
+ }
9784
+ function readMcp(filePath, format) {
9785
+ if (!import_fs14.default.existsSync(filePath)) return { wrapped: [], present: false };
9786
+ try {
9787
+ if (format === "toml") {
9788
+ const parsed2 = (0, import_smol_toml2.parse)(import_fs14.default.readFileSync(filePath, "utf-8"));
9789
+ return detectMcp(parsed2?.mcp_servers);
9790
+ }
9791
+ const parsed = readJson2(filePath);
9792
+ if (parsed === null || parsed === "invalid") return { wrapped: [], present: false };
9793
+ return detectMcp(parsed.mcpServers);
9794
+ } catch {
9795
+ return { wrapped: [], present: false };
9796
+ }
9797
+ }
9798
+ function getAgentWiring(home = import_os13.default.homedir()) {
9799
+ const detected = detectAgents(home);
9800
+ return AGENT_SPECS.map((spec) => {
9801
+ const present = spec.present(home);
9802
+ const pad = spec.labelPad ?? DEFAULT_LABEL_PAD;
9803
+ let hooks;
9804
+ let wireState;
9805
+ let hookLabel;
9806
+ let settingsPath;
9807
+ if (spec.shimFile) {
9808
+ const shimWired = exists(spec.shimFile(home));
9809
+ hooks = [{ label: "node9 plugin (node9 check)", wired: shimWired }];
9810
+ wireState = shimWired ? "wired" : present ? "unwired" : "absent";
9811
+ hookLabel = "node9 plugin";
9812
+ settingsPath = spec.shimFile(home);
9813
+ } else {
9814
+ const root = spec.hookFile ? readHookRoot(spec.hookFile(home), spec.hookFormat) : "absent";
9815
+ const primary = spec.hookEvents[0];
9816
+ const rootPresent = root !== "absent" && root !== "invalid";
9817
+ hooks = spec.hookEvents.map((ev) => ({
9818
+ label: hookLabelOf(ev, pad),
9819
+ wired: rootPresent && eventWired(root, ev, spec.hookFormat)
9820
+ }));
9821
+ if (root === "absent") wireState = "absent";
9822
+ else if (root === "invalid") wireState = "invalid";
9823
+ else wireState = primary && eventWired(root, primary, spec.hookFormat) ? "wired" : "unwired";
9824
+ hookLabel = primary ? `${primary.key} hook` : "MCP proxy";
9825
+ settingsPath = spec.hookFile ? spec.hookFile(home) : spec.mcpFile ? spec.mcpFile(home) : "";
9826
+ }
9827
+ const mcp = spec.mcpFile ? readMcp(spec.mcpFile(home), spec.mcpFormat ?? "json") : null;
9828
+ const anyHookWired = hooks.some((h) => h.wired);
9829
+ return {
9830
+ id: spec.id,
9831
+ label: spec.label,
9832
+ setupCommand: spec.setupCommand,
9833
+ installed: detected[spec.id],
9834
+ present,
9835
+ hooks,
9836
+ wireState,
9837
+ hookLabel,
9838
+ settingsPath,
9839
+ configFormat: spec.hookFormat === "yaml" ? "YAML" : "JSON",
9840
+ mcpServers: mcp ? mcp.wrapped : null,
9841
+ mcpProtected: mcp ? mcp.present : false,
9842
+ isProtected: anyHookWired || (mcp?.present ?? false)
9843
+ };
9844
+ });
9845
+ }
9846
+ var import_fs14, import_path16, import_os13, yaml2, import_smol_toml2, exists, ck, lg, DEFAULT_LABEL_PAD, hookLabelOf, AGENT_SPECS;
9847
+ var init_agent_wiring = __esm({
9848
+ "src/agent-wiring.ts"() {
9849
+ "use strict";
9850
+ import_fs14 = __toESM(require("fs"));
9851
+ import_path16 = __toESM(require("path"));
9852
+ import_os13 = __toESM(require("os"));
9853
+ yaml2 = __toESM(require("yaml"));
9854
+ import_smol_toml2 = require("smol-toml");
9855
+ init_setup();
9856
+ exists = (p) => {
9857
+ try {
9858
+ return import_fs14.default.existsSync(p);
9859
+ } catch {
9860
+ return false;
9861
+ }
9862
+ };
9863
+ ck = (key) => ({ key, kind: "check" });
9864
+ lg = (key) => ({ key, kind: "log" });
9865
+ DEFAULT_LABEL_PAD = 11;
9866
+ hookLabelOf = (ev, pad) => `${ev.key.padEnd(pad)} (node9 ${ev.kind})`;
9867
+ AGENT_SPECS = [
9868
+ {
9869
+ id: "claude",
9870
+ label: "Claude Code",
9871
+ setupCommand: "node9 agents add claude",
9872
+ hookFile: (h) => import_path16.default.join(h, ".claude", "settings.json"),
9873
+ hookFormat: "matcher",
9874
+ hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
9875
+ mcpFile: (h) => import_path16.default.join(h, ".claude.json"),
9876
+ present: (h) => exists(import_path16.default.join(h, ".claude", "settings.json")) || exists(import_path16.default.join(h, ".claude.json"))
9877
+ },
9878
+ {
9879
+ id: "gemini",
9880
+ label: "Gemini CLI",
9881
+ setupCommand: "node9 agents add gemini",
9882
+ hookFile: (h) => import_path16.default.join(h, ".gemini", "settings.json"),
9883
+ hookFormat: "matcher",
9884
+ hookEvents: [ck("BeforeTool"), lg("AfterTool")],
9885
+ mcpFile: (h) => import_path16.default.join(h, ".gemini", "settings.json"),
9886
+ present: (h) => exists(import_path16.default.join(h, ".gemini", "settings.json"))
9887
+ },
9888
+ {
9889
+ id: "codex",
9890
+ label: "Codex",
9891
+ setupCommand: "node9 agents add codex",
9892
+ hookFile: (h) => import_path16.default.join(h, ".codex", "hooks.json"),
9893
+ hookFormat: "matcher",
9894
+ hookEvents: [ck("PreToolUse"), ck("UserPromptSubmit")],
9895
+ mcpFile: (h) => import_path16.default.join(h, ".codex", "config.toml"),
9896
+ mcpFormat: "toml",
9897
+ present: (h) => exists(import_path16.default.join(h, ".codex"))
9898
+ },
9899
+ {
9900
+ id: "antigravity",
9901
+ label: "Antigravity",
9902
+ setupCommand: "node9 agents add antigravity",
9903
+ hookFile: (h) => import_path16.default.join(h, ".gemini", "config", "hooks.json"),
9904
+ hookFormat: "matcher",
9905
+ hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
9906
+ mcpFile: (h) => import_path16.default.join(h, ".gemini", "config", "mcp_config.json"),
9907
+ 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"))
9908
+ },
9909
+ {
9910
+ id: "copilot",
9911
+ label: "GitHub Copilot",
9912
+ setupCommand: "node9 agents add copilot",
9913
+ hookFile: (h) => import_path16.default.join(h, ".copilot", "hooks", "node9.json"),
9914
+ hookFormat: "flat",
9915
+ hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
9916
+ mcpFile: (h) => import_path16.default.join(h, ".copilot", "mcp-config.json"),
9917
+ present: (h) => exists(import_path16.default.join(h, ".copilot"))
9918
+ },
9919
+ {
9920
+ id: "cursor",
9921
+ label: "Cursor",
9922
+ setupCommand: "node9 agents add cursor",
9923
+ // MCP-only — no hook file (see note above).
9924
+ hookFormat: "flat",
9925
+ hookEvents: [],
9926
+ mcpFile: (h) => import_path16.default.join(h, ".cursor", "mcp.json"),
9927
+ present: (h) => exists(import_path16.default.join(h, ".cursor", "mcp.json"))
9928
+ },
9929
+ {
9930
+ id: "hermes",
9931
+ label: "Hermes Agent",
9932
+ setupCommand: "node9 agents add hermes",
9933
+ hookFile: (h) => hermesConfigPath(h),
9934
+ hookFormat: "yaml",
9935
+ hookEvents: [ck("pre_tool_call"), lg("post_tool_call")],
9936
+ labelPad: 14,
9937
+ // 'post_tool_call' is wider than the default
9938
+ present: (h) => exists(hermesConfigPath(h))
9939
+ },
9940
+ {
9941
+ // Plugin-shim agents — protected by a node9-authored plugin/extension file
9942
+ // (no hooks, no MCP). hookFormat is unused for these (shimFile drives it).
9943
+ id: "opencode",
9944
+ label: "OpenCode",
9945
+ setupCommand: "node9 agents add opencode",
9946
+ hookFormat: "flat",
9947
+ hookEvents: [],
9948
+ shimFile: (h) => import_path16.default.join(h, ".config", "opencode", "plugins", "node9.js"),
9949
+ present: (h) => exists(import_path16.default.join(h, ".config", "opencode")) || exists(import_path16.default.join(h, ".config", "opencode", "plugins", "node9.js"))
9950
+ },
9951
+ {
9952
+ id: "pi",
9953
+ label: "Pi",
9954
+ setupCommand: "node9 agents add pi",
9955
+ hookFormat: "flat",
9956
+ hookEvents: [],
9957
+ shimFile: (h) => import_path16.default.join(h, ".pi", "agent", "extensions", "node9.js"),
9958
+ present: (h) => exists(import_path16.default.join(h, ".pi", "agent")) || exists(import_path16.default.join(h, ".pi", "agent", "extensions", "node9.js"))
9959
+ }
9960
+ ];
9961
+ }
9962
+ });
9963
+
9728
9964
  // src/pricing/litellm.ts
9729
9965
  function normalizeModel(raw) {
9730
9966
  return raw.replace(/-\d{8}$/, "").toLowerCase();
9731
9967
  }
9732
9968
  function readCache() {
9733
9969
  try {
9734
- const raw = JSON.parse(import_fs14.default.readFileSync(CACHE_FILE(), "utf-8"));
9970
+ const raw = JSON.parse(import_fs15.default.readFileSync(CACHE_FILE(), "utf-8"));
9735
9971
  if (typeof raw.fetchedAt !== "string" || typeof raw.prices !== "object" || raw.prices === null) {
9736
9972
  return null;
9737
9973
  }
@@ -9745,18 +9981,18 @@ function readCache() {
9745
9981
  function writeCache(prices) {
9746
9982
  try {
9747
9983
  const target = CACHE_FILE();
9748
- const dir = import_path16.default.dirname(target);
9749
- if (!import_fs14.default.existsSync(dir)) import_fs14.default.mkdirSync(dir, { recursive: true });
9984
+ const dir = import_path17.default.dirname(target);
9985
+ if (!import_fs15.default.existsSync(dir)) import_fs15.default.mkdirSync(dir, { recursive: true });
9750
9986
  const tmp = target + ".tmp";
9751
9987
  const body = {
9752
9988
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
9753
9989
  prices
9754
9990
  };
9755
- import_fs14.default.writeFileSync(tmp, JSON.stringify(body) + "\n", "utf-8");
9756
- import_fs14.default.renameSync(tmp, target);
9991
+ import_fs15.default.writeFileSync(tmp, JSON.stringify(body) + "\n", "utf-8");
9992
+ import_fs15.default.renameSync(tmp, target);
9757
9993
  } catch (err2) {
9758
9994
  try {
9759
- import_fs14.default.appendFileSync(
9995
+ import_fs15.default.appendFileSync(
9760
9996
  HOOK_DEBUG_LOG,
9761
9997
  `[pricing] cache write failed: ${err2.message}
9762
9998
  `
@@ -9857,13 +10093,13 @@ function pricingFor(model) {
9857
10093
  lookupCache.set(norm, resolved);
9858
10094
  return resolved;
9859
10095
  }
9860
- var import_fs14, import_path16, import_os13, LITELLM_URL, BUNDLED_PRICING, CACHE_FILE, TTL_MS, memCache, memCacheAt, diskChecked, lookupCache;
10096
+ var import_fs15, import_path17, import_os14, LITELLM_URL, BUNDLED_PRICING, CACHE_FILE, TTL_MS, memCache, memCacheAt, diskChecked, lookupCache;
9861
10097
  var init_litellm = __esm({
9862
10098
  "src/pricing/litellm.ts"() {
9863
10099
  "use strict";
9864
- import_fs14 = __toESM(require("fs"));
9865
- import_path16 = __toESM(require("path"));
9866
- import_os13 = __toESM(require("os"));
10100
+ import_fs15 = __toESM(require("fs"));
10101
+ import_path17 = __toESM(require("path"));
10102
+ import_os14 = __toESM(require("os"));
9867
10103
  init_audit();
9868
10104
  LITELLM_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json";
9869
10105
  BUNDLED_PRICING = {
@@ -9903,7 +10139,7 @@ var init_litellm = __esm({
9903
10139
  "gemini-2.0-flash": [75e-9, 3e-7, 0, 0],
9904
10140
  "gemini-1.5-pro": [125e-8, 5e-6, 0, 0]
9905
10141
  };
9906
- CACHE_FILE = () => import_path16.default.join(import_os13.default.homedir(), ".node9", "model-pricing.json");
10142
+ CACHE_FILE = () => import_path17.default.join(import_os14.default.homedir(), ".node9", "model-pricing.json");
9907
10143
  TTL_MS = 24 * 60 * 60 * 1e3;
9908
10144
  memCache = null;
9909
10145
  memCacheAt = 0;
@@ -9914,7 +10150,7 @@ var init_litellm = __esm({
9914
10150
 
9915
10151
  // src/cost-gemini.ts
9916
10152
  function geminiTmpDir() {
9917
- return import_path17.default.join(import_os14.default.homedir(), ".gemini", "tmp");
10153
+ return import_path18.default.join(import_os15.default.homedir(), ".gemini", "tmp");
9918
10154
  }
9919
10155
  function geminiPriceFor(model) {
9920
10156
  let tuple = pricingFor(model);
@@ -9929,14 +10165,14 @@ function geminiPriceFor(model) {
9929
10165
  }
9930
10166
  function safeReaddir(dir) {
9931
10167
  try {
9932
- return import_fs15.default.readdirSync(dir);
10168
+ return import_fs16.default.readdirSync(dir);
9933
10169
  } catch {
9934
10170
  return [];
9935
10171
  }
9936
10172
  }
9937
10173
  function isDir(p) {
9938
10174
  try {
9939
- return import_fs15.default.statSync(p).isDirectory();
10175
+ return import_fs16.default.statSync(p).isDirectory();
9940
10176
  } catch {
9941
10177
  return false;
9942
10178
  }
@@ -9944,11 +10180,11 @@ function isDir(p) {
9944
10180
  function listGeminiSessionFiles(base) {
9945
10181
  const out = [];
9946
10182
  for (const project of safeReaddir(base)) {
9947
- const chats = import_path17.default.join(base, project, "chats");
10183
+ const chats = import_path18.default.join(base, project, "chats");
9948
10184
  if (!isDir(chats)) continue;
9949
10185
  for (const f of safeReaddir(chats)) {
9950
10186
  if (f.startsWith("session-") && f.endsWith(".jsonl")) {
9951
- out.push({ file: import_path17.default.join(chats, f), project });
10187
+ out.push({ file: import_path18.default.join(chats, f), project });
9952
10188
  }
9953
10189
  }
9954
10190
  }
@@ -10005,20 +10241,20 @@ function parseGeminiSession(lines, project) {
10005
10241
  if (runId) for (const e of byKey.values()) e.runId = runId;
10006
10242
  return [...byKey.values()];
10007
10243
  }
10008
- var import_fs15, import_os14, import_path17, GEMINI_FALLBACK_MODELS, geminiSource;
10244
+ var import_fs16, import_os15, import_path18, GEMINI_FALLBACK_MODELS, geminiSource;
10009
10245
  var init_cost_gemini = __esm({
10010
10246
  "src/cost-gemini.ts"() {
10011
10247
  "use strict";
10012
- import_fs15 = __toESM(require("fs"));
10013
- import_os14 = __toESM(require("os"));
10014
- import_path17 = __toESM(require("path"));
10248
+ import_fs16 = __toESM(require("fs"));
10249
+ import_os15 = __toESM(require("os"));
10250
+ import_path18 = __toESM(require("path"));
10015
10251
  init_litellm();
10016
10252
  GEMINI_FALLBACK_MODELS = ["gemini-2.5-flash", "gemini-2.0-flash"];
10017
10253
  geminiSource = {
10018
10254
  id: "gemini",
10019
10255
  available() {
10020
10256
  try {
10021
- return import_fs15.default.existsSync(geminiTmpDir());
10257
+ return import_fs16.default.existsSync(geminiTmpDir());
10022
10258
  } catch {
10023
10259
  return false;
10024
10260
  }
@@ -10027,13 +10263,13 @@ var init_cost_gemini = __esm({
10027
10263
  const combined = /* @__PURE__ */ new Map();
10028
10264
  for (const { file, project } of listGeminiSessionFiles(geminiTmpDir())) {
10029
10265
  try {
10030
- if (sinceMs !== void 0 && import_fs15.default.statSync(file).mtimeMs < sinceMs) continue;
10266
+ if (sinceMs !== void 0 && import_fs16.default.statSync(file).mtimeMs < sinceMs) continue;
10031
10267
  } catch {
10032
10268
  continue;
10033
10269
  }
10034
10270
  let content;
10035
10271
  try {
10036
- content = import_fs15.default.readFileSync(file, "utf8");
10272
+ content = import_fs16.default.readFileSync(file, "utf8");
10037
10273
  } catch {
10038
10274
  continue;
10039
10275
  }
@@ -10059,7 +10295,7 @@ var init_cost_gemini = __esm({
10059
10295
 
10060
10296
  // src/cost-codex.ts
10061
10297
  function codexSessionsDir() {
10062
- return import_path18.default.join(import_os15.default.homedir(), ".codex", "sessions");
10298
+ return import_path19.default.join(import_os16.default.homedir(), ".codex", "sessions");
10063
10299
  }
10064
10300
  function codexPriceFor(model) {
10065
10301
  return pricingFor(model) ?? CODEX_FALLBACK;
@@ -10072,16 +10308,16 @@ function codexSessionCost(model, tokens) {
10072
10308
  function listCodexSessionFiles(base) {
10073
10309
  const out = [];
10074
10310
  for (const y of safeReaddir2(base)) {
10075
- const yp = import_path18.default.join(base, y);
10311
+ const yp = import_path19.default.join(base, y);
10076
10312
  if (!isDir2(yp)) continue;
10077
10313
  for (const m of safeReaddir2(yp)) {
10078
- const mp = import_path18.default.join(yp, m);
10314
+ const mp = import_path19.default.join(yp, m);
10079
10315
  if (!isDir2(mp)) continue;
10080
10316
  for (const d of safeReaddir2(mp)) {
10081
- const dp = import_path18.default.join(mp, d);
10317
+ const dp = import_path19.default.join(mp, d);
10082
10318
  if (!isDir2(dp)) continue;
10083
10319
  for (const f of safeReaddir2(dp)) {
10084
- if (f.endsWith(".jsonl")) out.push(import_path18.default.join(dp, f));
10320
+ if (f.endsWith(".jsonl")) out.push(import_path19.default.join(dp, f));
10085
10321
  }
10086
10322
  }
10087
10323
  }
@@ -10090,14 +10326,14 @@ function listCodexSessionFiles(base) {
10090
10326
  }
10091
10327
  function safeReaddir2(dir) {
10092
10328
  try {
10093
- return import_fs16.default.readdirSync(dir);
10329
+ return import_fs17.default.readdirSync(dir);
10094
10330
  } catch {
10095
10331
  return [];
10096
10332
  }
10097
10333
  }
10098
10334
  function isDir2(p) {
10099
10335
  try {
10100
- return import_fs16.default.statSync(p).isDirectory();
10336
+ return import_fs17.default.statSync(p).isDirectory();
10101
10337
  } catch {
10102
10338
  return false;
10103
10339
  }
@@ -10157,20 +10393,20 @@ function parseCodexSession(lines) {
10157
10393
  cacheWriteTokens: 0
10158
10394
  };
10159
10395
  }
10160
- var import_fs16, import_os15, import_path18, CODEX_FALLBACK, codexSource;
10396
+ var import_fs17, import_os16, import_path19, CODEX_FALLBACK, codexSource;
10161
10397
  var init_cost_codex = __esm({
10162
10398
  "src/cost-codex.ts"() {
10163
10399
  "use strict";
10164
- import_fs16 = __toESM(require("fs"));
10165
- import_os15 = __toESM(require("os"));
10166
- import_path18 = __toESM(require("path"));
10400
+ import_fs17 = __toESM(require("fs"));
10401
+ import_os16 = __toESM(require("os"));
10402
+ import_path19 = __toESM(require("path"));
10167
10403
  init_litellm();
10168
10404
  CODEX_FALLBACK = [5e-6, 15e-6, 0, 25e-7];
10169
10405
  codexSource = {
10170
10406
  id: "codex",
10171
10407
  available() {
10172
10408
  try {
10173
- return import_fs16.default.existsSync(codexSessionsDir());
10409
+ return import_fs17.default.existsSync(codexSessionsDir());
10174
10410
  } catch {
10175
10411
  return false;
10176
10412
  }
@@ -10180,13 +10416,13 @@ var init_cost_codex = __esm({
10180
10416
  const combined = /* @__PURE__ */ new Map();
10181
10417
  for (const file of listCodexSessionFiles(base)) {
10182
10418
  try {
10183
- if (sinceMs !== void 0 && import_fs16.default.statSync(file).mtimeMs < sinceMs) continue;
10419
+ if (sinceMs !== void 0 && import_fs17.default.statSync(file).mtimeMs < sinceMs) continue;
10184
10420
  } catch {
10185
10421
  continue;
10186
10422
  }
10187
10423
  let content;
10188
10424
  try {
10189
- content = import_fs16.default.readFileSync(file, "utf8");
10425
+ content = import_fs17.default.readFileSync(file, "utf8");
10190
10426
  } catch {
10191
10427
  continue;
10192
10428
  }
@@ -10494,79 +10730,79 @@ var init_scan_summary = __esm({
10494
10730
  function buildSensitivePaths(home, cwd) {
10495
10731
  return [
10496
10732
  {
10497
- full: import_path19.default.join(home, ".ssh", "id_rsa"),
10733
+ full: import_path20.default.join(home, ".ssh", "id_rsa"),
10498
10734
  label: "~/.ssh/id_rsa",
10499
10735
  description: "RSA private key \u2014 grants SSH access to your servers",
10500
10736
  score: 20
10501
10737
  },
10502
10738
  {
10503
- full: import_path19.default.join(home, ".ssh", "id_ed25519"),
10739
+ full: import_path20.default.join(home, ".ssh", "id_ed25519"),
10504
10740
  label: "~/.ssh/id_ed25519",
10505
10741
  description: "Ed25519 private key \u2014 grants SSH access to your servers",
10506
10742
  score: 20
10507
10743
  },
10508
10744
  {
10509
- full: import_path19.default.join(home, ".ssh", "id_ecdsa"),
10745
+ full: import_path20.default.join(home, ".ssh", "id_ecdsa"),
10510
10746
  label: "~/.ssh/id_ecdsa",
10511
10747
  description: "ECDSA private key \u2014 grants SSH access to your servers",
10512
10748
  score: 20
10513
10749
  },
10514
10750
  {
10515
- full: import_path19.default.join(home, ".aws", "credentials"),
10751
+ full: import_path20.default.join(home, ".aws", "credentials"),
10516
10752
  label: "~/.aws/credentials",
10517
10753
  description: "AWS access keys \u2014 full cloud account access",
10518
10754
  score: 20
10519
10755
  },
10520
10756
  {
10521
- full: import_path19.default.join(home, ".aws", "config"),
10757
+ full: import_path20.default.join(home, ".aws", "config"),
10522
10758
  label: "~/.aws/config",
10523
10759
  description: "AWS configuration \u2014 account and region settings",
10524
10760
  score: 5
10525
10761
  },
10526
10762
  {
10527
- full: import_path19.default.join(home, ".config", "gcloud", "credentials.db"),
10763
+ full: import_path20.default.join(home, ".config", "gcloud", "credentials.db"),
10528
10764
  label: "~/.config/gcloud/credentials.db",
10529
10765
  description: "Google Cloud credentials",
10530
10766
  score: 15
10531
10767
  },
10532
10768
  {
10533
- full: import_path19.default.join(home, ".docker", "config.json"),
10769
+ full: import_path20.default.join(home, ".docker", "config.json"),
10534
10770
  label: "~/.docker/config.json",
10535
10771
  description: "Docker registry auth tokens",
10536
10772
  score: 10
10537
10773
  },
10538
10774
  {
10539
- full: import_path19.default.join(home, ".netrc"),
10775
+ full: import_path20.default.join(home, ".netrc"),
10540
10776
  label: "~/.netrc",
10541
10777
  description: "FTP/HTTP credentials in plain text",
10542
10778
  score: 15
10543
10779
  },
10544
10780
  {
10545
- full: import_path19.default.join(home, ".npmrc"),
10781
+ full: import_path20.default.join(home, ".npmrc"),
10546
10782
  label: "~/.npmrc",
10547
10783
  description: "npm auth token \u2014 can publish packages as you",
10548
10784
  score: 10
10549
10785
  },
10550
10786
  {
10551
- full: import_path19.default.join(home, ".node9", "credentials.json"),
10787
+ full: import_path20.default.join(home, ".node9", "credentials.json"),
10552
10788
  label: "~/.node9/credentials.json",
10553
10789
  description: "Node9 cloud API key",
10554
10790
  score: 10
10555
10791
  },
10556
10792
  {
10557
- full: import_path19.default.join(cwd, ".env"),
10793
+ full: import_path20.default.join(cwd, ".env"),
10558
10794
  label: ".env (current folder)",
10559
10795
  description: "App secrets \u2014 database passwords, API keys",
10560
10796
  score: 20
10561
10797
  },
10562
10798
  {
10563
- full: import_path19.default.join(cwd, ".env.local"),
10799
+ full: import_path20.default.join(cwd, ".env.local"),
10564
10800
  label: ".env.local (current folder)",
10565
10801
  description: "Local overrides \u2014 often contains real credentials",
10566
10802
  score: 15
10567
10803
  },
10568
10804
  {
10569
- full: import_path19.default.join(cwd, ".env.production"),
10805
+ full: import_path20.default.join(cwd, ".env.production"),
10570
10806
  label: ".env.production (current folder)",
10571
10807
  description: "Production secrets",
10572
10808
  score: 20
@@ -10575,7 +10811,7 @@ function buildSensitivePaths(home, cwd) {
10575
10811
  }
10576
10812
  function isReadable(filePath) {
10577
10813
  try {
10578
- import_fs17.default.accessSync(filePath, import_fs17.default.constants.R_OK);
10814
+ import_fs18.default.accessSync(filePath, import_fs18.default.constants.R_OK);
10579
10815
  return true;
10580
10816
  } catch {
10581
10817
  return false;
@@ -10588,13 +10824,13 @@ function scoreLabel(score) {
10588
10824
  return import_chalk2.default.red.bold(`${score}/100 Critical`);
10589
10825
  }
10590
10826
  function runBlast() {
10591
- const home = import_os16.default.homedir();
10827
+ const home = import_os17.default.homedir();
10592
10828
  const cwd = process.cwd();
10593
10829
  const paths = buildSensitivePaths(home, cwd);
10594
10830
  let scoreDeduction = 0;
10595
10831
  const reachable = [];
10596
10832
  for (const p of paths) {
10597
- if (import_fs17.default.existsSync(p.full) && isReadable(p.full)) {
10833
+ if (import_fs18.default.existsSync(p.full) && isReadable(p.full)) {
10598
10834
  reachable.push(p);
10599
10835
  scoreDeduction += p.score;
10600
10836
  }
@@ -10612,7 +10848,7 @@ function runBlast() {
10612
10848
  }
10613
10849
  function registerBlastCommand(program2) {
10614
10850
  program2.command("blast").description("Map what an AI agent can currently reach on this machine").action(() => {
10615
- const home = import_os16.default.homedir();
10851
+ const home = import_os17.default.homedir();
10616
10852
  const cwd = process.cwd();
10617
10853
  const { reachable, envFindings, score } = runBlast();
10618
10854
  console.log("");
@@ -10659,14 +10895,14 @@ function registerBlastCommand(program2) {
10659
10895
  console.log("");
10660
10896
  });
10661
10897
  }
10662
- var import_chalk2, import_fs17, import_path19, import_os16;
10898
+ var import_chalk2, import_fs18, import_path20, import_os17;
10663
10899
  var init_blast = __esm({
10664
10900
  "src/cli/commands/blast.ts"() {
10665
10901
  "use strict";
10666
10902
  import_chalk2 = __toESM(require("chalk"));
10667
- import_fs17 = __toESM(require("fs"));
10668
- import_path19 = __toESM(require("path"));
10669
- import_os16 = __toESM(require("os"));
10903
+ import_fs18 = __toESM(require("fs"));
10904
+ import_path20 = __toESM(require("path"));
10905
+ import_os17 = __toESM(require("os"));
10670
10906
  init_dlp();
10671
10907
  }
10672
10908
  });
@@ -10794,13 +11030,13 @@ var init_scan_json = __esm({
10794
11030
 
10795
11031
  // src/cli/render/scan-history.ts
10796
11032
  function defaultHistoryPath() {
10797
- return import_path20.default.join(import_os17.default.homedir(), ".node9", "scan-history.json");
11033
+ return import_path21.default.join(import_os18.default.homedir(), ".node9", "scan-history.json");
10798
11034
  }
10799
11035
  function readPreviousScan(opts = {}) {
10800
11036
  const filePath = opts.path ?? defaultHistoryPath();
10801
11037
  try {
10802
- if (!import_fs18.default.existsSync(filePath)) return null;
10803
- const raw = import_fs18.default.readFileSync(filePath, "utf8");
11038
+ if (!import_fs19.default.existsSync(filePath)) return null;
11039
+ const raw = import_fs19.default.readFileSync(filePath, "utf8");
10804
11040
  const parsed = JSON.parse(raw);
10805
11041
  if (!Array.isArray(parsed) || parsed.length === 0) return null;
10806
11042
  const last = parsed[parsed.length - 1];
@@ -10814,11 +11050,11 @@ function appendScanHistory(record, opts = {}) {
10814
11050
  const filePath = opts.path ?? defaultHistoryPath();
10815
11051
  const cap = opts.cap ?? SCAN_HISTORY_CAP;
10816
11052
  try {
10817
- import_fs18.default.mkdirSync(import_path20.default.dirname(filePath), { recursive: true });
11053
+ import_fs19.default.mkdirSync(import_path21.default.dirname(filePath), { recursive: true });
10818
11054
  let history = [];
10819
- if (import_fs18.default.existsSync(filePath)) {
11055
+ if (import_fs19.default.existsSync(filePath)) {
10820
11056
  try {
10821
- const parsed = JSON.parse(import_fs18.default.readFileSync(filePath, "utf8"));
11057
+ const parsed = JSON.parse(import_fs19.default.readFileSync(filePath, "utf8"));
10822
11058
  if (Array.isArray(parsed)) {
10823
11059
  history = parsed.filter(isValidRecord);
10824
11060
  }
@@ -10829,7 +11065,7 @@ function appendScanHistory(record, opts = {}) {
10829
11065
  if (history.length > cap) {
10830
11066
  history = history.slice(history.length - cap);
10831
11067
  }
10832
- import_fs18.default.writeFileSync(filePath, JSON.stringify(history, null, 2));
11068
+ import_fs19.default.writeFileSync(filePath, JSON.stringify(history, null, 2));
10833
11069
  } catch (err2) {
10834
11070
  process.stderr.write(
10835
11071
  `[node9] Warning: could not write scan-history.json: ${err2.message}
@@ -10851,24 +11087,24 @@ function isValidRecord(x) {
10851
11087
  const r = x;
10852
11088
  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
11089
  }
10854
- var import_fs18, import_path20, import_os17, SCAN_HISTORY_CAP;
11090
+ var import_fs19, import_path21, import_os18, SCAN_HISTORY_CAP;
10855
11091
  var init_scan_history = __esm({
10856
11092
  "src/cli/render/scan-history.ts"() {
10857
11093
  "use strict";
10858
- import_fs18 = __toESM(require("fs"));
10859
- import_path20 = __toESM(require("path"));
10860
- import_os17 = __toESM(require("os"));
11094
+ import_fs19 = __toESM(require("fs"));
11095
+ import_path21 = __toESM(require("path"));
11096
+ import_os18 = __toESM(require("os"));
10861
11097
  SCAN_HISTORY_CAP = 30;
10862
11098
  }
10863
11099
  });
10864
11100
 
10865
11101
  // src/cost-copilot.ts
10866
11102
  function copilotSessionsDir() {
10867
- return import_path21.default.join(import_os18.default.homedir(), ".copilot", "session-state");
11103
+ return import_path22.default.join(import_os19.default.homedir(), ".copilot", "session-state");
10868
11104
  }
10869
11105
  function safeReaddir3(dir) {
10870
11106
  try {
10871
- return import_fs19.default.readdirSync(dir);
11107
+ return import_fs20.default.readdirSync(dir);
10872
11108
  } catch {
10873
11109
  return [];
10874
11110
  }
@@ -10935,19 +11171,19 @@ function parseCopilotSession(lines) {
10935
11171
  }
10936
11172
  return rows;
10937
11173
  }
10938
- var import_fs19, import_os18, import_path21, copilotSource;
11174
+ var import_fs20, import_os19, import_path22, copilotSource;
10939
11175
  var init_cost_copilot = __esm({
10940
11176
  "src/cost-copilot.ts"() {
10941
11177
  "use strict";
10942
- import_fs19 = __toESM(require("fs"));
10943
- import_os18 = __toESM(require("os"));
10944
- import_path21 = __toESM(require("path"));
11178
+ import_fs20 = __toESM(require("fs"));
11179
+ import_os19 = __toESM(require("os"));
11180
+ import_path22 = __toESM(require("path"));
10945
11181
  init_litellm();
10946
11182
  copilotSource = {
10947
11183
  id: "copilot",
10948
11184
  available() {
10949
11185
  try {
10950
- return import_fs19.default.existsSync(copilotSessionsDir());
11186
+ return import_fs20.default.existsSync(copilotSessionsDir());
10951
11187
  } catch {
10952
11188
  return false;
10953
11189
  }
@@ -10956,15 +11192,15 @@ var init_cost_copilot = __esm({
10956
11192
  const base = copilotSessionsDir();
10957
11193
  const combined = /* @__PURE__ */ new Map();
10958
11194
  for (const sid of safeReaddir3(base)) {
10959
- const file = import_path21.default.join(base, sid, "events.jsonl");
11195
+ const file = import_path22.default.join(base, sid, "events.jsonl");
10960
11196
  try {
10961
- if (sinceMs !== void 0 && import_fs19.default.statSync(file).mtimeMs < sinceMs) continue;
11197
+ if (sinceMs !== void 0 && import_fs20.default.statSync(file).mtimeMs < sinceMs) continue;
10962
11198
  } catch {
10963
11199
  continue;
10964
11200
  }
10965
11201
  let content;
10966
11202
  try {
10967
- content = import_fs19.default.readFileSync(file, "utf8");
11203
+ content = import_fs20.default.readFileSync(file, "utf8");
10968
11204
  } catch {
10969
11205
  continue;
10970
11206
  }
@@ -10993,10 +11229,10 @@ function decodeProjectDirName(dirName) {
10993
11229
  return dirName.replace(/-/g, "/");
10994
11230
  }
10995
11231
  function parseJSONLFile(filePath, fallbackWorkingDir) {
10996
- const runId = import_path22.default.basename(filePath, ".jsonl");
11232
+ const runId = import_path23.default.basename(filePath, ".jsonl");
10997
11233
  let content;
10998
11234
  try {
10999
- content = import_fs20.default.readFileSync(filePath, "utf8");
11235
+ content = import_fs21.default.readFileSync(filePath, "utf8");
11000
11236
  } catch {
11001
11237
  return /* @__PURE__ */ new Map();
11002
11238
  }
@@ -11096,7 +11332,7 @@ async function postCostBatches(apiUrl, apiKey, machineId, entries) {
11096
11332
  signal: AbortSignal.timeout(15e3)
11097
11333
  });
11098
11334
  if (!res.ok) {
11099
- import_fs20.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
11335
+ import_fs21.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
11100
11336
  `);
11101
11337
  } else {
11102
11338
  let stored;
@@ -11106,7 +11342,7 @@ async function postCostBatches(apiUrl, apiKey, machineId, entries) {
11106
11342
  } catch {
11107
11343
  }
11108
11344
  if (typeof stored === "number" && stored < batch.length) {
11109
- import_fs20.default.appendFileSync(
11345
+ import_fs21.default.appendFileSync(
11110
11346
  HOOK_DEBUG_LOG,
11111
11347
  `[cost-sync] dropped ${batch.length - stored} of ${batch.length} rows
11112
11348
  `
@@ -11114,7 +11350,7 @@ async function postCostBatches(apiUrl, apiKey, machineId, entries) {
11114
11350
  }
11115
11351
  }
11116
11352
  } catch (err2) {
11117
- import_fs20.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
11353
+ import_fs21.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
11118
11354
  `);
11119
11355
  }
11120
11356
  }
@@ -11127,10 +11363,10 @@ async function syncCost() {
11127
11363
  if (entries.length === 0) return;
11128
11364
  let username = "unknown";
11129
11365
  try {
11130
- username = import_os19.default.userInfo().username;
11366
+ username = import_os20.default.userInfo().username;
11131
11367
  } catch {
11132
11368
  }
11133
- const machineId = `${import_os19.default.hostname()}:${username}`;
11369
+ const machineId = `${import_os20.default.hostname()}:${username}`;
11134
11370
  await postCostBatches(creds.apiUrl, creds.apiKey, machineId, entries);
11135
11371
  }
11136
11372
  function startCostSync() {
@@ -11142,13 +11378,13 @@ function startCostSync() {
11142
11378
  }, SYNC_INTERVAL_MS);
11143
11379
  timer.unref();
11144
11380
  }
11145
- var import_fs20, import_path22, import_os19, SYNC_INTERVAL_MS, claudeSource, COST_SOURCES, COST_BATCH_SIZE;
11381
+ var import_fs21, import_path23, import_os20, SYNC_INTERVAL_MS, claudeSource, COST_SOURCES, COST_BATCH_SIZE;
11146
11382
  var init_costSync = __esm({
11147
11383
  "src/costSync.ts"() {
11148
11384
  "use strict";
11149
- import_fs20 = __toESM(require("fs"));
11150
- import_path22 = __toESM(require("path"));
11151
- import_os19 = __toESM(require("os"));
11385
+ import_fs21 = __toESM(require("fs"));
11386
+ import_path23 = __toESM(require("path"));
11387
+ import_os20 = __toESM(require("os"));
11152
11388
  init_config();
11153
11389
  init_audit();
11154
11390
  init_litellm();
@@ -11159,37 +11395,37 @@ var init_costSync = __esm({
11159
11395
  claudeSource = {
11160
11396
  id: "claude",
11161
11397
  available() {
11162
- return import_fs20.default.existsSync(import_path22.default.join(import_os19.default.homedir(), ".claude", "projects"));
11398
+ return import_fs21.default.existsSync(import_path23.default.join(import_os20.default.homedir(), ".claude", "projects"));
11163
11399
  },
11164
11400
  collect(sinceMs) {
11165
- const projectsDir = import_path22.default.join(import_os19.default.homedir(), ".claude", "projects");
11166
- if (!import_fs20.default.existsSync(projectsDir)) return [];
11401
+ const projectsDir = import_path23.default.join(import_os20.default.homedir(), ".claude", "projects");
11402
+ if (!import_fs21.default.existsSync(projectsDir)) return [];
11167
11403
  const combined = /* @__PURE__ */ new Map();
11168
11404
  let dirs;
11169
11405
  try {
11170
- dirs = import_fs20.default.readdirSync(projectsDir);
11406
+ dirs = import_fs21.default.readdirSync(projectsDir);
11171
11407
  } catch {
11172
11408
  return [];
11173
11409
  }
11174
11410
  for (const dir of dirs) {
11175
- const dirPath = import_path22.default.join(projectsDir, dir);
11411
+ const dirPath = import_path23.default.join(projectsDir, dir);
11176
11412
  try {
11177
- if (!import_fs20.default.statSync(dirPath).isDirectory()) continue;
11413
+ if (!import_fs21.default.statSync(dirPath).isDirectory()) continue;
11178
11414
  } catch {
11179
11415
  continue;
11180
11416
  }
11181
11417
  let files;
11182
11418
  try {
11183
- files = import_fs20.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
11419
+ files = import_fs21.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
11184
11420
  } catch {
11185
11421
  continue;
11186
11422
  }
11187
11423
  const fallbackWorkingDir = decodeProjectDirName(dir);
11188
11424
  for (const file of files) {
11189
- const filePath = import_path22.default.join(dirPath, file);
11425
+ const filePath = import_path23.default.join(dirPath, file);
11190
11426
  if (sinceMs !== void 0) {
11191
11427
  try {
11192
- if (import_fs20.default.statSync(filePath).mtimeMs < sinceMs) continue;
11428
+ if (import_fs21.default.statSync(filePath).mtimeMs < sinceMs) continue;
11193
11429
  } catch {
11194
11430
  continue;
11195
11431
  }
@@ -11240,7 +11476,7 @@ function freshWatermark() {
11240
11476
  function loadWatermark() {
11241
11477
  let raw;
11242
11478
  try {
11243
- raw = import_fs21.default.readFileSync(WATERMARK_FILE(), "utf-8");
11479
+ raw = import_fs22.default.readFileSync(WATERMARK_FILE(), "utf-8");
11244
11480
  } catch {
11245
11481
  return { status: "fresh", wm: freshWatermark() };
11246
11482
  }
@@ -11292,28 +11528,28 @@ function loadWatermark() {
11292
11528
  function saveWatermark(wm) {
11293
11529
  if (wm.schemaVersion > WATERMARK_SCHEMA_VERSION) return;
11294
11530
  const target = WATERMARK_FILE();
11295
- const dir = import_path23.default.dirname(target);
11296
- if (!import_fs21.default.existsSync(dir)) import_fs21.default.mkdirSync(dir, { recursive: true });
11531
+ const dir = import_path24.default.dirname(target);
11532
+ if (!import_fs22.default.existsSync(dir)) import_fs22.default.mkdirSync(dir, { recursive: true });
11297
11533
  const tmp = target + ".tmp";
11298
- import_fs21.default.writeFileSync(tmp, JSON.stringify(wm, null, 2) + "\n", "utf-8");
11299
- import_fs21.default.renameSync(tmp, target);
11534
+ import_fs22.default.writeFileSync(tmp, JSON.stringify(wm, null, 2) + "\n", "utf-8");
11535
+ import_fs22.default.renameSync(tmp, target);
11300
11536
  }
11301
11537
  function listJsonlFiles() {
11302
11538
  const root = PROJECTS_DIR();
11303
- if (!import_fs21.default.existsSync(root)) return [];
11539
+ if (!import_fs22.default.existsSync(root)) return [];
11304
11540
  const out = [];
11305
- for (const entry of import_fs21.default.readdirSync(root, { withFileTypes: true })) {
11541
+ for (const entry of import_fs22.default.readdirSync(root, { withFileTypes: true })) {
11306
11542
  if (!entry.isDirectory()) continue;
11307
- const projectDir = import_path23.default.join(root, entry.name);
11543
+ const projectDir = import_path24.default.join(root, entry.name);
11308
11544
  let inner;
11309
11545
  try {
11310
- inner = import_fs21.default.readdirSync(projectDir, { withFileTypes: true });
11546
+ inner = import_fs22.default.readdirSync(projectDir, { withFileTypes: true });
11311
11547
  } catch {
11312
11548
  continue;
11313
11549
  }
11314
11550
  for (const file of inner) {
11315
11551
  if (file.isFile() && file.name.endsWith(".jsonl")) {
11316
- out.push(import_path23.default.join(projectDir, file.name));
11552
+ out.push(import_path24.default.join(projectDir, file.name));
11317
11553
  }
11318
11554
  }
11319
11555
  }
@@ -11321,7 +11557,7 @@ function listJsonlFiles() {
11321
11557
  }
11322
11558
  function fileSize(p) {
11323
11559
  try {
11324
- return import_fs21.default.statSync(p).size;
11560
+ return import_fs22.default.statSync(p).size;
11325
11561
  } catch {
11326
11562
  return 0;
11327
11563
  }
@@ -11329,7 +11565,7 @@ function fileSize(p) {
11329
11565
  async function scanDelta(filePath, fromByte, onLine) {
11330
11566
  const size = fileSize(filePath);
11331
11567
  if (size <= fromByte) return fromByte;
11332
- const stream = import_fs21.default.createReadStream(filePath, {
11568
+ const stream = import_fs22.default.createReadStream(filePath, {
11333
11569
  start: fromByte,
11334
11570
  end: size - 1,
11335
11571
  highWaterMark: 64 * 1024
@@ -11441,7 +11677,7 @@ async function tickForensicBroadcast(offsets) {
11441
11677
  continue;
11442
11678
  }
11443
11679
  if (size <= offset) continue;
11444
- const sessionId = import_path23.default.basename(file, ".jsonl");
11680
+ const sessionId = import_path24.default.basename(file, ".jsonl");
11445
11681
  const newOffset = await scanDelta(file, offset, (obj, lineIndex) => {
11446
11682
  out.push(...extractFindingsFromLine(obj, sessionId, lineIndex));
11447
11683
  });
@@ -11500,7 +11736,7 @@ function emptyTick(uploadAs) {
11500
11736
  function readRawWatermarkPreservingOffsets() {
11501
11737
  let raw;
11502
11738
  try {
11503
- raw = import_fs21.default.readFileSync(WATERMARK_FILE(), "utf-8");
11739
+ raw = import_fs22.default.readFileSync(WATERMARK_FILE(), "utf-8");
11504
11740
  } catch {
11505
11741
  return null;
11506
11742
  }
@@ -11534,13 +11770,13 @@ async function runActualTick(wm) {
11534
11770
  if (!known) {
11535
11771
  let mtimeMs = 0;
11536
11772
  try {
11537
- mtimeMs = import_fs21.default.statSync(filePath).mtime.getTime();
11773
+ mtimeMs = import_fs22.default.statSync(filePath).mtime.getTime();
11538
11774
  } catch {
11539
11775
  continue;
11540
11776
  }
11541
11777
  if (mtimeMs >= watermarkCreatedAt) {
11542
11778
  filesNew++;
11543
- const sessionId2 = import_path23.default.basename(filePath, ".jsonl");
11779
+ const sessionId2 = import_path24.default.basename(filePath, ".jsonl");
11544
11780
  const newScannedTo2 = await scanDelta(filePath, 0, (obj, lineIndex) => {
11545
11781
  totalToolCalls++;
11546
11782
  toolCallsBySession[sessionId2] = (toolCallsBySession[sessionId2] ?? 0) + 1;
@@ -11558,7 +11794,7 @@ async function runActualTick(wm) {
11558
11794
  filesSkipped++;
11559
11795
  continue;
11560
11796
  }
11561
- const sessionId = import_path23.default.basename(filePath, ".jsonl");
11797
+ const sessionId = import_path24.default.basename(filePath, ".jsonl");
11562
11798
  const newScannedTo = await scanDelta(filePath, known.scannedTo, (obj, lineIndex) => {
11563
11799
  totalToolCalls++;
11564
11800
  toolCallsBySession[sessionId] = (toolCallsBySession[sessionId] ?? 0) + 1;
@@ -11580,18 +11816,18 @@ async function runActualTick(wm) {
11580
11816
  schemaFuture: false
11581
11817
  };
11582
11818
  }
11583
- var import_fs21, import_os20, import_path23, import_readline, PROJECTS_DIR, WATERMARK_FILE, MAX_LINE_BYTES, WATERMARK_SCHEMA_VERSION, LONG_OUTPUT_THRESHOLD_BYTES2;
11819
+ var import_fs22, import_os21, import_path24, import_readline, PROJECTS_DIR, WATERMARK_FILE, MAX_LINE_BYTES, WATERMARK_SCHEMA_VERSION, LONG_OUTPUT_THRESHOLD_BYTES2;
11584
11820
  var init_scan_watermark = __esm({
11585
11821
  "src/daemon/scan-watermark.ts"() {
11586
11822
  "use strict";
11587
- import_fs21 = __toESM(require("fs"));
11588
- import_os20 = __toESM(require("os"));
11589
- import_path23 = __toESM(require("path"));
11823
+ import_fs22 = __toESM(require("fs"));
11824
+ import_os21 = __toESM(require("os"));
11825
+ import_path24 = __toESM(require("path"));
11590
11826
  import_readline = __toESM(require("readline"));
11591
11827
  init_dlp();
11592
11828
  init_dist();
11593
- PROJECTS_DIR = () => import_path23.default.join(import_os20.default.homedir(), ".claude", "projects");
11594
- WATERMARK_FILE = () => import_path23.default.join(import_os20.default.homedir(), ".node9", "scan-watermark.json");
11829
+ PROJECTS_DIR = () => import_path24.default.join(import_os21.default.homedir(), ".claude", "projects");
11830
+ WATERMARK_FILE = () => import_path24.default.join(import_os21.default.homedir(), ".node9", "scan-watermark.json");
11595
11831
  MAX_LINE_BYTES = 2 * 1024 * 1024;
11596
11832
  WATERMARK_SCHEMA_VERSION = 2;
11597
11833
  LONG_OUTPUT_THRESHOLD_BYTES2 = LONG_OUTPUT_THRESHOLD_BYTES;
@@ -11640,40 +11876,40 @@ function parseSinceCutoff(raw, now = /* @__PURE__ */ new Date()) {
11640
11876
  return now.getTime() - 90 * 864e5;
11641
11877
  }
11642
11878
  function* iterateJsonlFiles(cutoffMs) {
11643
- const projectsDir = import_path24.default.join(import_os21.default.homedir(), ".claude", "projects");
11879
+ const projectsDir = import_path25.default.join(import_os22.default.homedir(), ".claude", "projects");
11644
11880
  let dirs;
11645
11881
  try {
11646
- dirs = import_fs22.default.readdirSync(projectsDir);
11882
+ dirs = import_fs23.default.readdirSync(projectsDir);
11647
11883
  } catch {
11648
11884
  return;
11649
11885
  }
11650
11886
  for (const dir of dirs) {
11651
- const dirPath = import_path24.default.join(projectsDir, dir);
11887
+ const dirPath = import_path25.default.join(projectsDir, dir);
11652
11888
  let stats;
11653
11889
  try {
11654
- stats = import_fs22.default.statSync(dirPath);
11890
+ stats = import_fs23.default.statSync(dirPath);
11655
11891
  } catch {
11656
11892
  continue;
11657
11893
  }
11658
11894
  if (!stats.isDirectory()) continue;
11659
11895
  let files;
11660
11896
  try {
11661
- files = import_fs22.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
11897
+ files = import_fs23.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
11662
11898
  } catch {
11663
11899
  continue;
11664
11900
  }
11665
11901
  for (const file of files) {
11666
- const filePath = import_path24.default.join(dirPath, file);
11902
+ const filePath = import_path25.default.join(dirPath, file);
11667
11903
  let mtime = 0;
11668
11904
  try {
11669
- mtime = import_fs22.default.statSync(filePath).mtimeMs;
11905
+ mtime = import_fs23.default.statSync(filePath).mtimeMs;
11670
11906
  } catch {
11671
11907
  continue;
11672
11908
  }
11673
11909
  if (mtime < cutoffMs) continue;
11674
11910
  yield {
11675
11911
  filePath,
11676
- sessionId: import_path24.default.basename(file, ".jsonl"),
11912
+ sessionId: import_path25.default.basename(file, ".jsonl"),
11677
11913
  projectDir: dir
11678
11914
  };
11679
11915
  }
@@ -11741,7 +11977,7 @@ async function runUploadHistory(opts) {
11741
11977
  filesScanned++;
11742
11978
  let content;
11743
11979
  try {
11744
- content = import_fs22.default.readFileSync(filePath, "utf8");
11980
+ content = import_fs23.default.readFileSync(filePath, "utf8");
11745
11981
  } catch {
11746
11982
  continue;
11747
11983
  }
@@ -11815,10 +12051,10 @@ async function runUploadHistory(opts) {
11815
12051
  const costUrl = creds.apiUrl.endsWith("/policies/sync") ? creds.apiUrl.replace(/\/policies\/sync$/, "/cost-sync") : `${creds.apiUrl.replace(/\/$/, "")}/cost-sync`;
11816
12052
  let username = "unknown";
11817
12053
  try {
11818
- username = import_os21.default.userInfo().username;
12054
+ username = import_os22.default.userInfo().username;
11819
12055
  } catch {
11820
12056
  }
11821
- const machineId = `${import_os21.default.hostname()}:${username}`;
12057
+ const machineId = `${import_os22.default.hostname()}:${username}`;
11822
12058
  await postJson(costUrl, creds.apiKey, {
11823
12059
  machineId,
11824
12060
  entries: dailyEntries
@@ -11868,14 +12104,14 @@ async function postJson(url, apiKey, body) {
11868
12104
  req.end();
11869
12105
  });
11870
12106
  }
11871
- var import_fs22, import_https, import_os21, import_path24, import_chalk4, FINDING_TO_SIGNAL2;
12107
+ var import_fs23, import_https, import_os22, import_path25, import_chalk4, FINDING_TO_SIGNAL2;
11872
12108
  var init_scan_upload_history = __esm({
11873
12109
  "src/scan-upload-history.ts"() {
11874
12110
  "use strict";
11875
- import_fs22 = __toESM(require("fs"));
12111
+ import_fs23 = __toESM(require("fs"));
11876
12112
  import_https = __toESM(require("https"));
11877
- import_os21 = __toESM(require("os"));
11878
- import_path24 = __toESM(require("path"));
12113
+ import_os22 = __toESM(require("os"));
12114
+ import_path25 = __toESM(require("path"));
11879
12115
  import_chalk4 = __toESM(require("chalk"));
11880
12116
  init_dist();
11881
12117
  init_config();
@@ -12117,14 +12353,14 @@ function buildRuleSources() {
12117
12353
  }
12118
12354
  function countScanFiles() {
12119
12355
  let total = 0;
12120
- const claudeDir = import_path25.default.join(import_os22.default.homedir(), ".claude", "projects");
12121
- if (import_fs23.default.existsSync(claudeDir)) {
12356
+ const claudeDir = import_path26.default.join(import_os23.default.homedir(), ".claude", "projects");
12357
+ if (import_fs24.default.existsSync(claudeDir)) {
12122
12358
  try {
12123
- for (const proj of import_fs23.default.readdirSync(claudeDir)) {
12124
- const p = import_path25.default.join(claudeDir, proj);
12359
+ for (const proj of import_fs24.default.readdirSync(claudeDir)) {
12360
+ const p = import_path26.default.join(claudeDir, proj);
12125
12361
  try {
12126
- if (!import_fs23.default.statSync(p).isDirectory()) continue;
12127
- total += import_fs23.default.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
12362
+ if (!import_fs24.default.statSync(p).isDirectory()) continue;
12363
+ total += import_fs24.default.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
12128
12364
  } catch {
12129
12365
  continue;
12130
12366
  }
@@ -12132,17 +12368,17 @@ function countScanFiles() {
12132
12368
  } catch {
12133
12369
  }
12134
12370
  }
12135
- const geminiDir = import_path25.default.join(import_os22.default.homedir(), ".gemini", "tmp");
12136
- if (import_fs23.default.existsSync(geminiDir)) {
12371
+ const geminiDir = import_path26.default.join(import_os23.default.homedir(), ".gemini", "tmp");
12372
+ if (import_fs24.default.existsSync(geminiDir)) {
12137
12373
  try {
12138
- for (const slug2 of import_fs23.default.readdirSync(geminiDir)) {
12139
- const p = import_path25.default.join(geminiDir, slug2);
12374
+ for (const slug2 of import_fs24.default.readdirSync(geminiDir)) {
12375
+ const p = import_path26.default.join(geminiDir, slug2);
12140
12376
  try {
12141
- if (!import_fs23.default.statSync(p).isDirectory()) continue;
12142
- const chatsDir = import_path25.default.join(p, "chats");
12143
- if (import_fs23.default.existsSync(chatsDir)) {
12377
+ if (!import_fs24.default.statSync(p).isDirectory()) continue;
12378
+ const chatsDir = import_path26.default.join(p, "chats");
12379
+ if (import_fs24.default.existsSync(chatsDir)) {
12144
12380
  try {
12145
- total += import_fs23.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
12381
+ total += import_fs24.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
12146
12382
  } catch {
12147
12383
  }
12148
12384
  }
@@ -12154,15 +12390,15 @@ function countScanFiles() {
12154
12390
  }
12155
12391
  }
12156
12392
  for (const surface of ["antigravity-cli", "antigravity-ide"]) {
12157
- const brainDir = import_path25.default.join(import_os22.default.homedir(), ".gemini", surface, "brain");
12158
- if (!import_fs23.default.existsSync(brainDir)) continue;
12393
+ const brainDir = import_path26.default.join(import_os23.default.homedir(), ".gemini", surface, "brain");
12394
+ if (!import_fs24.default.existsSync(brainDir)) continue;
12159
12395
  try {
12160
- for (const conv of import_fs23.default.readdirSync(brainDir)) {
12161
- const convPath = import_path25.default.join(brainDir, conv);
12396
+ for (const conv of import_fs24.default.readdirSync(brainDir)) {
12397
+ const convPath = import_path26.default.join(brainDir, conv);
12162
12398
  try {
12163
- if (!import_fs23.default.statSync(convPath).isDirectory()) continue;
12164
- const logsDir = import_path25.default.join(convPath, ".system_generated", "logs");
12165
- if (import_fs23.default.existsSync(import_path25.default.join(logsDir, "transcript_full.jsonl")) || import_fs23.default.existsSync(import_path25.default.join(logsDir, "transcript.jsonl"))) {
12399
+ if (!import_fs24.default.statSync(convPath).isDirectory()) continue;
12400
+ const logsDir = import_path26.default.join(convPath, ".system_generated", "logs");
12401
+ 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
12402
  total += 1;
12167
12403
  }
12168
12404
  } catch {
@@ -12172,31 +12408,31 @@ function countScanFiles() {
12172
12408
  } catch {
12173
12409
  }
12174
12410
  }
12175
- const copilotDir = import_path25.default.join(import_os22.default.homedir(), ".copilot", "session-state");
12176
- if (import_fs23.default.existsSync(copilotDir)) {
12411
+ const copilotDir = import_path26.default.join(import_os23.default.homedir(), ".copilot", "session-state");
12412
+ if (import_fs24.default.existsSync(copilotDir)) {
12177
12413
  try {
12178
- for (const sid of import_fs23.default.readdirSync(copilotDir)) {
12179
- if (import_fs23.default.existsSync(import_path25.default.join(copilotDir, sid, "events.jsonl"))) total += 1;
12414
+ for (const sid of import_fs24.default.readdirSync(copilotDir)) {
12415
+ if (import_fs24.default.existsSync(import_path26.default.join(copilotDir, sid, "events.jsonl"))) total += 1;
12180
12416
  }
12181
12417
  } catch {
12182
12418
  }
12183
12419
  }
12184
- const codexDir = import_path25.default.join(import_os22.default.homedir(), ".codex", "sessions");
12185
- if (import_fs23.default.existsSync(codexDir)) {
12420
+ const codexDir = import_path26.default.join(import_os23.default.homedir(), ".codex", "sessions");
12421
+ if (import_fs24.default.existsSync(codexDir)) {
12186
12422
  try {
12187
- for (const year of import_fs23.default.readdirSync(codexDir)) {
12188
- const yp = import_path25.default.join(codexDir, year);
12423
+ for (const year of import_fs24.default.readdirSync(codexDir)) {
12424
+ const yp = import_path26.default.join(codexDir, year);
12189
12425
  try {
12190
- if (!import_fs23.default.statSync(yp).isDirectory()) continue;
12191
- for (const month of import_fs23.default.readdirSync(yp)) {
12192
- const mp = import_path25.default.join(yp, month);
12426
+ if (!import_fs24.default.statSync(yp).isDirectory()) continue;
12427
+ for (const month of import_fs24.default.readdirSync(yp)) {
12428
+ const mp = import_path26.default.join(yp, month);
12193
12429
  try {
12194
- if (!import_fs23.default.statSync(mp).isDirectory()) continue;
12195
- for (const day of import_fs23.default.readdirSync(mp)) {
12196
- const dp = import_path25.default.join(mp, day);
12430
+ if (!import_fs24.default.statSync(mp).isDirectory()) continue;
12431
+ for (const day of import_fs24.default.readdirSync(mp)) {
12432
+ const dp = import_path26.default.join(mp, day);
12197
12433
  try {
12198
- if (!import_fs23.default.statSync(dp).isDirectory()) continue;
12199
- total += import_fs23.default.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
12434
+ if (!import_fs24.default.statSync(dp).isDirectory()) continue;
12435
+ total += import_fs24.default.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
12200
12436
  } catch {
12201
12437
  continue;
12202
12438
  }
@@ -12232,7 +12468,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
12232
12468
  const sessionId = file.replace(/\.jsonl$/, "");
12233
12469
  let raw;
12234
12470
  try {
12235
- raw = import_fs23.default.readFileSync(import_path25.default.join(projPath, file), "utf-8");
12471
+ raw = import_fs24.default.readFileSync(import_path26.default.join(projPath, file), "utf-8");
12236
12472
  } catch {
12237
12473
  return;
12238
12474
  }
@@ -12284,7 +12520,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
12284
12520
  if (block.type !== "tool_result") continue;
12285
12521
  const filePath = block.tool_use_id ? toolUseFilePaths.get(block.tool_use_id) : void 0;
12286
12522
  if (filePath) {
12287
- const ext = import_path25.default.extname(filePath).toLowerCase();
12523
+ const ext = import_path26.default.extname(filePath).toLowerCase();
12288
12524
  if (CODE_EXTENSIONS.has(ext)) continue;
12289
12525
  }
12290
12526
  const resultText = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => c.text ?? "").join("\n") : null;
@@ -12341,7 +12577,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
12341
12577
  const rawCmd = String(input.command ?? "").trimStart();
12342
12578
  if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd)) continue;
12343
12579
  const inputFilePath = typeof input.file_path === "string" ? input.file_path : "";
12344
- const inputFileExt = inputFilePath ? import_path25.default.extname(inputFilePath).toLowerCase() : "";
12580
+ const inputFileExt = inputFilePath ? import_path26.default.extname(inputFilePath).toLowerCase() : "";
12345
12581
  if (CODE_EXTENSIONS.has(inputFileExt)) continue;
12346
12582
  const dlpMatch = scanArgs(input);
12347
12583
  if (dlpMatch) {
@@ -12438,19 +12674,19 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
12438
12674
  }
12439
12675
  }
12440
12676
  function processClaudeProject(proj, projectsDir, ruleSources, startDate, result, dedup, onProgress, onLine) {
12441
- const projPath = import_path25.default.join(projectsDir, proj);
12677
+ const projPath = import_path26.default.join(projectsDir, proj);
12442
12678
  try {
12443
- if (!import_fs23.default.statSync(projPath).isDirectory()) return;
12679
+ if (!import_fs24.default.statSync(projPath).isDirectory()) return;
12444
12680
  } catch {
12445
12681
  return;
12446
12682
  }
12447
- const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(import_os22.default.homedir(), "~")).slice(
12683
+ const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(import_os23.default.homedir(), "~")).slice(
12448
12684
  0,
12449
12685
  40
12450
12686
  );
12451
12687
  let files;
12452
12688
  try {
12453
- files = import_fs23.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
12689
+ files = import_fs24.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
12454
12690
  } catch {
12455
12691
  return;
12456
12692
  }
@@ -12484,12 +12720,12 @@ function emptyClaudeScan() {
12484
12720
  };
12485
12721
  }
12486
12722
  function scanClaudeHistory(startDate, onProgress, onLine) {
12487
- const projectsDir = import_path25.default.join(import_os22.default.homedir(), ".claude", "projects");
12723
+ const projectsDir = import_path26.default.join(import_os23.default.homedir(), ".claude", "projects");
12488
12724
  const result = emptyClaudeScan();
12489
- if (!import_fs23.default.existsSync(projectsDir)) return result;
12725
+ if (!import_fs24.default.existsSync(projectsDir)) return result;
12490
12726
  let projDirs;
12491
12727
  try {
12492
- projDirs = import_fs23.default.readdirSync(projectsDir);
12728
+ projDirs = import_fs24.default.readdirSync(projectsDir);
12493
12729
  } catch {
12494
12730
  return result;
12495
12731
  }
@@ -12510,7 +12746,7 @@ function scanClaudeHistory(startDate, onProgress, onLine) {
12510
12746
  return result;
12511
12747
  }
12512
12748
  function scanGeminiHistory(startDate, onProgress, onLine) {
12513
- const tmpDir = import_path25.default.join(import_os22.default.homedir(), ".gemini", "tmp");
12749
+ const tmpDir = import_path26.default.join(import_os23.default.homedir(), ".gemini", "tmp");
12514
12750
  const result = {
12515
12751
  filesScanned: 0,
12516
12752
  sessions: 0,
@@ -12525,33 +12761,33 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
12525
12761
  sessionsWithEarlySecrets: 0
12526
12762
  };
12527
12763
  const dedup = emptyScanDedup();
12528
- if (!import_fs23.default.existsSync(tmpDir)) return result;
12764
+ if (!import_fs24.default.existsSync(tmpDir)) return result;
12529
12765
  let slugDirs;
12530
12766
  try {
12531
- slugDirs = import_fs23.default.readdirSync(tmpDir);
12767
+ slugDirs = import_fs24.default.readdirSync(tmpDir);
12532
12768
  } catch {
12533
12769
  return result;
12534
12770
  }
12535
12771
  const ruleSources = buildRuleSources();
12536
12772
  for (const slug2 of slugDirs) {
12537
- const slugPath = import_path25.default.join(tmpDir, slug2);
12773
+ const slugPath = import_path26.default.join(tmpDir, slug2);
12538
12774
  try {
12539
- if (!import_fs23.default.statSync(slugPath).isDirectory()) continue;
12775
+ if (!import_fs24.default.statSync(slugPath).isDirectory()) continue;
12540
12776
  } catch {
12541
12777
  continue;
12542
12778
  }
12543
12779
  let projLabel = stripTerminalEscapes(slug2).slice(0, 40);
12544
12780
  try {
12545
12781
  projLabel = stripTerminalEscapes(
12546
- import_fs23.default.readFileSync(import_path25.default.join(slugPath, ".project_root"), "utf-8").trim()
12547
- ).replace(import_os22.default.homedir(), "~").slice(0, 40);
12782
+ import_fs24.default.readFileSync(import_path26.default.join(slugPath, ".project_root"), "utf-8").trim()
12783
+ ).replace(import_os23.default.homedir(), "~").slice(0, 40);
12548
12784
  } catch {
12549
12785
  }
12550
- const chatsDir = import_path25.default.join(slugPath, "chats");
12551
- if (!import_fs23.default.existsSync(chatsDir)) continue;
12786
+ const chatsDir = import_path26.default.join(slugPath, "chats");
12787
+ if (!import_fs24.default.existsSync(chatsDir)) continue;
12552
12788
  let chatFiles;
12553
12789
  try {
12554
- chatFiles = import_fs23.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json") || f.endsWith(".jsonl")).sort((a, b) => Number(b.endsWith(".jsonl")) - Number(a.endsWith(".jsonl")));
12790
+ 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
12791
  } catch {
12556
12792
  continue;
12557
12793
  }
@@ -12564,7 +12800,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
12564
12800
  onProgress?.(result.filesScanned);
12565
12801
  let raw;
12566
12802
  try {
12567
- raw = import_fs23.default.readFileSync(import_path25.default.join(chatsDir, chatFile), "utf-8");
12803
+ raw = import_fs24.default.readFileSync(import_path26.default.join(chatsDir, chatFile), "utf-8");
12568
12804
  } catch {
12569
12805
  continue;
12570
12806
  }
@@ -12737,13 +12973,13 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
12737
12973
  return result;
12738
12974
  }
12739
12975
  function antigravityBrainDirs() {
12740
- return ["antigravity-cli", "antigravity-ide"].map((surface) => import_path25.default.join(import_os22.default.homedir(), ".gemini", surface, "brain")).filter((p) => import_fs23.default.existsSync(p));
12976
+ 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
12977
  }
12742
12978
  function antigravityTranscriptPath(convPath) {
12743
- const logsDir = import_path25.default.join(convPath, ".system_generated", "logs");
12979
+ const logsDir = import_path26.default.join(convPath, ".system_generated", "logs");
12744
12980
  for (const name of ["transcript_full.jsonl", "transcript.jsonl"]) {
12745
- const p = import_path25.default.join(logsDir, name);
12746
- if (import_fs23.default.existsSync(p)) return p;
12981
+ const p = import_path26.default.join(logsDir, name);
12982
+ if (import_fs24.default.existsSync(p)) return p;
12747
12983
  }
12748
12984
  return null;
12749
12985
  }
@@ -12769,14 +13005,14 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
12769
13005
  for (const brainDir of brainDirs) {
12770
13006
  let convDirs;
12771
13007
  try {
12772
- convDirs = import_fs23.default.readdirSync(brainDir);
13008
+ convDirs = import_fs24.default.readdirSync(brainDir);
12773
13009
  } catch {
12774
13010
  continue;
12775
13011
  }
12776
13012
  for (const conv of convDirs) {
12777
- const convPath = import_path25.default.join(brainDir, conv);
13013
+ const convPath = import_path26.default.join(brainDir, conv);
12778
13014
  try {
12779
- if (!import_fs23.default.statSync(convPath).isDirectory()) continue;
13015
+ if (!import_fs24.default.statSync(convPath).isDirectory()) continue;
12780
13016
  } catch {
12781
13017
  continue;
12782
13018
  }
@@ -12786,7 +13022,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
12786
13022
  onProgress?.(result.filesScanned);
12787
13023
  let raw;
12788
13024
  try {
12789
- raw = import_fs23.default.readFileSync(transcriptFile, "utf-8");
13025
+ raw = import_fs24.default.readFileSync(transcriptFile, "utf-8");
12790
13026
  } catch {
12791
13027
  continue;
12792
13028
  }
@@ -12843,7 +13079,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
12843
13079
  result.bashCalls++;
12844
13080
  const cwd = String(input.cwd ?? "");
12845
13081
  if (cwd && projLabel === conv.slice(0, 8)) {
12846
- projLabel = stripTerminalEscapes(cwd).replace(import_os22.default.homedir(), "~").slice(0, 40);
13082
+ projLabel = stripTerminalEscapes(cwd).replace(import_os23.default.homedir(), "~").slice(0, 40);
12847
13083
  }
12848
13084
  }
12849
13085
  const rawCmd = String(input.command ?? "").trimStart();
@@ -12943,7 +13179,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
12943
13179
  return result;
12944
13180
  }
12945
13181
  function scanCopilotHistory(startDate, onProgress, onLine) {
12946
- const sessionDir = import_path25.default.join(import_os22.default.homedir(), ".copilot", "session-state");
13182
+ const sessionDir = import_path26.default.join(import_os23.default.homedir(), ".copilot", "session-state");
12947
13183
  const result = {
12948
13184
  filesScanned: 0,
12949
13185
  sessions: 0,
@@ -12959,22 +13195,22 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
12959
13195
  sessionsWithEarlySecrets: 0
12960
13196
  };
12961
13197
  const dedup = emptyScanDedup();
12962
- if (!import_fs23.default.existsSync(sessionDir)) return result;
13198
+ if (!import_fs24.default.existsSync(sessionDir)) return result;
12963
13199
  let sessionIds;
12964
13200
  try {
12965
- sessionIds = import_fs23.default.readdirSync(sessionDir);
13201
+ sessionIds = import_fs24.default.readdirSync(sessionDir);
12966
13202
  } catch {
12967
13203
  return result;
12968
13204
  }
12969
13205
  const ruleSources = buildRuleSources();
12970
13206
  for (const sessionId of sessionIds) {
12971
- const eventsPath = import_path25.default.join(sessionDir, sessionId, "events.jsonl");
12972
- if (!import_fs23.default.existsSync(eventsPath)) continue;
13207
+ const eventsPath = import_path26.default.join(sessionDir, sessionId, "events.jsonl");
13208
+ if (!import_fs24.default.existsSync(eventsPath)) continue;
12973
13209
  result.filesScanned++;
12974
13210
  onProgress?.(result.filesScanned);
12975
13211
  let raw;
12976
13212
  try {
12977
- raw = import_fs23.default.readFileSync(eventsPath, "utf-8");
13213
+ raw = import_fs24.default.readFileSync(eventsPath, "utf-8");
12978
13214
  } catch {
12979
13215
  continue;
12980
13216
  }
@@ -12994,7 +13230,7 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
12994
13230
  if (ev.type === "session.start") {
12995
13231
  const cwd = ev.data?.context?.cwd;
12996
13232
  if (typeof cwd === "string" && cwd) {
12997
- projLabel = stripTerminalEscapes(cwd).replace(import_os22.default.homedir(), "~").slice(0, 40);
13233
+ projLabel = stripTerminalEscapes(cwd).replace(import_os23.default.homedir(), "~").slice(0, 40);
12998
13234
  }
12999
13235
  continue;
13000
13236
  }
@@ -13126,7 +13362,7 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
13126
13362
  return result;
13127
13363
  }
13128
13364
  function scanCodexHistory(startDate, onProgress, onLine) {
13129
- const sessionsBase = import_path25.default.join(import_os22.default.homedir(), ".codex", "sessions");
13365
+ const sessionsBase = import_path26.default.join(import_os23.default.homedir(), ".codex", "sessions");
13130
13366
  const result = {
13131
13367
  filesScanned: 0,
13132
13368
  sessions: 0,
@@ -13141,32 +13377,32 @@ function scanCodexHistory(startDate, onProgress, onLine) {
13141
13377
  sessionsWithEarlySecrets: 0
13142
13378
  };
13143
13379
  const dedup = emptyScanDedup();
13144
- if (!import_fs23.default.existsSync(sessionsBase)) return result;
13380
+ if (!import_fs24.default.existsSync(sessionsBase)) return result;
13145
13381
  const jsonlFiles = [];
13146
13382
  try {
13147
- for (const year of import_fs23.default.readdirSync(sessionsBase)) {
13148
- const yearPath = import_path25.default.join(sessionsBase, year);
13383
+ for (const year of import_fs24.default.readdirSync(sessionsBase)) {
13384
+ const yearPath = import_path26.default.join(sessionsBase, year);
13149
13385
  try {
13150
- if (!import_fs23.default.statSync(yearPath).isDirectory()) continue;
13386
+ if (!import_fs24.default.statSync(yearPath).isDirectory()) continue;
13151
13387
  } catch {
13152
13388
  continue;
13153
13389
  }
13154
- for (const month of import_fs23.default.readdirSync(yearPath)) {
13155
- const monthPath = import_path25.default.join(yearPath, month);
13390
+ for (const month of import_fs24.default.readdirSync(yearPath)) {
13391
+ const monthPath = import_path26.default.join(yearPath, month);
13156
13392
  try {
13157
- if (!import_fs23.default.statSync(monthPath).isDirectory()) continue;
13393
+ if (!import_fs24.default.statSync(monthPath).isDirectory()) continue;
13158
13394
  } catch {
13159
13395
  continue;
13160
13396
  }
13161
- for (const day of import_fs23.default.readdirSync(monthPath)) {
13162
- const dayPath = import_path25.default.join(monthPath, day);
13397
+ for (const day of import_fs24.default.readdirSync(monthPath)) {
13398
+ const dayPath = import_path26.default.join(monthPath, day);
13163
13399
  try {
13164
- if (!import_fs23.default.statSync(dayPath).isDirectory()) continue;
13400
+ if (!import_fs24.default.statSync(dayPath).isDirectory()) continue;
13165
13401
  } catch {
13166
13402
  continue;
13167
13403
  }
13168
- for (const file of import_fs23.default.readdirSync(dayPath)) {
13169
- if (file.endsWith(".jsonl")) jsonlFiles.push(import_path25.default.join(dayPath, file));
13404
+ for (const file of import_fs24.default.readdirSync(dayPath)) {
13405
+ if (file.endsWith(".jsonl")) jsonlFiles.push(import_path26.default.join(dayPath, file));
13170
13406
  }
13171
13407
  }
13172
13408
  }
@@ -13180,7 +13416,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
13180
13416
  onProgress?.(result.filesScanned);
13181
13417
  let lines;
13182
13418
  try {
13183
- lines = import_fs23.default.readFileSync(filePath, "utf-8").split("\n");
13419
+ lines = import_fs24.default.readFileSync(filePath, "utf-8").split("\n");
13184
13420
  } catch {
13185
13421
  continue;
13186
13422
  }
@@ -13207,7 +13443,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
13207
13443
  sessionId = String(payload["id"] ?? filePath);
13208
13444
  startTime = String(payload["timestamp"] ?? "");
13209
13445
  const cwd = String(payload["cwd"] ?? "");
13210
- projLabel = stripTerminalEscapes(cwd.replace(import_os22.default.homedir(), "~")).slice(0, 40);
13446
+ projLabel = stripTerminalEscapes(cwd.replace(import_os23.default.homedir(), "~")).slice(0, 40);
13211
13447
  continue;
13212
13448
  }
13213
13449
  if (entry.type === "turn_context" && typeof payload["model"] === "string") {
@@ -13367,17 +13603,17 @@ function scanCodexHistory(startDate, onProgress, onLine) {
13367
13603
  return result;
13368
13604
  }
13369
13605
  function scanShellConfig() {
13370
- const home = import_os22.default.homedir();
13606
+ const home = import_os23.default.homedir();
13371
13607
  const configFiles = [".zshrc", ".bashrc", ".bash_profile", ".profile"].map(
13372
- (f) => import_path25.default.join(home, f)
13608
+ (f) => import_path26.default.join(home, f)
13373
13609
  );
13374
13610
  const findings = [];
13375
13611
  const seen = /* @__PURE__ */ new Set();
13376
13612
  for (const filePath of configFiles) {
13377
- if (!import_fs23.default.existsSync(filePath)) continue;
13613
+ if (!import_fs24.default.existsSync(filePath)) continue;
13378
13614
  let lines;
13379
13615
  try {
13380
- lines = import_fs23.default.readFileSync(filePath, "utf-8").split("\n");
13616
+ lines = import_fs24.default.readFileSync(filePath, "utf-8").split("\n");
13381
13617
  } catch {
13382
13618
  continue;
13383
13619
  }
@@ -14183,7 +14419,7 @@ function registerScanCommand(program2) {
14183
14419
  if (!drillDown) {
14184
14420
  const useInk2 = !options.classic;
14185
14421
  if (useInk2) {
14186
- const scanInkPath = import_path25.default.join(__dirname, "scan-ink.mjs");
14422
+ const scanInkPath = import_path26.default.join(__dirname, "scan-ink.mjs");
14187
14423
  const dynamicImport = new Function("id", "return import(id)");
14188
14424
  const mod = await dynamicImport(`file://${scanInkPath}`);
14189
14425
  const rangeLabel2 = options.all ? "all time" : `last ${options.days ?? 90} days`;
@@ -14415,14 +14651,14 @@ function registerScanCommand(program2) {
14415
14651
  }
14416
14652
  );
14417
14653
  }
14418
- var import_chalk5, import_fs23, import_path25, import_os22, 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;
14654
+ 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
14655
  var init_scan = __esm({
14420
14656
  "src/cli/commands/scan.ts"() {
14421
14657
  "use strict";
14422
14658
  import_chalk5 = __toESM(require("chalk"));
14423
- import_fs23 = __toESM(require("fs"));
14424
- import_path25 = __toESM(require("path"));
14425
- import_os22 = __toESM(require("os"));
14659
+ import_fs24 = __toESM(require("fs"));
14660
+ import_path26 = __toESM(require("path"));
14661
+ import_os23 = __toESM(require("os"));
14426
14662
  init_shields();
14427
14663
  init_config();
14428
14664
  init_policy();
@@ -14599,12 +14835,12 @@ var init_suggestion_tracker = __esm({
14599
14835
  });
14600
14836
 
14601
14837
  // src/daemon/taint-store.ts
14602
- var import_fs24, import_path26, DEFAULT_TTL_MS, TaintStore, SESSION_TAINT_TTL_MS, SessionTaintStore;
14838
+ var import_fs25, import_path27, DEFAULT_TTL_MS, TaintStore, SESSION_TAINT_TTL_MS, SessionTaintStore;
14603
14839
  var init_taint_store = __esm({
14604
14840
  "src/daemon/taint-store.ts"() {
14605
14841
  "use strict";
14606
- import_fs24 = __toESM(require("fs"));
14607
- import_path26 = __toESM(require("path"));
14842
+ import_fs25 = __toESM(require("fs"));
14843
+ import_path27 = __toESM(require("path"));
14608
14844
  DEFAULT_TTL_MS = 60 * 60 * 1e3;
14609
14845
  TaintStore = class {
14610
14846
  records = /* @__PURE__ */ new Map();
@@ -14670,9 +14906,9 @@ var init_taint_store = __esm({
14670
14906
  /** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
14671
14907
  _resolve(filePath) {
14672
14908
  try {
14673
- return import_fs24.default.realpathSync.native(import_path26.default.resolve(filePath));
14909
+ return import_fs25.default.realpathSync.native(import_path27.default.resolve(filePath));
14674
14910
  } catch {
14675
- return import_path26.default.resolve(filePath);
14911
+ return import_path27.default.resolve(filePath);
14676
14912
  }
14677
14913
  }
14678
14914
  };
@@ -14838,8 +15074,8 @@ var init_session_history = __esm({
14838
15074
  // src/daemon/state.ts
14839
15075
  function loadInsightCounts() {
14840
15076
  try {
14841
- if (!import_fs25.default.existsSync(INSIGHT_COUNTS_FILE)) return;
14842
- const data = JSON.parse(import_fs25.default.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
15077
+ if (!import_fs26.default.existsSync(INSIGHT_COUNTS_FILE)) return;
15078
+ const data = JSON.parse(import_fs26.default.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
14843
15079
  for (const [tool, count] of Object.entries(data)) {
14844
15080
  if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
14845
15081
  }
@@ -14878,23 +15114,23 @@ function markRejectionHandlerRegistered() {
14878
15114
  daemonRejectionHandlerRegistered = true;
14879
15115
  }
14880
15116
  function atomicWriteSync2(filePath, data, options) {
14881
- const dir = import_path27.default.dirname(filePath);
14882
- if (!import_fs25.default.existsSync(dir)) import_fs25.default.mkdirSync(dir, { recursive: true });
15117
+ const dir = import_path28.default.dirname(filePath);
15118
+ if (!import_fs26.default.existsSync(dir)) import_fs26.default.mkdirSync(dir, { recursive: true });
14883
15119
  const tmpPath = `${filePath}.${(0, import_crypto8.randomUUID)()}.tmp`;
14884
15120
  try {
14885
- import_fs25.default.writeFileSync(tmpPath, data, options);
15121
+ import_fs26.default.writeFileSync(tmpPath, data, options);
14886
15122
  } catch (err2) {
14887
15123
  try {
14888
- import_fs25.default.unlinkSync(tmpPath);
15124
+ import_fs26.default.unlinkSync(tmpPath);
14889
15125
  } catch {
14890
15126
  }
14891
15127
  throw err2;
14892
15128
  }
14893
15129
  try {
14894
- import_fs25.default.renameSync(tmpPath, filePath);
15130
+ import_fs26.default.renameSync(tmpPath, filePath);
14895
15131
  } catch (err2) {
14896
15132
  try {
14897
- import_fs25.default.unlinkSync(tmpPath);
15133
+ import_fs26.default.unlinkSync(tmpPath);
14898
15134
  } catch {
14899
15135
  }
14900
15136
  throw err2;
@@ -14918,16 +15154,16 @@ function appendAuditLog(data) {
14918
15154
  decision: data.decision,
14919
15155
  source: "daemon"
14920
15156
  };
14921
- const dir = import_path27.default.dirname(AUDIT_LOG_FILE);
14922
- if (!import_fs25.default.existsSync(dir)) import_fs25.default.mkdirSync(dir, { recursive: true });
14923
- import_fs25.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
15157
+ const dir = import_path28.default.dirname(AUDIT_LOG_FILE);
15158
+ if (!import_fs26.default.existsSync(dir)) import_fs26.default.mkdirSync(dir, { recursive: true });
15159
+ import_fs26.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
14924
15160
  } catch {
14925
15161
  }
14926
15162
  }
14927
15163
  function getAuditHistory(limit = 20) {
14928
15164
  try {
14929
- if (!import_fs25.default.existsSync(AUDIT_LOG_FILE)) return [];
14930
- const lines = import_fs25.default.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
15165
+ if (!import_fs26.default.existsSync(AUDIT_LOG_FILE)) return [];
15166
+ const lines = import_fs26.default.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
14931
15167
  if (lines.length === 1 && lines[0] === "") return [];
14932
15168
  return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
14933
15169
  } catch {
@@ -14936,7 +15172,7 @@ function getAuditHistory(limit = 20) {
14936
15172
  }
14937
15173
  function getOrgName() {
14938
15174
  try {
14939
- if (import_fs25.default.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
15175
+ if (import_fs26.default.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
14940
15176
  } catch {
14941
15177
  }
14942
15178
  return null;
@@ -14944,8 +15180,8 @@ function getOrgName() {
14944
15180
  function writeGlobalSetting(key, value) {
14945
15181
  let config = {};
14946
15182
  try {
14947
- if (import_fs25.default.existsSync(GLOBAL_CONFIG_FILE)) {
14948
- config = JSON.parse(import_fs25.default.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
15183
+ if (import_fs26.default.existsSync(GLOBAL_CONFIG_FILE)) {
15184
+ config = JSON.parse(import_fs26.default.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
14949
15185
  }
14950
15186
  } catch {
14951
15187
  }
@@ -14957,8 +15193,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
14957
15193
  try {
14958
15194
  let trust = { entries: [] };
14959
15195
  try {
14960
- if (import_fs25.default.existsSync(TRUST_FILE2))
14961
- trust = JSON.parse(import_fs25.default.readFileSync(TRUST_FILE2, "utf-8"));
15196
+ if (import_fs26.default.existsSync(TRUST_FILE2))
15197
+ trust = JSON.parse(import_fs26.default.readFileSync(TRUST_FILE2, "utf-8"));
14962
15198
  } catch {
14963
15199
  }
14964
15200
  trust.entries = trust.entries.filter(
@@ -14975,8 +15211,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
14975
15211
  }
14976
15212
  function readPersistentDecisions() {
14977
15213
  try {
14978
- if (import_fs25.default.existsSync(DECISIONS_FILE)) {
14979
- return JSON.parse(import_fs25.default.readFileSync(DECISIONS_FILE, "utf-8"));
15214
+ if (import_fs26.default.existsSync(DECISIONS_FILE)) {
15215
+ return JSON.parse(import_fs26.default.readFileSync(DECISIONS_FILE, "utf-8"));
14980
15216
  }
14981
15217
  } catch {
14982
15218
  }
@@ -15004,7 +15240,7 @@ function estimateToolCost(tool, args) {
15004
15240
  const filePath = a.file_path ?? a.path;
15005
15241
  if (filePath) {
15006
15242
  try {
15007
- const bytes = import_fs25.default.statSync(filePath).size;
15243
+ const bytes = import_fs26.default.statSync(filePath).size;
15008
15244
  return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
15009
15245
  } catch {
15010
15246
  }
@@ -15075,7 +15311,7 @@ function abandonPending() {
15075
15311
  });
15076
15312
  if (autoStarted) {
15077
15313
  try {
15078
- import_fs25.default.unlinkSync(DAEMON_PID_FILE);
15314
+ import_fs26.default.unlinkSync(DAEMON_PID_FILE);
15079
15315
  } catch {
15080
15316
  }
15081
15317
  setTimeout(() => {
@@ -15086,8 +15322,8 @@ function abandonPending() {
15086
15322
  }
15087
15323
  function logActivitySocket(msg) {
15088
15324
  try {
15089
- import_fs25.default.appendFileSync(
15090
- import_path27.default.join(homeDir, ".node9", "hook-debug.log"),
15325
+ import_fs26.default.appendFileSync(
15326
+ import_path28.default.join(homeDir, ".node9", "hook-debug.log"),
15091
15327
  `[${(/* @__PURE__ */ new Date()).toISOString()}] [activity-socket] ${msg}
15092
15328
  `
15093
15329
  );
@@ -15109,13 +15345,13 @@ function shouldRebind(now = Date.now()) {
15109
15345
  function startActivitySocket() {
15110
15346
  bindActivitySocket();
15111
15347
  activityHealthInterval = setInterval(() => {
15112
- if (!import_fs25.default.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
15348
+ if (!import_fs26.default.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
15113
15349
  }, ACTIVITY_HEALTH_PROBE_MS);
15114
15350
  activityHealthInterval.unref();
15115
15351
  process.on("exit", () => {
15116
15352
  if (activityHealthInterval) clearInterval(activityHealthInterval);
15117
15353
  try {
15118
- import_fs25.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
15354
+ import_fs26.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
15119
15355
  } catch {
15120
15356
  }
15121
15357
  });
@@ -15143,7 +15379,7 @@ function attemptRebind(reason) {
15143
15379
  }
15144
15380
  function bindActivitySocket() {
15145
15381
  try {
15146
- import_fs25.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
15382
+ import_fs26.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
15147
15383
  } catch {
15148
15384
  }
15149
15385
  const ACTIVITY_MAX_BYTES = 1024 * 1024;
@@ -15230,318 +15466,97 @@ function bindActivitySocket() {
15230
15466
  costEstimate,
15231
15467
  agent: data.agent,
15232
15468
  mcpServer: data.mcpServer,
15233
- 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"))
15469
+ sessionId: data.sessionId
15470
+ });
15471
+ }
15472
+ } catch {
15543
15473
  }
15544
- ];
15474
+ });
15475
+ socket.on("error", () => {
15476
+ });
15477
+ });
15478
+ unixServer.on("error", (err2) => {
15479
+ logActivitySocket(`server error: ${err2.message}`);
15480
+ });
15481
+ unixServer.listen(ACTIVITY_SOCKET_PATH2, () => {
15482
+ logActivitySocket(`bound to ${ACTIVITY_SOCKET_PATH2}`);
15483
+ });
15484
+ activitySocketServer = unixServer;
15485
+ }
15486
+ 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;
15487
+ var init_state2 = __esm({
15488
+ "src/daemon/state.ts"() {
15489
+ "use strict";
15490
+ import_net2 = __toESM(require("net"));
15491
+ import_fs26 = __toESM(require("fs"));
15492
+ import_path28 = __toESM(require("path"));
15493
+ import_os24 = __toESM(require("os"));
15494
+ import_crypto8 = require("crypto");
15495
+ init_daemon();
15496
+ init_suggestion_tracker();
15497
+ init_taint_store();
15498
+ init_session_counters();
15499
+ init_session_history();
15500
+ homeDir = import_os24.default.homedir();
15501
+ DAEMON_PID_FILE = import_path28.default.join(homeDir, ".node9", "daemon.pid");
15502
+ DECISIONS_FILE = import_path28.default.join(homeDir, ".node9", "decisions.json");
15503
+ AUDIT_LOG_FILE = import_path28.default.join(homeDir, ".node9", "audit.log");
15504
+ TRUST_FILE2 = import_path28.default.join(homeDir, ".node9", "trust.json");
15505
+ GLOBAL_CONFIG_FILE = import_path28.default.join(homeDir, ".node9", "config.json");
15506
+ CREDENTIALS_FILE = import_path28.default.join(homeDir, ".node9", "credentials.json");
15507
+ INSIGHT_COUNTS_FILE = import_path28.default.join(homeDir, ".node9", "insight-counts.json");
15508
+ pending = /* @__PURE__ */ new Map();
15509
+ sseClients = /* @__PURE__ */ new Set();
15510
+ suggestionTracker = new SuggestionTracker(3);
15511
+ taintStore = new TaintStore();
15512
+ sessionTaintStore = new SessionTaintStore();
15513
+ insightCounts = /* @__PURE__ */ new Map();
15514
+ _abandonTimer = null;
15515
+ _hadBrowserClient = false;
15516
+ _daemonServer = null;
15517
+ daemonRejectionHandlerRegistered = false;
15518
+ AUTO_DENY_MS = 12e4;
15519
+ TRUST_DURATIONS = {
15520
+ "30m": 30 * 6e4,
15521
+ "1h": 60 * 6e4,
15522
+ "2h": 2 * 60 * 6e4
15523
+ };
15524
+ autoStarted = process.env.NODE9_AUTO_STARTED === "1";
15525
+ ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path28.default.join(import_os24.default.tmpdir(), "node9-activity.sock");
15526
+ ACTIVITY_RING_SIZE = 100;
15527
+ activityRing = [];
15528
+ LARGE_RESPONSE_RING_SIZE = 20;
15529
+ largeResponseRing = [];
15530
+ cachedScanResult = null;
15531
+ cachedScanTs = 0;
15532
+ SCAN_CACHE_TTL_MS = 5 * 60 * 1e3;
15533
+ SECRET_KEY_RE = /password|secret|token|key|apikey|credential|auth/i;
15534
+ INPUT_PRICE_PER_1M = 3;
15535
+ OUTPUT_PRICE_PER_1M = 15;
15536
+ BYTES_PER_TOKEN = 4;
15537
+ CRITICAL_FORENSIC_CATEGORIES = /* @__PURE__ */ new Set([
15538
+ "privilege-escalation",
15539
+ "destructive-op",
15540
+ "eval-of-remote"
15541
+ ]);
15542
+ WRITE_TOOL_NAMES = /* @__PURE__ */ new Set([
15543
+ "write",
15544
+ "write_file",
15545
+ "create_file",
15546
+ "edit",
15547
+ "multiedit",
15548
+ "str_replace_based_edit_tool",
15549
+ "replace",
15550
+ "notebook_edit",
15551
+ "notebookedit"
15552
+ ]);
15553
+ ACTIVITY_REBIND_MAX_ATTEMPTS = 5;
15554
+ ACTIVITY_REBIND_WINDOW_MS = 6e4;
15555
+ ACTIVITY_HEALTH_PROBE_MS = 2e3;
15556
+ activitySocketServer = null;
15557
+ activityHealthInterval = null;
15558
+ activityRebindAttempts = [];
15559
+ activityCircuitTripped = false;
15545
15560
  }
15546
15561
  });
15547
15562
 
@@ -16643,6 +16658,93 @@ var init_ship = __esm({
16643
16658
  }
16644
16659
  });
16645
16660
 
16661
+ // src/policy-snapshot/build.ts
16662
+ function buildPolicySnapshot(config, activeShields, overrides) {
16663
+ const p = config.policy;
16664
+ return {
16665
+ mode: config.settings.mode,
16666
+ panicMode: config.settings.panicMode === true,
16667
+ // The proxy expresses shadow/observe as mode === 'observe' (cloud shadowMode
16668
+ // forces it); there's no separate settings flag.
16669
+ shadowMode: config.settings.mode === "observe",
16670
+ activeShields,
16671
+ shieldOverrides: overrides,
16672
+ smartRuleCount: p.smartRules.length,
16673
+ smartRules: p.smartRules.slice(0, MAX_RULES).map((r) => ({
16674
+ name: r.name,
16675
+ tool: r.tool,
16676
+ verdict: r.verdict,
16677
+ reason: r.reason
16678
+ })),
16679
+ egress: {
16680
+ enabled: p.egress.enabled,
16681
+ mode: p.egress.mode,
16682
+ allow: p.egress.allow.slice(0, MAX_EGRESS)
16683
+ },
16684
+ dlpEnabled: p.dlp.enabled,
16685
+ engineVersion: ENGINE_VERSION
16686
+ };
16687
+ }
16688
+ var MAX_RULES, MAX_EGRESS;
16689
+ var init_build = __esm({
16690
+ "src/policy-snapshot/build.ts"() {
16691
+ "use strict";
16692
+ init_dist();
16693
+ MAX_RULES = 500;
16694
+ MAX_EGRESS = 200;
16695
+ }
16696
+ });
16697
+
16698
+ // src/policy-snapshot/ship.ts
16699
+ function policySnapshotUrlFrom(apiUrl) {
16700
+ return apiUrl.endsWith("/policies/sync") ? apiUrl.replace(/\/policies\/sync$/, "/policy/snapshot") : null;
16701
+ }
16702
+ async function shipPolicySnapshot(body, creds) {
16703
+ const url = policySnapshotUrlFrom(creds.apiUrl);
16704
+ if (!url) return false;
16705
+ const payload = JSON.stringify(body);
16706
+ const parsed = new import_url2.URL(url);
16707
+ const transport = parsed.protocol === "http:" ? import_http2.default : import_https3.default;
16708
+ return new Promise((resolve) => {
16709
+ const req = transport.request(
16710
+ {
16711
+ hostname: parsed.hostname,
16712
+ port: parsed.port ? parseInt(parsed.port, 10) : void 0,
16713
+ path: parsed.pathname + parsed.search,
16714
+ method: "POST",
16715
+ headers: {
16716
+ "Content-Type": "application/json",
16717
+ "Content-Length": Buffer.byteLength(payload),
16718
+ Authorization: `Bearer ${creds.apiKey}`
16719
+ },
16720
+ timeout: 1e4
16721
+ },
16722
+ (res) => {
16723
+ const ok2 = !!res.statusCode && res.statusCode >= 200 && res.statusCode < 300;
16724
+ res.resume();
16725
+ res.on("end", () => resolve(ok2));
16726
+ res.on("error", () => resolve(false));
16727
+ }
16728
+ );
16729
+ req.on("error", () => resolve(false));
16730
+ req.on("timeout", () => {
16731
+ req.destroy();
16732
+ resolve(false);
16733
+ });
16734
+ req.write(payload);
16735
+ req.end();
16736
+ });
16737
+ }
16738
+ var import_http2, import_https3, import_url2;
16739
+ var init_ship2 = __esm({
16740
+ "src/policy-snapshot/ship.ts"() {
16741
+ "use strict";
16742
+ import_http2 = __toESM(require("http"));
16743
+ import_https3 = __toESM(require("https"));
16744
+ import_url2 = require("url");
16745
+ }
16746
+ });
16747
+
16646
16748
  // src/daemon/sync.ts
16647
16749
  function emptySignals3() {
16648
16750
  return {
@@ -16724,7 +16826,7 @@ function fetchCloudPolicy(apiKey, apiUrl, ifNoneMatch) {
16724
16826
  };
16725
16827
  if (ifNoneMatch) headers["If-None-Match"] = `"${ifNoneMatch}"`;
16726
16828
  return new Promise((resolve, reject) => {
16727
- const req = import_https3.default.request(
16829
+ const req = import_https4.default.request(
16728
16830
  {
16729
16831
  hostname: parsed.hostname,
16730
16832
  port: parsed.port ? parseInt(parsed.port, 10) : void 0,
@@ -16804,6 +16906,9 @@ async function syncOnce() {
16804
16906
  if (process.env.NODE9_POSTURE_DISABLE !== "1") {
16805
16907
  void pushPostureSnapshot(creds);
16806
16908
  }
16909
+ if (process.env.NODE9_POLICY_MIRROR_DISABLE !== "1") {
16910
+ void pushPolicySnapshot(creds);
16911
+ }
16807
16912
  }
16808
16913
  async function pushBlastSnapshot(creds) {
16809
16914
  try {
@@ -16813,7 +16918,7 @@ async function pushBlastSnapshot(creds) {
16813
16918
  if (!blastUrl) return;
16814
16919
  const parsed = new URL(blastUrl);
16815
16920
  await new Promise((resolve) => {
16816
- const req = import_https3.default.request(
16921
+ const req = import_https4.default.request(
16817
16922
  {
16818
16923
  hostname: parsed.hostname,
16819
16924
  port: parsed.port ? parseInt(parsed.port, 10) : void 0,
@@ -16850,6 +16955,29 @@ async function pushPostureSnapshot(creds) {
16850
16955
  } catch {
16851
16956
  }
16852
16957
  }
16958
+ async function pushPolicySnapshot(creds) {
16959
+ try {
16960
+ const body = buildPolicySnapshot(getConfig(), readActiveShields(), readShieldOverrides());
16961
+ await shipPolicySnapshot(body, creds);
16962
+ } catch {
16963
+ }
16964
+ }
16965
+ async function runPolicyPush() {
16966
+ const creds = readCredentials();
16967
+ if (!creds) {
16968
+ return {
16969
+ ok: false,
16970
+ reason: "No API key configured. Add credentials with: node9 login"
16971
+ };
16972
+ }
16973
+ try {
16974
+ const body = buildPolicySnapshot(getConfig(), readActiveShields(), readShieldOverrides());
16975
+ const sent = await shipPolicySnapshot(body, creds);
16976
+ return sent ? { ok: true } : { ok: false, reason: "Push failed (network or server error)" };
16977
+ } catch (e) {
16978
+ return { ok: false, reason: e instanceof Error ? e.message : String(e) };
16979
+ }
16980
+ }
16853
16981
  async function pushScanSnapshot(creds) {
16854
16982
  try {
16855
16983
  const tick = await tickScanWatcher();
@@ -16867,7 +16995,7 @@ async function pushScanSnapshot(creds) {
16867
16995
  const parsed = new URL(scanUrl);
16868
16996
  let posted = false;
16869
16997
  await new Promise((resolve) => {
16870
- const req = import_https3.default.request(
16998
+ const req = import_https4.default.request(
16871
16999
  {
16872
17000
  hostname: parsed.hostname,
16873
17001
  port: parsed.port ? parseInt(parsed.port, 10) : void 0,
@@ -16917,6 +17045,9 @@ async function runCloudSync() {
16917
17045
  if (process.env.NODE9_POSTURE_DISABLE !== "1") {
16918
17046
  void pushPostureSnapshot(creds);
16919
17047
  }
17048
+ if (process.env.NODE9_POLICY_MIRROR_DISABLE !== "1") {
17049
+ void pushPolicySnapshot(creds);
17050
+ }
16920
17051
  };
16921
17052
  try {
16922
17053
  const result = await fetchCloudPolicy(creds.apiKey, creds.apiUrl, readCachedEtag());
@@ -16995,18 +17126,21 @@ function startForensicBroadcast() {
16995
17126
  const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
16996
17127
  recurring.unref();
16997
17128
  }
16998
- var import_fs32, import_https3, import_os29, import_path31, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_HOURS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
17129
+ var import_fs32, import_https4, import_os29, import_path31, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_HOURS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
16999
17130
  var init_sync = __esm({
17000
17131
  "src/daemon/sync.ts"() {
17001
17132
  "use strict";
17002
17133
  import_fs32 = __toESM(require("fs"));
17003
- import_https3 = __toESM(require("https"));
17134
+ import_https4 = __toESM(require("https"));
17004
17135
  import_os29 = __toESM(require("os"));
17005
17136
  import_path31 = __toESM(require("path"));
17006
17137
  init_config();
17007
17138
  init_blast();
17008
17139
  init_posture();
17009
17140
  init_ship();
17141
+ init_build();
17142
+ init_ship2();
17143
+ init_shields();
17010
17144
  init_dist();
17011
17145
  init_scan_watermark();
17012
17146
  init_state2();
@@ -17509,7 +17643,7 @@ function startDaemon() {
17509
17643
  }
17510
17644
  resetIdleTimer();
17511
17645
  const allowedHosts = /* @__PURE__ */ new Set([`127.0.0.1:${DAEMON_PORT}`, `localhost:${DAEMON_PORT}`]);
17512
- const server = import_http2.default.createServer(async (req, res) => {
17646
+ const server = import_http3.default.createServer(async (req, res) => {
17513
17647
  const host = req.headers.host ?? "";
17514
17648
  if (!allowedHosts.has(host)) {
17515
17649
  res.writeHead(421, { "Content-Type": "text/plain" });
@@ -18411,11 +18545,11 @@ data: ${JSON.stringify(item.data)}
18411
18545
  }
18412
18546
  startActivitySocket();
18413
18547
  }
18414
- var import_http2, import_fs36, import_path35, import_os33, import_crypto10, import_child_process2, import_chalk6;
18548
+ var import_http3, import_fs36, import_path35, import_os33, import_crypto10, import_child_process2, import_chalk6;
18415
18549
  var init_server = __esm({
18416
18550
  "src/daemon/server.ts"() {
18417
18551
  "use strict";
18418
- import_http2 = __toESM(require("http"));
18552
+ import_http3 = __toESM(require("http"));
18419
18553
  import_fs36 = __toESM(require("fs"));
18420
18554
  import_path35 = __toESM(require("path"));
18421
18555
  import_os33 = __toESM(require("os"));
@@ -18772,18 +18906,18 @@ function getModelContextLimit(model) {
18772
18906
  return 2e5;
18773
18907
  }
18774
18908
  function readSessionUsage() {
18775
- const projectsDir = import_path61.default.join(import_os54.default.homedir(), ".claude", "projects");
18909
+ const projectsDir = import_path62.default.join(import_os55.default.homedir(), ".claude", "projects");
18776
18910
  if (!import_fs64.default.existsSync(projectsDir)) return null;
18777
18911
  let latestFile = null;
18778
18912
  let latestMtime = 0;
18779
18913
  try {
18780
18914
  for (const dir of import_fs64.default.readdirSync(projectsDir)) {
18781
- const dirPath = import_path61.default.join(projectsDir, dir);
18915
+ const dirPath = import_path62.default.join(projectsDir, dir);
18782
18916
  try {
18783
18917
  if (!import_fs64.default.statSync(dirPath).isDirectory()) continue;
18784
18918
  for (const file of import_fs64.default.readdirSync(dirPath)) {
18785
18919
  if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
18786
- const filePath = import_path61.default.join(dirPath, file);
18920
+ const filePath = import_path62.default.join(dirPath, file);
18787
18921
  try {
18788
18922
  const mtime = import_fs64.default.statSync(filePath).mtimeMs;
18789
18923
  if (mtime > latestMtime) {
@@ -18861,7 +18995,7 @@ function formatBase(activity) {
18861
18995
  const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
18862
18996
  const icon = getIcon(activity.tool);
18863
18997
  const toolName = activity.tool.slice(0, 16).padEnd(16);
18864
- const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os54.default.homedir(), "~");
18998
+ const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os55.default.homedir(), "~");
18865
18999
  const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
18866
19000
  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
19001
  }
@@ -18943,7 +19077,7 @@ function postDecisionHttp(id, decision, authToken, port, opts) {
18943
19077
  if (opts?.trustDuration) bodyObj.trustDuration = opts.trustDuration;
18944
19078
  if (opts?.reason) bodyObj.reason = opts.reason;
18945
19079
  const body = JSON.stringify(bodyObj);
18946
- const req = import_http3.default.request(
19080
+ const req = import_http4.default.request(
18947
19081
  {
18948
19082
  hostname: "127.0.0.1",
18949
19083
  port,
@@ -19058,7 +19192,7 @@ function buildRecoveryCardLines(req) {
19058
19192
  ];
19059
19193
  }
19060
19194
  function readApproversFromDisk() {
19061
- const configPath = import_path61.default.join(import_os54.default.homedir(), ".node9", "config.json");
19195
+ const configPath = import_path62.default.join(import_os55.default.homedir(), ".node9", "config.json");
19062
19196
  try {
19063
19197
  const raw = JSON.parse(import_fs64.default.readFileSync(configPath, "utf-8"));
19064
19198
  const settings = raw.settings ?? {};
@@ -19076,7 +19210,7 @@ function approverStatusLine() {
19076
19210
  return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
19077
19211
  }
19078
19212
  function toggleApprover(channel) {
19079
- const configPath = import_path61.default.join(import_os54.default.homedir(), ".node9", "config.json");
19213
+ const configPath = import_path62.default.join(import_os55.default.homedir(), ".node9", "config.json");
19080
19214
  try {
19081
19215
  const raw = JSON.parse(import_fs64.default.readFileSync(configPath, "utf-8"));
19082
19216
  const settings = raw.settings ?? {};
@@ -19094,7 +19228,7 @@ async function startTail(options = {}) {
19094
19228
  const port = await ensureDaemon();
19095
19229
  if (options.clear) {
19096
19230
  const result = await new Promise((resolve) => {
19097
- const req2 = import_http3.default.request(
19231
+ const req2 = import_http4.default.request(
19098
19232
  { method: "POST", hostname: "127.0.0.1", port, path: "/events/clear" },
19099
19233
  (res) => {
19100
19234
  const status = res.statusCode ?? 0;
@@ -19257,7 +19391,7 @@ async function startTail(options = {}) {
19257
19391
  postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
19258
19392
  try {
19259
19393
  import_fs64.default.appendFileSync(
19260
- import_path61.default.join(import_os54.default.homedir(), ".node9", "hook-debug.log"),
19394
+ import_path62.default.join(import_os55.default.homedir(), ".node9", "hook-debug.log"),
19261
19395
  `[tail] POST /decision failed: ${String(err2)}
19262
19396
  `
19263
19397
  );
@@ -19321,7 +19455,7 @@ async function startTail(options = {}) {
19321
19455
  };
19322
19456
  process.stdin.on("keypress", onKeypress);
19323
19457
  }
19324
- const auditLog = import_path61.default.join(import_os54.default.homedir(), ".node9", "audit.log");
19458
+ const auditLog = import_path62.default.join(import_os55.default.homedir(), ".node9", "audit.log");
19325
19459
  try {
19326
19460
  const unackedDlp = import_fs64.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
19327
19461
  if (unackedDlp > 0) {
@@ -19377,7 +19511,7 @@ async function startTail(options = {}) {
19377
19511
  }, STALL_THRESHOLD_MS / 2);
19378
19512
  stallWatchdog.unref();
19379
19513
  const sseUrl = `http://127.0.0.1:${port}/events?capabilities=input`;
19380
- const req = import_http3.default.get(
19514
+ const req = import_http4.default.get(
19381
19515
  sseUrl,
19382
19516
  {
19383
19517
  headers: authToken ? { "X-Node9-Internal": authToken } : {}
@@ -19548,20 +19682,20 @@ async function startTail(options = {}) {
19548
19682
  process.exit(1);
19549
19683
  });
19550
19684
  }
19551
- var import_http3, import_chalk35, import_fs64, import_os54, import_path61, 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;
19685
+ 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
19686
  var init_tail = __esm({
19553
19687
  "src/tui/tail.ts"() {
19554
19688
  "use strict";
19555
- import_http3 = __toESM(require("http"));
19689
+ import_http4 = __toESM(require("http"));
19556
19690
  import_chalk35 = __toESM(require("chalk"));
19557
19691
  import_fs64 = __toESM(require("fs"));
19558
- import_os54 = __toESM(require("os"));
19559
- import_path61 = __toESM(require("path"));
19692
+ import_os55 = __toESM(require("os"));
19693
+ import_path62 = __toESM(require("path"));
19560
19694
  import_readline6 = __toESM(require("readline"));
19561
19695
  import_child_process14 = require("child_process");
19562
19696
  init_daemon2();
19563
19697
  init_daemon();
19564
- PID_FILE = import_path61.default.join(import_os54.default.homedir(), ".node9", "daemon.pid");
19698
+ PID_FILE = import_path62.default.join(import_os55.default.homedir(), ".node9", "daemon.pid");
19565
19699
  ICONS = {
19566
19700
  bash: "\u{1F4BB}",
19567
19701
  shell: "\u{1F4BB}",
@@ -19626,7 +19760,7 @@ function queryDaemon() {
19626
19760
  return new Promise((resolve) => {
19627
19761
  const timeout = setTimeout(() => resolve(null), 50);
19628
19762
  try {
19629
- const req = import_http4.default.get(
19763
+ const req = import_http5.default.get(
19630
19764
  `http://${DAEMON_HOST}:${DAEMON_PORT}/status`,
19631
19765
  { timeout: 50 },
19632
19766
  (res) => {
@@ -19711,7 +19845,7 @@ function countRulesInDir(rulesDir) {
19711
19845
  try {
19712
19846
  for (const entry of import_fs65.default.readdirSync(rulesDir, { withFileTypes: true })) {
19713
19847
  if (entry.isDirectory()) {
19714
- count += countRulesInDir(import_path62.default.join(rulesDir, entry.name));
19848
+ count += countRulesInDir(import_path63.default.join(rulesDir, entry.name));
19715
19849
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
19716
19850
  count++;
19717
19851
  }
@@ -19722,46 +19856,46 @@ function countRulesInDir(rulesDir) {
19722
19856
  }
19723
19857
  function isSamePath(a, b) {
19724
19858
  try {
19725
- return import_path62.default.resolve(a) === import_path62.default.resolve(b);
19859
+ return import_path63.default.resolve(a) === import_path63.default.resolve(b);
19726
19860
  } catch {
19727
19861
  return false;
19728
19862
  }
19729
19863
  }
19730
19864
  function countConfigs(cwd) {
19731
- const homeDir2 = import_os55.default.homedir();
19732
- const claudeDir = import_path62.default.join(homeDir2, ".claude");
19865
+ const homeDir2 = import_os56.default.homedir();
19866
+ const claudeDir = import_path63.default.join(homeDir2, ".claude");
19733
19867
  let claudeMdCount = 0;
19734
19868
  let rulesCount = 0;
19735
19869
  let hooksCount = 0;
19736
19870
  const userMcpServers = /* @__PURE__ */ new Set();
19737
19871
  const projectMcpServers = /* @__PURE__ */ new Set();
19738
- if (import_fs65.default.existsSync(import_path62.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
19739
- rulesCount += countRulesInDir(import_path62.default.join(claudeDir, "rules"));
19740
- const userSettings = import_path62.default.join(claudeDir, "settings.json");
19872
+ if (import_fs65.default.existsSync(import_path63.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
19873
+ rulesCount += countRulesInDir(import_path63.default.join(claudeDir, "rules"));
19874
+ const userSettings = import_path63.default.join(claudeDir, "settings.json");
19741
19875
  for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
19742
19876
  hooksCount += countHooksInFile(userSettings);
19743
- const userClaudeJson = import_path62.default.join(homeDir2, ".claude.json");
19877
+ const userClaudeJson = import_path63.default.join(homeDir2, ".claude.json");
19744
19878
  for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
19745
19879
  for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
19746
19880
  userMcpServers.delete(name);
19747
19881
  }
19748
19882
  if (cwd) {
19749
- if (import_fs65.default.existsSync(import_path62.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
19750
- if (import_fs65.default.existsSync(import_path62.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
19751
- const projectClaudeDir = import_path62.default.join(cwd, ".claude");
19883
+ if (import_fs65.default.existsSync(import_path63.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
19884
+ if (import_fs65.default.existsSync(import_path63.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
19885
+ const projectClaudeDir = import_path63.default.join(cwd, ".claude");
19752
19886
  const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
19753
19887
  if (!overlapsUserScope) {
19754
- if (import_fs65.default.existsSync(import_path62.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
19755
- rulesCount += countRulesInDir(import_path62.default.join(projectClaudeDir, "rules"));
19756
- const projSettings = import_path62.default.join(projectClaudeDir, "settings.json");
19888
+ if (import_fs65.default.existsSync(import_path63.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
19889
+ rulesCount += countRulesInDir(import_path63.default.join(projectClaudeDir, "rules"));
19890
+ const projSettings = import_path63.default.join(projectClaudeDir, "settings.json");
19757
19891
  for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
19758
19892
  hooksCount += countHooksInFile(projSettings);
19759
19893
  }
19760
- if (import_fs65.default.existsSync(import_path62.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
19761
- const localSettings = import_path62.default.join(projectClaudeDir, "settings.local.json");
19894
+ if (import_fs65.default.existsSync(import_path63.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
19895
+ const localSettings = import_path63.default.join(projectClaudeDir, "settings.local.json");
19762
19896
  for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
19763
19897
  hooksCount += countHooksInFile(localSettings);
19764
- const mcpJsonServers = getMcpServerNames(import_path62.default.join(cwd, ".mcp.json"));
19898
+ const mcpJsonServers = getMcpServerNames(import_path63.default.join(cwd, ".mcp.json"));
19765
19899
  const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
19766
19900
  for (const name of disabledMcpJson) mcpJsonServers.delete(name);
19767
19901
  for (const name of mcpJsonServers) projectMcpServers.add(name);
@@ -19794,7 +19928,7 @@ function readActiveShieldsHud() {
19794
19928
  return shieldsCache.value;
19795
19929
  }
19796
19930
  try {
19797
- const shieldsPath = import_path62.default.join(import_os55.default.homedir(), ".node9", "shields.json");
19931
+ const shieldsPath = import_path63.default.join(import_os56.default.homedir(), ".node9", "shields.json");
19798
19932
  if (!import_fs65.default.existsSync(shieldsPath)) {
19799
19933
  shieldsCache = { value: [], ts: now };
19800
19934
  return [];
@@ -19901,9 +20035,9 @@ function renderContextLine(stdin) {
19901
20035
  async function main() {
19902
20036
  try {
19903
20037
  const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
19904
- if (import_fs65.default.existsSync(import_path62.default.join(import_os55.default.homedir(), ".node9", "hud-debug"))) {
20038
+ if (import_fs65.default.existsSync(import_path63.default.join(import_os56.default.homedir(), ".node9", "hud-debug"))) {
19905
20039
  try {
19906
- const logPath = import_path62.default.join(import_os55.default.homedir(), ".node9", "hud-debug.log");
20040
+ const logPath = import_path63.default.join(import_os56.default.homedir(), ".node9", "hud-debug.log");
19907
20041
  const MAX_LOG_SIZE = 10 * 1024 * 1024;
19908
20042
  let size = 0;
19909
20043
  try {
@@ -19932,8 +20066,8 @@ async function main() {
19932
20066
  try {
19933
20067
  const cwd = stdin.cwd ?? process.cwd();
19934
20068
  for (const configPath of [
19935
- import_path62.default.join(cwd, "node9.config.json"),
19936
- import_path62.default.join(import_os55.default.homedir(), ".node9", "config.json")
20069
+ import_path63.default.join(cwd, "node9.config.json"),
20070
+ import_path63.default.join(import_os56.default.homedir(), ".node9", "config.json")
19937
20071
  ]) {
19938
20072
  if (!import_fs65.default.existsSync(configPath)) continue;
19939
20073
  const cfg = JSON.parse(import_fs65.default.readFileSync(configPath, "utf-8"));
@@ -19954,14 +20088,14 @@ async function main() {
19954
20088
  renderOffline();
19955
20089
  }
19956
20090
  }
19957
- var import_fs65, import_path62, import_os55, import_http4, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
20091
+ 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
20092
  var init_hud = __esm({
19959
20093
  "src/cli/hud.ts"() {
19960
20094
  "use strict";
19961
20095
  import_fs65 = __toESM(require("fs"));
19962
- import_path62 = __toESM(require("path"));
19963
- import_os55 = __toESM(require("os"));
19964
- import_http4 = __toESM(require("http"));
20096
+ import_path63 = __toESM(require("path"));
20097
+ import_os56 = __toESM(require("os"));
20098
+ import_http5 = __toESM(require("http"));
19965
20099
  init_daemon();
19966
20100
  RESET3 = "\x1B[0m";
19967
20101
  BOLD3 = "\x1B[1m";
@@ -19985,11 +20119,44 @@ var init_hud = __esm({
19985
20119
  var import_commander = require("commander");
19986
20120
  init_core();
19987
20121
  init_setup();
20122
+
20123
+ // src/agent-teardowns.ts
20124
+ init_setup();
20125
+ var AGENT_TEARDOWNS = [
20126
+ { id: "claude", label: "Claude", fn: teardownClaude },
20127
+ { id: "gemini", label: "Gemini", fn: teardownGemini },
20128
+ { id: "codex", label: "Codex", fn: teardownCodex },
20129
+ { id: "cursor", label: "Cursor", fn: teardownCursor },
20130
+ { id: "windsurf", label: "Windsurf", fn: teardownWindsurf },
20131
+ { id: "vscode", label: "VSCode", fn: teardownVSCode },
20132
+ { id: "hermes", label: "Hermes", fn: teardownHermes },
20133
+ { id: "antigravity", label: "Antigravity", fn: teardownAntigravity, aliases: ["agy"] },
20134
+ { id: "copilot", label: "Copilot", fn: teardownCopilot },
20135
+ { id: "hud", label: "HUD", fn: teardownHud },
20136
+ {
20137
+ id: "claudedesktop",
20138
+ label: "Claude Desktop",
20139
+ fn: teardownClaudeDesktop,
20140
+ aliases: ["claude-desktop"]
20141
+ },
20142
+ { id: "opencode", label: "OpenCode", fn: teardownOpencode },
20143
+ { id: "pi", label: "Pi", fn: teardownPi }
20144
+ ];
20145
+ function resolveAgentTeardown(target) {
20146
+ const t = target.trim().toLowerCase();
20147
+ return AGENT_TEARDOWNS.find((a) => a.id === t || a.aliases?.includes(t));
20148
+ }
20149
+ function agentTeardownTargets() {
20150
+ return AGENT_TEARDOWNS.flatMap((a) => [a.id, ...a.aliases ?? []]);
20151
+ }
20152
+
20153
+ // src/cli.ts
20154
+ init_agent_wiring();
19988
20155
  init_daemon2();
19989
20156
  var import_chalk36 = __toESM(require("chalk"));
19990
20157
  var import_fs66 = __toESM(require("fs"));
19991
- var import_path63 = __toESM(require("path"));
19992
- var import_os56 = __toESM(require("os"));
20158
+ var import_path64 = __toESM(require("path"));
20159
+ var import_os57 = __toESM(require("os"));
19993
20160
  var import_child_process15 = require("child_process");
19994
20161
  var import_prompts2 = require("@inquirer/prompts");
19995
20162
 
@@ -21619,6 +21786,8 @@ function registerLogCommand(program2) {
21619
21786
  // src/cli/commands/shield.ts
21620
21787
  var import_chalk10 = __toESM(require("chalk"));
21621
21788
  var import_fs46 = __toESM(require("fs"));
21789
+ var import_path44 = __toESM(require("path"));
21790
+ var import_os40 = __toESM(require("os"));
21622
21791
  init_shields();
21623
21792
 
21624
21793
  // src/shields/build.ts
@@ -21749,10 +21918,10 @@ init_audit();
21749
21918
  init_config();
21750
21919
 
21751
21920
  // src/utils/https-fetch.ts
21752
- var import_https4 = __toESM(require("https"));
21921
+ var import_https5 = __toESM(require("https"));
21753
21922
  function httpsFetch(url) {
21754
21923
  return new Promise((resolve, reject) => {
21755
- import_https4.default.get(url, (res) => {
21924
+ import_https5.default.get(url, (res) => {
21756
21925
  if (res.statusCode !== 200) {
21757
21926
  reject(new Error(`HTTP ${String(res.statusCode)} for ${url}`));
21758
21927
  res.resume();
@@ -21768,6 +21937,22 @@ function httpsFetch(url) {
21768
21937
 
21769
21938
  // src/cli/commands/shield.ts
21770
21939
  var COMMUNITY_INDEX_URL = "https://raw.githubusercontent.com/node9ai/node9-proxy/main/shields/community/index.json";
21940
+ function readCloudShields() {
21941
+ const out = /* @__PURE__ */ new Set();
21942
+ try {
21943
+ const file = import_path44.default.join(import_os40.default.homedir(), ".node9", "rules-cache.json");
21944
+ const raw = JSON.parse(import_fs46.default.readFileSync(file, "utf-8"));
21945
+ for (const r of raw.rules ?? []) {
21946
+ const rule = r;
21947
+ const fromSource = rule.source?.startsWith("SHIELD:") ? rule.source.slice("SHIELD:".length).toLowerCase() : void 0;
21948
+ const fromDesc = !fromSource && rule.description ? /\b([a-z0-9-]+)\s+shield/i.exec(rule.description)?.[1]?.toLowerCase() : void 0;
21949
+ const name = fromSource ?? fromDesc;
21950
+ if (name) out.add(name);
21951
+ }
21952
+ } catch {
21953
+ }
21954
+ return out;
21955
+ }
21771
21956
  function registerShieldCommand(program2) {
21772
21957
  const shieldCmd = program2.command("shield").description("Manage pre-packaged security shield templates");
21773
21958
  shieldCmd.command("enable <service>").description("Enable a security shield for a specific service").action((service) => {
@@ -21854,10 +22039,17 @@ function registerShieldCommand(program2) {
21854
22039
  return;
21855
22040
  }
21856
22041
  const active = new Set(readActiveShields());
22042
+ const cloud = readCloudShields();
21857
22043
  console.log(import_chalk10.default.bold("\n\u{1F6E1}\uFE0F Available Shields\n"));
22044
+ console.log(import_chalk10.default.gray(" \u25CF local \xB7 \u2601 cloud\n"));
21858
22045
  for (const shield of listShields()) {
21859
- const status = active.has(shield.name) ? import_chalk10.default.green("\u25CF enabled") : import_chalk10.default.gray("\u25CB disabled");
21860
- console.log(` ${status} ${import_chalk10.default.cyan(shield.name.padEnd(12))} ${shield.description}`);
22046
+ const isLocal = active.has(shield.name);
22047
+ const isCloud = cloud.has(shield.name);
22048
+ 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");
22049
+ const via = isCloud && !isLocal ? import_chalk10.default.gray(" (via dashboard)") : "";
22050
+ console.log(
22051
+ ` ${status} ${import_chalk10.default.cyan(shield.name.padEnd(12))} ${shield.description}${via}`
22052
+ );
21861
22053
  if (shield.aliases.length > 0)
21862
22054
  console.log(import_chalk10.default.gray(` aliases: ${shield.aliases.join(", ")}`));
21863
22055
  }
@@ -22187,15 +22379,15 @@ function registerConfigShowCommand(program2) {
22187
22379
  // src/cli/commands/doctor.ts
22188
22380
  var import_chalk11 = __toESM(require("chalk"));
22189
22381
  var import_fs47 = __toESM(require("fs"));
22190
- var import_path44 = __toESM(require("path"));
22191
- var import_os40 = __toESM(require("os"));
22382
+ var import_path45 = __toESM(require("path"));
22383
+ var import_os41 = __toESM(require("os"));
22192
22384
  var import_child_process8 = require("child_process");
22193
22385
  init_daemon();
22194
22386
  init_config();
22195
22387
  init_agent_wiring();
22196
22388
  function registerDoctorCommand(program2, version2) {
22197
22389
  program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
22198
- const homeDir2 = import_os40.default.homedir();
22390
+ const homeDir2 = import_os41.default.homedir();
22199
22391
  let failures = 0;
22200
22392
  function pass(msg) {
22201
22393
  console.log(import_chalk11.default.green(" \u2705 ") + msg);
@@ -22241,7 +22433,7 @@ function registerDoctorCommand(program2, version2) {
22241
22433
  );
22242
22434
  }
22243
22435
  section("Configuration");
22244
- const globalConfigPath = import_path44.default.join(homeDir2, ".node9", "config.json");
22436
+ const globalConfigPath = import_path45.default.join(homeDir2, ".node9", "config.json");
22245
22437
  if (import_fs47.default.existsSync(globalConfigPath)) {
22246
22438
  try {
22247
22439
  JSON.parse(import_fs47.default.readFileSync(globalConfigPath, "utf-8"));
@@ -22252,7 +22444,7 @@ function registerDoctorCommand(program2, version2) {
22252
22444
  } else {
22253
22445
  warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
22254
22446
  }
22255
- const projectConfigPath = import_path44.default.join(process.cwd(), "node9.config.json");
22447
+ const projectConfigPath = import_path45.default.join(process.cwd(), "node9.config.json");
22256
22448
  if (import_fs47.default.existsSync(projectConfigPath)) {
22257
22449
  try {
22258
22450
  JSON.parse(import_fs47.default.readFileSync(projectConfigPath, "utf-8"));
@@ -22264,7 +22456,7 @@ function registerDoctorCommand(program2, version2) {
22264
22456
  );
22265
22457
  }
22266
22458
  }
22267
- const credsPath = import_path44.default.join(homeDir2, ".node9", "credentials.json");
22459
+ const credsPath = import_path45.default.join(homeDir2, ".node9", "credentials.json");
22268
22460
  if (import_fs47.default.existsSync(credsPath)) {
22269
22461
  pass("Cloud credentials found (~/.node9/credentials.json)");
22270
22462
  } else {
@@ -22309,7 +22501,7 @@ function registerDoctorCommand(program2, version2) {
22309
22501
  try {
22310
22502
  const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
22311
22503
  const cfg = getConfig();
22312
- const creds = import_fs47.default.existsSync(import_path44.default.join(import_os40.default.homedir(), ".node9", "credentials.json"));
22504
+ const creds = import_fs47.default.existsSync(import_path45.default.join(import_os41.default.homedir(), ".node9", "credentials.json"));
22313
22505
  if (!creds) {
22314
22506
  warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
22315
22507
  } else if (!cfg.settings.approvers.cloud) {
@@ -22360,8 +22552,8 @@ function registerDoctorCommand(program2, version2) {
22360
22552
  // src/cli/commands/audit.ts
22361
22553
  var import_chalk12 = __toESM(require("chalk"));
22362
22554
  var import_fs48 = __toESM(require("fs"));
22363
- var import_path45 = __toESM(require("path"));
22364
- var import_os41 = __toESM(require("os"));
22555
+ var import_path46 = __toESM(require("path"));
22556
+ var import_os42 = __toESM(require("os"));
22365
22557
  function formatRelativeTime(timestamp) {
22366
22558
  const diff = Date.now() - new Date(timestamp).getTime();
22367
22559
  const sec = Math.floor(diff / 1e3);
@@ -22374,7 +22566,7 @@ function formatRelativeTime(timestamp) {
22374
22566
  }
22375
22567
  function registerAuditCommand(program2) {
22376
22568
  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 = import_path45.default.join(import_os41.default.homedir(), ".node9", "audit.log");
22569
+ const logPath = import_path46.default.join(import_os42.default.homedir(), ".node9", "audit.log");
22378
22570
  if (!import_fs48.default.existsSync(logPath)) {
22379
22571
  console.log(
22380
22572
  import_chalk12.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
@@ -22438,8 +22630,8 @@ var import_chalk13 = __toESM(require("chalk"));
22438
22630
 
22439
22631
  // src/cli/aggregate/report-audit.ts
22440
22632
  var import_fs49 = __toESM(require("fs"));
22441
- var import_os42 = __toESM(require("os"));
22442
- var import_path46 = __toESM(require("path"));
22633
+ var import_os43 = __toESM(require("os"));
22634
+ var import_path47 = __toESM(require("path"));
22443
22635
  init_costSync();
22444
22636
  init_litellm();
22445
22637
  init_cost_codex();
@@ -22570,7 +22762,7 @@ function freezeClaudeCost(acc) {
22570
22762
  };
22571
22763
  }
22572
22764
  function processClaudeCostProject(proj, projectsDir, start, end, acc) {
22573
- const projPath = import_path46.default.join(projectsDir, proj);
22765
+ const projPath = import_path47.default.join(projectsDir, proj);
22574
22766
  let files;
22575
22767
  try {
22576
22768
  const stat = import_fs49.default.statSync(projPath);
@@ -22581,7 +22773,7 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
22581
22773
  }
22582
22774
  const startMs = start.getTime();
22583
22775
  for (const file of files) {
22584
- const filePath = import_path46.default.join(projPath, file);
22776
+ const filePath = import_path47.default.join(projPath, file);
22585
22777
  try {
22586
22778
  if (import_fs49.default.statSync(filePath).mtimeMs < startMs) continue;
22587
22779
  } catch {
@@ -22711,28 +22903,28 @@ function listCodexSessionFiles2(sessionsBase) {
22711
22903
  if (!import_fs49.default.existsSync(sessionsBase)) return jsonlFiles;
22712
22904
  try {
22713
22905
  for (const year of import_fs49.default.readdirSync(sessionsBase)) {
22714
- const yearPath = import_path46.default.join(sessionsBase, year);
22906
+ const yearPath = import_path47.default.join(sessionsBase, year);
22715
22907
  try {
22716
22908
  if (!import_fs49.default.statSync(yearPath).isDirectory()) continue;
22717
22909
  } catch {
22718
22910
  continue;
22719
22911
  }
22720
22912
  for (const month of import_fs49.default.readdirSync(yearPath)) {
22721
- const monthPath = import_path46.default.join(yearPath, month);
22913
+ const monthPath = import_path47.default.join(yearPath, month);
22722
22914
  try {
22723
22915
  if (!import_fs49.default.statSync(monthPath).isDirectory()) continue;
22724
22916
  } catch {
22725
22917
  continue;
22726
22918
  }
22727
22919
  for (const day of import_fs49.default.readdirSync(monthPath)) {
22728
- const dayPath = import_path46.default.join(monthPath, day);
22920
+ const dayPath = import_path47.default.join(monthPath, day);
22729
22921
  try {
22730
22922
  if (!import_fs49.default.statSync(dayPath).isDirectory()) continue;
22731
22923
  } catch {
22732
22924
  continue;
22733
22925
  }
22734
22926
  for (const file of import_fs49.default.readdirSync(dayPath)) {
22735
- if (file.endsWith(".jsonl")) jsonlFiles.push(import_path46.default.join(dayPath, file));
22927
+ if (file.endsWith(".jsonl")) jsonlFiles.push(import_path47.default.join(dayPath, file));
22736
22928
  }
22737
22929
  }
22738
22930
  }
@@ -22858,7 +23050,7 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
22858
23050
  return out;
22859
23051
  }
22860
23052
  for (const proj of dirs) {
22861
- const chatsDir = import_path46.default.join(geminiTmpDir2, proj, "chats");
23053
+ const chatsDir = import_path47.default.join(geminiTmpDir2, proj, "chats");
22862
23054
  let files;
22863
23055
  try {
22864
23056
  if (!import_fs49.default.statSync(chatsDir).isDirectory()) continue;
@@ -22868,7 +23060,7 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
22868
23060
  }
22869
23061
  for (const f of files) {
22870
23062
  if (!f.endsWith(".jsonl")) continue;
22871
- out.push({ projectKey: proj, file: import_path46.default.join(chatsDir, f) });
23063
+ out.push({ projectKey: proj, file: import_path47.default.join(chatsDir, f) });
22872
23064
  }
22873
23065
  }
22874
23066
  return out;
@@ -22883,10 +23075,10 @@ function loadGeminiCost(start, end, geminiTmpDir2) {
22883
23075
  }
22884
23076
  function aggregateReportFromAudit(period, opts = {}) {
22885
23077
  const now = opts.now ?? /* @__PURE__ */ new Date();
22886
- const auditLogPath = opts.auditLogPath ?? import_path46.default.join(import_os42.default.homedir(), ".node9", "audit.log");
22887
- const claudeProjectsDir = opts.claudeProjectsDir ?? import_path46.default.join(import_os42.default.homedir(), ".claude", "projects");
22888
- const codexSessionsDir2 = opts.codexSessionsDir ?? import_path46.default.join(import_os42.default.homedir(), ".codex", "sessions");
22889
- const geminiTmpDir2 = opts.geminiTmpDir ?? import_path46.default.join(import_os42.default.homedir(), ".gemini", "tmp");
23078
+ const auditLogPath = opts.auditLogPath ?? import_path47.default.join(import_os43.default.homedir(), ".node9", "audit.log");
23079
+ const claudeProjectsDir = opts.claudeProjectsDir ?? import_path47.default.join(import_os43.default.homedir(), ".claude", "projects");
23080
+ const codexSessionsDir2 = opts.codexSessionsDir ?? import_path47.default.join(import_os43.default.homedir(), ".codex", "sessions");
23081
+ const geminiTmpDir2 = opts.geminiTmpDir ?? import_path47.default.join(import_os43.default.homedir(), ".gemini", "tmp");
22890
23082
  const hasAuditFile = import_fs49.default.existsSync(auditLogPath);
22891
23083
  const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
22892
23084
  const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
@@ -23584,8 +23776,8 @@ function registerDaemonCommand(program2) {
23584
23776
  // src/cli/commands/status.ts
23585
23777
  var import_chalk15 = __toESM(require("chalk"));
23586
23778
  var import_fs50 = __toESM(require("fs"));
23587
- var import_path47 = __toESM(require("path"));
23588
- var import_os43 = __toESM(require("os"));
23779
+ var import_path48 = __toESM(require("path"));
23780
+ var import_os44 = __toESM(require("os"));
23589
23781
  init_core();
23590
23782
  init_daemon();
23591
23783
  init_agent_wiring();
@@ -23642,8 +23834,8 @@ function registerStatusCommand(program2) {
23642
23834
  console.log("");
23643
23835
  const modeLabel = settings.mode === "audit" ? import_chalk15.default.blue("audit") : settings.mode === "strict" ? import_chalk15.default.red("strict") : import_chalk15.default.white("standard");
23644
23836
  console.log(` Mode: ${modeLabel}`);
23645
- const projectConfig = import_path47.default.join(process.cwd(), "node9.config.json");
23646
- const globalConfig = import_path47.default.join(import_os43.default.homedir(), ".node9", "config.json");
23837
+ const projectConfig = import_path48.default.join(process.cwd(), "node9.config.json");
23838
+ const globalConfig = import_path48.default.join(import_os44.default.homedir(), ".node9", "config.json");
23647
23839
  console.log(
23648
23840
  ` Local: ${import_fs50.default.existsSync(projectConfig) ? import_chalk15.default.green("Active (node9.config.json)") : import_chalk15.default.gray("Not present")}`
23649
23841
  );
@@ -23655,7 +23847,7 @@ function registerStatusCommand(program2) {
23655
23847
  ` Sandbox: ${import_chalk15.default.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
23656
23848
  );
23657
23849
  }
23658
- const wiring = getAgentWiring(import_os43.default.homedir()).filter((a) => a.present);
23850
+ const wiring = getAgentWiring(import_os44.default.homedir()).filter((a) => a.present);
23659
23851
  if (wiring.length > 0) {
23660
23852
  console.log("");
23661
23853
  console.log(import_chalk15.default.bold(" Agent Wiring:"));
@@ -23691,9 +23883,9 @@ function registerStatusCommand(program2) {
23691
23883
  // src/cli/commands/init.ts
23692
23884
  var import_chalk16 = __toESM(require("chalk"));
23693
23885
  var import_fs51 = __toESM(require("fs"));
23694
- var import_path48 = __toESM(require("path"));
23695
- var import_os44 = __toESM(require("os"));
23696
- var import_https5 = __toESM(require("https"));
23886
+ var import_path49 = __toESM(require("path"));
23887
+ var import_os45 = __toESM(require("os"));
23888
+ var import_https6 = __toESM(require("https"));
23697
23889
  init_core();
23698
23890
  init_setup();
23699
23891
  init_shields();
@@ -23711,7 +23903,7 @@ function buildTelemetryPayload(agents, firstInstall) {
23711
23903
  function fireTelemetryPing(agents, firstInstall) {
23712
23904
  try {
23713
23905
  const body = JSON.stringify(buildTelemetryPayload(agents, firstInstall));
23714
- const req = import_https5.default.request(
23906
+ const req = import_https6.default.request(
23715
23907
  {
23716
23908
  hostname: "api.node9.ai",
23717
23909
  path: "/api/v1/telemetry",
@@ -23782,7 +23974,7 @@ function registerInitCommand(program2) {
23782
23974
  }
23783
23975
  console.log("");
23784
23976
  }
23785
- const configPath = import_path48.default.join(import_os44.default.homedir(), ".node9", "config.json");
23977
+ const configPath = import_path49.default.join(import_os45.default.homedir(), ".node9", "config.json");
23786
23978
  const isFirstInstall = !import_fs51.default.existsSync(configPath);
23787
23979
  if (import_fs51.default.existsSync(configPath) && !options.force) {
23788
23980
  try {
@@ -23804,7 +23996,7 @@ function registerInitCommand(program2) {
23804
23996
  ...DEFAULT_CONFIG,
23805
23997
  settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
23806
23998
  };
23807
- const dir = import_path48.default.dirname(configPath);
23999
+ const dir = import_path49.default.dirname(configPath);
23808
24000
  if (!import_fs51.default.existsSync(dir)) import_fs51.default.mkdirSync(dir, { recursive: true });
23809
24001
  import_fs51.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
23810
24002
  console.log(import_chalk16.default.green(`\u2705 Config created: ${configPath}`));
@@ -23911,7 +24103,7 @@ function registerInitCommand(program2) {
23911
24103
  }
23912
24104
 
23913
24105
  // src/cli/commands/undo.ts
23914
- var import_path49 = __toESM(require("path"));
24106
+ var import_path50 = __toESM(require("path"));
23915
24107
  var import_chalk18 = __toESM(require("chalk"));
23916
24108
 
23917
24109
  // src/tui/undo-navigator.ts
@@ -24070,7 +24262,7 @@ function findMatchingCwd(startDir, history) {
24070
24262
  let dir = startDir;
24071
24263
  while (true) {
24072
24264
  if (cwds.has(dir)) return dir;
24073
- const parent = import_path49.default.dirname(dir);
24265
+ const parent = import_path50.default.dirname(dir);
24074
24266
  if (parent === dir) return null;
24075
24267
  dir = parent;
24076
24268
  }
@@ -24706,8 +24898,8 @@ function registerMcpGatewayCommand(program2) {
24706
24898
  // src/mcp-server/index.ts
24707
24899
  var import_readline5 = __toESM(require("readline"));
24708
24900
  var import_fs53 = __toESM(require("fs"));
24709
- var import_os46 = __toESM(require("os"));
24710
- var import_path51 = __toESM(require("path"));
24901
+ var import_os47 = __toESM(require("os"));
24902
+ var import_path52 = __toESM(require("path"));
24711
24903
  var import_child_process11 = require("child_process");
24712
24904
  init_core();
24713
24905
  init_daemon();
@@ -24715,8 +24907,8 @@ init_shields();
24715
24907
 
24716
24908
  // src/auth/egress-config.ts
24717
24909
  var import_fs52 = __toESM(require("fs"));
24718
- var import_os45 = __toESM(require("os"));
24719
- var import_path50 = __toESM(require("path"));
24910
+ var import_os46 = __toESM(require("os"));
24911
+ var import_path51 = __toESM(require("path"));
24720
24912
  var DEFAULT_EGRESS = {
24721
24913
  enabled: false,
24722
24914
  mode: "review",
@@ -24725,7 +24917,7 @@ var DEFAULT_EGRESS = {
24725
24917
  allowPrivate: true
24726
24918
  };
24727
24919
  function egressConfigPath() {
24728
- return import_path50.default.join(import_os45.default.homedir(), ".node9", "config.json");
24920
+ return import_path51.default.join(import_os46.default.homedir(), ".node9", "config.json");
24729
24921
  }
24730
24922
  function readEgressRawConfig() {
24731
24923
  let text;
@@ -24745,7 +24937,7 @@ function readEgressRawConfig() {
24745
24937
  }
24746
24938
  function writeEgressRawConfig(config) {
24747
24939
  const p = egressConfigPath();
24748
- import_fs52.default.mkdirSync(import_path50.default.dirname(p), { recursive: true });
24940
+ import_fs52.default.mkdirSync(import_path51.default.dirname(p), { recursive: true });
24749
24941
  import_fs52.default.writeFileSync(p, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
24750
24942
  }
24751
24943
  function applyEgress(config, change) {
@@ -25131,8 +25323,8 @@ function handleStatus() {
25131
25323
  lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
25132
25324
  lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
25133
25325
  lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
25134
- const projectConfig = import_path51.default.join(process.cwd(), "node9.config.json");
25135
- const globalConfig = import_path51.default.join(import_os46.default.homedir(), ".node9", "config.json");
25326
+ const projectConfig = import_path52.default.join(process.cwd(), "node9.config.json");
25327
+ const globalConfig = import_path52.default.join(import_os47.default.homedir(), ".node9", "config.json");
25136
25328
  lines.push(
25137
25329
  `Project config (node9.config.json): ${import_fs53.default.existsSync(projectConfig) ? "present" : "not found"}`
25138
25330
  );
@@ -25243,7 +25435,7 @@ function handleEgressDeny(args) {
25243
25435
  addEgressHost("deny", host);
25244
25436
  return `Denied egress to ${host} (deny always wins over allow).`;
25245
25437
  }
25246
- var GLOBAL_CONFIG_PATH = import_path51.default.join(import_os46.default.homedir(), ".node9", "config.json");
25438
+ var GLOBAL_CONFIG_PATH = import_path52.default.join(import_os47.default.homedir(), ".node9", "config.json");
25247
25439
  var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
25248
25440
  function readGlobalConfigRaw() {
25249
25441
  try {
@@ -25255,7 +25447,7 @@ function readGlobalConfigRaw() {
25255
25447
  return {};
25256
25448
  }
25257
25449
  function writeGlobalConfigRaw(data) {
25258
- const dir = import_path51.default.dirname(GLOBAL_CONFIG_PATH);
25450
+ const dir = import_path52.default.dirname(GLOBAL_CONFIG_PATH);
25259
25451
  if (!import_fs53.default.existsSync(dir)) import_fs53.default.mkdirSync(dir, { recursive: true });
25260
25452
  import_fs53.default.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
25261
25453
  }
@@ -25301,7 +25493,7 @@ function handleApproverSet(args) {
25301
25493
  function handleAuditGet(args) {
25302
25494
  const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
25303
25495
  const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
25304
- const auditPath = import_path51.default.join(import_os46.default.homedir(), ".node9", "audit.log");
25496
+ const auditPath = import_path52.default.join(import_os47.default.homedir(), ".node9", "audit.log");
25305
25497
  if (!import_fs53.default.existsSync(auditPath)) return "No audit log found.";
25306
25498
  const rawLines = import_fs53.default.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
25307
25499
  const parsed = [];
@@ -25809,6 +26001,17 @@ var import_chalk22 = __toESM(require("chalk"));
25809
26001
  init_sync();
25810
26002
  function registerSyncCommand(program2) {
25811
26003
  const policy = program2.command("policy").description("Manage cloud policy rules");
26004
+ policy.command("push").description("Push this machine's effective policy to the node9 dashboard").action(async () => {
26005
+ process.stdout.write(import_chalk22.default.cyan("Pushing policy to the dashboard\u2026"));
26006
+ const result = await runPolicyPush();
26007
+ process.stdout.write("\n");
26008
+ if (!result.ok) {
26009
+ console.error(import_chalk22.default.red(`\u2717 ${result.reason}`));
26010
+ process.exit(1);
26011
+ }
26012
+ console.log(import_chalk22.default.green("\u2713 Policy mirrored to the dashboard"));
26013
+ console.log(import_chalk22.default.gray(" See it under Security Policy \u2192 Machines"));
26014
+ });
25812
26015
  policy.command("sync").description("Sync cloud policy rules to local cache (~/.node9/rules-cache.json)").action(async () => {
25813
26016
  process.stdout.write(import_chalk22.default.cyan("Syncing cloud policy rules\u2026"));
25814
26017
  const result = await runCloudSync();
@@ -26257,12 +26460,12 @@ var import_chalk27 = __toESM(require("chalk"));
26257
26460
 
26258
26461
  // src/shields/jail.ts
26259
26462
  var import_fs55 = __toESM(require("fs"));
26260
- var import_os47 = __toESM(require("os"));
26261
- var import_path52 = __toESM(require("path"));
26463
+ var import_os48 = __toESM(require("os"));
26464
+ var import_path53 = __toESM(require("path"));
26262
26465
  init_shields();
26263
26466
  var USER_JAIL_SHIELD = "user-jail";
26264
26467
  function jailStorePath() {
26265
- return import_path52.default.join(import_os47.default.homedir(), ".node9", "jail-paths.json");
26468
+ return import_path53.default.join(import_os48.default.homedir(), ".node9", "jail-paths.json");
26266
26469
  }
26267
26470
  function readJailPaths() {
26268
26471
  let text;
@@ -26285,7 +26488,7 @@ function readJailPaths() {
26285
26488
  }
26286
26489
  function writeJailPaths(paths) {
26287
26490
  const p = jailStorePath();
26288
- import_fs55.default.mkdirSync(import_path52.default.dirname(p), { recursive: true });
26491
+ import_fs55.default.mkdirSync(import_path53.default.dirname(p), { recursive: true });
26289
26492
  import_fs55.default.writeFileSync(p, JSON.stringify({ paths }, null, 2) + "\n", { mode: 384 });
26290
26493
  }
26291
26494
  function addJailPath(rawPath, verdict) {
@@ -26308,7 +26511,7 @@ function removeJailPath(rawPath) {
26308
26511
  return { removed, paths: after };
26309
26512
  }
26310
26513
  function regenerateUserJail(paths) {
26311
- const file = import_path52.default.join(USER_SHIELDS_DIR_PATH, `${USER_JAIL_SHIELD}.json`);
26514
+ const file = import_path53.default.join(USER_SHIELDS_DIR_PATH, `${USER_JAIL_SHIELD}.json`);
26312
26515
  if (paths.length === 0) {
26313
26516
  const active2 = readActiveShields();
26314
26517
  if (active2.includes(USER_JAIL_SHIELD)) {
@@ -26430,13 +26633,13 @@ function registerJailCommand(program2) {
26430
26633
  // src/cli/commands/sandbox.ts
26431
26634
  var import_chalk28 = __toESM(require("chalk"));
26432
26635
  var import_fs58 = __toESM(require("fs"));
26433
- var import_path55 = __toESM(require("path"));
26636
+ var import_path56 = __toESM(require("path"));
26434
26637
  var import_child_process13 = require("child_process");
26435
26638
  init_config();
26436
26639
 
26437
26640
  // src/sandbox/config.ts
26438
26641
  var import_fs56 = __toESM(require("fs"));
26439
- var import_path53 = __toESM(require("path"));
26642
+ var import_path54 = __toESM(require("path"));
26440
26643
  var import_yaml = require("yaml");
26441
26644
  var SANDBOX_CONFIG_FILE = "node9.sandbox.yaml";
26442
26645
  var FORBIDDEN_ENV = /* @__PURE__ */ new Set(["NODE9_API_KEY", "NODE9_API_URL"]);
@@ -26509,7 +26712,7 @@ function scaffoldSandboxYaml(agent) {
26509
26712
  return header + (0, import_yaml.stringify)(defaultSandboxConfig(agent));
26510
26713
  }
26511
26714
  function sandboxConfigPath(cwd = process.cwd()) {
26512
- return import_path53.default.join(cwd, SANDBOX_CONFIG_FILE);
26715
+ return import_path54.default.join(cwd, SANDBOX_CONFIG_FILE);
26513
26716
  }
26514
26717
  function loadSandboxConfig(cwd = process.cwd(), fallbackAgent = "claude") {
26515
26718
  const p = sandboxConfigPath(cwd);
@@ -26577,13 +26780,13 @@ init_templates();
26577
26780
 
26578
26781
  // src/sandbox/runtime.ts
26579
26782
  var import_fs57 = __toESM(require("fs"));
26580
- var import_os48 = __toESM(require("os"));
26581
- var import_path54 = __toESM(require("path"));
26783
+ var import_os49 = __toESM(require("os"));
26784
+ var import_path55 = __toESM(require("path"));
26582
26785
  var import_crypto13 = __toESM(require("crypto"));
26583
26786
  var import_child_process12 = require("child_process");
26584
26787
  init_templates();
26585
26788
  function sandboxDataDir(cwd = process.cwd()) {
26586
- return import_path54.default.join(cwd, ".node9", "sandbox", "data");
26789
+ return import_path55.default.join(cwd, ".node9", "sandbox", "data");
26587
26790
  }
26588
26791
  function detectEngine(engine) {
26589
26792
  const r = (0, import_child_process12.spawnSync)(engine, ["--version"], { encoding: "utf-8" });
@@ -26594,7 +26797,7 @@ function detectEngine(engine) {
26594
26797
  }
26595
26798
  function agentCredentialsMount(agent) {
26596
26799
  const rel = agent === "codex" ? ".codex/auth.json" : ".claude/.credentials.json";
26597
- return { hostPath: import_path54.default.join(import_os48.default.homedir(), rel), target: `/home/${RUN_AS_USER}/${rel}` };
26800
+ return { hostPath: import_path55.default.join(import_os49.default.homedir(), rel), target: `/home/${RUN_AS_USER}/${rel}` };
26598
26801
  }
26599
26802
  function buildRunArgs(opts) {
26600
26803
  const { config, workspaceHostPath, dataHostPath, allowlistHostPath, agentArgs } = opts;
@@ -26622,30 +26825,30 @@ function imageContentHash(dockerfile, entrypoint) {
26622
26825
  return import_crypto13.default.createHash("sha256").update(dockerfile).update("\0").update(entrypoint).digest("hex").slice(0, 16);
26623
26826
  }
26624
26827
  function sandboxBuildDir(cwd = process.cwd()) {
26625
- return import_path54.default.join(cwd, ".node9", "sandbox", "build");
26828
+ return import_path55.default.join(cwd, ".node9", "sandbox", "build");
26626
26829
  }
26627
26830
  function writeBuildContext(cwd, dockerfile, entrypoint) {
26628
26831
  const dir = sandboxBuildDir(cwd);
26629
26832
  import_fs57.default.mkdirSync(dir, { recursive: true });
26630
- import_fs57.default.writeFileSync(import_path54.default.join(dir, "Dockerfile"), dockerfile);
26631
- import_fs57.default.writeFileSync(import_path54.default.join(dir, "entrypoint.sh"), entrypoint);
26833
+ import_fs57.default.writeFileSync(import_path55.default.join(dir, "Dockerfile"), dockerfile);
26834
+ import_fs57.default.writeFileSync(import_path55.default.join(dir, "entrypoint.sh"), entrypoint);
26632
26835
  return dir;
26633
26836
  }
26634
26837
  function writeAllowlist(cwd, hosts) {
26635
- const dir = import_path54.default.join(cwd, ".node9", "sandbox");
26838
+ const dir = import_path55.default.join(cwd, ".node9", "sandbox");
26636
26839
  import_fs57.default.mkdirSync(dir, { recursive: true });
26637
- const p = import_path54.default.join(dir, "allowed-domains.txt");
26840
+ const p = import_path55.default.join(dir, "allowed-domains.txt");
26638
26841
  import_fs57.default.writeFileSync(p, hosts.join("\n") + "\n");
26639
26842
  return p;
26640
26843
  }
26641
26844
  function resolveHomePath(p) {
26642
- return p.startsWith("~") ? import_path54.default.join(import_os48.default.homedir(), p.slice(1)) : import_path54.default.resolve(p);
26845
+ return p.startsWith("~") ? import_path55.default.join(import_os49.default.homedir(), p.slice(1)) : import_path55.default.resolve(p);
26643
26846
  }
26644
26847
 
26645
26848
  // src/cli/commands/sandbox.ts
26646
26849
  function seedDataDirConfig(dataDir, sandbox) {
26647
26850
  import_fs58.default.mkdirSync(dataDir, { recursive: true });
26648
- const configPath = import_path55.default.join(dataDir, "config.json");
26851
+ const configPath = import_path56.default.join(dataDir, "config.json");
26649
26852
  const seed = {
26650
26853
  settings: {
26651
26854
  approvers: {
@@ -26710,7 +26913,7 @@ function registerSandboxCommand(program2, version2) {
26710
26913
  const buildDir = writeBuildContext(cwd, dockerfile, entrypoint);
26711
26914
  const hash = imageContentHash(dockerfile, entrypoint);
26712
26915
  const image = sandbox.runtime.image;
26713
- const hashFile = import_path55.default.join(sandboxBuildDir(cwd), ".image-hash");
26916
+ const hashFile = import_path56.default.join(sandboxBuildDir(cwd), ".image-hash");
26714
26917
  const lastHash = import_fs58.default.existsSync(hashFile) ? import_fs58.default.readFileSync(hashFile, "utf-8").trim() : "";
26715
26918
  const imageExists = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, ["image", "inspect", image], { stdio: "ignore" }).status === 0;
26716
26919
  const needBuild = sandbox.runtime.rebuild === "always" || !imageExists || sandbox.runtime.rebuild !== "never" && lastHash !== hash;
@@ -26753,7 +26956,7 @@ function registerSandboxCommand(program2, version2) {
26753
26956
  process.exit(r.status ?? 0);
26754
26957
  });
26755
26958
  cmd.command("tail").description("Stream the sandbox's audit log (host-side)").action(() => {
26756
- const auditPath = import_path55.default.join(sandboxDataDir(), "audit.log");
26959
+ const auditPath = import_path56.default.join(sandboxDataDir(), "audit.log");
26757
26960
  if (!import_fs58.default.existsSync(auditPath)) {
26758
26961
  console.log(import_chalk28.default.dim(" no sandbox audit yet."));
26759
26962
  return;
@@ -26761,7 +26964,7 @@ function registerSandboxCommand(program2, version2) {
26761
26964
  (0, import_child_process13.spawnSync)("tail", ["-f", auditPath], { stdio: "inherit" });
26762
26965
  });
26763
26966
  cmd.command("logs").description("Dump the sandbox's audit log").action(() => {
26764
- const auditPath = import_path55.default.join(sandboxDataDir(), "audit.log");
26967
+ const auditPath = import_path56.default.join(sandboxDataDir(), "audit.log");
26765
26968
  if (!import_fs58.default.existsSync(auditPath)) {
26766
26969
  console.log(import_chalk28.default.dim(" no sandbox audit yet."));
26767
26970
  return;
@@ -26780,7 +26983,7 @@ function registerSandboxCommand(program2, version2) {
26780
26983
  stdio: "ignore"
26781
26984
  });
26782
26985
  }
26783
- import_fs58.default.rmSync(import_path55.default.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
26986
+ import_fs58.default.rmSync(import_path56.default.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
26784
26987
  console.log(import_chalk28.default.green(" \u2713 sandbox image + build + data removed."));
26785
26988
  });
26786
26989
  }
@@ -26788,8 +26991,8 @@ function registerSandboxCommand(program2, version2) {
26788
26991
  // src/cli/commands/sessions.ts
26789
26992
  var import_chalk29 = __toESM(require("chalk"));
26790
26993
  var import_fs59 = __toESM(require("fs"));
26791
- var import_path56 = __toESM(require("path"));
26792
- var import_os49 = __toESM(require("os"));
26994
+ var import_path57 = __toESM(require("path"));
26995
+ var import_os50 = __toESM(require("os"));
26793
26996
  init_scan_summary();
26794
26997
  init_litellm();
26795
26998
  init_cost_gemini();
@@ -26810,10 +27013,10 @@ function encodeProjectPath(projectPath) {
26810
27013
  }
26811
27014
  function sessionJsonlPath(projectPath, sessionId) {
26812
27015
  const encoded = encodeProjectPath(projectPath);
26813
- return import_path56.default.join(import_os49.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
27016
+ return import_path57.default.join(import_os50.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
26814
27017
  }
26815
27018
  function projectLabel(projectPath) {
26816
- return projectPath.replace(import_os49.default.homedir(), "~");
27019
+ return projectPath.replace(import_os50.default.homedir(), "~");
26817
27020
  }
26818
27021
  function parseHistoryLines(lines) {
26819
27022
  const entries = [];
@@ -26882,7 +27085,7 @@ function parseSessionLines(lines) {
26882
27085
  return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
26883
27086
  }
26884
27087
  function loadAuditEntries(auditPath) {
26885
- const aPath = auditPath ?? import_path56.default.join(import_os49.default.homedir(), ".node9", "audit.log");
27088
+ const aPath = auditPath ?? import_path57.default.join(import_os50.default.homedir(), ".node9", "audit.log");
26886
27089
  let raw;
26887
27090
  try {
26888
27091
  raw = import_fs59.default.readFileSync(aPath, "utf-8");
@@ -26921,7 +27124,7 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
26921
27124
  return result;
26922
27125
  }
26923
27126
  function buildGeminiSessions(days, allAuditEntries) {
26924
- const tmpDir = import_path56.default.join(import_os49.default.homedir(), ".gemini", "tmp");
27127
+ const tmpDir = import_path57.default.join(import_os50.default.homedir(), ".gemini", "tmp");
26925
27128
  if (!import_fs59.default.existsSync(tmpDir)) return [];
26926
27129
  const cutoff = days !== null ? (() => {
26927
27130
  const d = /* @__PURE__ */ new Date();
@@ -26937,18 +27140,18 @@ function buildGeminiSessions(days, allAuditEntries) {
26937
27140
  }
26938
27141
  const summaries = [];
26939
27142
  for (const slug2 of slugDirs) {
26940
- const slugPath = import_path56.default.join(tmpDir, slug2);
27143
+ const slugPath = import_path57.default.join(tmpDir, slug2);
26941
27144
  try {
26942
27145
  if (!import_fs59.default.statSync(slugPath).isDirectory()) continue;
26943
27146
  } catch {
26944
27147
  continue;
26945
27148
  }
26946
- let projectRoot = import_path56.default.join(import_os49.default.homedir(), slug2);
27149
+ let projectRoot = import_path57.default.join(import_os50.default.homedir(), slug2);
26947
27150
  try {
26948
- projectRoot = import_fs59.default.readFileSync(import_path56.default.join(slugPath, ".project_root"), "utf-8").trim();
27151
+ projectRoot = import_fs59.default.readFileSync(import_path57.default.join(slugPath, ".project_root"), "utf-8").trim();
26949
27152
  } catch {
26950
27153
  }
26951
- const chatsDir = import_path56.default.join(slugPath, "chats");
27154
+ const chatsDir = import_path57.default.join(slugPath, "chats");
26952
27155
  if (!import_fs59.default.existsSync(chatsDir)) continue;
26953
27156
  let chatFiles;
26954
27157
  try {
@@ -26959,7 +27162,7 @@ function buildGeminiSessions(days, allAuditEntries) {
26959
27162
  for (const chatFile of chatFiles) {
26960
27163
  let raw;
26961
27164
  try {
26962
- raw = import_fs59.default.readFileSync(import_path56.default.join(chatsDir, chatFile), "utf-8");
27165
+ raw = import_fs59.default.readFileSync(import_path57.default.join(chatsDir, chatFile), "utf-8");
26963
27166
  } catch {
26964
27167
  continue;
26965
27168
  }
@@ -27039,7 +27242,7 @@ function buildGeminiSessions(days, allAuditEntries) {
27039
27242
  return summaries;
27040
27243
  }
27041
27244
  function buildCodexSessions(days, allAuditEntries) {
27042
- const sessionsBase = import_path56.default.join(import_os49.default.homedir(), ".codex", "sessions");
27245
+ const sessionsBase = import_path57.default.join(import_os50.default.homedir(), ".codex", "sessions");
27043
27246
  if (!import_fs59.default.existsSync(sessionsBase)) return [];
27044
27247
  const cutoff = days !== null ? (() => {
27045
27248
  const d = /* @__PURE__ */ new Date();
@@ -27050,28 +27253,28 @@ function buildCodexSessions(days, allAuditEntries) {
27050
27253
  const jsonlFiles = [];
27051
27254
  try {
27052
27255
  for (const year of import_fs59.default.readdirSync(sessionsBase)) {
27053
- const yearPath = import_path56.default.join(sessionsBase, year);
27256
+ const yearPath = import_path57.default.join(sessionsBase, year);
27054
27257
  try {
27055
27258
  if (!import_fs59.default.statSync(yearPath).isDirectory()) continue;
27056
27259
  } catch {
27057
27260
  continue;
27058
27261
  }
27059
27262
  for (const month of import_fs59.default.readdirSync(yearPath)) {
27060
- const monthPath = import_path56.default.join(yearPath, month);
27263
+ const monthPath = import_path57.default.join(yearPath, month);
27061
27264
  try {
27062
27265
  if (!import_fs59.default.statSync(monthPath).isDirectory()) continue;
27063
27266
  } catch {
27064
27267
  continue;
27065
27268
  }
27066
27269
  for (const day of import_fs59.default.readdirSync(monthPath)) {
27067
- const dayPath = import_path56.default.join(monthPath, day);
27270
+ const dayPath = import_path57.default.join(monthPath, day);
27068
27271
  try {
27069
27272
  if (!import_fs59.default.statSync(dayPath).isDirectory()) continue;
27070
27273
  } catch {
27071
27274
  continue;
27072
27275
  }
27073
27276
  for (const file of import_fs59.default.readdirSync(dayPath)) {
27074
- if (file.endsWith(".jsonl")) jsonlFiles.push(import_path56.default.join(dayPath, file));
27277
+ if (file.endsWith(".jsonl")) jsonlFiles.push(import_path57.default.join(dayPath, file));
27075
27278
  }
27076
27279
  }
27077
27280
  }
@@ -27169,7 +27372,7 @@ function buildCodexSessions(days, allAuditEntries) {
27169
27372
  return summaries;
27170
27373
  }
27171
27374
  function buildSessions(days, historyPath) {
27172
- const hPath = historyPath ?? import_path56.default.join(import_os49.default.homedir(), ".claude", "history.jsonl");
27375
+ const hPath = historyPath ?? import_path57.default.join(import_os50.default.homedir(), ".claude", "history.jsonl");
27173
27376
  let historyRaw = "";
27174
27377
  try {
27175
27378
  historyRaw = import_fs59.default.readFileSync(hPath, "utf-8");
@@ -27591,11 +27794,11 @@ function registerSessionTaintCommand(program2) {
27591
27794
  // src/cli/commands/skill-pin.ts
27592
27795
  var import_chalk31 = __toESM(require("chalk"));
27593
27796
  var import_fs60 = __toESM(require("fs"));
27594
- var import_os50 = __toESM(require("os"));
27595
- var import_path57 = __toESM(require("path"));
27797
+ var import_os51 = __toESM(require("os"));
27798
+ var import_path58 = __toESM(require("path"));
27596
27799
  function wipeSkillSessions() {
27597
27800
  try {
27598
- import_fs60.default.rmSync(import_path57.default.join(import_os50.default.homedir(), ".node9", "skill-sessions"), {
27801
+ import_fs60.default.rmSync(import_path58.default.join(import_os51.default.homedir(), ".node9", "skill-sessions"), {
27599
27802
  recursive: true,
27600
27803
  force: true
27601
27804
  });
@@ -27678,10 +27881,10 @@ function registerSkillPinCommand(program2) {
27678
27881
 
27679
27882
  // src/cli/commands/decisions.ts
27680
27883
  var import_fs61 = __toESM(require("fs"));
27681
- var import_os51 = __toESM(require("os"));
27682
- var import_path58 = __toESM(require("path"));
27884
+ var import_os52 = __toESM(require("os"));
27885
+ var import_path59 = __toESM(require("path"));
27683
27886
  var import_chalk32 = __toESM(require("chalk"));
27684
- var DECISIONS_FILE2 = import_path58.default.join(import_os51.default.homedir(), ".node9", "decisions.json");
27887
+ var DECISIONS_FILE2 = import_path59.default.join(import_os52.default.homedir(), ".node9", "decisions.json");
27685
27888
  function readDecisions() {
27686
27889
  try {
27687
27890
  if (!import_fs61.default.existsSync(DECISIONS_FILE2)) return {};
@@ -27697,7 +27900,7 @@ function readDecisions() {
27697
27900
  }
27698
27901
  }
27699
27902
  function writeDecisions(d) {
27700
- const dir = import_path58.default.dirname(DECISIONS_FILE2);
27903
+ const dir = import_path59.default.dirname(DECISIONS_FILE2);
27701
27904
  if (!import_fs61.default.existsSync(dir)) import_fs61.default.mkdirSync(dir, { recursive: true });
27702
27905
  const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
27703
27906
  import_fs61.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
@@ -27759,10 +27962,10 @@ Persistent decisions (${entries.length})
27759
27962
  // src/cli/commands/dlp.ts
27760
27963
  var import_chalk33 = __toESM(require("chalk"));
27761
27964
  var import_fs62 = __toESM(require("fs"));
27762
- var import_path59 = __toESM(require("path"));
27763
- var import_os52 = __toESM(require("os"));
27764
- var AUDIT_LOG = import_path59.default.join(import_os52.default.homedir(), ".node9", "audit.log");
27765
- var RESOLVED_FILE = import_path59.default.join(import_os52.default.homedir(), ".node9", "dlp-resolved.json");
27965
+ var import_path60 = __toESM(require("path"));
27966
+ var import_os53 = __toESM(require("os"));
27967
+ var AUDIT_LOG = import_path60.default.join(import_os53.default.homedir(), ".node9", "audit.log");
27968
+ var RESOLVED_FILE = import_path60.default.join(import_os53.default.homedir(), ".node9", "dlp-resolved.json");
27766
27969
  var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
27767
27970
  function stripAnsi(s) {
27768
27971
  return s.replace(ANSI_RE, "");
@@ -27882,14 +28085,14 @@ function registerDlpCommand(program2) {
27882
28085
  // src/cli/commands/mask.ts
27883
28086
  var import_chalk34 = __toESM(require("chalk"));
27884
28087
  var import_fs63 = __toESM(require("fs"));
27885
- var import_path60 = __toESM(require("path"));
27886
- var import_os53 = __toESM(require("os"));
28088
+ var import_path61 = __toESM(require("path"));
28089
+ var import_os54 = __toESM(require("os"));
27887
28090
  init_dlp();
27888
28091
  function findJsonlFiles(dir) {
27889
28092
  const results = [];
27890
28093
  if (!import_fs63.default.existsSync(dir)) return results;
27891
28094
  for (const entry of import_fs63.default.readdirSync(dir, { withFileTypes: true })) {
27892
- const full = import_path60.default.join(dir, entry.name);
28095
+ const full = import_path61.default.join(dir, entry.name);
27893
28096
  if (entry.isDirectory()) results.push(...findJsonlFiles(full));
27894
28097
  else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
27895
28098
  }
@@ -27992,7 +28195,7 @@ function findJsonFiles(dir) {
27992
28195
  const results = [];
27993
28196
  if (!import_fs63.default.existsSync(dir)) return results;
27994
28197
  for (const entry of import_fs63.default.readdirSync(dir, { withFileTypes: true })) {
27995
- const full = import_path60.default.join(dir, entry.name);
28198
+ const full = import_path61.default.join(dir, entry.name);
27996
28199
  if (entry.isDirectory()) results.push(...findJsonFiles(full));
27997
28200
  else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
27998
28201
  }
@@ -28001,9 +28204,9 @@ function findJsonFiles(dir) {
28001
28204
  function registerMaskCommand(program2) {
28002
28205
  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
28206
  const dryRun = !!options.dryRun;
28004
- const home = import_os53.default.homedir();
28005
- const claudeDir = import_path60.default.join(home, ".claude", "projects");
28006
- const geminiDir = import_path60.default.join(home, ".gemini", "tmp");
28207
+ const home = import_os54.default.homedir();
28208
+ const claudeDir = import_path61.default.join(home, ".claude", "projects");
28209
+ const geminiDir = import_path61.default.join(home, ".gemini", "tmp");
28007
28210
  const allFiles = [
28008
28211
  ...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
28009
28212
  ...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
@@ -28067,15 +28270,15 @@ function registerMaskCommand(program2) {
28067
28270
  // src/cli.ts
28068
28271
  init_blast();
28069
28272
  var { version } = JSON.parse(
28070
- import_fs66.default.readFileSync(import_path63.default.join(__dirname, "../package.json"), "utf-8")
28273
+ import_fs66.default.readFileSync(import_path64.default.join(__dirname, "../package.json"), "utf-8")
28071
28274
  );
28072
28275
  var program = new import_commander.Command();
28073
28276
  program.name("node9").description("The Sudo Command for AI Agents").version(version);
28074
28277
  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
28278
  const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
28076
- const credPath = import_path63.default.join(import_os56.default.homedir(), ".node9", "credentials.json");
28077
- if (!import_fs66.default.existsSync(import_path63.default.dirname(credPath)))
28078
- import_fs66.default.mkdirSync(import_path63.default.dirname(credPath), { recursive: true });
28279
+ const credPath = import_path64.default.join(import_os57.default.homedir(), ".node9", "credentials.json");
28280
+ if (!import_fs66.default.existsSync(import_path64.default.dirname(credPath)))
28281
+ import_fs66.default.mkdirSync(import_path64.default.dirname(credPath), { recursive: true });
28079
28282
  const profileName = options.profile || "default";
28080
28283
  let existingCreds = {};
28081
28284
  try {
@@ -28095,7 +28298,7 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
28095
28298
  import_fs66.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
28096
28299
  let effectiveCloud = null;
28097
28300
  if (profileName === "default") {
28098
- const configPath = import_path63.default.join(import_os56.default.homedir(), ".node9", "config.json");
28301
+ const configPath = import_path64.default.join(import_os57.default.homedir(), ".node9", "config.json");
28099
28302
  let config = {};
28100
28303
  try {
28101
28304
  if (import_fs66.default.existsSync(configPath))
@@ -28114,8 +28317,8 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
28114
28317
  approvers.cloud = false;
28115
28318
  }
28116
28319
  s.approvers = approvers;
28117
- if (!import_fs66.default.existsSync(import_path63.default.dirname(configPath)))
28118
- import_fs66.default.mkdirSync(import_path63.default.dirname(configPath), { recursive: true });
28320
+ if (!import_fs66.default.existsSync(import_path64.default.dirname(configPath)))
28321
+ import_fs66.default.mkdirSync(import_path64.default.dirname(configPath), { recursive: true });
28119
28322
  import_fs66.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
28120
28323
  effectiveCloud = approvers.cloud === true;
28121
28324
  }
@@ -28225,37 +28428,21 @@ program.command("setup", { hidden: true }).description('Alias for "addto" \u2014
28225
28428
  );
28226
28429
  process.exit(1);
28227
28430
  });
28228
- program.command("removefrom", { hidden: true }).description("Remove Node9 hooks from an AI agent configuration").addHelpText(
28229
- "after",
28230
- "\n Supported targets: claude antigravity copilot gemini cursor codex windsurf vscode hud"
28231
- ).argument(
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 {
28431
+ program.command("removefrom", { hidden: true }).description("Remove Node9 hooks from an AI agent configuration").addHelpText("after", `
28432
+ Supported targets: ${agentTeardownTargets().join(" ")}`).argument("<target>", `The agent to remove from: ${agentTeardownTargets().join(" | ")}`).action((target) => {
28433
+ const agent = resolveAgentTeardown(target);
28434
+ if (!agent) {
28247
28435
  console.error(
28248
- import_chalk36.default.red(
28249
- `Unknown target: "${target}". Supported: claude, antigravity, copilot, gemini, cursor, codex, windsurf, vscode, hermes, hud`
28250
- )
28436
+ import_chalk36.default.red(`Unknown target: "${target}". Supported: ${agentTeardownTargets().join(", ")}`)
28251
28437
  );
28252
28438
  process.exit(1);
28439
+ return;
28253
28440
  }
28254
28441
  console.log(import_chalk36.default.cyan(`
28255
- \u{1F6E1}\uFE0F Node9: removing hooks from ${target}...
28442
+ \u{1F6E1}\uFE0F Node9: removing hooks from ${agent.label}...
28256
28443
  `));
28257
28444
  try {
28258
- fn();
28445
+ agent.fn();
28259
28446
  } catch (err2) {
28260
28447
  console.error(import_chalk36.default.red(` \u26A0\uFE0F Failed: ${err2 instanceof Error ? err2.message : String(err2)}`));
28261
28448
  process.exit(1);
@@ -28273,15 +28460,7 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
28273
28460
  }
28274
28461
  console.log(import_chalk36.default.bold("\nRemoving hooks..."));
28275
28462
  let teardownFailed = false;
28276
- for (const [label2, fn] of [
28277
- ["Claude", teardownClaude],
28278
- ["Gemini", teardownGemini],
28279
- ["Cursor", teardownCursor],
28280
- ["Codex", teardownCodex],
28281
- ["Windsurf", teardownWindsurf],
28282
- ["VSCode", teardownVSCode],
28283
- ["Hermes", teardownHermes]
28284
- ]) {
28463
+ for (const { label: label2, fn } of AGENT_TEARDOWNS) {
28285
28464
  try {
28286
28465
  fn();
28287
28466
  } catch (err2) {
@@ -28293,8 +28472,21 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
28293
28472
  );
28294
28473
  }
28295
28474
  }
28475
+ try {
28476
+ const residual = getAgentWiring().filter((a) => a.wireState === "wired");
28477
+ if (residual.length === 0) {
28478
+ console.log(import_chalk36.default.green(" \u2705 Verified \u2014 no node9 hooks or plugin shims remain"));
28479
+ } else {
28480
+ teardownFailed = true;
28481
+ console.error(import_chalk36.default.red(" \u26A0\uFE0F Still wired after teardown:"));
28482
+ for (const a of residual) {
28483
+ console.error(import_chalk36.default.red(` \u2022 ${a.label} \u2014 ${a.settingsPath}`));
28484
+ }
28485
+ }
28486
+ } catch {
28487
+ }
28296
28488
  if (options.purge) {
28297
- const node9Dir = import_path63.default.join(import_os56.default.homedir(), ".node9");
28489
+ const node9Dir = import_path64.default.join(import_os57.default.homedir(), ".node9");
28298
28490
  if (import_fs66.default.existsSync(node9Dir)) {
28299
28491
  const confirmed = await (0, import_prompts2.confirm)({
28300
28492
  message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
@@ -28425,7 +28617,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
28425
28617
  });
28426
28618
  program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
28427
28619
  try {
28428
- const dashboardPath = import_path63.default.join(__dirname, "dashboard.mjs");
28620
+ const dashboardPath = import_path64.default.join(__dirname, "dashboard.mjs");
28429
28621
  const dynamicImport = new Function("id", "return import(id)");
28430
28622
  const mod = await dynamicImport(`file://${dashboardPath}`);
28431
28623
  await mod.startMonitor();
@@ -28463,9 +28655,9 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
28463
28655
  Run "node9 addto claude" to register it as the statusLine.`
28464
28656
  ).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
28657
  if (subcommand === "debug") {
28466
- const flagFile = import_path63.default.join(import_os56.default.homedir(), ".node9", "hud-debug");
28658
+ const flagFile = import_path64.default.join(import_os57.default.homedir(), ".node9", "hud-debug");
28467
28659
  if (state === "on") {
28468
- import_fs66.default.mkdirSync(import_path63.default.dirname(flagFile), { recursive: true });
28660
+ import_fs66.default.mkdirSync(import_path64.default.dirname(flagFile), { recursive: true });
28469
28661
  import_fs66.default.writeFileSync(flagFile, "");
28470
28662
  console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
28471
28663
  console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
@@ -28592,7 +28784,7 @@ if (process.argv[2] !== "daemon") {
28592
28784
  const isCheckHook = process.argv[2] === "check";
28593
28785
  if (isCheckHook) {
28594
28786
  if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
28595
- const logPath = import_path63.default.join(import_os56.default.homedir(), ".node9", "hook-debug.log");
28787
+ const logPath = import_path64.default.join(import_os57.default.homedir(), ".node9", "hook-debug.log");
28596
28788
  const msg = reason instanceof Error ? reason.message : String(reason);
28597
28789
  import_fs66.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
28598
28790
  `);