@node9/proxy 2.47.2 → 2.48.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-main.js CHANGED
@@ -19279,8 +19279,8 @@ var init_audit = __esm({
19279
19279
  // src/config-schema.ts
19280
19280
  function formatIssues(issues) {
19281
19281
  const lines = issues.map((issue) => {
19282
- const path108 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
19283
- return ` \u2022 ${path108}: ${issue.message}`;
19282
+ const path110 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
19283
+ return ` \u2022 ${path110}: ${issue.message}`;
19284
19284
  });
19285
19285
  return `Invalid config:
19286
19286
  ${lines.join("\n")}`;
@@ -19293,9 +19293,9 @@ function prunePaths(root, paths) {
19293
19293
  const yi = y[y.length - 1];
19294
19294
  return typeof xi === "number" && typeof yi === "number" ? yi - xi : 0;
19295
19295
  });
19296
- for (const path108 of ordered) {
19296
+ for (const path110 of ordered) {
19297
19297
  let cur = root;
19298
- for (const key of path108.slice(0, -1)) {
19298
+ for (const key of path110.slice(0, -1)) {
19299
19299
  if (cur === null || typeof cur !== "object") {
19300
19300
  cur = void 0;
19301
19301
  break;
@@ -19303,7 +19303,7 @@ function prunePaths(root, paths) {
19303
19303
  cur = cur[key];
19304
19304
  }
19305
19305
  if (cur === null || typeof cur !== "object") continue;
19306
- const last = path108[path108.length - 1];
19306
+ const last = path110[path110.length - 1];
19307
19307
  if (Array.isArray(cur)) {
19308
19308
  const i = Number(last);
19309
19309
  if (Number.isInteger(i) && i >= 0 && i < cur.length) {
@@ -19339,7 +19339,7 @@ function sanitizeConfig(raw) {
19339
19339
  return issue.keys.map((k) => [...at, k]);
19340
19340
  }
19341
19341
  return [at.slice(0, -level || void 0)];
19342
- }).filter((path108) => path108.length > 0);
19342
+ }).filter((path110) => path110.length > 0);
19343
19343
  if (paths.length === 0 || !prunePaths(working, paths)) break;
19344
19344
  }
19345
19345
  if (ConfigFileSchema.safeParse(working).success) break;
@@ -20933,13 +20933,13 @@ function getConfig(cwd) {
20933
20933
  }
20934
20934
  if (Array.isArray(mc.jailPaths)) {
20935
20935
  for (const jp of mc.jailPaths) {
20936
- const path108 = typeof jp?.path === "string" ? jp.path.trim() : "";
20937
- if (!path108) continue;
20936
+ const path110 = typeof jp?.path === "string" ? jp.path.trim() : "";
20937
+ if (!path110) continue;
20938
20938
  const verdict = jp?.verdict === "review" ? "review" : "block";
20939
- for (const r of pathRules(path108, verdict, "org-managed jail")) {
20939
+ for (const r of pathRules(path110, verdict, "org-managed jail")) {
20940
20940
  mergedPolicy.smartRules.push({ ...r, name: `org:${r.name}` });
20941
20941
  }
20942
- mergedPolicy.managedJailPaths.push({ path: path108, verdict });
20942
+ mergedPolicy.managedJailPaths.push({ path: path110, verdict });
20943
20943
  }
20944
20944
  }
20945
20945
  if (Array.isArray(mc.trustedHosts)) {
@@ -26723,6 +26723,70 @@ var init_loop_detector = __esm({
26723
26723
  });
26724
26724
 
26725
26725
  // src/policy/negotiation.ts
26726
+ function oneLine(text) {
26727
+ return stripTerminalEscapes(text.slice(0, ONE_LINE_INPUT_MAX)).replace(/\s*\u2014\s*/g, ", ").replace(/\s+/g, " ").trim();
26728
+ }
26729
+ function bounded(text, max2 = USER_LINE_PART_MAX) {
26730
+ return text.length > max2 ? `${text.slice(0, max2 - 3).trimEnd()}...` : text;
26731
+ }
26732
+ function userLinePart(text) {
26733
+ return bounded(oneLine(text).replace(/[.\s]+$/, ""));
26734
+ }
26735
+ function userLineValue(text, max2 = 80) {
26736
+ const v = bounded(oneLine(text).replace(/`/g, "'"), max2);
26737
+ return v ? `\`${v}\`` : "";
26738
+ }
26739
+ function userLineOf(message) {
26740
+ const first = message.split("\n", 1)[0];
26741
+ return first.startsWith(USER_LINE_ICON) ? first : void 0;
26742
+ }
26743
+ function withUserLine(line, body) {
26744
+ return `${USER_LINE_ICON} ${line}
26745
+ ${QUOTE_INSTRUCTION}
26746
+ ${body}`;
26747
+ }
26748
+ function blockedLine(context, fallback) {
26749
+ return `Node9 blocked: ${ruleWhat(context?.ruleDescription) || fallback}`;
26750
+ }
26751
+ function firstSentence(text) {
26752
+ const plain = oneLine(text.replace(PICTOGRAPHS, ""));
26753
+ return plain.split(/(?<=[.!?])\s+(?=[A-Z])/)[0] ?? plain;
26754
+ }
26755
+ function withoutLeadingVerdict(text) {
26756
+ return text.replace(/^node9\b\s*:?\s*/i, "").replace(/^blocked\b\s*:?\s*/i, "");
26757
+ }
26758
+ function ruleWhat(description) {
26759
+ if (!description) return "";
26760
+ const s = firstSentence(description).replace(/^node9\s*:\s*/i, "").replace(/^blocked\s*:\s*/i, "");
26761
+ if (!/[\p{L}\p{N}]/u.test(s)) return "";
26762
+ const by = s.match(IS_BLOCKED_BY) ?? s.match(COMMA_BLOCKED_BY);
26763
+ if (by) return userLinePart(`${by[1]} (${by[2]})`);
26764
+ const bare = s.match(IS_BLOCKED);
26765
+ return userLinePart(bare ? bare[1] : s);
26766
+ }
26767
+ function reasonSentence(reason) {
26768
+ if (!reason) return "";
26769
+ const s = withoutLeadingVerdict(firstSentence(reason));
26770
+ if (/^("[^"]*")?\.?$/.test(s)) return "";
26771
+ return userLinePart(s);
26772
+ }
26773
+ function maliciousPackageLine(reason) {
26774
+ if (!reason) return "";
26775
+ const names = [...reason.matchAll(/"([^"]+)"/g)].map((m) => {
26776
+ const spec = m[1];
26777
+ const at = spec.lastIndexOf("@");
26778
+ return at > 0 ? spec.slice(0, at) : spec;
26779
+ });
26780
+ if (names.length === 0) return "";
26781
+ const advisories = [...reason.matchAll(/\b((?:MAL|GHSA|CVE|OSV|PYSEC|RUSTSEC)-[\w-]+)/g)].map(
26782
+ (m) => m[1]
26783
+ );
26784
+ const unique2 = [...new Set(names)];
26785
+ const suffix = advisories.length ? ` (${[...new Set(advisories)].join(", ")})` : "";
26786
+ return userLinePart(
26787
+ unique2.length === 1 ? `${unique2[0]} is a known malicious package${suffix}` : `${unique2.join(", ")} are known malicious packages${suffix}`
26788
+ );
26789
+ }
26726
26790
  function buildNegotiationMessage(blockedByLabel, isHumanDecision2, humanReason, recoveryCommand, context) {
26727
26791
  if (isHumanDecision2 && context?.redirect && humanReason) {
26728
26792
  return `NODE9: The user stopped this action and gave you an instruction.
@@ -26732,88 +26796,138 @@ INSTRUCTIONS:
26732
26796
  - Retry the original action only if the instruction says you may.`;
26733
26797
  }
26734
26798
  if (isHumanDecision2) {
26735
- return `NODE9: The human user rejected this action.
26799
+ return withUserLine(
26800
+ "Node9: you blocked this action",
26801
+ `NODE9: The human user rejected this action.
26736
26802
  REASON: ${humanReason || "No specific reason provided."}
26737
26803
  INSTRUCTIONS:
26738
26804
  - Do NOT retry this exact command.
26739
26805
  - Acknowledge the block to the user and ask if there is an alternative approach.
26740
- - If you believe this action is critical, explain your reasoning and ask them to run "node9 pause 15m" to proceed.`;
26806
+ - If you believe this action is critical, explain your reasoning and ask them to run "node9 pause 15m" to proceed.`
26807
+ );
26741
26808
  }
26742
26809
  if (context?.kind === "protected-path") {
26743
26810
  const subject = context.path ? `${context.path} is a protected file` : "This file is protected";
26744
- return `NODE9: Blocked. ${subject}, and node9 stopped this call to it. The call did not run, so nothing was exposed.
26811
+ const shown = context.path ? userLineValue(context.path) : "";
26812
+ const line2 = shown ? `Node9 blocked access to ${shown} (protected file)` : "Node9 blocked access to a protected file";
26813
+ return withUserLine(
26814
+ line2,
26815
+ `NODE9: Blocked. ${subject}, and node9 stopped this call to it. The call did not run, so nothing was exposed.
26745
26816
  INSTRUCTIONS:
26746
26817
  - Do NOT retry, and do NOT reach the file another way (cat, grep, a copy, a script, a redirect).
26747
26818
  - If this step needs that file, ask the user to provide what you need or to do the step themselves.
26748
- - Tell the user node9 protected this file, then ask how to proceed.`;
26819
+ - Tell the user node9 protected this file, then ask how to proceed.`
26820
+ );
26749
26821
  }
26750
26822
  const label3 = blockedByLabel.toLowerCase();
26751
26823
  if (label3.includes("dlp") || label3.includes("secret detected") || label3.includes("credential review")) {
26752
- return `NODE9 SECURITY ALERT: A sensitive credential (API key, token, or private key) was found in your tool call arguments.
26824
+ return withUserLine(
26825
+ "Node9 blocked this command: it contains a secret",
26826
+ `NODE9 SECURITY ALERT: A sensitive credential (API key, token, or private key) was found in your tool call arguments.
26753
26827
  CRITICAL INSTRUCTION: Do NOT retry this action.
26754
26828
  REQUIRED ACTIONS:
26755
26829
  1. Remove the hardcoded credential from your command or code.
26756
26830
  2. Use an environment variable or a dedicated secrets manager instead.
26757
26831
  3. Treat the leaked credential as compromised and rotate it immediately.
26758
26832
  Do NOT attempt to bypass this check or pass the credential through another tool.
26759
- - Tell the user node9 blocked this and why, then ask how to proceed.`;
26833
+ - Tell the user node9 blocked this and why, then ask how to proceed.`
26834
+ );
26760
26835
  }
26761
26836
  if (label3.includes("package check")) {
26762
- return `NODE9: Blocked \u2014 ${humanReason || "a package in this command is known to be malicious."}
26837
+ const pkg = maliciousPackageLine(humanReason);
26838
+ return withUserLine(
26839
+ pkg ? `Node9 blocked: ${pkg}` : "Node9 blocked: this package is known to be malicious",
26840
+ `NODE9: Blocked \u2014 ${humanReason || "a package in this command is known to be malicious."}
26763
26841
  INSTRUCTIONS:
26764
26842
  - Do NOT install this package, and do NOT fetch it another way (a different package manager, a tarball URL, a git URL, a mirror).
26765
26843
  - If a dependency is needed, suggest a well-known alternative and let the user choose.
26766
- - Tell the user node9 blocked this install and name the advisory, then ask how to proceed.`;
26844
+ - Tell the user node9 blocked this install and name the advisory, then ask how to proceed.`
26845
+ );
26767
26846
  }
26768
26847
  if (label3.includes("sql safety") && label3.includes("delete without where")) {
26769
- return `NODE9: Blocked \u2014 DELETE without WHERE clause would wipe the entire table.
26848
+ return withUserLine(
26849
+ blockedLine(context, "DELETE without WHERE would wipe the whole table"),
26850
+ `NODE9: Blocked \u2014 DELETE without WHERE clause would wipe the entire table.
26770
26851
  INSTRUCTION: Add a WHERE clause to scope the deletion (e.g. WHERE id = <value>).
26771
26852
  Do NOT retry without a WHERE clause.
26772
- - Tell the user node9 blocked this and why, then ask how to proceed.`;
26853
+ - Tell the user node9 blocked this and why, then ask how to proceed.`
26854
+ );
26773
26855
  }
26774
26856
  if (label3.includes("sql safety") && label3.includes("update without where")) {
26775
- return `NODE9: Blocked \u2014 UPDATE without WHERE clause would update every row.
26857
+ return withUserLine(
26858
+ blockedLine(context, "UPDATE without WHERE would change every row"),
26859
+ `NODE9: Blocked \u2014 UPDATE without WHERE clause would update every row.
26776
26860
  INSTRUCTION: Add a WHERE clause to scope the update (e.g. WHERE id = <value>).
26777
26861
  Do NOT retry without a WHERE clause.
26778
- - Tell the user node9 blocked this and why, then ask how to proceed.`;
26862
+ - Tell the user node9 blocked this and why, then ask how to proceed.`
26863
+ );
26779
26864
  }
26780
26865
  if (label3.includes("dangerous word")) {
26781
26866
  const match = blockedByLabel.match(/dangerous word: "([^"]+)"/i);
26782
26867
  const word = match?.[1] ?? "a dangerous keyword";
26783
- return `NODE9: Blocked \u2014 command contains forbidden keyword "${word}".
26868
+ return withUserLine(
26869
+ blockedLine(context, `the command contains ${userLineValue(word)}`),
26870
+ `NODE9: Blocked \u2014 command contains forbidden keyword "${word}".
26784
26871
  INSTRUCTION: Do NOT use "${word}". Use a non-destructive alternative.
26785
26872
  Do NOT attempt to bypass this with shell tricks or aliases \u2014 it will be blocked again.
26786
- - Tell the user node9 blocked this and why, then ask how to proceed.`;
26873
+ - Tell the user node9 blocked this and why, then ask how to proceed.`
26874
+ );
26787
26875
  }
26788
26876
  if (label3.includes("path blocked") || label3.includes("sandbox")) {
26789
- return `NODE9: Blocked \u2014 operation targets a path outside the allowed sandbox.
26877
+ return withUserLine(
26878
+ blockedLine(context, "this path is outside the allowed sandbox"),
26879
+ `NODE9: Blocked \u2014 operation targets a path outside the allowed sandbox.
26790
26880
  INSTRUCTION: Move your output to an allowed directory such as /tmp/ or the project directory.
26791
26881
  Do NOT retry on the same path.
26792
- - Tell the user node9 blocked this and why, then ask how to proceed.`;
26882
+ - Tell the user node9 blocked this and why, then ask how to proceed.`
26883
+ );
26793
26884
  }
26794
26885
  if (label3.includes("inline execution")) {
26795
- return `NODE9: Blocked \u2014 inline code execution (e.g. bash -c "...") is not allowed.
26886
+ return withUserLine(
26887
+ blockedLine(context, "inline code execution is not allowed"),
26888
+ `NODE9: Blocked \u2014 inline code execution (e.g. bash -c "...") is not allowed.
26796
26889
  INSTRUCTION: Use individual tool calls instead of embedding code in a shell string.
26797
- - Tell the user node9 blocked this and why, then ask how to proceed.`;
26890
+ - Tell the user node9 blocked this and why, then ask how to proceed.`
26891
+ );
26798
26892
  }
26799
26893
  if (label3.includes("strict mode")) {
26800
- return `NODE9: Blocked \u2014 the Block all level is on. All tool calls require explicit human approval.
26801
- INSTRUCTION: Inform the user this action is pending approval. Wait for them to approve via the dashboard or run "node9 pause".`;
26894
+ return withUserLine(
26895
+ "Node9: the Block all level is on, so every action needs your approval",
26896
+ `NODE9: Blocked \u2014 the Block all level is on. All tool calls require explicit human approval.
26897
+ INSTRUCTION: Inform the user this action is pending approval. Wait for them to approve via the dashboard or run "node9 pause".`
26898
+ );
26802
26899
  }
26803
26900
  if (label3.includes("rule") && label3.includes("default block")) {
26804
26901
  const match = blockedByLabel.match(/rule "([^"]+)"/i);
26805
- const rule = match?.[1] ?? "a policy rule";
26806
- return `NODE9: Blocked \u2014 action "${rule}" is forbidden by security policy.
26807
- INSTRUCTION: Do NOT use "${rule}". Find a read-only or non-destructive alternative.
26902
+ const rule2 = match?.[1] ?? "a policy rule";
26903
+ return withUserLine(
26904
+ blockedLine(context, `${userLineValue(rule2)} is not allowed by policy`),
26905
+ `NODE9: Blocked \u2014 action "${rule2}" is forbidden by security policy.
26906
+ INSTRUCTION: Do NOT use "${rule2}". Find a read-only or non-destructive alternative.
26808
26907
  Do NOT attempt to bypass this rule.
26809
- - Tell the user node9 blocked this and why, then ask how to proceed.`;
26908
+ - Tell the user node9 blocked this and why, then ask how to proceed.`
26909
+ );
26910
+ }
26911
+ const timedOut = label3.includes("approval timeout");
26912
+ const rule = ruleWhat(context?.ruleDescription);
26913
+ let line;
26914
+ if (timedOut) {
26915
+ line = rule ? `Node9 blocked: no one approved this in time (${rule.replace(/ \(([^()]+)\)$/, ", $1")})` : "Node9 blocked: no one approved this in time";
26916
+ } else if (rule) {
26917
+ line = `Node9 blocked: ${rule}`;
26918
+ } else {
26919
+ const why = reasonSentence(humanReason);
26920
+ line = why ? `Node9 blocked: ${why}` : `Node9 blocked this action (${userLinePart(agentFacingLabel(blockedByLabel))})`;
26810
26921
  }
26811
26922
  const recovery = recoveryCommand ? `
26812
26923
  REQUIRED ACTION: Run \`${recoveryCommand}\` first, then retry your original command.` : "\n- Pivot to a non-destructive or read-only alternative.";
26813
- return `NODE9: Action blocked by security policy [${agentFacingLabel(blockedByLabel)}].
26924
+ return withUserLine(
26925
+ line,
26926
+ `NODE9: Action blocked by security policy [${agentFacingLabel(blockedByLabel)}].
26814
26927
  INSTRUCTIONS:
26815
26928
  - Do NOT retry this exact command or attempt to bypass the rule.${recovery}
26816
- - Inform the user which security rule was triggered and ask how to proceed.`;
26929
+ - Inform the user which security rule was triggered and ask how to proceed.`
26930
+ );
26817
26931
  }
26818
26932
  function buildReviewMessage(blockedByLabel, ruleDescription, reason) {
26819
26933
  const why = ruleDescription || (reason && reason !== blockedByLabel ? reason : void 0) || blockedByLabel || "this action needs your review";
@@ -26828,7 +26942,7 @@ function isHumanDecision(label3, blockedBy, decidedBy) {
26828
26942
  return l.includes("user") || l.includes("daemon") || l.includes("decision");
26829
26943
  }
26830
26944
  function agentFacingLabel(label3) {
26831
- const plain = label3.replace(/[\p{Extended_Pictographic}\u200D\uFE0F]/gu, "").replace(/\bNode9\b/g, "node9").replace(/\s+/g, " ").trim();
26945
+ const plain = label3.replace(PICTOGRAPHS, "").replace(/\bNode9\b/g, "node9").replace(/\s+/g, " ").trim();
26832
26946
  return plain || "Security Policy";
26833
26947
  }
26834
26948
  function asApprovalRequest(description) {
@@ -26844,11 +26958,20 @@ function asApprovalRequest(description) {
26844
26958
  }
26845
26959
  return description;
26846
26960
  }
26847
- var BLOCKED_BY, DASH_BLOCKED_BY, SHIELD;
26961
+ var USER_LINE_ICON, QUOTE_INSTRUCTION, USER_LINE_PART_MAX, ONE_LINE_INPUT_MAX, PICTOGRAPHS, IS_BLOCKED_BY, IS_BLOCKED, COMMA_BLOCKED_BY, BLOCKED_BY, DASH_BLOCKED_BY, SHIELD;
26848
26962
  var init_negotiation = __esm({
26849
26963
  "src/policy/negotiation.ts"() {
26850
26964
  "use strict";
26851
26965
  init_cjs_shims();
26966
+ init_dist();
26967
+ USER_LINE_ICON = "\u{1F6E1}\uFE0F";
26968
+ QUOTE_INSTRUCTION = "Start your reply with the line above, exactly as written, on its own line.";
26969
+ USER_LINE_PART_MAX = 160;
26970
+ ONE_LINE_INPUT_MAX = 1e3;
26971
+ PICTOGRAPHS = /[\p{Extended_Pictographic}\u200D\uFE0F]/gu;
26972
+ IS_BLOCKED_BY = /^(.+?) (?:is|are) blocked by (.+?)\.?$/i;
26973
+ IS_BLOCKED = /^(.+?) (?:is|are) blocked\.?$/i;
26974
+ COMMA_BLOCKED_BY = /^(.+?), blocked by (.+?)\.?$/i;
26852
26975
  BLOCKED_BY = " is blocked by ";
26853
26976
  DASH_BLOCKED_BY = " \u2014 blocked by ";
26854
26977
  SHIELD = " shield";
@@ -45916,21 +46039,21 @@ function patchConfig(configPath2, patch) {
45916
46039
  throw err2;
45917
46040
  }
45918
46041
  }
45919
- var import_path84, import_os71, GLOBAL_CONFIG_PATH;
46042
+ var import_path86, import_os72, GLOBAL_CONFIG_PATH;
45920
46043
  var init_patch = __esm({
45921
46044
  "src/config/patch.ts"() {
45922
46045
  "use strict";
45923
46046
  init_cjs_shims();
45924
- import_path84 = __toESM(require("path"));
45925
- import_os71 = __toESM(require("os"));
46047
+ import_path86 = __toESM(require("path"));
46048
+ import_os72 = __toESM(require("os"));
45926
46049
  init_write();
45927
- GLOBAL_CONFIG_PATH = import_path84.default.join(import_os71.default.homedir(), ".node9", "config.json");
46050
+ GLOBAL_CONFIG_PATH = import_path86.default.join(import_os72.default.homedir(), ".node9", "config.json");
45928
46051
  }
45929
46052
  });
45930
46053
 
45931
46054
  // src/auth/egress-config.ts
45932
46055
  function egressConfigPath() {
45933
- return import_path85.default.join(import_os72.default.homedir(), ".node9", "config.json");
46056
+ return import_path87.default.join(import_os73.default.homedir(), ".node9", "config.json");
45934
46057
  }
45935
46058
  function readEgressRawConfig() {
45936
46059
  return readConfigFileLegacy(egressConfigPath());
@@ -45990,14 +46113,14 @@ function normalizeEgressHost(host2) {
45990
46113
  function isValidEgressHost(host2) {
45991
46114
  return EGRESS_HOST_RE.test(host2);
45992
46115
  }
45993
- var import_os72, import_path85, DEFAULT_EGRESS, EGRESS_HOST_RE;
46116
+ var import_os73, import_path87, DEFAULT_EGRESS, EGRESS_HOST_RE;
45994
46117
  var init_egress_config = __esm({
45995
46118
  "src/auth/egress-config.ts"() {
45996
46119
  "use strict";
45997
46120
  init_cjs_shims();
45998
46121
  init_write();
45999
- import_os72 = __toESM(require("os"));
46000
- import_path85 = __toESM(require("path"));
46122
+ import_os73 = __toESM(require("os"));
46123
+ import_path87 = __toESM(require("path"));
46001
46124
  init_dist();
46002
46125
  DEFAULT_EGRESS = {
46003
46126
  enabled: false,
@@ -46025,27 +46148,27 @@ __export(local_setup_exports, {
46025
46148
  runLocalSetup: () => runLocalSetup
46026
46149
  });
46027
46150
  function configPath() {
46028
- return import_path86.default.join(import_os73.default.homedir(), ".node9", "config.json");
46151
+ return import_path88.default.join(import_os74.default.homedir(), ".node9", "config.json");
46029
46152
  }
46030
46153
  function combined(values) {
46031
46154
  return values.every(Boolean) ? "on" : values.some(Boolean) ? "partial" : "off";
46032
46155
  }
46033
46156
  function readLocalState(opts = {}) {
46034
46157
  const file2 = configPath();
46035
- if (import_fs86.default.existsSync(file2) && !opts.replaceConfig) {
46158
+ if (import_fs88.default.existsSync(file2) && !opts.replaceConfig) {
46036
46159
  let raw;
46037
46160
  try {
46038
- raw = JSON.parse(import_fs86.default.readFileSync(file2, "utf8"));
46161
+ raw = JSON.parse(import_fs88.default.readFileSync(file2, "utf8"));
46039
46162
  } catch {
46040
46163
  raw = void 0;
46041
46164
  }
46042
46165
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) throw invalidConfig();
46043
46166
  }
46044
- const config = getConfig(import_path86.default.join(import_os73.default.homedir(), ".node9"));
46167
+ const config = getConfig(import_path88.default.join(import_os74.default.homedir(), ".node9"));
46045
46168
  const active = readActiveShields();
46046
46169
  const installed = isDaemonServiceInstalled();
46047
46170
  return {
46048
- fresh: !import_fs86.default.existsSync(file2),
46171
+ fresh: !import_fs88.default.existsSync(file2),
46049
46172
  managed: config.policySource === "workspace",
46050
46173
  shields: combined(DEFAULT_SHIELDS.map((s) => active.includes(s))),
46051
46174
  dlp: combined([config.policy.dlp.enabled, config.policy.dlp.pii !== "off"]),
@@ -46093,7 +46216,7 @@ function diffChoices(state, selected, partial = {}) {
46093
46216
  }
46094
46217
  function setAutostart(enabled) {
46095
46218
  const file2 = configPath();
46096
- const raw = JSON.parse(import_fs86.default.readFileSync(file2, "utf8"));
46219
+ const raw = JSON.parse(import_fs88.default.readFileSync(file2, "utf8"));
46097
46220
  if (raw.settings?.autoStartDaemon === enabled) return;
46098
46221
  raw.settings = { ...raw.settings, autoStartDaemon: enabled };
46099
46222
  atomicWriteSync(file2, JSON.stringify(raw, null, 2) + "\n", { mode: 384 });
@@ -46260,14 +46383,14 @@ async function runLocalSetup(opts) {
46260
46383
  if (interactive && !state.managed && !opts.skipSetup) await askTelemetry(agents, firstInstall);
46261
46384
  return collectSummary(applied);
46262
46385
  }
46263
- var import_fs86, import_os73, import_path86, DEFAULT_SHIELDS;
46386
+ var import_fs88, import_os74, import_path88, DEFAULT_SHIELDS;
46264
46387
  var init_local_setup = __esm({
46265
46388
  "src/cli/local-setup.ts"() {
46266
46389
  "use strict";
46267
46390
  init_cjs_shims();
46268
- import_fs86 = __toESM(require("fs"));
46269
- import_os73 = __toESM(require("os"));
46270
- import_path86 = __toESM(require("path"));
46391
+ import_fs88 = __toESM(require("fs"));
46392
+ import_os74 = __toESM(require("os"));
46393
+ import_path88 = __toESM(require("path"));
46271
46394
  init_config();
46272
46395
  init_patch();
46273
46396
  init_keyed_guard();
@@ -46330,8 +46453,8 @@ async function askTelemetry(agents, firstInstall) {
46330
46453
  }
46331
46454
  }
46332
46455
  function ensureConfig(mode, force = false) {
46333
- const file2 = import_path87.default.join(import_os74.default.homedir(), ".node9", "config.json");
46334
- const firstInstall = !import_fs87.default.existsSync(file2);
46456
+ const file2 = import_path89.default.join(import_os75.default.homedir(), ".node9", "config.json");
46457
+ const firstInstall = !import_fs89.default.existsSync(file2);
46335
46458
  if (firstInstall || force) {
46336
46459
  const body = legacyToV2(
46337
46460
  mode !== void 0 && mode !== DEFAULT_CONFIG.settings.mode ? { settings: { mode } } : {}
@@ -46383,16 +46506,16 @@ function registerInitCommand(program2) {
46383
46506
  }
46384
46507
  );
46385
46508
  }
46386
- var import_fs87, import_path87, import_os74, import_https6, TELEMETRY_PROMPT;
46509
+ var import_fs89, import_path89, import_os75, import_https6, TELEMETRY_PROMPT;
46387
46510
  var init_init = __esm({
46388
46511
  "src/cli/commands/init.ts"() {
46389
46512
  "use strict";
46390
46513
  init_cjs_shims();
46391
46514
  init_v2();
46392
46515
  init_write();
46393
- import_fs87 = __toESM(require("fs"));
46394
- import_path87 = __toESM(require("path"));
46395
- import_os74 = __toESM(require("os"));
46516
+ import_fs89 = __toESM(require("fs"));
46517
+ import_path89 = __toESM(require("path"));
46518
+ import_os75 = __toESM(require("os"));
46396
46519
  import_https6 = __toESM(require("https"));
46397
46520
  init_config();
46398
46521
  init_setup();
@@ -47519,14 +47642,14 @@ var require_util = __commonJS({
47519
47642
  }
47520
47643
  const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
47521
47644
  let origin = url.origin != null ? url.origin : `${url.protocol || ""}//${url.hostname || ""}:${port}`;
47522
- let path108 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
47645
+ let path110 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
47523
47646
  if (origin[origin.length - 1] === "/") {
47524
47647
  origin = origin.slice(0, origin.length - 1);
47525
47648
  }
47526
- if (path108 && path108[0] !== "/") {
47527
- path108 = `/${path108}`;
47649
+ if (path110 && path110[0] !== "/") {
47650
+ path110 = `/${path110}`;
47528
47651
  }
47529
- return new URL(`${origin}${path108}`);
47652
+ return new URL(`${origin}${path110}`);
47530
47653
  }
47531
47654
  if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
47532
47655
  throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
@@ -48349,9 +48472,9 @@ var require_diagnostics = __commonJS({
48349
48472
  "undici:client:sendHeaders",
48350
48473
  (evt) => {
48351
48474
  const {
48352
- request: { method, path: path108, origin }
48475
+ request: { method, path: path110, origin }
48353
48476
  } = evt;
48354
- debugLog2("sending request to %s %s%s", method, origin, path108);
48477
+ debugLog2("sending request to %s %s%s", method, origin, path110);
48355
48478
  }
48356
48479
  );
48357
48480
  }
@@ -48369,14 +48492,14 @@ var require_diagnostics = __commonJS({
48369
48492
  "undici:request:headers",
48370
48493
  (evt) => {
48371
48494
  const {
48372
- request: { method, path: path108, origin },
48495
+ request: { method, path: path110, origin },
48373
48496
  response: { statusCode }
48374
48497
  } = evt;
48375
48498
  debugLog2(
48376
48499
  "received response to %s %s%s - HTTP %d",
48377
48500
  method,
48378
48501
  origin,
48379
- path108,
48502
+ path110,
48380
48503
  statusCode
48381
48504
  );
48382
48505
  }
@@ -48385,23 +48508,23 @@ var require_diagnostics = __commonJS({
48385
48508
  "undici:request:trailers",
48386
48509
  (evt) => {
48387
48510
  const {
48388
- request: { method, path: path108, origin }
48511
+ request: { method, path: path110, origin }
48389
48512
  } = evt;
48390
- debugLog2("trailers received from %s %s%s", method, origin, path108);
48513
+ debugLog2("trailers received from %s %s%s", method, origin, path110);
48391
48514
  }
48392
48515
  );
48393
48516
  diagnosticsChannel.subscribe(
48394
48517
  "undici:request:error",
48395
48518
  (evt) => {
48396
48519
  const {
48397
- request: { method, path: path108, origin },
48520
+ request: { method, path: path110, origin },
48398
48521
  error
48399
48522
  } = evt;
48400
48523
  debugLog2(
48401
48524
  "request to %s %s%s errored - %s",
48402
48525
  method,
48403
48526
  origin,
48404
- path108,
48527
+ path110,
48405
48528
  error.message
48406
48529
  );
48407
48530
  }
@@ -48517,7 +48640,7 @@ var require_request = __commonJS({
48517
48640
  var kHandler = /* @__PURE__ */ Symbol("handler");
48518
48641
  var Request = class {
48519
48642
  constructor(origin, {
48520
- path: path108,
48643
+ path: path110,
48521
48644
  method,
48522
48645
  body,
48523
48646
  headers,
@@ -48534,11 +48657,11 @@ var require_request = __commonJS({
48534
48657
  maxRedirections,
48535
48658
  typeOfService
48536
48659
  }, handler) {
48537
- if (typeof path108 !== "string") {
48660
+ if (typeof path110 !== "string") {
48538
48661
  throw new InvalidArgumentError("path must be a string");
48539
- } else if (path108[0] !== "/" && !(path108.startsWith("http://") || path108.startsWith("https://")) && method !== "CONNECT") {
48662
+ } else if (path110[0] !== "/" && !(path110.startsWith("http://") || path110.startsWith("https://")) && method !== "CONNECT") {
48540
48663
  throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
48541
- } else if (invalidPathRegex.test(path108)) {
48664
+ } else if (invalidPathRegex.test(path110)) {
48542
48665
  throw new InvalidArgumentError("invalid request path");
48543
48666
  }
48544
48667
  if (typeof method !== "string") {
@@ -48613,7 +48736,7 @@ var require_request = __commonJS({
48613
48736
  this.completed = false;
48614
48737
  this.aborted = false;
48615
48738
  this.upgrade = upgrade || null;
48616
- this.path = query ? serializePathWithQuery(path108, query) : path108;
48739
+ this.path = query ? serializePathWithQuery(path110, query) : path110;
48617
48740
  this.origin = origin;
48618
48741
  this.protocol = getProtocolFromUrlString(origin);
48619
48742
  this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
@@ -53860,7 +53983,7 @@ var require_client_h1 = __commonJS({
53860
53983
  return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
53861
53984
  }
53862
53985
  function writeH1(client, request2) {
53863
- const { method, path: path108, host: host2, upgrade, blocking, reset } = request2;
53986
+ const { method, path: path110, host: host2, upgrade, blocking, reset } = request2;
53864
53987
  let { body, headers, contentLength } = request2;
53865
53988
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
53866
53989
  if (util.isFormDataLike(body)) {
@@ -53938,7 +54061,7 @@ var require_client_h1 = __commonJS({
53938
54061
  if (socket.setTypeOfService) {
53939
54062
  socket.setTypeOfService(request2.typeOfService);
53940
54063
  }
53941
- let header = `${method} ${path108} HTTP/1.1\r
54064
+ let header = `${method} ${path110} HTTP/1.1\r
53942
54065
  `;
53943
54066
  if (typeof host2 === "string") {
53944
54067
  header += `host: ${host2}\r
@@ -54616,7 +54739,7 @@ var require_client_h2 = __commonJS({
54616
54739
  const headersTimeout = request2.headersTimeout ?? client[kHeadersTimeout];
54617
54740
  const bodyTimeout = request2.bodyTimeout ?? client[kBodyTimeout];
54618
54741
  const session = client[kHTTP2Session];
54619
- const { method, path: path108, host: host2, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2;
54742
+ const { method, path: path110, host: host2, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2;
54620
54743
  let { body } = request2;
54621
54744
  if (upgrade != null && upgrade !== "websocket") {
54622
54745
  util.errorRequest(client, request2, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
@@ -54685,7 +54808,7 @@ var require_client_h2 = __commonJS({
54685
54808
  }
54686
54809
  headers[HTTP2_HEADER_METHOD] = "CONNECT";
54687
54810
  headers[HTTP2_HEADER_PROTOCOL] = "websocket";
54688
- headers[HTTP2_HEADER_PATH] = path108;
54811
+ headers[HTTP2_HEADER_PATH] = path110;
54689
54812
  if (protocol === "ws:" || protocol === "wss:") {
54690
54813
  headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
54691
54814
  } else {
@@ -54737,7 +54860,7 @@ var require_client_h2 = __commonJS({
54737
54860
  stream.setTimeout(headersTimeout);
54738
54861
  return true;
54739
54862
  }
54740
- headers[HTTP2_HEADER_PATH] = path108;
54863
+ headers[HTTP2_HEADER_PATH] = path110;
54741
54864
  headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
54742
54865
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
54743
54866
  if (body && typeof body.read === "function") {
@@ -57104,10 +57227,10 @@ var require_proxy_agent = __commonJS({
57104
57227
  };
57105
57228
  const {
57106
57229
  origin,
57107
- path: path108 = "/",
57230
+ path: path110 = "/",
57108
57231
  headers = {}
57109
57232
  } = opts;
57110
- opts.path = origin + path108;
57233
+ opts.path = origin + path110;
57111
57234
  if (!("host" in headers) && !("Host" in headers)) {
57112
57235
  const { host: host2 } = new URL(origin);
57113
57236
  headers.host = host2;
@@ -59282,20 +59405,20 @@ var require_mock_utils = __commonJS({
59282
59405
  }
59283
59406
  return normalizedQp;
59284
59407
  }
59285
- function safeUrl(path108) {
59286
- if (typeof path108 !== "string") {
59287
- return path108;
59408
+ function safeUrl(path110) {
59409
+ if (typeof path110 !== "string") {
59410
+ return path110;
59288
59411
  }
59289
- const pathSegments = path108.split("?", 3);
59412
+ const pathSegments = path110.split("?", 3);
59290
59413
  if (pathSegments.length !== 2) {
59291
- return path108;
59414
+ return path110;
59292
59415
  }
59293
59416
  const qp = new URLSearchParams(pathSegments.pop());
59294
59417
  qp.sort();
59295
59418
  return [...pathSegments, qp.toString()].join("?");
59296
59419
  }
59297
- function matchKey(mockDispatch2, { path: path108, method, body, headers }) {
59298
- const pathMatch = matchValue(mockDispatch2.path, path108);
59420
+ function matchKey(mockDispatch2, { path: path110, method, body, headers }) {
59421
+ const pathMatch = matchValue(mockDispatch2.path, path110);
59299
59422
  const methodMatch = matchValue(mockDispatch2.method, method);
59300
59423
  const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
59301
59424
  const headersMatch = matchHeaders(mockDispatch2, headers);
@@ -59320,8 +59443,8 @@ var require_mock_utils = __commonJS({
59320
59443
  const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path;
59321
59444
  const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
59322
59445
  const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
59323
- let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path108, ignoreTrailingSlash }) => {
59324
- return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path108)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path108), resolvedPath);
59446
+ let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path110, ignoreTrailingSlash }) => {
59447
+ return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path110)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path110), resolvedPath);
59325
59448
  });
59326
59449
  if (matchedMockDispatches.length === 0) {
59327
59450
  throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
@@ -59360,19 +59483,19 @@ var require_mock_utils = __commonJS({
59360
59483
  mockDispatches.splice(index, 1);
59361
59484
  }
59362
59485
  }
59363
- function removeTrailingSlash(path108) {
59364
- while (path108.endsWith("/")) {
59365
- path108 = path108.slice(0, -1);
59486
+ function removeTrailingSlash(path110) {
59487
+ while (path110.endsWith("/")) {
59488
+ path110 = path110.slice(0, -1);
59366
59489
  }
59367
- if (path108.length === 0) {
59368
- path108 = "/";
59490
+ if (path110.length === 0) {
59491
+ path110 = "/";
59369
59492
  }
59370
- return path108;
59493
+ return path110;
59371
59494
  }
59372
59495
  function buildKey(opts) {
59373
- const { path: path108, method, body, headers, query } = opts;
59496
+ const { path: path110, method, body, headers, query } = opts;
59374
59497
  return {
59375
- path: path108,
59498
+ path: path110,
59376
59499
  method,
59377
59500
  body,
59378
59501
  headers,
@@ -60067,10 +60190,10 @@ var require_pending_interceptors_formatter = __commonJS({
60067
60190
  }
60068
60191
  format(pendingInterceptors) {
60069
60192
  const withPrettyHeaders = pendingInterceptors.map(
60070
- ({ method, path: path108, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
60193
+ ({ method, path: path110, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
60071
60194
  Method: method,
60072
60195
  Origin: origin,
60073
- Path: path108,
60196
+ Path: path110,
60074
60197
  "Status code": statusCode,
60075
60198
  Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
60076
60199
  Invocations: timesInvoked,
@@ -60153,9 +60276,9 @@ var require_mock_agent = __commonJS({
60153
60276
  const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
60154
60277
  const dispatchOpts = { ...opts };
60155
60278
  if (acceptNonStandardSearchParameters && dispatchOpts.path) {
60156
- const [path108, searchParams] = dispatchOpts.path.split("?");
60279
+ const [path110, searchParams] = dispatchOpts.path.split("?");
60157
60280
  const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
60158
- dispatchOpts.path = `${path108}?${normalizedSearchParams}`;
60281
+ dispatchOpts.path = `${path110}?${normalizedSearchParams}`;
60159
60282
  }
60160
60283
  return this[kAgent].dispatch(dispatchOpts, handler);
60161
60284
  }
@@ -60558,12 +60681,12 @@ var require_snapshot_recorder = __commonJS({
60558
60681
  * @return {Promise<void>} - Resolves when snapshots are loaded
60559
60682
  */
60560
60683
  async loadSnapshots(filePath) {
60561
- const path108 = filePath || this.#snapshotPath;
60562
- if (!path108) {
60684
+ const path110 = filePath || this.#snapshotPath;
60685
+ if (!path110) {
60563
60686
  throw new InvalidArgumentError("Snapshot path is required");
60564
60687
  }
60565
60688
  try {
60566
- const data = await readFile(resolve2(path108), "utf8");
60689
+ const data = await readFile(resolve2(path110), "utf8");
60567
60690
  const parsed = JSON.parse(data);
60568
60691
  if (Array.isArray(parsed)) {
60569
60692
  this.#snapshots.clear();
@@ -60577,7 +60700,7 @@ var require_snapshot_recorder = __commonJS({
60577
60700
  if (error.code === "ENOENT") {
60578
60701
  this.#snapshots.clear();
60579
60702
  } else {
60580
- throw new UndiciError(`Failed to load snapshots from ${path108}`, { cause: error });
60703
+ throw new UndiciError(`Failed to load snapshots from ${path110}`, { cause: error });
60581
60704
  }
60582
60705
  }
60583
60706
  }
@@ -60588,11 +60711,11 @@ var require_snapshot_recorder = __commonJS({
60588
60711
  * @returns {Promise<void>} - Resolves when snapshots are saved
60589
60712
  */
60590
60713
  async saveSnapshots(filePath) {
60591
- const path108 = filePath || this.#snapshotPath;
60592
- if (!path108) {
60714
+ const path110 = filePath || this.#snapshotPath;
60715
+ if (!path110) {
60593
60716
  throw new InvalidArgumentError("Snapshot path is required");
60594
60717
  }
60595
- const resolvedPath = resolve2(path108);
60718
+ const resolvedPath = resolve2(path110);
60596
60719
  await mkdir(dirname3(resolvedPath), { recursive: true });
60597
60720
  const data = Array.from(this.#snapshots.entries()).map(([hash2, snapshot]) => ({
60598
60721
  hash: hash2,
@@ -61233,15 +61356,15 @@ var require_redirect_handler = __commonJS({
61233
61356
  }
61234
61357
  this.history[kRedirectCacheControl].push(headers["cache-control"]);
61235
61358
  const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
61236
- const path108 = search ? `${pathname}${search}` : pathname;
61237
- const redirectUrlString = `${origin}${path108}`;
61359
+ const path110 = search ? `${pathname}${search}` : pathname;
61360
+ const redirectUrlString = `${origin}${path110}`;
61238
61361
  for (const historyUrl of this.history) {
61239
61362
  if (historyUrl.toString() === redirectUrlString) {
61240
61363
  throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`);
61241
61364
  }
61242
61365
  }
61243
61366
  this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
61244
- this.opts.path = path108;
61367
+ this.opts.path = path110;
61245
61368
  this.opts.origin = origin;
61246
61369
  this.opts.query = null;
61247
61370
  }
@@ -63017,10 +63140,10 @@ var require_cache_handler = __commonJS({
63017
63140
  }
63018
63141
  return locationUrl.pathname + locationUrl.search;
63019
63142
  }
63020
- function deleteCachedUri(store, cacheKey, path108) {
63143
+ function deleteCachedUri(store, cacheKey, path110) {
63021
63144
  deleteCachedValue(store, {
63022
63145
  ...cacheKey,
63023
- path: path108
63146
+ path: path110
63024
63147
  });
63025
63148
  for (let i = 0; i < util.safeHTTPMethods.length; i++) {
63026
63149
  const method = util.safeHTTPMethods[i];
@@ -63028,7 +63151,7 @@ var require_cache_handler = __commonJS({
63028
63151
  deleteCachedValue(store, {
63029
63152
  ...cacheKey,
63030
63153
  method,
63031
- path: path108
63154
+ path: path110
63032
63155
  });
63033
63156
  }
63034
63157
  }
@@ -63039,9 +63162,9 @@ var require_cache_handler = __commonJS({
63039
63162
  }
63040
63163
  const values = Array.isArray(headerValue) ? headerValue : [headerValue];
63041
63164
  for (let i = 0; i < values.length; i++) {
63042
- const path108 = getSameOriginPath(cacheKey, values[i]);
63043
- if (path108 !== void 0) {
63044
- deleteCachedUri(store, cacheKey, path108);
63165
+ const path110 = getSameOriginPath(cacheKey, values[i]);
63166
+ if (path110 !== void 0) {
63167
+ deleteCachedUri(store, cacheKey, path110);
63045
63168
  }
63046
63169
  }
63047
63170
  }
@@ -68264,11 +68387,11 @@ var require_fetch = __commonJS({
68264
68387
  function dispatch({ body }) {
68265
68388
  const url = requestCurrentURL(request2);
68266
68389
  const agent = fetchParams.controller.dispatcher;
68267
- const path108 = url.pathname + url.search;
68390
+ const path110 = url.pathname + url.search;
68268
68391
  const hasTrailingQuestionMark = url.search.length === 0 && url.href[url.href.length - url.hash.length - 1] === "?";
68269
68392
  return new Promise((resolve2, reject) => agent.dispatch(
68270
68393
  {
68271
- path: hasTrailingQuestionMark ? `${path108}?` : path108,
68394
+ path: hasTrailingQuestionMark ? `${path110}?` : path110,
68272
68395
  origin: url.origin,
68273
68396
  method: request2.method,
68274
68397
  body: agent.isMockActive ? request2.body && (request2.body.source || request2.body.stream) : body,
@@ -69220,9 +69343,9 @@ var require_util4 = __commonJS({
69220
69343
  }
69221
69344
  }
69222
69345
  }
69223
- function validateCookiePath(path108) {
69224
- for (let i = 0; i < path108.length; ++i) {
69225
- const code2 = path108.charCodeAt(i);
69346
+ function validateCookiePath(path110) {
69347
+ for (let i = 0; i < path110.length; ++i) {
69348
+ const code2 = path110.charCodeAt(i);
69226
69349
  if (code2 < 32 || // exclude CTLs (0-31)
69227
69350
  code2 > 126 || // exclude DEL and non-ascii
69228
69351
  code2 === 59) {
@@ -72675,11 +72798,11 @@ var require_undici = __commonJS({
72675
72798
  if (typeof opts.path !== "string") {
72676
72799
  throw new InvalidArgumentError("invalid opts.path");
72677
72800
  }
72678
- let path108 = opts.path;
72801
+ let path110 = opts.path;
72679
72802
  if (!opts.path.startsWith("/")) {
72680
- path108 = `/${path108}`;
72803
+ path110 = `/${path110}`;
72681
72804
  }
72682
- url = new URL(util.parseOrigin(url).origin + path108);
72805
+ url = new URL(util.parseOrigin(url).origin + path110);
72683
72806
  } else {
72684
72807
  if (!opts) {
72685
72808
  opts = typeof url === "object" ? url : {};
@@ -72801,10 +72924,10 @@ function readFirstRunEnv() {
72801
72924
  stdinTTY: !!process.stdin.isTTY,
72802
72925
  stdoutTTY: !!process.stdout.isTTY,
72803
72926
  ci: isCI() || process.env.NODE9_NONINTERACTIVE === "1",
72804
- hasConfig: import_fs101.default.existsSync(import_path100.default.join(import_os82.default.homedir(), ".node9/config.json")),
72927
+ hasConfig: import_fs103.default.existsSync(import_path102.default.join(import_os83.default.homedir(), ".node9/config.json")),
72805
72928
  // Any stored profile means this is not a never-configured machine. Treat
72806
72929
  // malformed credential files conservatively and leave repair to explicit setup.
72807
- hasCredentials: !!getCredentials() || import_fs101.default.existsSync(import_path100.default.join(import_os82.default.homedir(), ".node9/credentials.json"))
72930
+ hasCredentials: !!getCredentials() || import_fs103.default.existsSync(import_path102.default.join(import_os83.default.homedir(), ".node9/credentials.json"))
72808
72931
  };
72809
72932
  }
72810
72933
  function shouldOfferFirstRun(env) {
@@ -72909,14 +73032,14 @@ async function runSetupWizard(opts) {
72909
73032
  process.exitCode = 130;
72910
73033
  }
72911
73034
  }
72912
- var import_fs101, import_os82, import_path100;
73035
+ var import_fs103, import_os83, import_path102;
72913
73036
  var init_first_run = __esm({
72914
73037
  "src/cli/first-run.ts"() {
72915
73038
  "use strict";
72916
73039
  init_cjs_shims();
72917
- import_fs101 = __toESM(require("fs"));
72918
- import_os82 = __toESM(require("os"));
72919
- import_path100 = __toESM(require("path"));
73040
+ import_fs103 = __toESM(require("fs"));
73041
+ import_os83 = __toESM(require("os"));
73042
+ import_path102 = __toESM(require("path"));
72920
73043
  init_config();
72921
73044
  init_agent_wiring();
72922
73045
  init_browser_login();
@@ -72962,20 +73085,20 @@ function getModelContextLimit(model) {
72962
73085
  return 2e5;
72963
73086
  }
72964
73087
  function readSessionUsage() {
72965
- const projectsDir = import_path101.default.join(import_os83.default.homedir(), ".claude", "projects");
72966
- if (!import_fs102.default.existsSync(projectsDir)) return null;
73088
+ const projectsDir = import_path103.default.join(import_os84.default.homedir(), ".claude", "projects");
73089
+ if (!import_fs104.default.existsSync(projectsDir)) return null;
72967
73090
  let latestFile = null;
72968
73091
  let latestMtime = 0;
72969
73092
  try {
72970
- for (const dir2 of import_fs102.default.readdirSync(projectsDir)) {
72971
- const dirPath = import_path101.default.join(projectsDir, dir2);
73093
+ for (const dir2 of import_fs104.default.readdirSync(projectsDir)) {
73094
+ const dirPath = import_path103.default.join(projectsDir, dir2);
72972
73095
  try {
72973
- if (!import_fs102.default.statSync(dirPath).isDirectory()) continue;
72974
- for (const file2 of import_fs102.default.readdirSync(dirPath)) {
73096
+ if (!import_fs104.default.statSync(dirPath).isDirectory()) continue;
73097
+ for (const file2 of import_fs104.default.readdirSync(dirPath)) {
72975
73098
  if (!file2.endsWith(".jsonl") || file2.startsWith("agent-")) continue;
72976
- const filePath = import_path101.default.join(dirPath, file2);
73099
+ const filePath = import_path103.default.join(dirPath, file2);
72977
73100
  try {
72978
- const mtime = import_fs102.default.statSync(filePath).mtimeMs;
73101
+ const mtime = import_fs104.default.statSync(filePath).mtimeMs;
72979
73102
  if (mtime > latestMtime) {
72980
73103
  latestMtime = mtime;
72981
73104
  latestFile = filePath;
@@ -72990,7 +73113,7 @@ function readSessionUsage() {
72990
73113
  }
72991
73114
  if (!latestFile) return null;
72992
73115
  try {
72993
- const lines = import_fs102.default.readFileSync(latestFile, "utf-8").split("\n");
73116
+ const lines = import_fs104.default.readFileSync(latestFile, "utf-8").split("\n");
72994
73117
  let lastModel = "";
72995
73118
  let lastInput = 0;
72996
73119
  let lastOutput = 0;
@@ -73051,7 +73174,7 @@ function formatBase(activity) {
73051
73174
  const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
73052
73175
  const icon = getIcon(activity.tool);
73053
73176
  const toolName = activity.tool.slice(0, 16).padEnd(16);
73054
- const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os83.default.homedir(), "~");
73177
+ const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os84.default.homedir(), "~");
73055
73178
  const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
73056
73179
  return `${import_chalk49.default.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${import_chalk49.default.white.bold(toolName)} ${import_chalk49.default.dim(argsPreview)}`;
73057
73180
  }
@@ -73090,9 +73213,9 @@ function renderPending(activity) {
73090
73213
  }
73091
73214
  async function ensureDaemon() {
73092
73215
  let pidPort = null;
73093
- if (import_fs102.default.existsSync(PID_FILE)) {
73216
+ if (import_fs104.default.existsSync(PID_FILE)) {
73094
73217
  try {
73095
- const { port } = JSON.parse(import_fs102.default.readFileSync(PID_FILE, "utf-8"));
73218
+ const { port } = JSON.parse(import_fs104.default.readFileSync(PID_FILE, "utf-8"));
73096
73219
  pidPort = port;
73097
73220
  } catch {
73098
73221
  console.error(import_chalk49.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
@@ -73118,7 +73241,7 @@ async function ensureDaemon() {
73118
73241
  child.unref();
73119
73242
  if (startupFd !== void 0) {
73120
73243
  try {
73121
- import_fs102.default.closeSync(startupFd);
73244
+ import_fs104.default.closeSync(startupFd);
73122
73245
  } catch {
73123
73246
  }
73124
73247
  }
@@ -73488,8 +73611,8 @@ async function startTail(options = {}) {
73488
73611
  );
73489
73612
  }).catch((err2) => {
73490
73613
  try {
73491
- import_fs102.default.appendFileSync(
73492
- import_path101.default.join(import_os83.default.homedir(), ".node9", "hook-debug.log"),
73614
+ import_fs104.default.appendFileSync(
73615
+ import_path103.default.join(import_os84.default.homedir(), ".node9", "hook-debug.log"),
73493
73616
  `[tail] POST /decision failed: ${String(err2)}
73494
73617
  `
73495
73618
  );
@@ -73555,9 +73678,9 @@ async function startTail(options = {}) {
73555
73678
  };
73556
73679
  process.stdin.on("keypress", onKeypress);
73557
73680
  }
73558
- const auditLog = import_path101.default.join(import_os83.default.homedir(), ".node9", "audit.log");
73681
+ const auditLog = import_path103.default.join(import_os84.default.homedir(), ".node9", "audit.log");
73559
73682
  try {
73560
- const unackedDlp = import_fs102.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
73683
+ const unackedDlp = import_fs104.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
73561
73684
  if (unackedDlp > 0) {
73562
73685
  console.log("");
73563
73686
  console.log(
@@ -73597,7 +73720,7 @@ async function startTail(options = {}) {
73597
73720
  if (stallWarned) return;
73598
73721
  if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
73599
73722
  try {
73600
- const auditMtime = import_fs102.default.statSync(auditLog).mtimeMs;
73723
+ const auditMtime = import_fs104.default.statSync(auditLog).mtimeMs;
73601
73724
  if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
73602
73725
  console.log("");
73603
73726
  console.log(
@@ -73769,7 +73892,7 @@ async function startTail(options = {}) {
73769
73892
  process.exit(1);
73770
73893
  });
73771
73894
  }
73772
- var import_http6, import_chalk49, import_fs102, import_os83, import_path101, import_readline5, import_child_process17, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET, BOLD, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
73895
+ var import_http6, import_chalk49, import_fs104, import_os84, import_path103, import_readline5, import_child_process17, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET, BOLD, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
73773
73896
  var init_tail = __esm({
73774
73897
  "src/tui/tail.ts"() {
73775
73898
  "use strict";
@@ -73777,16 +73900,16 @@ var init_tail = __esm({
73777
73900
  import_http6 = __toESM(require("http"));
73778
73901
  init_write();
73779
73902
  import_chalk49 = __toESM(require("chalk"));
73780
- import_fs102 = __toESM(require("fs"));
73781
- import_os83 = __toESM(require("os"));
73782
- import_path101 = __toESM(require("path"));
73903
+ import_fs104 = __toESM(require("fs"));
73904
+ import_os84 = __toESM(require("os"));
73905
+ import_path103 = __toESM(require("path"));
73783
73906
  import_readline5 = __toESM(require("readline"));
73784
73907
  import_child_process17 = require("child_process");
73785
73908
  init_startup_log();
73786
73909
  init_daemon3();
73787
73910
  init_daemon();
73788
73911
  init_safe_text();
73789
- PID_FILE = import_path101.default.join(import_os83.default.homedir(), ".node9", "daemon.pid");
73912
+ PID_FILE = import_path103.default.join(import_os84.default.homedir(), ".node9", "daemon.pid");
73790
73913
  ICONS = {
73791
73914
  bash: "\u{1F4BB}",
73792
73915
  shell: "\u{1F4BB}",
@@ -73908,9 +74031,9 @@ function formatTimeLeft(resetsAt) {
73908
74031
  return ` (${m}m left)`;
73909
74032
  }
73910
74033
  function safeReadJson(filePath) {
73911
- if (!import_fs103.default.existsSync(filePath)) return null;
74034
+ if (!import_fs105.default.existsSync(filePath)) return null;
73912
74035
  try {
73913
- return JSON.parse(import_fs103.default.readFileSync(filePath, "utf-8"));
74036
+ return JSON.parse(import_fs105.default.readFileSync(filePath, "utf-8"));
73914
74037
  } catch {
73915
74038
  return null;
73916
74039
  }
@@ -73931,12 +74054,12 @@ function countHooksInFile(filePath) {
73931
74054
  return Object.keys(cfg.hooks).length;
73932
74055
  }
73933
74056
  function countRulesInDir(rulesDir) {
73934
- if (!import_fs103.default.existsSync(rulesDir)) return 0;
74057
+ if (!import_fs105.default.existsSync(rulesDir)) return 0;
73935
74058
  let count = 0;
73936
74059
  try {
73937
- for (const entry of import_fs103.default.readdirSync(rulesDir, { withFileTypes: true })) {
74060
+ for (const entry of import_fs105.default.readdirSync(rulesDir, { withFileTypes: true })) {
73938
74061
  if (entry.isDirectory()) {
73939
- count += countRulesInDir(import_path102.default.join(rulesDir, entry.name));
74062
+ count += countRulesInDir(import_path104.default.join(rulesDir, entry.name));
73940
74063
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
73941
74064
  count++;
73942
74065
  }
@@ -73947,46 +74070,46 @@ function countRulesInDir(rulesDir) {
73947
74070
  }
73948
74071
  function isSamePath(a, b) {
73949
74072
  try {
73950
- return import_path102.default.resolve(a) === import_path102.default.resolve(b);
74073
+ return import_path104.default.resolve(a) === import_path104.default.resolve(b);
73951
74074
  } catch {
73952
74075
  return false;
73953
74076
  }
73954
74077
  }
73955
74078
  function countConfigs(cwd) {
73956
- const homeDir2 = import_os84.default.homedir();
73957
- const claudeDir = import_path102.default.join(homeDir2, ".claude");
74079
+ const homeDir2 = import_os85.default.homedir();
74080
+ const claudeDir = import_path104.default.join(homeDir2, ".claude");
73958
74081
  let claudeMdCount = 0;
73959
74082
  let rulesCount = 0;
73960
74083
  let hooksCount = 0;
73961
74084
  const userMcpServers = /* @__PURE__ */ new Set();
73962
74085
  const projectMcpServers = /* @__PURE__ */ new Set();
73963
- if (import_fs103.default.existsSync(import_path102.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
73964
- rulesCount += countRulesInDir(import_path102.default.join(claudeDir, "rules"));
73965
- const userSettings = import_path102.default.join(claudeDir, "settings.json");
74086
+ if (import_fs105.default.existsSync(import_path104.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
74087
+ rulesCount += countRulesInDir(import_path104.default.join(claudeDir, "rules"));
74088
+ const userSettings = import_path104.default.join(claudeDir, "settings.json");
73966
74089
  for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
73967
74090
  hooksCount += countHooksInFile(userSettings);
73968
- const userClaudeJson = import_path102.default.join(homeDir2, ".claude.json");
74091
+ const userClaudeJson = import_path104.default.join(homeDir2, ".claude.json");
73969
74092
  for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
73970
74093
  for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
73971
74094
  userMcpServers.delete(name);
73972
74095
  }
73973
74096
  if (cwd) {
73974
- if (import_fs103.default.existsSync(import_path102.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
73975
- if (import_fs103.default.existsSync(import_path102.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
73976
- const projectClaudeDir = import_path102.default.join(cwd, ".claude");
74097
+ if (import_fs105.default.existsSync(import_path104.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
74098
+ if (import_fs105.default.existsSync(import_path104.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
74099
+ const projectClaudeDir = import_path104.default.join(cwd, ".claude");
73977
74100
  const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
73978
74101
  if (!overlapsUserScope) {
73979
- if (import_fs103.default.existsSync(import_path102.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
73980
- rulesCount += countRulesInDir(import_path102.default.join(projectClaudeDir, "rules"));
73981
- const projSettings = import_path102.default.join(projectClaudeDir, "settings.json");
74102
+ if (import_fs105.default.existsSync(import_path104.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
74103
+ rulesCount += countRulesInDir(import_path104.default.join(projectClaudeDir, "rules"));
74104
+ const projSettings = import_path104.default.join(projectClaudeDir, "settings.json");
73982
74105
  for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
73983
74106
  hooksCount += countHooksInFile(projSettings);
73984
74107
  }
73985
- if (import_fs103.default.existsSync(import_path102.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
73986
- const localSettings = import_path102.default.join(projectClaudeDir, "settings.local.json");
74108
+ if (import_fs105.default.existsSync(import_path104.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
74109
+ const localSettings = import_path104.default.join(projectClaudeDir, "settings.local.json");
73987
74110
  for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
73988
74111
  hooksCount += countHooksInFile(localSettings);
73989
- const mcpJsonServers = getMcpServerNames(import_path102.default.join(cwd, ".mcp.json"));
74112
+ const mcpJsonServers = getMcpServerNames(import_path104.default.join(cwd, ".mcp.json"));
73990
74113
  const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
73991
74114
  for (const name of disabledMcpJson) mcpJsonServers.delete(name);
73992
74115
  for (const name of mcpJsonServers) projectMcpServers.add(name);
@@ -74019,12 +74142,12 @@ function readActiveShieldsHud() {
74019
74142
  return shieldsCache.value;
74020
74143
  }
74021
74144
  try {
74022
- const shieldsPath = import_path102.default.join(import_os84.default.homedir(), ".node9", "shields.json");
74023
- if (!import_fs103.default.existsSync(shieldsPath)) {
74145
+ const shieldsPath = import_path104.default.join(import_os85.default.homedir(), ".node9", "shields.json");
74146
+ if (!import_fs105.default.existsSync(shieldsPath)) {
74024
74147
  shieldsCache = { value: [], ts: now };
74025
74148
  return [];
74026
74149
  }
74027
- const parsed = JSON.parse(import_fs103.default.readFileSync(shieldsPath, "utf-8"));
74150
+ const parsed = JSON.parse(import_fs105.default.readFileSync(shieldsPath, "utf-8"));
74028
74151
  if (!Array.isArray(parsed.active)) {
74029
74152
  shieldsCache = { value: [], ts: now };
74030
74153
  return [];
@@ -74126,17 +74249,17 @@ function renderContextLine(stdin) {
74126
74249
  async function main() {
74127
74250
  try {
74128
74251
  const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
74129
- if (import_fs103.default.existsSync(import_path102.default.join(import_os84.default.homedir(), ".node9", "hud-debug"))) {
74252
+ if (import_fs105.default.existsSync(import_path104.default.join(import_os85.default.homedir(), ".node9", "hud-debug"))) {
74130
74253
  try {
74131
- const logPath = import_path102.default.join(import_os84.default.homedir(), ".node9", "hud-debug.log");
74254
+ const logPath = import_path104.default.join(import_os85.default.homedir(), ".node9", "hud-debug.log");
74132
74255
  const MAX_LOG_SIZE = 10 * 1024 * 1024;
74133
74256
  let size = 0;
74134
74257
  try {
74135
- size = import_fs103.default.statSync(logPath).size;
74258
+ size = import_fs105.default.statSync(logPath).size;
74136
74259
  } catch {
74137
74260
  }
74138
74261
  if (size < MAX_LOG_SIZE) {
74139
- import_fs103.default.appendFileSync(
74262
+ import_fs105.default.appendFileSync(
74140
74263
  logPath,
74141
74264
  JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
74142
74265
  );
@@ -74157,11 +74280,11 @@ async function main() {
74157
74280
  try {
74158
74281
  const cwd = stdin.cwd ?? process.cwd();
74159
74282
  for (const configPath2 of [
74160
- import_path102.default.join(cwd, "node9.config.json"),
74161
- import_path102.default.join(import_os84.default.homedir(), ".node9", "config.json")
74283
+ import_path104.default.join(cwd, "node9.config.json"),
74284
+ import_path104.default.join(import_os85.default.homedir(), ".node9", "config.json")
74162
74285
  ]) {
74163
- if (!import_fs103.default.existsSync(configPath2)) continue;
74164
- const cfg = JSON.parse(import_fs103.default.readFileSync(configPath2, "utf-8"));
74286
+ if (!import_fs105.default.existsSync(configPath2)) continue;
74287
+ const cfg = JSON.parse(import_fs105.default.readFileSync(configPath2, "utf-8"));
74165
74288
  const hud = cfg.settings?.hud;
74166
74289
  if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
74167
74290
  }
@@ -74179,14 +74302,14 @@ async function main() {
74179
74302
  renderOffline();
74180
74303
  }
74181
74304
  }
74182
- var import_fs103, import_path102, import_os84, import_http7, RESET2, BOLD2, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
74305
+ var import_fs105, import_path104, import_os85, import_http7, RESET2, BOLD2, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
74183
74306
  var init_hud = __esm({
74184
74307
  "src/cli/hud.ts"() {
74185
74308
  "use strict";
74186
74309
  init_cjs_shims();
74187
- import_fs103 = __toESM(require("fs"));
74188
- import_path102 = __toESM(require("path"));
74189
- import_os84 = __toESM(require("os"));
74310
+ import_fs105 = __toESM(require("fs"));
74311
+ import_path104 = __toESM(require("path"));
74312
+ import_os85 = __toESM(require("os"));
74190
74313
  import_http7 = __toESM(require("http"));
74191
74314
  init_daemon();
74192
74315
  init_dist();
@@ -74251,9 +74374,9 @@ init_agent_wiring();
74251
74374
  init_credentials();
74252
74375
  init_daemon3();
74253
74376
  var import_chalk50 = __toESM(require("chalk"));
74254
- var import_fs104 = __toESM(require("fs"));
74255
- var import_path103 = __toESM(require("path"));
74256
- var import_os85 = __toESM(require("os"));
74377
+ var import_fs106 = __toESM(require("fs"));
74378
+ var import_path105 = __toESM(require("path"));
74379
+ var import_os86 = __toESM(require("os"));
74257
74380
  var import_prompts4 = require("@inquirer/prompts");
74258
74381
 
74259
74382
  // src/utils/duration.ts
@@ -74341,7 +74464,8 @@ async function runProxy(targetCommand) {
74341
74464
  {
74342
74465
  kind: result.blockKind,
74343
74466
  path: result.blockedPath,
74344
- redirect: !!result.redirect
74467
+ redirect: !!result.redirect,
74468
+ ruleDescription: result.ruleDescription
74345
74469
  }
74346
74470
  );
74347
74471
  const errorResponse = {
@@ -74461,10 +74585,10 @@ function buildExplainJsonError(message) {
74461
74585
  // src/cli/commands/check.ts
74462
74586
  init_cjs_shims();
74463
74587
  var import_chalk14 = __toESM(require("chalk"));
74464
- var import_fs73 = __toESM(require("fs"));
74588
+ var import_fs75 = __toESM(require("fs"));
74465
74589
  var import_child_process9 = require("child_process");
74466
- var import_path73 = __toESM(require("path"));
74467
- var import_os61 = __toESM(require("os"));
74590
+ var import_path75 = __toESM(require("path"));
74591
+ var import_os62 = __toESM(require("os"));
74468
74592
  init_orchestrator();
74469
74593
  init_state();
74470
74594
  init_daemon();
@@ -74750,6 +74874,112 @@ function discardPendingReview(key, now = Date.now()) {
74750
74874
  // src/cli/commands/check.ts
74751
74875
  init_hook_payload();
74752
74876
  init_safe_text();
74877
+ init_atomic_write();
74878
+
74879
+ // src/utils/own-dir.ts
74880
+ init_cjs_shims();
74881
+ var import_fs73 = __toESM(require("fs"));
74882
+ var import_path73 = __toESM(require("path"));
74883
+ var SESSION_FLAG_SUFFIX = ".node9-flag";
74884
+ var SESSION_FLAG_NAME = /^[A-Za-z0-9_-]{1,128}\.node9-flag$/;
74885
+ function isSessionFlagName(name) {
74886
+ return SESSION_FLAG_NAME.test(name);
74887
+ }
74888
+ function ownRealDir(st) {
74889
+ if (st.isSymbolicLink() || !st.isDirectory()) return false;
74890
+ return typeof process.getuid !== "function" || st.uid === process.getuid();
74891
+ }
74892
+ function ensureOwnDir(dir2) {
74893
+ try {
74894
+ import_fs73.default.mkdirSync(dir2, { recursive: true, mode: 448 });
74895
+ const st = import_fs73.default.lstatSync(dir2);
74896
+ return ownRealDir(st) ? { dev: st.dev, ino: st.ino } : null;
74897
+ } catch {
74898
+ return null;
74899
+ }
74900
+ }
74901
+ function isSameOwnDir(dir2, seen) {
74902
+ try {
74903
+ const st = import_fs73.default.lstatSync(dir2);
74904
+ return ownRealDir(st) && st.dev === seen.dev && st.ino === seen.ino;
74905
+ } catch {
74906
+ return false;
74907
+ }
74908
+ }
74909
+ function removeOldFlag(dir2, seen, name, cutoffMs) {
74910
+ if (!isSessionFlagName(name)) return;
74911
+ const p = import_path73.default.join(dir2, name);
74912
+ try {
74913
+ const st = import_fs73.default.lstatSync(p);
74914
+ if (!st.isFile() || st.mtimeMs >= cutoffMs) return;
74915
+ if (!isSameOwnDir(dir2, seen)) return;
74916
+ import_fs73.default.unlinkSync(p);
74917
+ } catch {
74918
+ }
74919
+ }
74920
+
74921
+ // src/notices/session-notice.ts
74922
+ init_cjs_shims();
74923
+ var import_fs74 = __toESM(require("fs"));
74924
+ var import_os61 = __toESM(require("os"));
74925
+ var import_path74 = __toESM(require("path"));
74926
+ init_dist();
74927
+ var ICON2 = "\u{1F6E1}\uFE0F";
74928
+ var LEVEL_NAMES = {
74929
+ audit: "Audit",
74930
+ soft: "Soft",
74931
+ standard: "Standard",
74932
+ strict: "Strict",
74933
+ "block-all": "Block all"
74934
+ };
74935
+ var SESSION_NOTICE_INSTRUCTION = "Start your next reply to the user with the line above, exactly as written, on its own line.";
74936
+ var FLAG_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
74937
+ var SAFE_SESSION_ID = /^[A-Za-z0-9_-]{1,128}$/;
74938
+ function sessionNoticeLine(mode) {
74939
+ const level = levelOf(mode);
74940
+ if (level === "audit") {
74941
+ return `${ICON2} Node9 is in Audit mode: actions are logged, nothing is blocked.`;
74942
+ }
74943
+ return `${ICON2} Node9 is on (${LEVEL_NAMES[level]}). Every action in this session is checked.`;
74944
+ }
74945
+ function sessionNoticeOutput(mode) {
74946
+ const line = sessionNoticeLine(mode);
74947
+ return JSON.stringify({
74948
+ hookSpecificOutput: {
74949
+ hookEventName: "PreToolUse",
74950
+ additionalContext: `${line}
74951
+ ${SESSION_NOTICE_INSTRUCTION}`
74952
+ },
74953
+ systemMessage: line
74954
+ });
74955
+ }
74956
+ function sessionNoticeEnabled(env = process.env) {
74957
+ if (env.NODE9_SESSION_NOTICE === "1") return true;
74958
+ return env.NODE9_TESTING !== "1";
74959
+ }
74960
+ function claimSessionNotice(sessionId, home = import_os61.default.homedir()) {
74961
+ if (!sessionId || !SAFE_SESSION_ID.test(sessionId)) return false;
74962
+ const dir2 = import_path74.default.join(home, ".node9", "notice-sessions");
74963
+ const seen = ensureOwnDir(dir2);
74964
+ if (!seen) return false;
74965
+ try {
74966
+ if (!isSameOwnDir(dir2, seen)) return false;
74967
+ import_fs74.default.closeSync(import_fs74.default.openSync(import_path74.default.join(dir2, sessionId + SESSION_FLAG_SUFFIX), "wx"));
74968
+ } catch {
74969
+ return false;
74970
+ }
74971
+ removeOldFlags(dir2, seen);
74972
+ return true;
74973
+ }
74974
+ function removeOldFlags(dir2, seen) {
74975
+ const cutoff = Date.now() - FLAG_TTL_MS;
74976
+ try {
74977
+ for (const name of import_fs74.default.readdirSync(dir2)) removeOldFlag(dir2, seen, name, cutoff);
74978
+ } catch {
74979
+ }
74980
+ }
74981
+
74982
+ // src/cli/commands/check.ts
74753
74983
  function detectAiAgent(payload) {
74754
74984
  const meta = payload.meta;
74755
74985
  if (meta && typeof meta === "object") {
@@ -74827,9 +75057,9 @@ function registerCheckCommand(program2) {
74827
75057
  } catch (err2) {
74828
75058
  const tempConfig = getConfig();
74829
75059
  if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
74830
- const logPath = import_path73.default.join(import_os61.default.homedir(), ".node9", "hook-debug.log");
75060
+ const logPath = import_path75.default.join(import_os62.default.homedir(), ".node9", "hook-debug.log");
74831
75061
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
74832
- import_fs73.default.appendFileSync(
75062
+ import_fs75.default.appendFileSync(
74833
75063
  logPath,
74834
75064
  `[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
74835
75065
  RAW: ${raw}
@@ -74842,14 +75072,14 @@ RAW: ${raw}
74842
75072
  const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
74843
75073
  if (process.env.NODE9_DEBUG === "1") {
74844
75074
  try {
74845
- const logPath = import_path73.default.join(import_os61.default.homedir(), ".node9", "hook-debug.log");
74846
- if (!import_fs73.default.existsSync(import_path73.default.dirname(logPath)))
74847
- import_fs73.default.mkdirSync(import_path73.default.dirname(logPath), { recursive: true });
75075
+ const logPath = import_path75.default.join(import_os62.default.homedir(), ".node9", "hook-debug.log");
75076
+ if (!import_fs75.default.existsSync(import_path75.default.dirname(logPath)))
75077
+ import_fs75.default.mkdirSync(import_path75.default.dirname(logPath), { recursive: true });
74848
75078
  const sanitized = JSON.stringify({
74849
75079
  ...payload,
74850
75080
  prompt: `<redacted, ${prompt.length} bytes>`
74851
75081
  });
74852
- import_fs73.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
75082
+ import_fs75.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
74853
75083
  `);
74854
75084
  } catch {
74855
75085
  }
@@ -74867,7 +75097,7 @@ RAW: ${raw}
74867
75097
  if (!dlpMatch && !canaryHit) {
74868
75098
  try {
74869
75099
  const sid = typeof payload.session_id === "string" ? payload.session_id : typeof payload.conversationId === "string" ? payload.conversationId : "";
74870
- const promptCwd = typeof payload.cwd === "string" && import_path73.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
75100
+ const promptCwd = typeof payload.cwd === "string" && import_path75.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
74871
75101
  if (sid && getConfig(promptCwd).policy.untrustedContent?.enabled) {
74872
75102
  await notifyUserMentions(sid, extractContentDestinations(prompt));
74873
75103
  }
@@ -74908,8 +75138,8 @@ RAW: ${raw}
74908
75138
  );
74909
75139
  const reason = `\u{1F6A8} Node9 DLP: ${shownPattern} detected in prompt (${shownSample}). Prompt was not submitted \u2014 remove the credential and try again.`;
74910
75140
  try {
74911
- const ttyFd = import_fs73.default.openSync("/dev/tty", "w");
74912
- import_fs73.default.writeSync(
75141
+ const ttyFd = import_fs75.default.openSync("/dev/tty", "w");
75142
+ import_fs75.default.writeSync(
74913
75143
  ttyFd,
74914
75144
  import_chalk14.default.bgRed.white.bold(`
74915
75145
  \u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
@@ -74919,7 +75149,7 @@ RAW: ${raw}
74919
75149
 
74920
75150
  `)
74921
75151
  );
74922
- import_fs73.default.closeSync(ttyFd);
75152
+ import_fs75.default.closeSync(ttyFd);
74923
75153
  } catch {
74924
75154
  }
74925
75155
  const isCodex = agent2 === "Codex";
@@ -74938,17 +75168,17 @@ RAW: ${raw}
74938
75168
  process.exit(2);
74939
75169
  }
74940
75170
  const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
74941
- const safeCwdForConfig = typeof payloadCwd === "string" && import_path73.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
75171
+ const safeCwdForConfig = typeof payloadCwd === "string" && import_path75.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
74942
75172
  const config = getConfig(safeCwdForConfig);
74943
75173
  const daemonDown = !isDaemonRunning();
74944
75174
  if (config.settings.autoStartDaemon && daemonDown && !process.env.NODE9_NO_AUTO_DAEMON) {
74945
75175
  try {
74946
75176
  const scriptPath = process.argv[1];
74947
- if (typeof scriptPath !== "string" || !import_path73.default.isAbsolute(scriptPath))
75177
+ if (typeof scriptPath !== "string" || !import_path75.default.isAbsolute(scriptPath))
74948
75178
  throw new Error("node9: argv[1] is not an absolute path");
74949
- const resolvedScript = import_fs73.default.realpathSync(scriptPath);
74950
- const packageDist = import_fs73.default.realpathSync(import_path73.default.resolve(__dirname, "../.."));
74951
- if (!resolvedScript.startsWith(packageDist + import_path73.default.sep) && resolvedScript !== packageDist)
75179
+ const resolvedScript = import_fs75.default.realpathSync(scriptPath);
75180
+ const packageDist = import_fs75.default.realpathSync(import_path75.default.resolve(__dirname, "../.."));
75181
+ if (!resolvedScript.startsWith(packageDist + import_path75.default.sep) && resolvedScript !== packageDist)
74952
75182
  throw new Error(
74953
75183
  `node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
74954
75184
  );
@@ -74978,17 +75208,17 @@ RAW: ${raw}
74978
75208
  } finally {
74979
75209
  if (startupFd !== void 0) {
74980
75210
  try {
74981
- import_fs73.default.closeSync(startupFd);
75211
+ import_fs75.default.closeSync(startupFd);
74982
75212
  } catch {
74983
75213
  }
74984
75214
  }
74985
75215
  }
74986
75216
  } catch (spawnErr) {
74987
- const logPath = import_path73.default.join(import_os61.default.homedir(), ".node9", "hook-debug.log");
75217
+ const logPath = import_path75.default.join(import_os62.default.homedir(), ".node9", "hook-debug.log");
74988
75218
  const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
74989
75219
  recordStartupState("failed", "spawn-aborted", msg);
74990
75220
  try {
74991
- import_fs73.default.appendFileSync(
75221
+ import_fs75.default.appendFileSync(
74992
75222
  logPath,
74993
75223
  `[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
74994
75224
  `
@@ -75002,10 +75232,10 @@ RAW: ${raw}
75002
75232
  );
75003
75233
  }
75004
75234
  if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
75005
- const logPath = import_path73.default.join(import_os61.default.homedir(), ".node9", "hook-debug.log");
75006
- if (!import_fs73.default.existsSync(import_path73.default.dirname(logPath)))
75007
- import_fs73.default.mkdirSync(import_path73.default.dirname(logPath), { recursive: true });
75008
- import_fs73.default.appendFileSync(
75235
+ const logPath = import_path75.default.join(import_os62.default.homedir(), ".node9", "hook-debug.log");
75236
+ if (!import_fs75.default.existsSync(import_path75.default.dirname(logPath)))
75237
+ import_fs75.default.mkdirSync(import_path75.default.dirname(logPath), { recursive: true });
75238
+ import_fs75.default.appendFileSync(
75009
75239
  logPath,
75010
75240
  `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${JSON.stringify(raw)}
75011
75241
  `
@@ -75026,8 +75256,8 @@ RAW: ${raw}
75026
75256
  );
75027
75257
  let ttyFd = null;
75028
75258
  try {
75029
- ttyFd = import_fs73.default.openSync("/dev/tty", "w");
75030
- const writeTty = (line) => import_fs73.default.writeSync(ttyFd, line + "\n");
75259
+ ttyFd = import_fs75.default.openSync("/dev/tty", "w");
75260
+ const writeTty = (line) => import_fs75.default.writeSync(ttyFd, line + "\n");
75031
75261
  if (result2?.blockKind === "protected-path") {
75032
75262
  writeTty(
75033
75263
  import_chalk14.default.red.bold(
@@ -75054,7 +75284,7 @@ RAW: ${raw}
75054
75284
  } finally {
75055
75285
  if (ttyFd !== null)
75056
75286
  try {
75057
- import_fs73.default.closeSync(ttyFd);
75287
+ import_fs75.default.closeSync(ttyFd);
75058
75288
  } catch {
75059
75289
  }
75060
75290
  }
@@ -75063,7 +75293,12 @@ RAW: ${raw}
75063
75293
  humanDecision,
75064
75294
  msg,
75065
75295
  result2?.recoveryCommand,
75066
- { kind: result2?.blockKind, path: result2?.blockedPath, redirect: !!result2?.redirect }
75296
+ {
75297
+ kind: result2?.blockKind,
75298
+ path: result2?.blockedPath,
75299
+ redirect: !!result2?.redirect,
75300
+ ruleDescription: result2?.ruleDescription
75301
+ }
75067
75302
  );
75068
75303
  if (agent === "Antigravity") {
75069
75304
  process.stdout.write(
@@ -75080,11 +75315,13 @@ RAW: ${raw}
75080
75315
  );
75081
75316
  process.exit(0);
75082
75317
  }
75318
+ const userLine = userLineOf(aiFeedbackMessage);
75083
75319
  process.stdout.write(
75084
75320
  JSON.stringify({
75085
75321
  decision: "block",
75086
75322
  reason: aiFeedbackMessage,
75087
75323
  // This is the core instruction
75324
+ ...agent === "Claude Code" && userLine ? { systemMessage: userLine } : {},
75088
75325
  hookSpecificOutput: {
75089
75326
  hookEventName: "PreToolUse",
75090
75327
  permissionDecision: "deny",
@@ -75118,8 +75355,8 @@ RAW: ${raw}
75118
75355
  } catch {
75119
75356
  }
75120
75357
  try {
75121
- const ttyFd = import_fs73.default.openSync("/dev/tty", "w");
75122
- import_fs73.default.writeSync(
75358
+ const ttyFd = import_fs75.default.openSync("/dev/tty", "w");
75359
+ import_fs75.default.writeSync(
75123
75360
  ttyFd,
75124
75361
  import_chalk14.default.yellow(
75125
75362
  `
@@ -75127,7 +75364,7 @@ RAW: ${raw}
75127
75364
  `
75128
75365
  )
75129
75366
  );
75130
- import_fs73.default.closeSync(ttyFd);
75367
+ import_fs75.default.closeSync(ttyFd);
75131
75368
  } catch {
75132
75369
  }
75133
75370
  if (agent === "GitHub Copilot") {
@@ -75159,17 +75396,20 @@ RAW: ${raw}
75159
75396
  const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
75160
75397
  if (skillPinCfg.enabled && safeSessionId) {
75161
75398
  try {
75162
- const sessionsDir = import_path73.default.join(import_os61.default.homedir(), ".node9", "skill-sessions");
75163
- const flagPath = import_path73.default.join(sessionsDir, `${safeSessionId}.json`);
75399
+ const sessionsDir = import_path75.default.join(import_os62.default.homedir(), ".node9", "skill-sessions");
75400
+ const flagPath = import_path75.default.join(sessionsDir, `${safeSessionId}${SESSION_FLAG_SUFFIX}`);
75401
+ const memo = ensureOwnDir(sessionsDir);
75164
75402
  let flag = null;
75165
75403
  try {
75166
- flag = JSON.parse(import_fs73.default.readFileSync(flagPath, "utf-8"));
75404
+ const st = memo ? import_fs75.default.lstatSync(flagPath) : null;
75405
+ if (st && st.isFile() && st.nlink === 1)
75406
+ flag = JSON.parse(import_fs75.default.readFileSync(flagPath, "utf-8"));
75167
75407
  } catch {
75168
75408
  }
75169
75409
  const writeFlag = (data2) => {
75410
+ if (!memo || !isSameOwnDir(sessionsDir, memo)) return;
75170
75411
  try {
75171
- import_fs73.default.mkdirSync(sessionsDir, { recursive: true });
75172
- import_fs73.default.writeFileSync(
75412
+ atomicWriteSync(
75173
75413
  flagPath,
75174
75414
  JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
75175
75415
  { mode: 384 }
@@ -75180,8 +75420,8 @@ RAW: ${raw}
75180
75420
  const sendSkillWarn = (detail, recoveryCmd) => {
75181
75421
  let ttyFd = null;
75182
75422
  try {
75183
- ttyFd = import_fs73.default.openSync("/dev/tty", "w");
75184
- const w = (line) => import_fs73.default.writeSync(ttyFd, line + "\n");
75423
+ ttyFd = import_fs75.default.openSync("/dev/tty", "w");
75424
+ const w = (line) => import_fs75.default.writeSync(ttyFd, line + "\n");
75185
75425
  w(import_chalk14.default.yellow(`
75186
75426
  \u26A0\uFE0F Node9: installed skill drift detected`));
75187
75427
  w(import_chalk14.default.gray(` ${detail}`));
@@ -75196,7 +75436,7 @@ RAW: ${raw}
75196
75436
  } finally {
75197
75437
  if (ttyFd !== null)
75198
75438
  try {
75199
- import_fs73.default.closeSync(ttyFd);
75439
+ import_fs75.default.closeSync(ttyFd);
75200
75440
  } catch {
75201
75441
  }
75202
75442
  }
@@ -75212,7 +75452,7 @@ RAW: ${raw}
75212
75452
  return;
75213
75453
  }
75214
75454
  if (!flag || flag.state !== "verified" && flag.state !== "warned") {
75215
- const absoluteCwd = typeof payloadCwd === "string" && import_path73.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
75455
+ const absoluteCwd = typeof payloadCwd === "string" && import_path75.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
75216
75456
  const extraRoots = skillPinCfg.roots;
75217
75457
  const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
75218
75458
  const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
@@ -75251,31 +75491,27 @@ RAW: ${raw}
75251
75491
  } else {
75252
75492
  writeFlag({ state: "verified" });
75253
75493
  }
75254
- try {
75255
- const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
75256
- for (const name of import_fs73.default.readdirSync(sessionsDir)) {
75257
- const p = import_path73.default.join(sessionsDir, name);
75258
- try {
75259
- if (import_fs73.default.statSync(p).mtimeMs < cutoff) import_fs73.default.unlinkSync(p);
75260
- } catch {
75261
- }
75494
+ if (memo)
75495
+ try {
75496
+ const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
75497
+ for (const name of import_fs75.default.readdirSync(sessionsDir))
75498
+ removeOldFlag(sessionsDir, memo, name, cutoff);
75499
+ } catch {
75262
75500
  }
75263
- } catch {
75264
- }
75265
75501
  }
75266
75502
  } catch (err2) {
75267
75503
  if (process.env.NODE9_DEBUG === "1") {
75268
75504
  try {
75269
- const dbg = import_path73.default.join(import_os61.default.homedir(), ".node9", "hook-debug.log");
75505
+ const dbg = import_path75.default.join(import_os62.default.homedir(), ".node9", "hook-debug.log");
75270
75506
  const msg = err2 instanceof Error ? err2.message : String(err2);
75271
- import_fs73.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
75507
+ import_fs75.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
75272
75508
  `);
75273
75509
  } catch {
75274
75510
  }
75275
75511
  }
75276
75512
  }
75277
75513
  }
75278
- const safeCwdForAuth = typeof payloadCwd === "string" && import_path73.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
75514
+ const safeCwdForAuth = typeof payloadCwd === "string" && import_path75.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
75279
75515
  const askMode = resolveAskMode(agent, opts, config);
75280
75516
  const result = await authorizeHeadless(toolName, toolInput, meta, {
75281
75517
  cwd: safeCwdForAuth,
@@ -75288,11 +75524,21 @@ RAW: ${raw}
75288
75524
  } catch {
75289
75525
  }
75290
75526
  }
75527
+ const isSubagentCall = typeof payload.agent_id === "string" && payload.agent_id !== "";
75528
+ const allowExit = (checkedBy) => {
75529
+ if (checkedBy !== "paused" && agent === "Claude Code" && !isSubagentCall && sessionNoticeEnabled() && claimSessionNotice(safeSessionId)) {
75530
+ try {
75531
+ import_fs75.default.writeSync(1, sessionNoticeOutput(config.settings.mode) + "\n");
75532
+ } catch {
75533
+ }
75534
+ }
75535
+ process.exit(0);
75536
+ };
75291
75537
  if (result.approved) {
75292
75538
  if (result.checkedBy && process.env.NODE9_DEBUG === "1")
75293
75539
  process.stderr.write(`\u2713 node9 [${result.checkedBy}]: "${toolName}" allowed
75294
75540
  `);
75295
- process.exit(0);
75541
+ allowExit(result.checkedBy);
75296
75542
  }
75297
75543
  if (result.review) {
75298
75544
  sendAsk(result);
@@ -75300,12 +75546,12 @@ RAW: ${raw}
75300
75546
  }
75301
75547
  if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
75302
75548
  try {
75303
- const tty = import_fs73.default.openSync("/dev/tty", "w");
75304
- import_fs73.default.writeSync(
75549
+ const tty = import_fs75.default.openSync("/dev/tty", "w");
75550
+ import_fs75.default.writeSync(
75305
75551
  tty,
75306
75552
  import_chalk14.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
75307
75553
  );
75308
- import_fs73.default.closeSync(tty);
75554
+ import_fs75.default.closeSync(tty);
75309
75555
  } catch {
75310
75556
  }
75311
75557
  const daemonReady = await autoStartDaemonAndWait();
@@ -75317,7 +75563,7 @@ RAW: ${raw}
75317
75563
  if (retry.checkedBy && process.env.NODE9_DEBUG === "1")
75318
75564
  process.stderr.write(`\u2713 node9 [${retry.checkedBy}]: "${toolName}" allowed
75319
75565
  `);
75320
- process.exit(0);
75566
+ allowExit(retry.checkedBy);
75321
75567
  }
75322
75568
  sendBlock(retry.reason ?? `Node9 blocked "${toolName}".`, {
75323
75569
  ...retry,
@@ -75332,9 +75578,9 @@ RAW: ${raw}
75332
75578
  });
75333
75579
  } catch (err2) {
75334
75580
  if (process.env.NODE9_DEBUG === "1") {
75335
- const logPath = import_path73.default.join(import_os61.default.homedir(), ".node9", "hook-debug.log");
75581
+ const logPath = import_path75.default.join(import_os62.default.homedir(), ".node9", "hook-debug.log");
75336
75582
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
75337
- import_fs73.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
75583
+ import_fs75.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
75338
75584
  `);
75339
75585
  }
75340
75586
  process.exit(0);
@@ -75369,9 +75615,9 @@ RAW: ${raw}
75369
75615
 
75370
75616
  // src/cli/commands/log.ts
75371
75617
  init_cjs_shims();
75372
- var import_fs74 = __toESM(require("fs"));
75373
- var import_path74 = __toESM(require("path"));
75374
- var import_os62 = __toESM(require("os"));
75618
+ var import_fs76 = __toESM(require("fs"));
75619
+ var import_path76 = __toESM(require("path"));
75620
+ var import_os63 = __toESM(require("os"));
75375
75621
  init_audit();
75376
75622
  init_config();
75377
75623
  init_daemon();
@@ -75651,12 +75897,12 @@ function registerLogCommand(program2) {
75651
75897
  if (rawToolName !== tool) entry.agentToolName = rawToolName;
75652
75898
  const payloadSessionId = payload.session_id ?? payload.conversationId;
75653
75899
  if (payloadSessionId) entry.sessionId = payloadSessionId;
75654
- const logPath = import_path74.default.join(import_os62.default.homedir(), ".node9", "audit.log");
75655
- if (!import_fs74.default.existsSync(import_path74.default.dirname(logPath)))
75656
- import_fs74.default.mkdirSync(import_path74.default.dirname(logPath), { recursive: true });
75657
- import_fs74.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
75900
+ const logPath = import_path76.default.join(import_os63.default.homedir(), ".node9", "audit.log");
75901
+ if (!import_fs76.default.existsSync(import_path76.default.dirname(logPath)))
75902
+ import_fs76.default.mkdirSync(import_path76.default.dirname(logPath), { recursive: true });
75903
+ import_fs76.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
75658
75904
  const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
75659
- const safeCwd = typeof payloadCwd === "string" && import_path74.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
75905
+ const safeCwd = typeof payloadCwd === "string" && import_path76.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
75660
75906
  if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
75661
75907
  const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
75662
75908
  if (command) {
@@ -75877,9 +76123,9 @@ function registerLogCommand(program2) {
75877
76123
  const msg = err2 instanceof Error ? err2.message : String(err2);
75878
76124
  process.stderr.write(`[Node9] audit log error: ${msg}
75879
76125
  `);
75880
- const debugPath = import_path74.default.join(import_os62.default.homedir(), ".node9", "hook-debug.log");
76126
+ const debugPath = import_path76.default.join(import_os63.default.homedir(), ".node9", "hook-debug.log");
75881
76127
  try {
75882
- import_fs74.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
76128
+ import_fs76.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
75883
76129
  `);
75884
76130
  } catch {
75885
76131
  }
@@ -75902,9 +76148,9 @@ function registerLogCommand(program2) {
75902
76148
  });
75903
76149
  }
75904
76150
  function absolutePathFor(spelled, cwd) {
75905
- const expanded = spelled === "~" || spelled.startsWith("~/") ? import_path74.default.join(import_os62.default.homedir(), spelled.slice(1)) : spelled;
75906
- if (import_path74.default.isAbsolute(expanded)) return expanded;
75907
- return cwd ? import_path74.default.resolve(cwd, expanded) : import_path74.default.resolve(expanded);
76151
+ const expanded = spelled === "~" || spelled.startsWith("~/") ? import_path76.default.join(import_os63.default.homedir(), spelled.slice(1)) : spelled;
76152
+ if (import_path76.default.isAbsolute(expanded)) return expanded;
76153
+ return cwd ? import_path76.default.resolve(cwd, expanded) : import_path76.default.resolve(expanded);
75908
76154
  }
75909
76155
  async function carryTaintAcrossWrites(command, cwd) {
75910
76156
  let pairs;
@@ -75923,23 +76169,23 @@ async function carryTaintAcrossWrites(command, cwd) {
75923
76169
  continue;
75924
76170
  }
75925
76171
  const sensitive = scanFilePath(src, cwd);
75926
- if (sensitive) await notifyTaint(dst, `copy:${sensitive.patternName}:${import_path74.default.basename(src)}`);
76172
+ if (sensitive) await notifyTaint(dst, `copy:${sensitive.patternName}:${import_path76.default.basename(src)}`);
75927
76173
  }
75928
76174
  }
75929
76175
 
75930
76176
  // src/cli/commands/shield.ts
75931
76177
  init_cjs_shims();
75932
76178
  var import_chalk16 = __toESM(require("chalk"));
75933
- var import_fs76 = __toESM(require("fs"));
75934
- var import_path76 = __toESM(require("path"));
75935
- var import_os63 = __toESM(require("os"));
76179
+ var import_fs78 = __toESM(require("fs"));
76180
+ var import_path78 = __toESM(require("path"));
76181
+ var import_os64 = __toESM(require("os"));
75936
76182
  init_shields();
75937
76183
  init_build();
75938
76184
 
75939
76185
  // src/shields/create.ts
75940
76186
  init_cjs_shims();
75941
- var import_fs75 = __toESM(require("fs"));
75942
- var import_path75 = __toESM(require("path"));
76187
+ var import_fs77 = __toESM(require("fs"));
76188
+ var import_path77 = __toESM(require("path"));
75943
76189
  init_dist();
75944
76190
  init_shields();
75945
76191
  init_audit();
@@ -75959,8 +76205,8 @@ function createShield(def, opts = {}) {
75959
76205
  error: `"${name}" is a built-in shield \u2014 choose a different name (a user shield with this name would shadow the built-in).`
75960
76206
  };
75961
76207
  }
75962
- const filePath = import_path75.default.join(USER_SHIELDS_DIR_PATH, `${name}.json`);
75963
- if (!opts.overwrite && import_fs75.default.existsSync(filePath)) {
76208
+ const filePath = import_path77.default.join(USER_SHIELDS_DIR_PATH, `${name}.json`);
76209
+ if (!opts.overwrite && import_fs77.default.existsSync(filePath)) {
75964
76210
  return {
75965
76211
  ok: false,
75966
76212
  error: `Shield "${name}" already exists at ${filePath}. Pass --overwrite to replace it.`
@@ -76058,8 +76304,8 @@ var COMMUNITY_INDEX_URL = "https://raw.githubusercontent.com/node9ai/node9-proxy
76058
76304
  function readCloudShields() {
76059
76305
  const out = /* @__PURE__ */ new Set();
76060
76306
  try {
76061
- const file2 = import_path76.default.join(import_os63.default.homedir(), ".node9", "rules-cache.json");
76062
- const raw = JSON.parse(import_fs76.default.readFileSync(file2, "utf-8"));
76307
+ const file2 = import_path78.default.join(import_os64.default.homedir(), ".node9", "rules-cache.json");
76308
+ const raw = JSON.parse(import_fs78.default.readFileSync(file2, "utf-8"));
76063
76309
  for (const r of raw.rules ?? []) {
76064
76310
  const rule = r;
76065
76311
  const fromSource = rule.source?.startsWith("SHIELD:") ? rule.source.slice("SHIELD:".length).toLowerCase() : void 0;
@@ -76396,7 +76642,7 @@ function registerShieldCommand(program2) {
76396
76642
  if (opts.fromFile) {
76397
76643
  let raw;
76398
76644
  try {
76399
- raw = JSON.parse(import_fs76.default.readFileSync(opts.fromFile, "utf-8"));
76645
+ raw = JSON.parse(import_fs78.default.readFileSync(opts.fromFile, "utf-8"));
76400
76646
  } catch (err2) {
76401
76647
  console.error(
76402
76648
  import_chalk16.default.red(`
@@ -76744,9 +76990,9 @@ init_migrate();
76744
76990
  // src/cli/commands/doctor.ts
76745
76991
  init_cjs_shims();
76746
76992
  var import_chalk19 = __toESM(require("chalk"));
76747
- var import_fs78 = __toESM(require("fs"));
76748
- var import_path78 = __toESM(require("path"));
76749
- var import_os65 = __toESM(require("os"));
76993
+ var import_fs80 = __toESM(require("fs"));
76994
+ var import_path80 = __toESM(require("path"));
76995
+ var import_os66 = __toESM(require("os"));
76750
76996
  var import_child_process10 = require("child_process");
76751
76997
  init_daemon();
76752
76998
  init_build_id();
@@ -76775,22 +77021,22 @@ init_startup_log();
76775
77021
 
76776
77022
  // src/utils/undo-leftovers.ts
76777
77023
  init_cjs_shims();
76778
- var import_fs77 = __toESM(require("fs"));
76779
- var import_os64 = __toESM(require("os"));
76780
- var import_path77 = __toESM(require("path"));
77024
+ var import_fs79 = __toESM(require("fs"));
77025
+ var import_os65 = __toESM(require("os"));
77026
+ var import_path79 = __toESM(require("path"));
76781
77027
  function candidates(homeDir2) {
76782
- const node9Dir = import_path77.default.join(homeDir2, ".node9");
77028
+ const node9Dir = import_path79.default.join(homeDir2, ".node9");
76783
77029
  return [
76784
- import_path77.default.join(node9Dir, "snapshots"),
76785
- import_path77.default.join(node9Dir, "snapshots.json"),
76786
- import_path77.default.join(node9Dir, "undo_latest.txt")
77030
+ import_path79.default.join(node9Dir, "snapshots"),
77031
+ import_path79.default.join(node9Dir, "snapshots.json"),
77032
+ import_path79.default.join(node9Dir, "undo_latest.txt")
76787
77033
  ];
76788
77034
  }
76789
- function undoLeftoverPaths(homeDir2 = import_os64.default.homedir()) {
77035
+ function undoLeftoverPaths(homeDir2 = import_os65.default.homedir()) {
76790
77036
  const found = [];
76791
77037
  for (const p of candidates(homeDir2)) {
76792
77038
  try {
76793
- import_fs77.default.lstatSync(p);
77039
+ import_fs79.default.lstatSync(p);
76794
77040
  found.push(p);
76795
77041
  } catch (err2) {
76796
77042
  if (err2.code !== "ENOENT") found.push(p);
@@ -76798,11 +77044,11 @@ function undoLeftoverPaths(homeDir2 = import_os64.default.homedir()) {
76798
77044
  }
76799
77045
  return found;
76800
77046
  }
76801
- function purgeUndoLeftovers(homeDir2 = import_os64.default.homedir()) {
77047
+ function purgeUndoLeftovers(homeDir2 = import_os65.default.homedir()) {
76802
77048
  const out = { deleted: [], skipped: [], failed: [] };
76803
77049
  for (const p of undoLeftoverPaths(homeDir2)) {
76804
77050
  try {
76805
- if (import_fs77.default.lstatSync(p).isSymbolicLink()) {
77051
+ if (import_fs79.default.lstatSync(p).isSymbolicLink()) {
76806
77052
  out.skipped.push({
76807
77053
  path: p,
76808
77054
  reason: "is a symlink \u2014 remove it yourself so nothing else is followed"
@@ -76815,11 +77061,11 @@ function purgeUndoLeftovers(homeDir2 = import_os64.default.homedir()) {
76815
77061
  }
76816
77062
  let reason = null;
76817
77063
  try {
76818
- import_fs77.default.rmSync(p, { recursive: true, force: true });
77064
+ import_fs79.default.rmSync(p, { recursive: true, force: true });
76819
77065
  } catch (err2) {
76820
77066
  reason = err2.message;
76821
77067
  }
76822
- if (import_fs77.default.existsSync(p)) {
77068
+ if (import_fs79.default.existsSync(p)) {
76823
77069
  out.failed.push({ path: p, reason: reason ?? "still present after removal" });
76824
77070
  } else {
76825
77071
  out.deleted.push(p);
@@ -76835,7 +77081,7 @@ function keyRejected(health) {
76835
77081
  }
76836
77082
  function registerDoctorCommand(program2, version2) {
76837
77083
  program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
76838
- const homeDir2 = import_os65.default.homedir();
77084
+ const homeDir2 = import_os66.default.homedir();
76839
77085
  let failures = 0;
76840
77086
  let warnings = 0;
76841
77087
  function pass(msg) {
@@ -76889,10 +77135,10 @@ function registerDoctorCommand(program2, version2) {
76889
77135
  "Policy source: workspace config (app.node9.ai) \u2014 local config files govern operational settings only"
76890
77136
  );
76891
77137
  }
76892
- const globalConfigPath2 = import_path78.default.join(homeDir2, ".node9", "config.json");
76893
- if (import_fs78.default.existsSync(globalConfigPath2)) {
77138
+ const globalConfigPath2 = import_path80.default.join(homeDir2, ".node9", "config.json");
77139
+ if (import_fs80.default.existsSync(globalConfigPath2)) {
76894
77140
  try {
76895
- JSON.parse(import_fs78.default.readFileSync(globalConfigPath2, "utf-8"));
77141
+ JSON.parse(import_fs80.default.readFileSync(globalConfigPath2, "utf-8"));
76896
77142
  pass(
76897
77143
  wsGoverned ? "~/.node9/config.json found and valid (policy fields ignored \u2014 workspace governs)" : "~/.node9/config.json found and valid"
76898
77144
  );
@@ -76911,10 +77157,10 @@ function registerDoctorCommand(program2, version2) {
76911
77157
  "Remove them when ready: node9 undo --purge"
76912
77158
  );
76913
77159
  }
76914
- const projectConfigPath = import_path78.default.join(process.cwd(), "node9.config.json");
76915
- if (import_fs78.default.existsSync(projectConfigPath)) {
77160
+ const projectConfigPath = import_path80.default.join(process.cwd(), "node9.config.json");
77161
+ if (import_fs80.default.existsSync(projectConfigPath)) {
76916
77162
  try {
76917
- JSON.parse(import_fs78.default.readFileSync(projectConfigPath, "utf-8"));
77163
+ JSON.parse(import_fs80.default.readFileSync(projectConfigPath, "utf-8"));
76918
77164
  pass("node9.config.json found and valid (project)");
76919
77165
  } catch {
76920
77166
  fail2(
@@ -76923,8 +77169,8 @@ function registerDoctorCommand(program2, version2) {
76923
77169
  );
76924
77170
  }
76925
77171
  }
76926
- const credsPath = import_path78.default.join(homeDir2, ".node9", "credentials.json");
76927
- if (import_fs78.default.existsSync(credsPath)) {
77172
+ const credsPath = import_path80.default.join(homeDir2, ".node9", "credentials.json");
77173
+ if (import_fs80.default.existsSync(credsPath)) {
76928
77174
  pass("Cloud credentials found (~/.node9/credentials.json)");
76929
77175
  } else {
76930
77176
  warn(
@@ -76978,7 +77224,7 @@ function registerDoctorCommand(program2, version2) {
76978
77224
  )
76979
77225
  );
76980
77226
  }
76981
- const cloudOn = import_fs78.default.existsSync(import_path78.default.join(homeDir2, ".node9", "credentials.json")) && !!getConfig().settings.approvers?.cloud;
77227
+ const cloudOn = import_fs80.default.existsSync(import_path80.default.join(homeDir2, ".node9", "credentials.json")) && !!getConfig().settings.approvers?.cloud;
76982
77228
  section(cloudOn ? "Daemon" : "Daemon (optional)");
76983
77229
  if (isDaemonRunning()) {
76984
77230
  pass(
@@ -77016,7 +77262,7 @@ function registerDoctorCommand(program2, version2) {
77016
77262
  cloudEnabled: !!getConfig().settings.approvers?.cloud
77017
77263
  });
77018
77264
  if (autostart) warn(autostart.message, autostart.hint);
77019
- if (import_fs78.default.existsSync(import_path78.default.join(import_os65.default.homedir(), ".node9", "credentials.json")) && getConfig().settings.approvers?.cloud) {
77265
+ if (import_fs80.default.existsSync(import_path80.default.join(import_os66.default.homedir(), ".node9", "credentials.json")) && getConfig().settings.approvers?.cloud) {
77020
77266
  section("Policy sync");
77021
77267
  const health = readSyncHealth();
77022
77268
  if (keyRejected(health)) {
@@ -77042,7 +77288,7 @@ function registerDoctorCommand(program2, version2) {
77042
77288
  try {
77043
77289
  const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
77044
77290
  const cfg = getConfig();
77045
- const creds = import_fs78.default.existsSync(import_path78.default.join(import_os65.default.homedir(), ".node9", "credentials.json"));
77291
+ const creds = import_fs80.default.existsSync(import_path80.default.join(import_os66.default.homedir(), ".node9", "credentials.json"));
77046
77292
  if (!creds) {
77047
77293
  warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
77048
77294
  } else if (!cfg.settings.approvers.cloud) {
@@ -77108,10 +77354,10 @@ function registerDoctorCommand(program2, version2) {
77108
77354
  // src/cli/commands/audit.ts
77109
77355
  init_cjs_shims();
77110
77356
  var import_chalk20 = __toESM(require("chalk"));
77111
- var import_fs79 = __toESM(require("fs"));
77112
- var import_path79 = __toESM(require("path"));
77357
+ var import_fs81 = __toESM(require("fs"));
77358
+ var import_path81 = __toESM(require("path"));
77113
77359
  init_decision();
77114
- var import_os66 = __toESM(require("os"));
77360
+ var import_os67 = __toESM(require("os"));
77115
77361
  function formatRelativeTime(timestamp2) {
77116
77362
  const diff = Date.now() - new Date(timestamp2).getTime();
77117
77363
  const sec = Math.floor(diff / 1e3);
@@ -77124,14 +77370,14 @@ function formatRelativeTime(timestamp2) {
77124
77370
  }
77125
77371
  function registerAuditCommand(program2) {
77126
77372
  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) => {
77127
- const logPath = import_path79.default.join(import_os66.default.homedir(), ".node9", "audit.log");
77128
- if (!import_fs79.default.existsSync(logPath)) {
77373
+ const logPath = import_path81.default.join(import_os67.default.homedir(), ".node9", "audit.log");
77374
+ if (!import_fs81.default.existsSync(logPath)) {
77129
77375
  console.log(
77130
77376
  import_chalk20.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
77131
77377
  );
77132
77378
  return;
77133
77379
  }
77134
- const raw = import_fs79.default.readFileSync(logPath, "utf-8");
77380
+ const raw = import_fs81.default.readFileSync(logPath, "utf-8");
77135
77381
  const lines = raw.split("\n").filter((l) => l.trim() !== "");
77136
77382
  let entries = lines.flatMap((line) => {
77137
77383
  try {
@@ -77194,7 +77440,7 @@ init_cjs_shims();
77194
77440
 
77195
77441
  // src/apps/report.ts
77196
77442
  init_cjs_shims();
77197
- var import_fs80 = __toESM(require("fs"));
77443
+ var import_fs82 = __toESM(require("fs"));
77198
77444
  init_catalog();
77199
77445
  init_dist();
77200
77446
  function appsReportLines(file2, activeShields, opts = {}) {
@@ -77224,17 +77470,17 @@ var AUDIT_TAIL_BYTES2 = 5 * 1024 * 1024;
77224
77470
  function readTail2(file2) {
77225
77471
  let fd;
77226
77472
  try {
77227
- fd = import_fs80.default.openSync(file2, "r");
77228
- const size = import_fs80.default.fstatSync(fd).size;
77473
+ fd = import_fs82.default.openSync(file2, "r");
77474
+ const size = import_fs82.default.fstatSync(fd).size;
77229
77475
  const start = Math.max(0, size - AUDIT_TAIL_BYTES2);
77230
77476
  const buf = Buffer.alloc(size - start);
77231
- import_fs80.default.readSync(fd, buf, 0, buf.length, start);
77477
+ import_fs82.default.readSync(fd, buf, 0, buf.length, start);
77232
77478
  const text = buf.toString("utf8");
77233
77479
  return start > 0 ? text.slice(text.indexOf("\n") + 1) : text;
77234
77480
  } catch {
77235
77481
  return "";
77236
77482
  } finally {
77237
- if (fd !== void 0) import_fs80.default.closeSync(fd);
77483
+ if (fd !== void 0) import_fs82.default.closeSync(fd);
77238
77484
  }
77239
77485
  }
77240
77486
  function approvalsFromAudit(auditFile, sinceMs) {
@@ -77289,21 +77535,21 @@ init_detect();
77289
77535
 
77290
77536
  // src/apps/nudges.ts
77291
77537
  init_cjs_shims();
77292
- var import_fs81 = __toESM(require("fs"));
77293
- var import_os67 = __toESM(require("os"));
77294
- var import_path80 = __toESM(require("path"));
77538
+ var import_fs83 = __toESM(require("fs"));
77539
+ var import_os68 = __toESM(require("os"));
77540
+ var import_path82 = __toESM(require("path"));
77295
77541
  var import_child_process11 = require("child_process");
77296
77542
  var UNANSWERED_AT = 3;
77297
77543
  var QUESTIONS_AT = 10;
77298
77544
  var TEAM_AUTHORS_AT = 2;
77299
77545
  var TEAM_PROJECTS = 5;
77300
77546
  var GIT_TIMEOUT_MS = 2e3;
77301
- function nudgesFilePath(home = import_os67.default.homedir()) {
77302
- return import_path80.default.join(home, ".node9", "nudges.json");
77547
+ function nudgesFilePath(home = import_os68.default.homedir()) {
77548
+ return import_path82.default.join(home, ".node9", "nudges.json");
77303
77549
  }
77304
77550
  function readShownNudges(home) {
77305
77551
  try {
77306
- const raw = JSON.parse(import_fs81.default.readFileSync(nudgesFilePath(home), "utf8"));
77552
+ const raw = JSON.parse(import_fs83.default.readFileSync(nudgesFilePath(home), "utf8"));
77307
77553
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return /* @__PURE__ */ new Set();
77308
77554
  return new Set(
77309
77555
  Object.keys(raw).filter(
@@ -77318,14 +77564,14 @@ function markNudgeShown(key, home, now = /* @__PURE__ */ new Date()) {
77318
77564
  const file2 = nudgesFilePath(home);
77319
77565
  let data = {};
77320
77566
  try {
77321
- const raw = JSON.parse(import_fs81.default.readFileSync(file2, "utf8"));
77567
+ const raw = JSON.parse(import_fs83.default.readFileSync(file2, "utf8"));
77322
77568
  if (raw && typeof raw === "object" && !Array.isArray(raw)) data = raw;
77323
77569
  } catch {
77324
77570
  }
77325
77571
  data[key] = now.toISOString();
77326
77572
  try {
77327
- import_fs81.default.mkdirSync(import_path80.default.dirname(file2), { recursive: true });
77328
- import_fs81.default.writeFileSync(file2, JSON.stringify(data, null, 2) + "\n", { mode: 384 });
77573
+ import_fs83.default.mkdirSync(import_path82.default.dirname(file2), { recursive: true });
77574
+ import_fs83.default.writeFileSync(file2, JSON.stringify(data, null, 2) + "\n", { mode: 384 });
77329
77575
  } catch {
77330
77576
  }
77331
77577
  }
@@ -77346,7 +77592,7 @@ function recentAuthorCount(dir2) {
77346
77592
  }
77347
77593
  function teamProject(dirs, countAuthors = recentAuthorCount) {
77348
77594
  for (const dir2 of dirs.slice(0, TEAM_PROJECTS)) {
77349
- if (countAuthors(dir2) >= TEAM_AUTHORS_AT) return import_path80.default.basename(dir2);
77595
+ if (countAuthors(dir2) >= TEAM_AUTHORS_AT) return import_path82.default.basename(dir2);
77350
77596
  }
77351
77597
  return void 0;
77352
77598
  }
@@ -77381,9 +77627,9 @@ var import_chalk22 = __toESM(require("chalk"));
77381
77627
 
77382
77628
  // src/cli/aggregate/report-audit.ts
77383
77629
  init_cjs_shims();
77384
- var import_fs82 = __toESM(require("fs"));
77385
- var import_os68 = __toESM(require("os"));
77386
- var import_path81 = __toESM(require("path"));
77630
+ var import_fs84 = __toESM(require("fs"));
77631
+ var import_os69 = __toESM(require("os"));
77632
+ var import_path83 = __toESM(require("path"));
77387
77633
  init_costSync();
77388
77634
  init_litellm();
77389
77635
  init_cost_codex();
@@ -77468,8 +77714,8 @@ function getDateRange(period, now) {
77468
77714
  }
77469
77715
  }
77470
77716
  function parseAuditLog(logPath) {
77471
- if (!import_fs82.default.existsSync(logPath)) return [];
77472
- const raw = import_fs82.default.readFileSync(logPath, "utf-8");
77717
+ if (!import_fs84.default.existsSync(logPath)) return [];
77718
+ const raw = import_fs84.default.readFileSync(logPath, "utf-8");
77473
77719
  return raw.split("\n").flatMap((line) => {
77474
77720
  if (!line.trim()) return [];
77475
77721
  try {
@@ -77523,10 +77769,10 @@ function freezeClaudeCost(acc) {
77523
77769
  };
77524
77770
  }
77525
77771
  function processClaudeCostProject(proj, projectsDir, start, end, acc) {
77526
- const projPath = import_path81.default.join(projectsDir, proj);
77772
+ const projPath = import_path83.default.join(projectsDir, proj);
77527
77773
  let files;
77528
77774
  try {
77529
- const stat = import_fs82.default.statSync(projPath);
77775
+ const stat = import_fs84.default.statSync(projPath);
77530
77776
  if (!stat.isDirectory()) return;
77531
77777
  files = listSessionFiles(projPath);
77532
77778
  } catch {
@@ -77534,14 +77780,14 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
77534
77780
  }
77535
77781
  const startMs = start.getTime();
77536
77782
  for (const file2 of files) {
77537
- const filePath = import_path81.default.join(projPath, file2);
77783
+ const filePath = import_path83.default.join(projPath, file2);
77538
77784
  try {
77539
- if (import_fs82.default.statSync(filePath).mtimeMs < startMs) continue;
77785
+ if (import_fs84.default.statSync(filePath).mtimeMs < startMs) continue;
77540
77786
  } catch {
77541
77787
  continue;
77542
77788
  }
77543
77789
  try {
77544
- const raw = import_fs82.default.readFileSync(filePath, "utf-8");
77790
+ const raw = import_fs84.default.readFileSync(filePath, "utf-8");
77545
77791
  for (const line of raw.split("\n")) {
77546
77792
  if (!line.trim()) continue;
77547
77793
  let entry;
@@ -77591,10 +77837,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
77591
77837
  }
77592
77838
  function loadClaudeCost(start, end, projectsDir) {
77593
77839
  const acc = emptyClaudeCostAccumulator();
77594
- if (!import_fs82.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
77840
+ if (!import_fs84.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
77595
77841
  let dirs;
77596
77842
  try {
77597
- dirs = import_fs82.default.readdirSync(projectsDir);
77843
+ dirs = import_fs84.default.readdirSync(projectsDir);
77598
77844
  } catch {
77599
77845
  return freezeClaudeCost(acc);
77600
77846
  }
@@ -77606,7 +77852,7 @@ function loadClaudeCost(start, end, projectsDir) {
77606
77852
  function processCodexCostFile(filePath, start, end, acc) {
77607
77853
  let lines;
77608
77854
  try {
77609
- lines = import_fs82.default.readFileSync(filePath, "utf-8").split("\n");
77855
+ lines = import_fs84.default.readFileSync(filePath, "utf-8").split("\n");
77610
77856
  } catch {
77611
77857
  return;
77612
77858
  }
@@ -77681,13 +77927,13 @@ function freezeGeminiCost(acc) {
77681
77927
  function processGeminiCostFile(filePath, projectKey, start, end, acc) {
77682
77928
  const startMs = start.getTime();
77683
77929
  try {
77684
- if (import_fs82.default.statSync(filePath).mtimeMs < startMs) return;
77930
+ if (import_fs84.default.statSync(filePath).mtimeMs < startMs) return;
77685
77931
  } catch {
77686
77932
  return;
77687
77933
  }
77688
77934
  let raw;
77689
77935
  try {
77690
- raw = import_fs82.default.readFileSync(filePath, "utf-8");
77936
+ raw = import_fs84.default.readFileSync(filePath, "utf-8");
77691
77937
  } catch {
77692
77938
  return;
77693
77939
  }
@@ -77736,30 +77982,30 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
77736
77982
  const out = [];
77737
77983
  let dirs;
77738
77984
  try {
77739
- if (!import_fs82.default.statSync(geminiTmpDir2).isDirectory()) return out;
77740
- dirs = import_fs82.default.readdirSync(geminiTmpDir2);
77985
+ if (!import_fs84.default.statSync(geminiTmpDir2).isDirectory()) return out;
77986
+ dirs = import_fs84.default.readdirSync(geminiTmpDir2);
77741
77987
  } catch {
77742
77988
  return out;
77743
77989
  }
77744
77990
  for (const proj of dirs) {
77745
- const chatsDir = import_path81.default.join(geminiTmpDir2, proj, "chats");
77991
+ const chatsDir = import_path83.default.join(geminiTmpDir2, proj, "chats");
77746
77992
  let files;
77747
77993
  try {
77748
- if (!import_fs82.default.statSync(chatsDir).isDirectory()) continue;
77749
- files = import_fs82.default.readdirSync(chatsDir);
77994
+ if (!import_fs84.default.statSync(chatsDir).isDirectory()) continue;
77995
+ files = import_fs84.default.readdirSync(chatsDir);
77750
77996
  } catch {
77751
77997
  continue;
77752
77998
  }
77753
77999
  for (const f of files) {
77754
78000
  if (!f.endsWith(".jsonl")) continue;
77755
- out.push({ projectKey: proj, file: import_path81.default.join(chatsDir, f) });
78001
+ out.push({ projectKey: proj, file: import_path83.default.join(chatsDir, f) });
77756
78002
  }
77757
78003
  }
77758
78004
  return out;
77759
78005
  }
77760
78006
  function loadGeminiCost(start, end, geminiTmpDir2) {
77761
78007
  const acc = emptyGeminiAccumulator();
77762
- if (!import_fs82.default.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
78008
+ if (!import_fs84.default.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
77763
78009
  for (const { projectKey, file: file2 } of listGeminiSessionFiles2(geminiTmpDir2)) {
77764
78010
  processGeminiCostFile(file2, projectKey, start, end, acc);
77765
78011
  }
@@ -77780,11 +78026,11 @@ function dimensionOfBlock(checkedBy, ruleName) {
77780
78026
  }
77781
78027
  function aggregateReportFromAudit(period, opts = {}) {
77782
78028
  const now = opts.now ?? /* @__PURE__ */ new Date();
77783
- const auditLogPath = opts.auditLogPath ?? import_path81.default.join(import_os68.default.homedir(), ".node9", "audit.log");
77784
- const claudeProjectsDir = opts.claudeProjectsDir ?? import_path81.default.join(import_os68.default.homedir(), ".claude", "projects");
78029
+ const auditLogPath = opts.auditLogPath ?? import_path83.default.join(import_os69.default.homedir(), ".node9", "audit.log");
78030
+ const claudeProjectsDir = opts.claudeProjectsDir ?? import_path83.default.join(import_os69.default.homedir(), ".claude", "projects");
77785
78031
  const codexSessionsDir2 = opts.codexSessionsDir ?? codexSessionsDir();
77786
- const geminiTmpDir2 = opts.geminiTmpDir ?? import_path81.default.join(import_os68.default.homedir(), ".gemini", "tmp");
77787
- const hasAuditFile = import_fs82.default.existsSync(auditLogPath);
78032
+ const geminiTmpDir2 = opts.geminiTmpDir ?? import_path83.default.join(import_os69.default.homedir(), ".gemini", "tmp");
78033
+ const hasAuditFile = import_fs84.default.existsSync(auditLogPath);
77788
78034
  const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
77789
78035
  const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
77790
78036
  const { start, end } = getDateRange(period, now);
@@ -78070,10 +78316,10 @@ function buildReportJson(input) {
78070
78316
  // src/cli/commands/sessions.ts
78071
78317
  init_cjs_shims();
78072
78318
  var import_chalk21 = __toESM(require("chalk"));
78073
- var import_fs83 = __toESM(require("fs"));
78074
- var import_path82 = __toESM(require("path"));
78319
+ var import_fs85 = __toESM(require("fs"));
78320
+ var import_path84 = __toESM(require("path"));
78075
78321
  init_decision();
78076
- var import_os69 = __toESM(require("os"));
78322
+ var import_os70 = __toESM(require("os"));
78077
78323
  init_scan_summary();
78078
78324
  init_litellm();
78079
78325
  init_cost_gemini();
@@ -78094,10 +78340,10 @@ function encodeProjectPath(projectPath) {
78094
78340
  }
78095
78341
  function sessionJsonlPath(projectPath, sessionId) {
78096
78342
  const encoded = encodeProjectPath(projectPath);
78097
- return import_path82.default.join(import_os69.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
78343
+ return import_path84.default.join(import_os70.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
78098
78344
  }
78099
78345
  function projectLabel(projectPath) {
78100
- return projectPath.replace(import_os69.default.homedir(), "~");
78346
+ return projectPath.replace(import_os70.default.homedir(), "~");
78101
78347
  }
78102
78348
  function parseHistoryLines(lines) {
78103
78349
  const entries = [];
@@ -78166,10 +78412,10 @@ function parseSessionLines(lines) {
78166
78412
  return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
78167
78413
  }
78168
78414
  function loadAuditEntries(auditPath) {
78169
- const aPath = auditPath ?? import_path82.default.join(import_os69.default.homedir(), ".node9", "audit.log");
78415
+ const aPath = auditPath ?? import_path84.default.join(import_os70.default.homedir(), ".node9", "audit.log");
78170
78416
  let raw;
78171
78417
  try {
78172
- raw = import_fs83.default.readFileSync(aPath, "utf-8");
78418
+ raw = import_fs85.default.readFileSync(aPath, "utf-8");
78173
78419
  } catch {
78174
78420
  return [];
78175
78421
  }
@@ -78205,8 +78451,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
78205
78451
  return result;
78206
78452
  }
78207
78453
  function buildGeminiSessions(days, allAuditEntries) {
78208
- const tmpDir = import_path82.default.join(import_os69.default.homedir(), ".gemini", "tmp");
78209
- if (!import_fs83.default.existsSync(tmpDir)) return [];
78454
+ const tmpDir = import_path84.default.join(import_os70.default.homedir(), ".gemini", "tmp");
78455
+ if (!import_fs85.default.existsSync(tmpDir)) return [];
78210
78456
  const cutoff = days !== null ? (() => {
78211
78457
  const d = /* @__PURE__ */ new Date();
78212
78458
  d.setDate(d.getDate() - days);
@@ -78215,35 +78461,35 @@ function buildGeminiSessions(days, allAuditEntries) {
78215
78461
  })() : null;
78216
78462
  let slugDirs;
78217
78463
  try {
78218
- slugDirs = import_fs83.default.readdirSync(tmpDir);
78464
+ slugDirs = import_fs85.default.readdirSync(tmpDir);
78219
78465
  } catch {
78220
78466
  return [];
78221
78467
  }
78222
78468
  const summaries = [];
78223
78469
  for (const slug2 of slugDirs) {
78224
- const slugPath = import_path82.default.join(tmpDir, slug2);
78470
+ const slugPath = import_path84.default.join(tmpDir, slug2);
78225
78471
  try {
78226
- if (!import_fs83.default.statSync(slugPath).isDirectory()) continue;
78472
+ if (!import_fs85.default.statSync(slugPath).isDirectory()) continue;
78227
78473
  } catch {
78228
78474
  continue;
78229
78475
  }
78230
- let projectRoot = import_path82.default.join(import_os69.default.homedir(), slug2);
78476
+ let projectRoot = import_path84.default.join(import_os70.default.homedir(), slug2);
78231
78477
  try {
78232
- projectRoot = import_fs83.default.readFileSync(import_path82.default.join(slugPath, ".project_root"), "utf-8").trim();
78478
+ projectRoot = import_fs85.default.readFileSync(import_path84.default.join(slugPath, ".project_root"), "utf-8").trim();
78233
78479
  } catch {
78234
78480
  }
78235
- const chatsDir = import_path82.default.join(slugPath, "chats");
78236
- if (!import_fs83.default.existsSync(chatsDir)) continue;
78481
+ const chatsDir = import_path84.default.join(slugPath, "chats");
78482
+ if (!import_fs85.default.existsSync(chatsDir)) continue;
78237
78483
  let chatFiles;
78238
78484
  try {
78239
- chatFiles = import_fs83.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
78485
+ chatFiles = import_fs85.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
78240
78486
  } catch {
78241
78487
  continue;
78242
78488
  }
78243
78489
  for (const chatFile of chatFiles) {
78244
78490
  let raw;
78245
78491
  try {
78246
- raw = import_fs83.default.readFileSync(import_path82.default.join(chatsDir, chatFile), "utf-8");
78492
+ raw = import_fs85.default.readFileSync(import_path84.default.join(chatsDir, chatFile), "utf-8");
78247
78493
  } catch {
78248
78494
  continue;
78249
78495
  }
@@ -78334,7 +78580,7 @@ function buildCodexSessions(days, allAuditEntries) {
78334
78580
  for (const filePath of jsonlFiles) {
78335
78581
  let lines;
78336
78582
  try {
78337
- lines = import_fs83.default.readFileSync(filePath, "utf-8").split("\n");
78583
+ lines = import_fs85.default.readFileSync(filePath, "utf-8").split("\n");
78338
78584
  } catch {
78339
78585
  continue;
78340
78586
  }
@@ -78405,10 +78651,10 @@ function buildCodexSessions(days, allAuditEntries) {
78405
78651
  return summaries;
78406
78652
  }
78407
78653
  function buildSessions(days, historyPath) {
78408
- const hPath = historyPath ?? import_path82.default.join(import_os69.default.homedir(), ".claude", "history.jsonl");
78654
+ const hPath = historyPath ?? import_path84.default.join(import_os70.default.homedir(), ".claude", "history.jsonl");
78409
78655
  let historyRaw = "";
78410
78656
  try {
78411
- historyRaw = import_fs83.default.readFileSync(hPath, "utf-8");
78657
+ historyRaw = import_fs85.default.readFileSync(hPath, "utf-8");
78412
78658
  } catch {
78413
78659
  }
78414
78660
  const cutoff = days !== null ? (() => {
@@ -78432,7 +78678,7 @@ function buildSessions(days, historyPath) {
78432
78678
  const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
78433
78679
  let sessionLines = [];
78434
78680
  try {
78435
- sessionLines = import_fs83.default.readFileSync(jsonlFile, "utf-8").split("\n");
78681
+ sessionLines = import_fs85.default.readFileSync(jsonlFile, "utf-8").split("\n");
78436
78682
  } catch {
78437
78683
  }
78438
78684
  const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
@@ -79223,7 +79469,7 @@ init_cjs_shims();
79223
79469
  var import_chalk23 = __toESM(require("chalk"));
79224
79470
  var import_child_process12 = require("child_process");
79225
79471
  init_daemon();
79226
- var import_fs84 = __toESM(require("fs"));
79472
+ var import_fs86 = __toESM(require("fs"));
79227
79473
  init_startup_log();
79228
79474
  init_daemon3();
79229
79475
  init_service();
@@ -79300,7 +79546,7 @@ function registerDaemonCommand(program2) {
79300
79546
  child.unref();
79301
79547
  if (restartFd !== void 0) {
79302
79548
  try {
79303
- import_fs84.default.closeSync(restartFd);
79549
+ import_fs86.default.closeSync(restartFd);
79304
79550
  } catch {
79305
79551
  }
79306
79552
  }
@@ -79351,7 +79597,7 @@ function registerDaemonCommand(program2) {
79351
79597
  } finally {
79352
79598
  if (startupFd !== void 0) {
79353
79599
  try {
79354
- import_fs84.default.closeSync(startupFd);
79600
+ import_fs86.default.closeSync(startupFd);
79355
79601
  } catch {
79356
79602
  }
79357
79603
  }
@@ -79366,9 +79612,9 @@ function registerDaemonCommand(program2) {
79366
79612
  // src/cli/commands/status.ts
79367
79613
  init_cjs_shims();
79368
79614
  var import_chalk24 = __toESM(require("chalk"));
79369
- var import_fs85 = __toESM(require("fs"));
79370
- var import_path83 = __toESM(require("path"));
79371
- var import_os70 = __toESM(require("os"));
79615
+ var import_fs87 = __toESM(require("fs"));
79616
+ var import_path85 = __toESM(require("path"));
79617
+ var import_os71 = __toESM(require("os"));
79372
79618
  init_core();
79373
79619
  init_daemon();
79374
79620
  init_build_id();
@@ -79469,20 +79715,20 @@ function registerStatusCommand(program2) {
79469
79715
  console.log(` Policy: ${import_chalk24.default.cyan("Workspace config (app.node9.ai)")}`);
79470
79716
  }
79471
79717
  const ignoredLabel = import_chalk24.default.gray("Present \u2014 ignored (workspace config governs)");
79472
- const projectConfig = import_path83.default.join(process.cwd(), "node9.config.json");
79473
- const globalConfig = import_path83.default.join(import_os70.default.homedir(), ".node9", "config.json");
79718
+ const projectConfig = import_path85.default.join(process.cwd(), "node9.config.json");
79719
+ const globalConfig = import_path85.default.join(import_os71.default.homedir(), ".node9", "config.json");
79474
79720
  console.log(
79475
- ` Local: ${import_fs85.default.existsSync(projectConfig) ? wsGoverned ? ignoredLabel : import_chalk24.default.green("Active (node9.config.json)") : import_chalk24.default.gray("Not present")}`
79721
+ ` Local: ${import_fs87.default.existsSync(projectConfig) ? wsGoverned ? ignoredLabel : import_chalk24.default.green("Active (node9.config.json)") : import_chalk24.default.gray("Not present")}`
79476
79722
  );
79477
79723
  console.log(
79478
- ` Global: ${import_fs85.default.existsSync(globalConfig) ? wsGoverned ? ignoredLabel : import_chalk24.default.green("Active (~/.node9/config.json)") : import_chalk24.default.gray("Not present")}`
79724
+ ` Global: ${import_fs87.default.existsSync(globalConfig) ? wsGoverned ? ignoredLabel : import_chalk24.default.green("Active (~/.node9/config.json)") : import_chalk24.default.gray("Not present")}`
79479
79725
  );
79480
79726
  if (mergedConfig.policy.sandboxPaths.length > 0) {
79481
79727
  console.log(
79482
79728
  ` Sandbox: ${import_chalk24.default.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
79483
79729
  );
79484
79730
  }
79485
- const wiring = getAgentWiring(import_os70.default.homedir()).filter((a) => a.present);
79731
+ const wiring = getAgentWiring(import_os71.default.homedir()).filter((a) => a.present);
79486
79732
  if (wiring.length > 0) {
79487
79733
  console.log("");
79488
79734
  console.log(import_chalk24.default.bold(" Agent Wiring:"));
@@ -79501,7 +79747,7 @@ function registerStatusCommand(program2) {
79501
79747
  a.mcpServers
79502
79748
  );
79503
79749
  if (a.id === "codex" && a.hooks.some((h) => h.wired)) {
79504
- const t = assessCodexTrust(import_os70.default.homedir());
79750
+ const t = assessCodexTrust(import_os71.default.homedir());
79505
79751
  if (t.state === "observed") {
79506
79752
  console.log(
79507
79753
  import_chalk24.default.green(
@@ -79545,7 +79791,7 @@ init_init();
79545
79791
  // src/cli/commands/heal.ts
79546
79792
  init_cjs_shims();
79547
79793
  var import_chalk25 = __toESM(require("chalk"));
79548
- var import_fs88 = __toESM(require("fs"));
79794
+ var import_fs90 = __toESM(require("fs"));
79549
79795
  init_agent_wiring();
79550
79796
  init_mcp_wrap();
79551
79797
  init_setup();
@@ -79553,7 +79799,7 @@ init_hook_baseline();
79553
79799
  var hasHookSurface = (a) => a.hooks.length > 0;
79554
79800
  function backupForHeal(file2) {
79555
79801
  try {
79556
- if (file2 && import_fs88.default.existsSync(file2)) import_fs88.default.copyFileSync(file2, `${file2}.node9-heal-bak`);
79802
+ if (file2 && import_fs90.default.existsSync(file2)) import_fs90.default.copyFileSync(file2, `${file2}.node9-heal-bak`);
79557
79803
  } catch {
79558
79804
  }
79559
79805
  }
@@ -80174,7 +80420,12 @@ async function runMcpGateway(upstreamCommand, configName) {
80174
80420
  humanDecision,
80175
80421
  result.reason,
80176
80422
  void 0,
80177
- { kind: result.blockKind, path: result.blockedPath, redirect: !!result.redirect }
80423
+ {
80424
+ kind: result.blockKind,
80425
+ path: result.blockedPath,
80426
+ redirect: !!result.redirect,
80427
+ ruleDescription: result.ruleDescription
80428
+ }
80178
80429
  );
80179
80430
  const errorResponse = {
80180
80431
  jsonrpc: "2.0",
@@ -80518,9 +80769,9 @@ init_cjs_shims();
80518
80769
  init_cjs_shims();
80519
80770
  var import_readline4 = __toESM(require("readline"));
80520
80771
  init_write();
80521
- var import_fs89 = __toESM(require("fs"));
80522
- var import_os75 = __toESM(require("os"));
80523
- var import_path88 = __toESM(require("path"));
80772
+ var import_fs91 = __toESM(require("fs"));
80773
+ var import_os76 = __toESM(require("os"));
80774
+ var import_path90 = __toESM(require("path"));
80524
80775
  var import_child_process14 = require("child_process");
80525
80776
  init_decision();
80526
80777
  init_core();
@@ -81071,14 +81322,14 @@ function handleStatus() {
81071
81322
  const state = !a.installed ? "not installed" : hooked ? "wired" : a.isProtected ? "protected through MCP" : "not wired";
81072
81323
  lines.push(` ${a.label}: ${state}`);
81073
81324
  }
81074
- const projectConfig = import_path88.default.join(process.cwd(), "node9.config.json");
81075
- const globalConfig = import_path88.default.join(import_os75.default.homedir(), ".node9", "config.json");
81325
+ const projectConfig = import_path90.default.join(process.cwd(), "node9.config.json");
81326
+ const globalConfig = import_path90.default.join(import_os76.default.homedir(), ".node9", "config.json");
81076
81327
  const presentLabel = wsGoverned ? "present \u2014 ignored (workspace config governs)" : "present";
81077
81328
  lines.push(
81078
- `Project config (node9.config.json): ${import_fs89.default.existsSync(projectConfig) ? presentLabel : "not found"}`
81329
+ `Project config (node9.config.json): ${import_fs91.default.existsSync(projectConfig) ? presentLabel : "not found"}`
81079
81330
  );
81080
81331
  lines.push(
81081
- `Global config (~/.node9/config.json): ${import_fs89.default.existsSync(globalConfig) ? presentLabel : "not found"}`
81332
+ `Global config (~/.node9/config.json): ${import_fs91.default.existsSync(globalConfig) ? presentLabel : "not found"}`
81082
81333
  );
81083
81334
  return lines.join("\n");
81084
81335
  }
@@ -81215,7 +81466,7 @@ function handleEgressDeny(args) {
81215
81466
  addEgressHost("deny", host2);
81216
81467
  return `Denied egress to ${host2} (deny always wins over allow).`;
81217
81468
  }
81218
- var GLOBAL_CONFIG_PATH2 = import_path88.default.join(import_os75.default.homedir(), ".node9", "config.json");
81469
+ var GLOBAL_CONFIG_PATH2 = import_path90.default.join(import_os76.default.homedir(), ".node9", "config.json");
81219
81470
  var APPROVER_CHANNELS2 = ["native", "browser", "cloud", "terminal"];
81220
81471
  function handleApproverList() {
81221
81472
  const config = getConfig();
@@ -81256,9 +81507,9 @@ function handleApproverSet(args) {
81256
81507
  function handleAuditGet(args) {
81257
81508
  const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
81258
81509
  const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
81259
- const auditPath = import_path88.default.join(import_os75.default.homedir(), ".node9", "audit.log");
81260
- if (!import_fs89.default.existsSync(auditPath)) return "No audit log found.";
81261
- const rawLines = import_fs89.default.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
81510
+ const auditPath = import_path90.default.join(import_os76.default.homedir(), ".node9", "audit.log");
81511
+ if (!import_fs91.default.existsSync(auditPath)) return "No audit log found.";
81512
+ const rawLines = import_fs91.default.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
81262
81513
  const wanted = filter === "block" ? "deny" : filter;
81263
81514
  const parsed = [];
81264
81515
  for (const line of rawLines) {
@@ -81618,7 +81869,7 @@ function registerTrustCommand(program2) {
81618
81869
  init_cjs_shims();
81619
81870
  var import_chalk32 = __toESM(require("chalk"));
81620
81871
  init_mcp_pin();
81621
- var import_fs90 = __toESM(require("fs"));
81872
+ var import_fs92 = __toESM(require("fs"));
81622
81873
 
81623
81874
  // src/cli/commands/mcp-gateway-cmd.ts
81624
81875
  init_cjs_shims();
@@ -81827,7 +82078,7 @@ function registerMcpPinCommand(program2) {
81827
82078
  let repoCorrupt = false;
81828
82079
  if (found.source === "repo") {
81829
82080
  try {
81830
- const raw = import_fs90.default.readFileSync(found.path, "utf-8");
82081
+ const raw = import_fs92.default.readFileSync(found.path, "utf-8");
81831
82082
  const parsed = JSON.parse(raw);
81832
82083
  repoEntries = parsed.servers ?? {};
81833
82084
  } catch {
@@ -82279,8 +82530,8 @@ init_cjs_shims();
82279
82530
 
82280
82531
  // src/ci-check/fetch.ts
82281
82532
  init_cjs_shims();
82282
- var import_fs91 = __toESM(require("fs"));
82283
- var import_path89 = __toESM(require("path"));
82533
+ var import_fs93 = __toESM(require("fs"));
82534
+ var import_path91 = __toESM(require("path"));
82284
82535
  var import_node_child_process = require("child_process");
82285
82536
  var import_undici = __toESM(require_undici());
82286
82537
 
@@ -82480,8 +82731,8 @@ function isOfficialInstaller(u) {
82480
82731
  if (u.username || u.password) return false;
82481
82732
  const host2 = u.hostname.toLowerCase().replace(/^www\./, "");
82482
82733
  if (OFFICIAL_HOSTS.has(host2)) return true;
82483
- const path108 = OFFICIAL_PATHS[host2];
82484
- return !!path108 && path108.test(u.pathname);
82734
+ const path110 = OFFICIAL_PATHS[host2];
82735
+ return !!path110 && path110.test(u.pathname);
82485
82736
  }
82486
82737
  function onlyOfficialInstaller(s) {
82487
82738
  const urls = s.match(URL_RE3);
@@ -82672,21 +82923,21 @@ function appSkillDirsOf(paths, skillDirs) {
82672
82923
  }
82673
82924
  return apps;
82674
82925
  }
82675
- function isSkillSupportFile(path108, skillDirs, appDirs) {
82676
- if (!path108.endsWith(".md") || /(^|\/)[Ss][Kk][Ii][Ll][Ll]\.md$/.test(path108)) return false;
82677
- for (let d = path108.lastIndexOf("/"); d > 0; d = path108.lastIndexOf("/", d - 1)) {
82678
- const dir2 = path108.slice(0, d);
82926
+ function isSkillSupportFile(path110, skillDirs, appDirs) {
82927
+ if (!path110.endsWith(".md") || /(^|\/)[Ss][Kk][Ii][Ll][Ll]\.md$/.test(path110)) return false;
82928
+ for (let d = path110.lastIndexOf("/"); d > 0; d = path110.lastIndexOf("/", d - 1)) {
82929
+ const dir2 = path110.slice(0, d);
82679
82930
  if (!skillDirs.has(dir2)) continue;
82680
- return !appDirs?.has(dir2) || SKILL_LAYOUT_RE.test(path108.slice(d + 1));
82931
+ return !appDirs?.has(dir2) || SKILL_LAYOUT_RE.test(path110.slice(d + 1));
82681
82932
  }
82682
82933
  return false;
82683
82934
  }
82684
- function isAppDoc(path108, skillDirs, appDirs) {
82685
- if (!path108.endsWith(".md") || INSTRUCTION_FILE_RE.test(path108)) return false;
82686
- for (let d = path108.lastIndexOf("/"); d > 0; d = path108.lastIndexOf("/", d - 1)) {
82687
- const dir2 = path108.slice(0, d);
82935
+ function isAppDoc(path110, skillDirs, appDirs) {
82936
+ if (!path110.endsWith(".md") || INSTRUCTION_FILE_RE.test(path110)) return false;
82937
+ for (let d = path110.lastIndexOf("/"); d > 0; d = path110.lastIndexOf("/", d - 1)) {
82938
+ const dir2 = path110.slice(0, d);
82688
82939
  if (!skillDirs.has(dir2)) continue;
82689
- return appDirs.has(dir2) && !SKILL_LAYOUT_RE.test(path108.slice(d + 1));
82940
+ return appDirs.has(dir2) && !SKILL_LAYOUT_RE.test(path110.slice(d + 1));
82690
82941
  }
82691
82942
  return false;
82692
82943
  }
@@ -82709,20 +82960,20 @@ function namedDocs(dir2, skillMd) {
82709
82960
  return out;
82710
82961
  }
82711
82962
  var SCRIPT_EXT_RE = /\.(sh|bash|zsh|py|js|mjs|cjs|ts|rb|pl|ps1)$/i;
82712
- function isHookScript(path108) {
82713
- return /(^|\/)\.claude\/hooks\/.+/.test(path108) && SCRIPT_EXT_RE.test(path108);
82714
- }
82715
- function isSkillScript(path108, skillDirs) {
82716
- if (!SCRIPT_EXT_RE.test(path108)) return false;
82717
- for (let d = path108.lastIndexOf("/"); d > 0; d = path108.lastIndexOf("/", d - 1)) {
82718
- if (!skillDirs.has(path108.slice(0, d))) continue;
82719
- const rel = path108.slice(d + 1);
82963
+ function isHookScript(path110) {
82964
+ return /(^|\/)\.claude\/hooks\/.+/.test(path110) && SCRIPT_EXT_RE.test(path110);
82965
+ }
82966
+ function isSkillScript(path110, skillDirs) {
82967
+ if (!SCRIPT_EXT_RE.test(path110)) return false;
82968
+ for (let d = path110.lastIndexOf("/"); d > 0; d = path110.lastIndexOf("/", d - 1)) {
82969
+ if (!skillDirs.has(path110.slice(0, d))) continue;
82970
+ const rel = path110.slice(d + 1);
82720
82971
  return !rel.includes("/") || /^(scripts|bin)\//.test(rel);
82721
82972
  }
82722
82973
  return false;
82723
82974
  }
82724
- function isInstructionFile(path108, skillDirs, appDirs) {
82725
- return INSTRUCTION_FILE_RE.test(path108) || isSkillSupportFile(path108, skillDirs, appDirs);
82975
+ function isInstructionFile(path110, skillDirs, appDirs) {
82976
+ return INSTRUCTION_FILE_RE.test(path110) || isSkillSupportFile(path110, skillDirs, appDirs);
82726
82977
  }
82727
82978
  var OVERRIDE_RE = /ignore\s+(all\s+)?(previous|prior|the\s+above)\s+(instructions|prompts?|rules)|disregard\s+(the\s+|your\s+)?(system\s+)?(prompt|instructions|rules)|forget\s+(everything|all\s+(previous|prior))|you\s+are\s+now\s+(a|an|the)\b|<\/?system>/i;
82728
82979
  var FETCH_WORD_RE = /\b(curl|wget|iwr|invoke-webrequest)\b/gi;
@@ -82859,21 +83110,21 @@ function decodeSuspiciousBase64(text) {
82859
83110
  }
82860
83111
  return out;
82861
83112
  }
82862
- function mk2(rule, severity, title, signals, fix, path108, line) {
83113
+ function mk2(rule, severity, title, signals, fix, path110, line) {
82863
83114
  return {
82864
83115
  check: "CI-6",
82865
83116
  rule,
82866
83117
  dimension: "instructions",
82867
83118
  severity,
82868
83119
  title,
82869
- file: path108,
83120
+ file: path110,
82870
83121
  ...line ? { line } : {},
82871
83122
  signals,
82872
83123
  fix
82873
83124
  };
82874
83125
  }
82875
83126
  var lineAt = (text, i) => i >= 0 ? lineAtIndex(text, i) : void 0;
82876
- function analyzeInstructionFile(path108, content) {
83127
+ function analyzeInstructionFile(path110, content) {
82877
83128
  const findings = [];
82878
83129
  const decoded = decodeSuspiciousBase64(content);
82879
83130
  const glyph = homoglyphWord(content);
@@ -82887,7 +83138,7 @@ function analyzeInstructionFile(path108, content) {
82887
83138
  `\`${glyph.folded}\` is written with ${glyph.count} non-Latin look-alike letter(s): it reads the same to a reviewer, but a search, a replace or a policy check on the real word misses it`
82888
83139
  ],
82889
83140
  "Spell the word with plain Latin letters, or explain on the same line why the look-alikes are there.",
82890
- path108,
83141
+ path110,
82891
83142
  glyph.line
82892
83143
  )
82893
83144
  );
@@ -82901,7 +83152,7 @@ function analyzeInstructionFile(path108, content) {
82901
83152
  "contains Unicode tag characters (U+E0000\u2013E007F): an invisible instruction-smuggling channel with no legitimate use in text"
82902
83153
  ],
82903
83154
  "Remove the tag characters. Instruction files must be plain, reviewable text.",
82904
- path108,
83155
+ path110,
82905
83156
  lineAt(content, content.search(TAG_CHARS))
82906
83157
  )
82907
83158
  );
@@ -82915,7 +83166,7 @@ function analyzeInstructionFile(path108, content) {
82915
83166
  "contains a bidi override (U+202D/U+202E): a Trojan-Source technique that visually reorders text so a human reads something different from what the agent parses"
82916
83167
  ],
82917
83168
  "Remove the bidi override characters.",
82918
- path108,
83169
+ path110,
82919
83170
  lineAt(content, content.search(BIDI_OVERRIDE))
82920
83171
  )
82921
83172
  );
@@ -82929,7 +83180,7 @@ function analyzeInstructionFile(path108, content) {
82929
83180
  "contains bidi embed/isolate characters (U+202A\u2013202C / U+2066\u20132069): legitimate in right-to-left text, but confirm they are not being used to hide or reorder instructions"
82930
83181
  ],
82931
83182
  "Confirm the bidi marks are legitimate RTL formatting; remove otherwise.",
82932
- path108,
83183
+ path110,
82933
83184
  lineAt(content, content.search(BIDI_EMBED_ISOLATE))
82934
83185
  )
82935
83186
  );
@@ -82945,7 +83196,7 @@ function analyzeInstructionFile(path108, content) {
82945
83196
  revealed ? "a zero-width character conceals a prompt-override directive that only appears once the hidden characters are stripped" : "a zero-width character splits a visible Latin word: a concealment technique (hides text from human review while the agent reads it as contiguous)"
82946
83197
  ],
82947
83198
  "Remove the zero-width characters. Instruction files must be plain, reviewable text.",
82948
- path108,
83199
+ path110,
82949
83200
  lineAt(content, zw.first)
82950
83201
  )
82951
83202
  );
@@ -82964,7 +83215,7 @@ function analyzeInstructionFile(path108, content) {
82964
83215
  `contains a prompt-override / role-impersonation directive (\`${safeText(m[0].slice(0, 60).trim(), 60)}\`)${ovEnc ? ", concealed in a base64 blob" : ""}`
82965
83216
  ],
82966
83217
  "Remove the override text. An instruction file should not tell the agent to ignore its own rules.",
82967
- path108,
83218
+ path110,
82968
83219
  ov ? lineAt(content, ov.index) : void 0
82969
83220
  // concealed in base64: no line, never a wrong one
82970
83221
  )
@@ -82981,7 +83232,7 @@ function analyzeInstructionFile(path108, content) {
82981
83232
  `\`${safeText(fo[0].slice(0, 70).trim(), 70)}\`: fetch-and-obey, outside an install/setup section`
82982
83233
  ],
82983
83234
  "Do not instruct the agent to pipe remote content into a shell; pin and vendor scripts instead.",
82984
- path108,
83235
+ path110,
82985
83236
  lineAt(content, fo.index)
82986
83237
  )
82987
83238
  );
@@ -82997,7 +83248,7 @@ function analyzeInstructionFile(path108, content) {
82997
83248
  `references \`${safeText(sp[0].slice(0, 50).trim(), 50)}\`: directs the agent toward secrets`
82998
83249
  ],
82999
83250
  "Do not reference credential files or paths in agent instructions.",
83000
- path108,
83251
+ path110,
83001
83252
  lineAt(content, sp.index)
83002
83253
  )
83003
83254
  );
@@ -83020,7 +83271,7 @@ function analyzeInstructionFile(path108, content) {
83020
83271
  "Instruction directs the agent to send data to an external endpoint",
83021
83272
  [`\`${safeText(ex[0].slice(0, 70).trim(), 70)}\`: possible exfiltration directive`],
83022
83273
  "Remove external post/upload directives from agent instructions.",
83023
- path108,
83274
+ path110,
83024
83275
  lineAt(content, ex.index)
83025
83276
  )
83026
83277
  );
@@ -83031,18 +83282,18 @@ function analyzeInstructionFile(path108, content) {
83031
83282
  // src/ci-check/route.ts
83032
83283
  var MCP_CONFIG_RE = /\.mcp\.json$|\.cursor\/mcp\.json$|(^|\/)\.vscode\/mcp\.json$|(^|\/)\.kiro\/settings\/mcp\.json$|(^|\/)\.gemini\/settings\.json$|(^|\/)opencode\.json$|(^|\/)\.opencode\/config\.json$/;
83033
83284
  var ISSUE_FORM_RE = /^\.github\/ISSUE_TEMPLATE\/[^/]+\.(ya?ml|md)$/i;
83034
- function routeOf(path108, skillDirs, appDirs = /* @__PURE__ */ new Set()) {
83035
- if (path108 === SUPPRESSIONS_FILE) return "suppressions";
83036
- if (/\.github\/workflows\/.+\.ya?ml$/.test(path108)) return "workflow";
83037
- if (ISSUE_FORM_RE.test(path108)) return "issue-form";
83038
- if (path108 === "package.json" || path108 === "pyproject.toml") return "manifest";
83039
- if (/\.claude\/settings(\.local)?\.json$/.test(path108)) return "agent-config";
83040
- if (isHookScript(path108)) return "hook-script";
83041
- if (isSkillScript(path108, skillDirs)) return "skill-script";
83042
- if (MCP_CONFIG_RE.test(path108)) return "mcp";
83043
- if (/(^|\/)\.codex\/config\.toml$/.test(path108)) return "codex";
83044
- if (isInstructionFile(path108, skillDirs, appDirs)) return "instruction";
83045
- if (isAppDoc(path108, skillDirs, appDirs)) return "app-doc";
83285
+ function routeOf(path110, skillDirs, appDirs = /* @__PURE__ */ new Set()) {
83286
+ if (path110 === SUPPRESSIONS_FILE) return "suppressions";
83287
+ if (/\.github\/workflows\/.+\.ya?ml$/.test(path110)) return "workflow";
83288
+ if (ISSUE_FORM_RE.test(path110)) return "issue-form";
83289
+ if (path110 === "package.json" || path110 === "pyproject.toml") return "manifest";
83290
+ if (/\.claude\/settings(\.local)?\.json$/.test(path110)) return "agent-config";
83291
+ if (isHookScript(path110)) return "hook-script";
83292
+ if (isSkillScript(path110, skillDirs)) return "skill-script";
83293
+ if (MCP_CONFIG_RE.test(path110)) return "mcp";
83294
+ if (/(^|\/)\.codex\/config\.toml$/.test(path110)) return "codex";
83295
+ if (isInstructionFile(path110, skillDirs, appDirs)) return "instruction";
83296
+ if (isAppDoc(path110, skillDirs, appDirs)) return "app-doc";
83046
83297
  return null;
83047
83298
  }
83048
83299
 
@@ -83171,7 +83422,7 @@ function parseRepoUrl(input) {
83171
83422
  function isLocalPath(input) {
83172
83423
  if (input.startsWith(".") || input.startsWith("/") || input.startsWith("~")) return true;
83173
83424
  try {
83174
- return import_fs91.default.existsSync(input) && import_fs91.default.statSync(input).isDirectory();
83425
+ return import_fs93.default.existsSync(input) && import_fs93.default.statSync(input).isDirectory();
83175
83426
  } catch {
83176
83427
  return false;
83177
83428
  }
@@ -83532,7 +83783,7 @@ function capNested(reads, cap, notes) {
83532
83783
  }
83533
83784
  var overLimit = (text) => Buffer.byteLength(text, "utf8") > MAX_FILE_BYTES3;
83534
83785
  var RAW_LIMIT = 2 * MAX_FILE_BYTES3;
83535
- var OPEN_READ = import_fs91.default.constants.O_RDONLY | (import_fs91.default.constants.O_NOFOLLOW ?? 0) | (import_fs91.default.constants.O_NONBLOCK ?? 0);
83786
+ var OPEN_READ = import_fs93.default.constants.O_RDONLY | (import_fs93.default.constants.O_NOFOLLOW ?? 0) | (import_fs93.default.constants.O_NONBLOCK ?? 0);
83536
83787
  var MAX_WALK_ENTRIES = 1e6;
83537
83788
  var direntKind = (e) => e.isSymbolicLink() ? "link" : e.isDirectory() ? "dir" : e.isFile() ? "file" : "other";
83538
83789
  function walkDisk(root, notes) {
@@ -83547,7 +83798,7 @@ function walkDisk(root, notes) {
83547
83798
  const relDir = stack.pop();
83548
83799
  let dirents;
83549
83800
  try {
83550
- dirents = import_fs91.default.readdirSync(import_path89.default.join(root, relDir), { withFileTypes: true });
83801
+ dirents = import_fs93.default.readdirSync(import_path91.default.join(root, relDir), { withFileTypes: true });
83551
83802
  } catch (e) {
83552
83803
  unlistable.push(`${relDir || "."} (${e?.code ?? "error"})`);
83553
83804
  continue;
@@ -83561,7 +83812,7 @@ function walkDisk(root, notes) {
83561
83812
  const k = direntKind(e);
83562
83813
  kinds2.set(rel, k);
83563
83814
  if (k !== "dir" || isUnwalked(`${rel}/`)) continue;
83564
- if (import_fs91.default.existsSync(import_path89.default.join(root, rel, ".git"))) {
83815
+ if (import_fs93.default.existsSync(import_path91.default.join(root, rel, ".git"))) {
83565
83816
  sealed.add(rel);
83566
83817
  nestedRepos.push(rel);
83567
83818
  } else stack.push(rel);
@@ -83584,7 +83835,7 @@ function walkDisk(root, notes) {
83584
83835
  }
83585
83836
  function gitmodulePaths(root) {
83586
83837
  try {
83587
- const text = readLocalFile(import_path89.default.join(root, ".gitmodules"), ".gitmodules");
83838
+ const text = readLocalFile(import_path91.default.join(root, ".gitmodules"), ".gitmodules");
83588
83839
  return [...text.matchAll(/^\s*path\s*=\s*(.+?)\s*$/gm)].map((m) => m[1].replace(/\/+$/, ""));
83589
83840
  } catch {
83590
83841
  return [];
@@ -83592,9 +83843,9 @@ function gitmodulePaths(root) {
83592
83843
  }
83593
83844
  function localLinkText(root, rel) {
83594
83845
  try {
83595
- const t = import_fs91.default.readlinkSync(import_path89.default.join(root, rel));
83846
+ const t = import_fs93.default.readlinkSync(import_path91.default.join(root, rel));
83596
83847
  if (process.platform !== "win32") return t;
83597
- return import_path89.default.win32.isAbsolute(t) ? `/${t.replace(/\\/g, "/")}` : t.replace(/\\/g, "/");
83848
+ return import_path91.default.win32.isAbsolute(t) ? `/${t.replace(/\\/g, "/")}` : t.replace(/\\/g, "/");
83598
83849
  } catch {
83599
83850
  return null;
83600
83851
  }
@@ -83602,11 +83853,11 @@ function localLinkText(root, rel) {
83602
83853
  function readLocalFile(abs, rel) {
83603
83854
  let fd;
83604
83855
  try {
83605
- fd = import_fs91.default.openSync(abs, OPEN_READ);
83606
- const st = import_fs91.default.fstatSync(fd);
83856
+ fd = import_fs93.default.openSync(abs, OPEN_READ);
83857
+ const st = import_fs93.default.fstatSync(fd);
83607
83858
  if (!st.isFile()) throw new Error(unreadNote(rel, "no longer a regular file"));
83608
83859
  if (st.size > RAW_LIMIT) throw new Error(tooLargeNote(rel));
83609
- const text = lf(import_fs91.default.readFileSync(fd, "utf8"));
83860
+ const text = lf(import_fs93.default.readFileSync(fd, "utf8"));
83610
83861
  if (overLimit(text)) throw new Error(tooLargeNote(rel));
83611
83862
  return text;
83612
83863
  } catch (e) {
@@ -83614,7 +83865,7 @@ function readLocalFile(abs, rel) {
83614
83865
  if (msg.includes(INCOMPLETE)) throw e;
83615
83866
  throw new Error(unreadNote(rel, e?.code ?? "error"));
83616
83867
  } finally {
83617
- if (fd !== void 0) import_fs91.default.closeSync(fd);
83868
+ if (fd !== void 0) import_fs93.default.closeSync(fd);
83618
83869
  }
83619
83870
  }
83620
83871
  function localGitHubRepo(root) {
@@ -83635,10 +83886,10 @@ function readLocalTree(dir2) {
83635
83886
  notes.push(...plan.notes);
83636
83887
  const files = [];
83637
83888
  for (const { rel, real, route } of plan.reads) {
83638
- const abs = import_path89.default.join(root, real);
83889
+ const abs = import_path91.default.join(root, real);
83639
83890
  let size = 0;
83640
83891
  try {
83641
- size = import_fs91.default.lstatSync(abs).size;
83892
+ size = import_fs93.default.lstatSync(abs).size;
83642
83893
  } catch {
83643
83894
  }
83644
83895
  if (size > RAW_LIMIT) {
@@ -85146,17 +85397,17 @@ function localTarget(uses, self) {
85146
85397
  if (!f) return null;
85147
85398
  return f[1].toLowerCase() === self.owner.toLowerCase() && f[2].toLowerCase() === self.repo.toLowerCase() ? `.github/workflows/${f[3]}` : null;
85148
85399
  }
85149
- function localCallsOf(path108, content, autoLabels, trustedRunSources, self) {
85400
+ function localCallsOf(path110, content, autoLabels, trustedRunSources, self) {
85150
85401
  AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
85151
85402
  TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
85152
85403
  try {
85153
- return localCallsOfInner(path108, content, self);
85404
+ return localCallsOfInner(path110, content, self);
85154
85405
  } finally {
85155
85406
  AUTO_LABELS = /* @__PURE__ */ new Set();
85156
85407
  TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
85157
85408
  }
85158
85409
  }
85159
- function localCallsOfInner(path108, content, self) {
85410
+ function localCallsOfInner(path110, content, self) {
85160
85411
  let raw;
85161
85412
  try {
85162
85413
  raw = loadWorkflow(content).raw;
@@ -85174,7 +85425,7 @@ function localCallsOfInner(path108, content, self) {
85174
85425
  out.push({
85175
85426
  target,
85176
85427
  caller: {
85177
- file: path108,
85428
+ file: path110,
85178
85429
  keys: reach.keys,
85179
85430
  untrusted: reach.untrusted,
85180
85431
  secretExposed: reach.secretExposed,
@@ -85410,7 +85661,7 @@ function upstreamRunTrusted(wf, raw) {
85410
85661
  const names = Array.isArray(run?.workflows) ? run.workflows.map(String) : [];
85411
85662
  return names.length > 0 && names.every((n) => TRUSTED_RUN_SOURCES.has(n));
85412
85663
  }
85413
- function runSourceOf(path108, content, autoLabels) {
85664
+ function runSourceOf(path110, content, autoLabels) {
85414
85665
  AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
85415
85666
  try {
85416
85667
  let raw;
@@ -85423,7 +85674,7 @@ function runSourceOf(path108, content, autoLabels) {
85423
85674
  const wf = raw;
85424
85675
  CALLERS.delete(wf);
85425
85676
  const reach = triggerReach(wf, raw);
85426
- const name = typeof raw["name"] === "string" && raw["name"] ? raw["name"] : path108;
85677
+ const name = typeof raw["name"] === "string" && raw["name"] ? raw["name"] : path110;
85427
85678
  return { name, trusted: !reach.untrusted && !reach.reusable };
85428
85679
  } finally {
85429
85680
  AUTO_LABELS = /* @__PURE__ */ new Set();
@@ -85893,18 +86144,18 @@ function severityFromScore(score) {
85893
86144
  if (score >= 1) return "advisory";
85894
86145
  return null;
85895
86146
  }
85896
- function analyzeWorkflow(path108, content, callers, autoLabels, trustedRunSources) {
86147
+ function analyzeWorkflow(path110, content, callers, autoLabels, trustedRunSources) {
85897
86148
  AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
85898
86149
  TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
85899
86150
  try {
85900
- return analyzeWorkflowInner(path108, content, callers);
86151
+ return analyzeWorkflowInner(path110, content, callers);
85901
86152
  } finally {
85902
86153
  AUTO_LABELS = /* @__PURE__ */ new Set();
85903
86154
  TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
85904
86155
  UPSTREAM_TRUSTED = false;
85905
86156
  }
85906
86157
  }
85907
- function analyzeWorkflowInner(path108, content, callers) {
86158
+ function analyzeWorkflowInner(path110, content, callers) {
85908
86159
  let raw;
85909
86160
  try {
85910
86161
  raw = loadWorkflow(content).raw;
@@ -86113,7 +86364,7 @@ function analyzeWorkflowInner(path108, content, callers) {
86113
86364
  dimension: "workflows",
86114
86365
  severity,
86115
86366
  title,
86116
- file: path108,
86367
+ file: path110,
86117
86368
  signals,
86118
86369
  mitigations: mitigations.length ? mitigations : void 0,
86119
86370
  fix: head === "root" && privileged ? "Do not check out the untrusted PR head into the workspace root under a privileged trigger (pull_request_target/workflow_run): check out the base ref, or isolate the head in a subdir (--add-dir). Add an actor gate and scope the agent tools." : head === "root" ? "This runs under `pull_request` (fork PRs get a read-only token), so the head checkout is low-risk today: keep it on `pull_request` (not `pull_request_target`) and keep the actor gate + scoped tools." : "Add/verify an actor gate, scope the agent tools to read-only, and env-deny secrets. See Anthropic\u2019s claude-code-action security doc."
@@ -86217,18 +86468,18 @@ function evalAgentJob(job, wf, raw, untrustedTrigger, reusable) {
86217
86468
  if (reusable && !loadedGun && SEVERITY_RANK2[severity] > SEVERITY_RANK2.medium) severity = "medium";
86218
86469
  return { severity, secrets, injectable, canReadEnv };
86219
86470
  }
86220
- function analyzeWorkflowSecrets(path108, content, callers, autoLabels, trustedRunSources) {
86471
+ function analyzeWorkflowSecrets(path110, content, callers, autoLabels, trustedRunSources) {
86221
86472
  AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
86222
86473
  TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
86223
86474
  try {
86224
- return analyzeWorkflowSecretsInner(path108, content, callers);
86475
+ return analyzeWorkflowSecretsInner(path110, content, callers);
86225
86476
  } finally {
86226
86477
  AUTO_LABELS = /* @__PURE__ */ new Set();
86227
86478
  TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
86228
86479
  UPSTREAM_TRUSTED = false;
86229
86480
  }
86230
86481
  }
86231
- function analyzeWorkflowSecretsInner(path108, content, callers) {
86482
+ function analyzeWorkflowSecretsInner(path110, content, callers) {
86232
86483
  let raw;
86233
86484
  try {
86234
86485
  raw = loadWorkflow(content).raw;
@@ -86255,7 +86506,7 @@ function analyzeWorkflowSecretsInner(path108, content, callers) {
86255
86506
  dimension: "data",
86256
86507
  severity: worst.severity,
86257
86508
  title: worst.severity === "advisory" ? "Secrets reachable by the agent: hardening" : "Exfiltratable secrets reachable by an injectable agent",
86258
- file: path108,
86509
+ file: path110,
86259
86510
  signals: [
86260
86511
  `agent can reach: ${worst.secrets.map((s) => s.name).join(", ")}`,
86261
86512
  worst.injectable ? "the agent is externally triggerable (untrusted trigger, no gate)" : "gated / not externally triggerable: latent risk only",
@@ -86277,7 +86528,7 @@ function marketplaceOwner(market) {
86277
86528
  market
86278
86529
  )?.[1] ?? /^([\w.-]{1,100})\/[\w.-]{1,100}(?:[#@].*)?$/.exec(market)?.[1];
86279
86530
  }
86280
- function analyzeWorkflowPlugins(path108, content, owner) {
86531
+ function analyzeWorkflowPlugins(path110, content, owner) {
86281
86532
  let raw;
86282
86533
  try {
86283
86534
  raw = loadWorkflow(content).raw;
@@ -86307,7 +86558,7 @@ function analyzeWorkflowPlugins(path108, content, owner) {
86307
86558
  dimension: "mcp",
86308
86559
  severity: "medium",
86309
86560
  title: "Agent installs plugins from a third-party marketplace on every run",
86310
- file: path108,
86561
+ file: path110,
86311
86562
  signals: [
86312
86563
  `\`plugin_marketplaces: ${safeText(market, 120)}\` is not pinned to a commit: whoever controls it changes the code and prompts the agent runs`
86313
86564
  ],
@@ -86323,11 +86574,11 @@ function readsItemList(text) {
86323
86574
  if (text.length > 2e5) return ITEM_LIST_RE.test(text);
86324
86575
  return text.replace(/\\\r?\n/g, " ").split("\n").some((l) => ITEM_LIST_RE.test(l) && !sanitizedListing(l));
86325
86576
  }
86326
- function analyzeTrustedReaders(path108, content, autoLabels, callers, trustedRunSources) {
86577
+ function analyzeTrustedReaders(path110, content, autoLabels, callers, trustedRunSources) {
86327
86578
  AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
86328
86579
  TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
86329
86580
  try {
86330
- return analyzeTrustedReadersInner(path108, content, callers);
86581
+ return analyzeTrustedReadersInner(path110, content, callers);
86331
86582
  } finally {
86332
86583
  AUTO_LABELS = /* @__PURE__ */ new Set();
86333
86584
  TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
@@ -86336,7 +86587,7 @@ function analyzeTrustedReaders(path108, content, autoLabels, callers, trustedRun
86336
86587
  function keysWithCallers(keys, callers) {
86337
86588
  return [.../* @__PURE__ */ new Set([...keys, ...(callers ?? []).flatMap((c) => c.keys)])];
86338
86589
  }
86339
- function analyzeTrustedReadersInner(path108, content, callers) {
86590
+ function analyzeTrustedReadersInner(path110, content, callers) {
86340
86591
  let raw;
86341
86592
  try {
86342
86593
  raw = loadWorkflow(content).raw;
@@ -86397,7 +86648,7 @@ function analyzeTrustedReadersInner(path108, content, callers) {
86397
86648
  dimension: "workflows",
86398
86649
  severity: "advisory",
86399
86650
  title: "Agent on a trusted trigger reads content strangers write, with a write token",
86400
- file: path108,
86651
+ file: path110,
86401
86652
  signals: [
86402
86653
  `runs on ${keys.map((k) => safeText(k, 40)).join(", ")}: no stranger starts it`,
86403
86654
  ...reads.map((r) => `the agent ${r}`),
@@ -86485,17 +86736,17 @@ function requiresTrustedAuthor(src) {
86485
86736
  };
86486
86737
  return req(x);
86487
86738
  }
86488
- function analyzeForkCodeOnTrust(path108, content, callers, autoLabels, trustedRunSources) {
86739
+ function analyzeForkCodeOnTrust(path110, content, callers, autoLabels, trustedRunSources) {
86489
86740
  AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
86490
86741
  TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
86491
86742
  try {
86492
- return analyzeForkCodeOnTrustInner(path108, content, callers);
86743
+ return analyzeForkCodeOnTrustInner(path110, content, callers);
86493
86744
  } finally {
86494
86745
  AUTO_LABELS = /* @__PURE__ */ new Set();
86495
86746
  TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
86496
86747
  }
86497
86748
  }
86498
- function analyzeForkCodeOnTrustInner(path108, content, callers) {
86749
+ function analyzeForkCodeOnTrustInner(path110, content, callers) {
86499
86750
  let raw;
86500
86751
  try {
86501
86752
  raw = loadWorkflow(content).raw;
@@ -86534,7 +86785,7 @@ function analyzeForkCodeOnTrustInner(path108, content, callers) {
86534
86785
  dimension: "workflows",
86535
86786
  severity: "advisory",
86536
86787
  title: "A maintainer's action runs the agent inside the fork's code",
86537
- file: path108,
86788
+ file: path110,
86538
86789
  signals: [
86539
86790
  `triggered by ${forkKeys.map((k) => safeText(k, 40)).join(", ")}, behind a gate a maintainer passes (a comment, a label, a push to the PR branch, a reopen)`,
86540
86791
  "checks out the untrusted PR head into the workspace root",
@@ -86566,18 +86817,18 @@ function laterSecrets(wf, job, from) {
86566
86817
  if (!/^GITHUB_TOKEN$/i.test(m[1])) out.add(m[1]);
86567
86818
  return [...out];
86568
86819
  }
86569
- function analyzeAgentOutputToEnv(path108, content, callers, autoLabels, trustedRunSources) {
86820
+ function analyzeAgentOutputToEnv(path110, content, callers, autoLabels, trustedRunSources) {
86570
86821
  AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
86571
86822
  TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
86572
86823
  try {
86573
- return analyzeAgentOutputToEnvInner(path108, content, callers);
86824
+ return analyzeAgentOutputToEnvInner(path110, content, callers);
86574
86825
  } finally {
86575
86826
  AUTO_LABELS = /* @__PURE__ */ new Set();
86576
86827
  TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
86577
86828
  UPSTREAM_TRUSTED = false;
86578
86829
  }
86579
86830
  }
86580
- function analyzeAgentOutputToEnvInner(path108, content, callers) {
86831
+ function analyzeAgentOutputToEnvInner(path110, content, callers) {
86581
86832
  let raw;
86582
86833
  try {
86583
86834
  raw = loadWorkflow(content).raw;
@@ -86673,7 +86924,7 @@ function analyzeAgentOutputToEnvInner(path108, content, callers) {
86673
86924
  dimension: "workflows",
86674
86925
  severity,
86675
86926
  title: sink.target === "GITHUB_PATH" ? "The agent's output is added to the job's PATH" : "The agent's output is written into the job's environment",
86676
- file: path108,
86927
+ file: path110,
86677
86928
  signals,
86678
86929
  fix: `Write the agent's result to a file and read it with a strict parser in the next step (a fixed set of values, or a number); never append free text from the agent to \`${target}\`. If a value must go there, strip newlines (\`tr -d '\\n'\`) and write it under a fixed name, or use a delimiter generated at run time.`,
86679
86930
  explain: explainAgentOutputEnv({
@@ -86701,7 +86952,7 @@ function analyzeAgentOutputToEnvInner(path108, content, callers) {
86701
86952
 
86702
86953
  // src/ci-check/agent-config.ts
86703
86954
  init_cjs_shims();
86704
- var import_path90 = __toESM(require("path"));
86955
+ var import_path92 = __toESM(require("path"));
86705
86956
  function asStrings(v) {
86706
86957
  return Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
86707
86958
  }
@@ -86809,7 +87060,7 @@ function hookScriptPath(cmd) {
86809
87060
  if (/^(https?:|\$|-)/.test(t)) continue;
86810
87061
  t = t.replace(/^\.\//, "");
86811
87062
  if (!SCRIPT_EXT_RE.test(t) && !/(^|\/)\.claude\/hooks\//.test(t)) continue;
86812
- const norm = import_path90.default.posix.normalize(t);
87063
+ const norm = import_path92.default.posix.normalize(t);
86813
87064
  if (norm.startsWith("..") || norm.startsWith("/") || norm.includes("/../")) return null;
86814
87065
  return norm;
86815
87066
  }
@@ -86819,7 +87070,7 @@ function cmdLine(content, cmd) {
86819
87070
  const i = jsonValueIndex(content, cmd);
86820
87071
  return i >= 0 ? lineAtIndex(content, i) : void 0;
86821
87072
  }
86822
- function analyzeAgentConfig(path108, content, tree) {
87073
+ function analyzeAgentConfig(path110, content, tree) {
86823
87074
  let cfg;
86824
87075
  try {
86825
87076
  cfg = JSON.parse(content);
@@ -86842,7 +87093,7 @@ function analyzeAgentConfig(path108, content, tree) {
86842
87093
  dimension: "toolRules",
86843
87094
  severity: high ? "high" : "medium",
86844
87095
  title: high ? "Agent hook runs UNPINNED/remote third-party code on every action" : "Agent hook runs third-party code in the agent hot path",
86845
- file: path108,
87096
+ file: path110,
86846
87097
  ...cmdLine(content, cmd) ? { line: cmdLine(content, cmd) } : {},
86847
87098
  signals: [
86848
87099
  `hook command: \`${safeText(cmd, 120)}\``,
@@ -86863,7 +87114,7 @@ function analyzeAgentConfig(path108, content, tree) {
86863
87114
  dimension: "toolRules",
86864
87115
  severity: "medium",
86865
87116
  title: "Agent hook runs a script that is not committed",
86866
- file: path108,
87117
+ file: path110,
86867
87118
  ...cmdLine(content, cmd) ? { line: cmdLine(content, cmd) } : {},
86868
87119
  signals: [
86869
87120
  `hook command: \`${safeText(cmd, 120)}\``,
@@ -86879,7 +87130,7 @@ function analyzeAgentConfig(path108, content, tree) {
86879
87130
  dimension: "toolRules",
86880
87131
  severity: "advisory",
86881
87132
  title: "Agent hook runs a committed script this scan did not read",
86882
- file: path108,
87133
+ file: path110,
86883
87134
  ...cmdLine(content, cmd) ? { line: cmdLine(content, cmd) } : {},
86884
87135
  signals: [
86885
87136
  `hook command: \`${safeText(cmd, 120)}\``,
@@ -86908,12 +87159,12 @@ function analyzeAgentConfig(path108, content, tree) {
86908
87159
  dimension: "toolRules",
86909
87160
  severity: high ? "high" : "medium",
86910
87161
  title: high ? "Committed agent config pre-authorizes broad tools with no deny backstop" : "Committed agent config pre-authorizes broad tools",
86911
- file: path108,
87162
+ file: path110,
86912
87163
  signals,
86913
87164
  fix: "Scope the allow-list to specific read-only subcommands (e.g. `Bash(gh pr view:*)`); avoid bare `Bash`/`git:`/`Write`, or add a `deny` backstop.",
86914
87165
  explain: explainGrant({
86915
87166
  high,
86916
- file: path108,
87167
+ file: path110,
86917
87168
  broad: grade.broad,
86918
87169
  bareShell: grade.bareShell,
86919
87170
  hasBackstop: grade.bareShell ? deny.some((d) => /^Bash\b/.test(d)) : deny.some((d) => /Bash|Write|Edit/.test(d))
@@ -86930,7 +87181,7 @@ function analyzeAgentConfig(path108, content, tree) {
86930
87181
  dimension: "toolRules",
86931
87182
  severity: "medium",
86932
87183
  title: "Committed agent config pre-approves a command that can run other programs",
86933
- file: path108,
87184
+ file: path110,
86934
87185
  signals: [
86935
87186
  `pre-approved: ${escapes.slice(0, 5).map((e) => `\`${safeText(e, 80)}\``).join(", ")}`,
86936
87187
  "`find -exec` and `make -n --eval` run other programs without a prompt"
@@ -86945,8 +87196,8 @@ var ROOT_SURFACE_RE = /^\.(claude|agents|github|codex|cursor|gemini)\//;
86945
87196
  var ITEM_TEXT_RE = /gh\s+(?:pr|issue)\s+(?:view|diff|list)\b|gh\s+pr\s+checkout\b|git\s+fetch\s+[^\n]{0,80}\bpull\/|gh\s+api\s+graphql\b|gh\s+api\s+[^\n]{0,120}\/(?:pulls|issues)\b|mcp__github__(?:get_issue|get_pull_request|list_issues|search_issues)|--json\s+[^\n]{0,120}\b(?:body|title)\b/;
86946
87197
  var PR_TEXT_RE = /gh\s+pr\s+(?:view|diff)\b|gh\s+api\s+[^\n]{0,120}\/pulls\b/;
86947
87198
  var WEB_TEXT_RE = /\bsearch the web\b|\bfetch (?:the )?(?:url|page)\b/i;
86948
- function skillReadsUntrusted(path108, content, allow, broad) {
86949
- if (!ROOT_SURFACE_RE.test(path108)) return null;
87199
+ function skillReadsUntrusted(path110, content, allow, broad) {
87200
+ if (!ROOT_SURFACE_RE.test(path110)) return null;
86950
87201
  const body = content.replace(/^---[\s\S]*?\n---/, "");
86951
87202
  const runsCode = broad.map((a) => a.replace(/^PowerShell(?=$|\()/, "Bash")).some((a) => /^Bash$|^Bash\(\s*\*/.test(a) || openRunner(a) && !/^Bash\(\s*gh\b/.test(a));
86952
87203
  const webGrant = allow.some((a) => /^(WebFetch|WebSearch)\b/.test(a));
@@ -86961,8 +87212,8 @@ function skillReadsUntrusted(path108, content, allow, broad) {
86961
87212
  return "it reads pull request text that strangers write, and may edit files and run git/gh on it";
86962
87213
  return null;
86963
87214
  }
86964
- function analyzeSkillGrants(path108, content) {
86965
- if (!GRANT_CARRIER_RE.test(path108)) return [];
87215
+ function analyzeSkillGrants(path110, content) {
87216
+ if (!GRANT_CARRIER_RE.test(path110)) return [];
86966
87217
  const allow = allowedToolsOf(parseFrontmatter(content));
86967
87218
  if (allow.length === 0) return [];
86968
87219
  const grade = gradeBroadGrant(allow, [], {
@@ -86970,9 +87221,9 @@ function analyzeSkillGrants(path108, content) {
86970
87221
  scope: "whenever this skill or command is active, for everyone who opens this repo with the agent"
86971
87222
  });
86972
87223
  if (!grade) return [];
86973
- const kind = /commands\//.test(path108) ? "slash command" : "skill";
87224
+ const kind = /commands\//.test(path110) ? "slash command" : "skill";
86974
87225
  const at = content.search(/^allowed-tools\s*:/m);
86975
- const untrusted = skillReadsUntrusted(path108, content, allow, grade.broad);
87226
+ const untrusted = skillReadsUntrusted(path110, content, allow, grade.broad);
86976
87227
  if (untrusted)
86977
87228
  return [
86978
87229
  {
@@ -86982,7 +87233,7 @@ function analyzeSkillGrants(path108, content) {
86982
87233
  dimension: "toolRules",
86983
87234
  severity: "advisory",
86984
87235
  title: `Committed ${kind} runs code or writes with text strangers control`,
86985
- file: path108,
87236
+ file: path110,
86986
87237
  signals: [...grade.signals, untrusted],
86987
87238
  fix: "Drop the shell or interpreter grant from a skill that reads PRs, issues or the web, or have it treat that text as data in a read-only step first."
86988
87239
  }
@@ -86999,7 +87250,7 @@ function analyzeSkillGrants(path108, content) {
86999
87250
  // shell — the cap is on reach, not on honesty.
87000
87251
  severity: "medium",
87001
87252
  title: grade.high ? `Committed ${kind} pre-authorizes an unrestricted shell while active` : `Committed ${kind} pre-authorizes broad tools while active`,
87002
- file: path108,
87253
+ file: path110,
87003
87254
  signals: grade.signals,
87004
87255
  fix: "Scope `allowed-tools` to the specific commands the skill needs (e.g. `Bash(git status:*)`); avoid a bare `Bash`, `Write` or `Edit`."
87005
87256
  }
@@ -87131,7 +87382,7 @@ function ownPackageNames(manifests) {
87131
87382
  }
87132
87383
  return out;
87133
87384
  }
87134
- function analyzeMcp(path108, content, own = /* @__PURE__ */ new Set()) {
87385
+ function analyzeMcp(path110, content, own = /* @__PURE__ */ new Set()) {
87135
87386
  let cfg;
87136
87387
  try {
87137
87388
  cfg = JSON.parse(content);
@@ -87167,9 +87418,9 @@ function analyzeMcp(path108, content, own = /* @__PURE__ */ new Set()) {
87167
87418
  const key = (count.get(name) ?? 0) > 1 ? `${section}.${name}` : name;
87168
87419
  servers[key] = { ...spec, anchor: name };
87169
87420
  }
87170
- return analyzeMcpServers(servers, path108, content, own);
87421
+ return analyzeMcpServers(servers, path110, content, own);
87171
87422
  }
87172
- function analyzeMcpServers(servers, path108, content = "", own = /* @__PURE__ */ new Set()) {
87423
+ function analyzeMcpServers(servers, path110, content = "", own = /* @__PURE__ */ new Set()) {
87173
87424
  const findings = [];
87174
87425
  for (const [name, srv] of Object.entries(servers ?? {})) {
87175
87426
  if (!srv || srv.disabled) continue;
@@ -87188,7 +87439,7 @@ function analyzeMcpServers(servers, path108, content = "", own = /* @__PURE__ */
87188
87439
  dimension: "mcp",
87189
87440
  severity: "medium",
87190
87441
  title: `MCP server "${name}" runs an unpinned executable`,
87191
- file: path108,
87442
+ file: path110,
87192
87443
  ...line ? { line } : {},
87193
87444
  signals: [
87194
87445
  why.launcher === "npx" ? `\`${safeText(argv, 120)}\`: unversioned/@latest npx` : `\`${safeText(argv, 120)}\`: unversioned/latest ${why.launcher}`
@@ -87213,7 +87464,7 @@ function analyzeMcpServers(servers, path108, content = "", own = /* @__PURE__ */
87213
87464
  dimension: "mcp",
87214
87465
  severity: "high",
87215
87466
  title: `MCP server "${name}" has an inline credential`,
87216
- file: path108,
87467
+ file: path110,
87217
87468
  ...line ? { line } : {},
87218
87469
  signals: [
87219
87470
  `env.${k} matches ${hit.patternName}: agent-reachable secret committed to the repo`
@@ -87229,7 +87480,7 @@ function analyzeMcpServers(servers, path108, content = "", own = /* @__PURE__ */
87229
87480
  // src/ci-check/codex.ts
87230
87481
  init_cjs_shims();
87231
87482
  var import_smol_toml7 = require("smol-toml");
87232
- function analyzeCodexConfig(path108, content, own = /* @__PURE__ */ new Set()) {
87483
+ function analyzeCodexConfig(path110, content, own = /* @__PURE__ */ new Set()) {
87233
87484
  let cfg;
87234
87485
  try {
87235
87486
  cfg = (0, import_smol_toml7.parse)(content);
@@ -87237,7 +87488,7 @@ function analyzeCodexConfig(path108, content, own = /* @__PURE__ */ new Set()) {
87237
87488
  return [];
87238
87489
  }
87239
87490
  const findings = [];
87240
- findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {}, path108, content, own));
87491
+ findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {}, path110, content, own));
87241
87492
  const sandbox = typeof cfg.sandbox_mode === "string" ? cfg.sandbox_mode : "";
87242
87493
  const approval = typeof cfg.approval_policy === "string" ? cfg.approval_policy : "";
87243
87494
  const fullAccess = /danger-full-access/i.test(sandbox);
@@ -87260,7 +87511,7 @@ function analyzeCodexConfig(path108, content, own = /* @__PURE__ */ new Set()) {
87260
87511
  dimension: "toolRules",
87261
87512
  severity: fullAccess ? "high" : "medium",
87262
87513
  title: fullAccess ? "Codex config grants a full-access sandbox" : "Codex config never requires approval",
87263
- file: path108,
87514
+ file: path110,
87264
87515
  signals,
87265
87516
  fix: 'Commit a least-privilege Codex config: prefer `sandbox_mode = "read-only"` (or `"workspace-write"`) and `approval_policy = "on-request"`/`"on-failure"`. A repo-committed config applies to every contributor who runs Codex here.'
87266
87517
  });
@@ -87314,7 +87565,7 @@ function reviewQuestion(rule) {
87314
87565
  return "Is this an instruction the agent follows, or text for a person?";
87315
87566
  }
87316
87567
  var RANK2 = { critical: 4, high: 3, medium: 2, advisory: 1 };
87317
- var worstRank = (fs109) => Math.max(...fs109.map((f) => RANK2[f.severity] ?? 0));
87568
+ var worstRank = (fs111) => Math.max(...fs111.map((f) => RANK2[f.severity] ?? 0));
87318
87569
  var fileOrder = (a, b) => worstRank(b[1]) - worstRank(a[1]) || b[1].length - a[1].length;
87319
87570
  function groupReview(findings) {
87320
87571
  const byFile = /* @__PURE__ */ new Map();
@@ -87379,7 +87630,7 @@ function logicalLines2(content) {
87379
87630
  }
87380
87631
  return out;
87381
87632
  }
87382
- function analyzeScript(path108, content, rulePrefix) {
87633
+ function analyzeScript(path110, content, rulePrefix) {
87383
87634
  const check = rulePrefix.startsWith("CI-1") ? "CI-1" : "CI-6";
87384
87635
  const dimension = check === "CI-1" ? "toolRules" : "instructions";
87385
87636
  const mk3 = (suffix, severity, title, signal, fix, line) => ({
@@ -87388,7 +87639,7 @@ function analyzeScript(path108, content, rulePrefix) {
87388
87639
  dimension,
87389
87640
  severity,
87390
87641
  title,
87391
- file: path108,
87642
+ file: path110,
87392
87643
  ...line ? { line } : {},
87393
87644
  signals: [signal],
87394
87645
  fix
@@ -87814,7 +88065,7 @@ async function scanRepo(input, onProgress) {
87814
88065
  // src/ci-check/render.ts
87815
88066
  init_cjs_shims();
87816
88067
  var import_chalk36 = __toESM(require("chalk"));
87817
- var listed = (fs109) => fs109.filter((f) => f.tier !== "review");
88068
+ var listed = (fs111) => fs111.filter((f) => f.tier !== "review");
87818
88069
  function excerpt(f) {
87819
88070
  const m = /`([^`]+)`/.exec(f.signals[0] ?? "");
87820
88071
  return safeText(m ? m[1] : f.title, 120).replace(/`/g, "'");
@@ -87830,14 +88081,14 @@ function reviewMd(findings) {
87830
88081
  L.push("");
87831
88082
  const files = [...byFile.keys()];
87832
88083
  for (const file2 of files.slice(0, REVIEW_FILES)) {
87833
- const fs109 = byFile.get(file2);
88084
+ const fs111 = byFile.get(file2);
87834
88085
  L.push(`- \`${safeText(file2, 300)}\``);
87835
- for (const f of fs109.slice(0, REVIEW_LINES_PER_FILE))
88086
+ for (const f of fs111.slice(0, REVIEW_LINES_PER_FILE))
87836
88087
  L.push(
87837
88088
  ` - ${f.line ? `line ${Number(f.line)}: ` : ""}\`${excerpt(f)}\`. Check: ${reviewQuestion(f.rule)}`
87838
88089
  );
87839
- if (fs109.length > REVIEW_LINES_PER_FILE)
87840
- L.push(` - and ${fs109.length - REVIEW_LINES_PER_FILE} similar lines in this file`);
88090
+ if (fs111.length > REVIEW_LINES_PER_FILE)
88091
+ L.push(` - and ${fs111.length - REVIEW_LINES_PER_FILE} similar lines in this file`);
87841
88092
  }
87842
88093
  const more = files.length - REVIEW_FILES;
87843
88094
  if (more > 0) L.push(`- and ${more} more file${more === 1 ? "" : "s"}`);
@@ -87853,7 +88104,7 @@ function reviewMd(findings) {
87853
88104
  }
87854
88105
  function reviewTerminal(findings) {
87855
88106
  const { byFile, grants } = groupReview(findings);
87856
- const items = [...byFile.values()].reduce((a, fs109) => a + fs109.length, 0);
88107
+ const items = [...byFile.values()].reduce((a, fs111) => a + fs111.length, 0);
87857
88108
  if (!items && !grants) return [];
87858
88109
  const L = [];
87859
88110
  if (items) {
@@ -87862,12 +88113,12 @@ function reviewTerminal(findings) {
87862
88113
  );
87863
88114
  const files = [...byFile.keys()];
87864
88115
  for (const file2 of files.slice(0, REVIEW_FILES)) {
87865
- const fs109 = byFile.get(file2);
88116
+ const fs111 = byFile.get(file2);
87866
88117
  L.push(import_chalk36.default.gray(` ${file2}`));
87867
- for (const f of fs109.slice(0, REVIEW_LINES_PER_FILE))
88118
+ for (const f of fs111.slice(0, REVIEW_LINES_PER_FILE))
87868
88119
  L.push(` \u2022 ${f.line ? `line ${f.line}: ` : ""}${excerpt(f)}`);
87869
- if (fs109.length > REVIEW_LINES_PER_FILE)
87870
- L.push(import_chalk36.default.gray(` and ${fs109.length - REVIEW_LINES_PER_FILE} similar lines`));
88120
+ if (fs111.length > REVIEW_LINES_PER_FILE)
88121
+ L.push(import_chalk36.default.gray(` and ${fs111.length - REVIEW_LINES_PER_FILE} similar lines`));
87871
88122
  }
87872
88123
  const more = files.length - REVIEW_FILES;
87873
88124
  if (more > 0) L.push(import_chalk36.default.gray(` and ${more} more file${more === 1 ? "" : "s"}`));
@@ -87881,7 +88132,7 @@ function reviewTerminal(findings) {
87881
88132
  L.push("");
87882
88133
  return L;
87883
88134
  }
87884
- var ICON2 = {
88135
+ var ICON3 = {
87885
88136
  critical: "\u{1F534}",
87886
88137
  high: "\u{1F534}",
87887
88138
  medium: "\u{1F7E1}",
@@ -87941,7 +88192,7 @@ function mdLine(v) {
87941
88192
  function findingMd(f, L) {
87942
88193
  const ex = f.explain;
87943
88194
  L.push(
87944
- `**${ICON2[f.severity]} ${f.severity.toUpperCase()}: ${mdLine(ex ? ex.headline : f.title)}**` + (f.suppressed ? ` _(suppressed: \`${safeText(f.suppressed.reason, 200)}\`)_` : "")
88195
+ `**${ICON3[f.severity]} ${f.severity.toUpperCase()}: ${mdLine(ex ? ex.headline : f.title)}**` + (f.suppressed ? ` _(suppressed: \`${safeText(f.suppressed.reason, 200)}\`)_` : "")
87945
88196
  );
87946
88197
  L.push(`\`${safeText(f.file, 300)}${f.line ? ":" + Number(f.line) : ""}\` \xB7 ${f.rule}`);
87947
88198
  L.push("");
@@ -87997,7 +88248,7 @@ function renderScan(res, diff) {
87997
88248
  for (const f of shown) {
87998
88249
  const ex = f.explain;
87999
88250
  L.push(
88000
- `${ICON2[f.severity]} ${COLOR[f.severity](f.severity.toUpperCase())} ${import_chalk36.default.bold(ex ? ex.headline : f.title)}`
88251
+ `${ICON3[f.severity]} ${COLOR[f.severity](f.severity.toUpperCase())} ${import_chalk36.default.bold(ex ? ex.headline : f.title)}`
88001
88252
  );
88002
88253
  L.push(import_chalk36.default.gray(` ${f.file}${f.line ? ":" + f.line : ""} \xB7 ${f.check}`));
88003
88254
  if (ex) {
@@ -88519,16 +88770,16 @@ var import_chalk40 = __toESM(require("chalk"));
88519
88770
 
88520
88771
  // src/canary/plant.ts
88521
88772
  init_cjs_shims();
88522
- var import_fs93 = __toESM(require("fs"));
88523
- var import_os76 = __toESM(require("os"));
88524
- var import_path92 = __toESM(require("path"));
88773
+ var import_fs95 = __toESM(require("fs"));
88774
+ var import_os77 = __toESM(require("os"));
88775
+ var import_path94 = __toESM(require("path"));
88525
88776
  init_jail();
88526
88777
  init_registry2();
88527
88778
 
88528
88779
  // src/canary/sites.ts
88529
88780
  init_cjs_shims();
88530
- var import_fs92 = __toESM(require("fs"));
88531
- var import_path91 = __toESM(require("path"));
88781
+ var import_fs94 = __toESM(require("fs"));
88782
+ var import_path93 = __toESM(require("path"));
88532
88783
 
88533
88784
  // src/canary/generate.ts
88534
88785
  init_cjs_shims();
@@ -88623,26 +88874,26 @@ function generateSshKey() {
88623
88874
  var SITES = {
88624
88875
  "aws-profile": {
88625
88876
  kind: "aws-profile",
88626
- primary: (h) => import_path91.default.join(h, ".aws", "credentials"),
88627
- fallback: (h) => import_path91.default.join(h, ".aws", "credentials.bak"),
88877
+ primary: (h) => import_path93.default.join(h, ".aws", "credentials"),
88878
+ fallback: (h) => import_path93.default.join(h, ".aws", "credentials.bak"),
88628
88879
  // SSO / profile-only / credential_process setups have ~/.aws/config and no
88629
88880
  // credentials file; the SDK and CLI then parse ~/.aws/credentials on every
88630
88881
  // profile lookup. A planted primary would be a file real tools read.
88631
- preferFallback: (h) => import_fs92.default.existsSync(import_path91.default.join(h, ".aws", "config")),
88882
+ preferFallback: (h) => import_fs94.default.existsSync(import_path93.default.join(h, ".aws", "config")),
88632
88883
  dirMode: 448,
88633
88884
  generate: generateAwsProfile
88634
88885
  },
88635
88886
  "env-file": {
88636
88887
  kind: "env-file",
88637
- primary: (h) => import_path91.default.join(h, ".env.bak"),
88638
- fallback: (h) => import_path91.default.join(h, ".env.local.bak"),
88888
+ primary: (h) => import_path93.default.join(h, ".env.bak"),
88889
+ fallback: (h) => import_path93.default.join(h, ".env.local.bak"),
88639
88890
  dirMode: 493,
88640
88891
  generate: generateEnvFile
88641
88892
  },
88642
88893
  "ssh-key": {
88643
88894
  kind: "ssh-key",
88644
- primary: (h) => import_path91.default.join(h, ".ssh", "id_rsa_backup"),
88645
- fallback: (h) => import_path91.default.join(h, ".ssh", "id_rsa.old"),
88895
+ primary: (h) => import_path93.default.join(h, ".ssh", "id_rsa_backup"),
88896
+ fallback: (h) => import_path93.default.join(h, ".ssh", "id_rsa.old"),
88646
88897
  // ssh refuses a group-writable ~/.ssh for config / known_hosts reads.
88647
88898
  dirMode: 448,
88648
88899
  generate: generateSshKey
@@ -88655,12 +88906,12 @@ var isKind = (s) => ALL_KINDS.includes(s);
88655
88906
  var liveRecords = (kind) => loadCanaries().filter((r) => r.kind === kind && !r.retiredAt);
88656
88907
  var fileHashOf = (p) => {
88657
88908
  try {
88658
- return sha256Hex(import_fs93.default.readFileSync(p));
88909
+ return sha256Hex(import_fs95.default.readFileSync(p));
88659
88910
  } catch {
88660
88911
  return null;
88661
88912
  }
88662
88913
  };
88663
- function plantKind(kind, home = import_os76.default.homedir()) {
88914
+ function plantKind(kind, home = import_os77.default.homedir()) {
88664
88915
  const site = SITES[kind];
88665
88916
  const live = liveRecords(kind);
88666
88917
  if (live.length > 0) {
@@ -88679,8 +88930,8 @@ function plantKind(kind, home = import_os76.default.homedir()) {
88679
88930
  const primary = site.primary(home);
88680
88931
  const fallback = site.fallback(home);
88681
88932
  let target;
88682
- if (!import_fs93.default.existsSync(primary) && !site.preferFallback?.(home)) target = primary;
88683
- else if (!import_fs93.default.existsSync(fallback)) target = fallback;
88933
+ if (!import_fs95.default.existsSync(primary) && !site.preferFallback?.(home)) target = primary;
88934
+ else if (!import_fs95.default.existsSync(fallback)) target = fallback;
88684
88935
  else {
88685
88936
  return {
88686
88937
  kind,
@@ -88691,11 +88942,11 @@ function plantKind(kind, home = import_os76.default.homedir()) {
88691
88942
  recordIds: []
88692
88943
  };
88693
88944
  }
88694
- const dir2 = import_path92.default.dirname(target);
88945
+ const dir2 = import_path94.default.dirname(target);
88695
88946
  const gen = site.generate();
88696
- const createdDir = import_fs93.default.mkdirSync(dir2, { recursive: true, mode: site.dirMode }) !== void 0;
88697
- import_fs93.default.writeFileSync(target, gen.text, { mode: 384, flag: "wx" });
88698
- import_fs93.default.chmodSync(target, 384);
88947
+ const createdDir = import_fs95.default.mkdirSync(dir2, { recursive: true, mode: site.dirMode }) !== void 0;
88948
+ import_fs95.default.writeFileSync(target, gen.text, { mode: 384, flag: "wx" });
88949
+ import_fs95.default.chmodSync(target, 384);
88699
88950
  const fileHash = sha256Hex(gen.text);
88700
88951
  regenerateUserJail(addJailPath(target, "block"));
88701
88952
  const recordIds = gen.values.map(
@@ -88713,14 +88964,14 @@ function plantKind(kind, home = import_os76.default.homedir()) {
88713
88964
  }
88714
88965
  function allowedPathsFor(kind, home) {
88715
88966
  const site = SITES[kind];
88716
- return [site.primary(home), site.fallback(home)].map((x) => import_path92.default.resolve(x));
88967
+ return [site.primary(home), site.fallback(home)].map((x) => import_path94.default.resolve(x));
88717
88968
  }
88718
- function removeKind(kind, home = import_os76.default.homedir()) {
88969
+ function removeKind(kind, home = import_os77.default.homedir()) {
88719
88970
  const live = liveRecords(kind);
88720
88971
  if (live.length === 0) return { kind, action: "absent" };
88721
88972
  const p = live[0].path;
88722
88973
  const { fileHash, createdDir } = live[0];
88723
- if (!allowedPathsFor(kind, home).includes(import_path92.default.resolve(p))) {
88974
+ if (!allowedPathsFor(kind, home).includes(import_path94.default.resolve(p))) {
88724
88975
  return {
88725
88976
  kind,
88726
88977
  action: "refused",
@@ -88728,7 +88979,7 @@ function removeKind(kind, home = import_os76.default.homedir()) {
88728
88979
  reason: `${p} is not a path node9 plants a ${kind} decoy at; refusing to delete it. If you believe this is a decoy, remove it by hand.`
88729
88980
  };
88730
88981
  }
88731
- if (!import_fs93.default.existsSync(p)) {
88982
+ if (!import_fs95.default.existsSync(p)) {
88732
88983
  for (const r of live) retireCanary(r.id);
88733
88984
  unjail(p);
88734
88985
  return { kind, action: "already-gone", path: p };
@@ -88741,13 +88992,13 @@ function removeKind(kind, home = import_os76.default.homedir()) {
88741
88992
  reason: `${p} changed since node9 wrote it; inspect and remove it by hand`
88742
88993
  };
88743
88994
  }
88744
- import_fs93.default.unlinkSync(p);
88995
+ import_fs95.default.unlinkSync(p);
88745
88996
  let dirRemoved = false;
88746
88997
  if (createdDir) {
88747
- const dir2 = import_path92.default.dirname(p);
88998
+ const dir2 = import_path94.default.dirname(p);
88748
88999
  try {
88749
- if (import_fs93.default.readdirSync(dir2).length === 0) {
88750
- import_fs93.default.rmdirSync(dir2);
89000
+ if (import_fs95.default.readdirSync(dir2).length === 0) {
89001
+ import_fs95.default.rmdirSync(dir2);
88751
89002
  dirRemoved = true;
88752
89003
  }
88753
89004
  } catch {
@@ -88771,14 +89022,14 @@ function statusAll() {
88771
89022
  const p = live[0].path;
88772
89023
  return {
88773
89024
  kind,
88774
- state: import_fs93.default.existsSync(p) ? "planted" : "missing",
89025
+ state: import_fs95.default.existsSync(p) ? "planted" : "missing",
88775
89026
  path: p,
88776
89027
  records: live.length,
88777
89028
  plantedAt: live[0].plantedAt
88778
89029
  };
88779
89030
  });
88780
89031
  }
88781
- function rotateKind(kind, home = import_os76.default.homedir()) {
89032
+ function rotateKind(kind, home = import_os77.default.homedir()) {
88782
89033
  const removed = removeKind(kind);
88783
89034
  if (removed.action === "refused") return { removed };
88784
89035
  return { removed, planted: plantKind(kind, home) };
@@ -88867,15 +89118,15 @@ init_daemon3();
88867
89118
  // src/cli/commands/sandbox.ts
88868
89119
  init_cjs_shims();
88869
89120
  var import_chalk41 = __toESM(require("chalk"));
88870
- var import_fs96 = __toESM(require("fs"));
88871
- var import_path95 = __toESM(require("path"));
89121
+ var import_fs98 = __toESM(require("fs"));
89122
+ var import_path97 = __toESM(require("path"));
88872
89123
  var import_child_process16 = require("child_process");
88873
89124
  init_config();
88874
89125
 
88875
89126
  // src/sandbox/config.ts
88876
89127
  init_cjs_shims();
88877
- var import_fs94 = __toESM(require("fs"));
88878
- var import_path93 = __toESM(require("path"));
89128
+ var import_fs96 = __toESM(require("fs"));
89129
+ var import_path95 = __toESM(require("path"));
88879
89130
  var import_yaml2 = require("yaml");
88880
89131
  var SANDBOX_CONFIG_FILE = "node9.sandbox.yaml";
88881
89132
  var FORBIDDEN_ENV = /* @__PURE__ */ new Set(["NODE9_API_KEY", "NODE9_API_URL"]);
@@ -88948,16 +89199,16 @@ function scaffoldSandboxYaml(agent) {
88948
89199
  return header + (0, import_yaml2.stringify)(defaultSandboxConfig(agent));
88949
89200
  }
88950
89201
  function sandboxConfigPath(cwd = process.cwd()) {
88951
- return import_path93.default.join(cwd, SANDBOX_CONFIG_FILE);
89202
+ return import_path95.default.join(cwd, SANDBOX_CONFIG_FILE);
88952
89203
  }
88953
89204
  function loadSandboxConfig(cwd = process.cwd(), fallbackAgent = "claude") {
88954
89205
  const p = sandboxConfigPath(cwd);
88955
- if (!import_fs94.default.existsSync(p)) {
89206
+ if (!import_fs96.default.existsSync(p)) {
88956
89207
  throw new Error(`sandbox: ${SANDBOX_CONFIG_FILE} not found \u2014 run \`node9 sandbox new\` first.`);
88957
89208
  }
88958
89209
  let raw;
88959
89210
  try {
88960
- raw = (0, import_yaml2.parse)(import_fs94.default.readFileSync(p, "utf-8"));
89211
+ raw = (0, import_yaml2.parse)(import_fs96.default.readFileSync(p, "utf-8"));
88961
89212
  } catch (err2) {
88962
89213
  throw new Error(
88963
89214
  `sandbox: ${SANDBOX_CONFIG_FILE} is not valid YAML \u2014 ${err2.message}`
@@ -89018,14 +89269,14 @@ init_atomic_write();
89018
89269
 
89019
89270
  // src/sandbox/runtime.ts
89020
89271
  init_cjs_shims();
89021
- var import_fs95 = __toESM(require("fs"));
89022
- var import_os77 = __toESM(require("os"));
89023
- var import_path94 = __toESM(require("path"));
89272
+ var import_fs97 = __toESM(require("fs"));
89273
+ var import_os78 = __toESM(require("os"));
89274
+ var import_path96 = __toESM(require("path"));
89024
89275
  var import_crypto26 = __toESM(require("crypto"));
89025
89276
  var import_child_process15 = require("child_process");
89026
89277
  init_templates();
89027
89278
  function sandboxDataDir(cwd = process.cwd()) {
89028
- return import_path94.default.join(cwd, ".node9", "sandbox", "data");
89279
+ return import_path96.default.join(cwd, ".node9", "sandbox", "data");
89029
89280
  }
89030
89281
  function detectEngine(engine) {
89031
89282
  const r = (0, import_child_process15.spawnSync)(engine, ["--version"], { encoding: "utf-8" });
@@ -89036,7 +89287,7 @@ function detectEngine(engine) {
89036
89287
  }
89037
89288
  function agentCredentialsMount(agent) {
89038
89289
  const rel = agent === "codex" ? ".codex/auth.json" : ".claude/.credentials.json";
89039
- return { hostPath: import_path94.default.join(import_os77.default.homedir(), rel), target: `/home/${RUN_AS_USER}/${rel}` };
89290
+ return { hostPath: import_path96.default.join(import_os78.default.homedir(), rel), target: `/home/${RUN_AS_USER}/${rel}` };
89040
89291
  }
89041
89292
  function buildRunArgs(opts) {
89042
89293
  const { config, workspaceHostPath, dataHostPath, allowlistHostPath, agentArgs } = opts;
@@ -89046,7 +89297,7 @@ function buildRunArgs(opts) {
89046
89297
  args.push("-v", `${allowlistHostPath}:${ALLOWED_DOMAINS_PATH}:ro`);
89047
89298
  if (config.node9.mountAgentCredentials) {
89048
89299
  const creds = agentCredentialsMount(config.agent);
89049
- if (import_fs95.default.existsSync(creds.hostPath)) {
89300
+ if (import_fs97.default.existsSync(creds.hostPath)) {
89050
89301
  args.push("-v", `${creds.hostPath}:${creds.target}`);
89051
89302
  }
89052
89303
  }
@@ -89064,30 +89315,30 @@ function imageContentHash(dockerfile, entrypoint) {
89064
89315
  return import_crypto26.default.createHash("sha256").update(dockerfile).update("\0").update(entrypoint).digest("hex").slice(0, 16);
89065
89316
  }
89066
89317
  function sandboxBuildDir(cwd = process.cwd()) {
89067
- return import_path94.default.join(cwd, ".node9", "sandbox", "build");
89318
+ return import_path96.default.join(cwd, ".node9", "sandbox", "build");
89068
89319
  }
89069
89320
  function writeBuildContext(cwd, dockerfile, entrypoint) {
89070
89321
  const dir2 = sandboxBuildDir(cwd);
89071
- import_fs95.default.mkdirSync(dir2, { recursive: true });
89072
- import_fs95.default.writeFileSync(import_path94.default.join(dir2, "Dockerfile"), dockerfile);
89073
- import_fs95.default.writeFileSync(import_path94.default.join(dir2, "entrypoint.sh"), entrypoint);
89322
+ import_fs97.default.mkdirSync(dir2, { recursive: true });
89323
+ import_fs97.default.writeFileSync(import_path96.default.join(dir2, "Dockerfile"), dockerfile);
89324
+ import_fs97.default.writeFileSync(import_path96.default.join(dir2, "entrypoint.sh"), entrypoint);
89074
89325
  return dir2;
89075
89326
  }
89076
89327
  function writeAllowlist(cwd, hosts) {
89077
- const dir2 = import_path94.default.join(cwd, ".node9", "sandbox");
89078
- import_fs95.default.mkdirSync(dir2, { recursive: true });
89079
- const p = import_path94.default.join(dir2, "allowed-domains.txt");
89080
- import_fs95.default.writeFileSync(p, hosts.join("\n") + "\n");
89328
+ const dir2 = import_path96.default.join(cwd, ".node9", "sandbox");
89329
+ import_fs97.default.mkdirSync(dir2, { recursive: true });
89330
+ const p = import_path96.default.join(dir2, "allowed-domains.txt");
89331
+ import_fs97.default.writeFileSync(p, hosts.join("\n") + "\n");
89081
89332
  return p;
89082
89333
  }
89083
89334
  function resolveHomePath(p) {
89084
- return p.startsWith("~") ? import_path94.default.join(import_os77.default.homedir(), p.slice(1)) : import_path94.default.resolve(p);
89335
+ return p.startsWith("~") ? import_path96.default.join(import_os78.default.homedir(), p.slice(1)) : import_path96.default.resolve(p);
89085
89336
  }
89086
89337
 
89087
89338
  // src/cli/commands/sandbox.ts
89088
89339
  function seedDataDirConfig(dataDir, sandbox) {
89089
- import_fs96.default.mkdirSync(dataDir, { recursive: true });
89090
- const configPath2 = import_path95.default.join(dataDir, "config.json");
89340
+ import_fs98.default.mkdirSync(dataDir, { recursive: true });
89341
+ const configPath2 = import_path97.default.join(dataDir, "config.json");
89091
89342
  const seed = {
89092
89343
  settings: {
89093
89344
  approvers: {
@@ -89098,7 +89349,7 @@ function seedDataDirConfig(dataDir, sandbox) {
89098
89349
  }
89099
89350
  }
89100
89351
  };
89101
- import_fs96.default.writeFileSync(configPath2, JSON.stringify(seed, null, 2), { mode: 384 });
89352
+ import_fs98.default.writeFileSync(configPath2, JSON.stringify(seed, null, 2), { mode: 384 });
89102
89353
  }
89103
89354
  function registerSandboxCommand(program2, version2) {
89104
89355
  const node9Version2 = pinnedNode9Version(version2);
@@ -89107,7 +89358,7 @@ function registerSandboxCommand(program2, version2) {
89107
89358
  const agent = opts.agent === "codex" ? "codex" : "claude";
89108
89359
  const p = sandboxConfigPath();
89109
89360
  try {
89110
- import_fs96.default.writeFileSync(p, scaffoldSandboxYaml(agent), { flag: "wx" });
89361
+ import_fs98.default.writeFileSync(p, scaffoldSandboxYaml(agent), { flag: "wx" });
89111
89362
  } catch (e) {
89112
89363
  if (e.code !== "EEXIST") throw e;
89113
89364
  console.log(
@@ -89154,8 +89405,8 @@ function registerSandboxCommand(program2, version2) {
89154
89405
  const buildDir = writeBuildContext(cwd, dockerfile, entrypoint);
89155
89406
  const hash2 = imageContentHash(dockerfile, entrypoint);
89156
89407
  const image = sandbox.runtime.image;
89157
- const hashFile = import_path95.default.join(sandboxBuildDir(cwd), ".image-hash");
89158
- const lastHash = import_fs96.default.existsSync(hashFile) ? import_fs96.default.readFileSync(hashFile, "utf-8").trim() : "";
89408
+ const hashFile = import_path97.default.join(sandboxBuildDir(cwd), ".image-hash");
89409
+ const lastHash = import_fs98.default.existsSync(hashFile) ? import_fs98.default.readFileSync(hashFile, "utf-8").trim() : "";
89159
89410
  const imageExists = (0, import_child_process16.spawnSync)(sandbox.runtime.engine, ["image", "inspect", image], { stdio: "ignore" }).status === 0;
89160
89411
  const needBuild = sandbox.runtime.rebuild === "always" || !imageExists || sandbox.runtime.rebuild !== "never" && lastHash !== hash2;
89161
89412
  if (needBuild) {
@@ -89181,7 +89432,7 @@ function registerSandboxCommand(program2, version2) {
89181
89432
  });
89182
89433
  if (sandbox.node9.mountAgentCredentials) {
89183
89434
  const creds = agentCredentialsMount(sandbox.agent);
89184
- if (import_fs96.default.existsSync(creds.hostPath)) {
89435
+ if (import_fs98.default.existsSync(creds.hostPath)) {
89185
89436
  console.log(import_chalk41.default.dim(` mounting ${creds.hostPath} (agent credentials, rw)`));
89186
89437
  } else {
89187
89438
  console.log(
@@ -89197,20 +89448,20 @@ function registerSandboxCommand(program2, version2) {
89197
89448
  process.exit(r.status ?? 0);
89198
89449
  });
89199
89450
  cmd.command("tail").description("Stream the sandbox's audit log (host-side)").action(() => {
89200
- const auditPath = import_path95.default.join(sandboxDataDir(), "audit.log");
89201
- if (!import_fs96.default.existsSync(auditPath)) {
89451
+ const auditPath = import_path97.default.join(sandboxDataDir(), "audit.log");
89452
+ if (!import_fs98.default.existsSync(auditPath)) {
89202
89453
  console.log(import_chalk41.default.dim(" no sandbox audit yet."));
89203
89454
  return;
89204
89455
  }
89205
89456
  (0, import_child_process16.spawnSync)("tail", ["-f", auditPath], { stdio: "inherit" });
89206
89457
  });
89207
89458
  cmd.command("logs").description("Dump the sandbox's audit log").action(() => {
89208
- const auditPath = import_path95.default.join(sandboxDataDir(), "audit.log");
89209
- if (!import_fs96.default.existsSync(auditPath)) {
89459
+ const auditPath = import_path97.default.join(sandboxDataDir(), "audit.log");
89460
+ if (!import_fs98.default.existsSync(auditPath)) {
89210
89461
  console.log(import_chalk41.default.dim(" no sandbox audit yet."));
89211
89462
  return;
89212
89463
  }
89213
- process.stdout.write(import_fs96.default.readFileSync(auditPath, "utf-8"));
89464
+ process.stdout.write(import_fs98.default.readFileSync(auditPath, "utf-8"));
89214
89465
  });
89215
89466
  cmd.command("clean").description("Remove the sandbox image, build context, and data").action(() => {
89216
89467
  const cwd = process.cwd();
@@ -89224,7 +89475,7 @@ function registerSandboxCommand(program2, version2) {
89224
89475
  stdio: "ignore"
89225
89476
  });
89226
89477
  }
89227
- import_fs96.default.rmSync(import_path95.default.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
89478
+ import_fs98.default.rmSync(import_path97.default.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
89228
89479
  console.log(import_chalk41.default.green(" \u2713 sandbox image + build + data removed."));
89229
89480
  });
89230
89481
  }
@@ -89453,12 +89704,12 @@ function registerPackageIndexCommand(program2) {
89453
89704
  // src/cli/commands/skill-pin.ts
89454
89705
  init_cjs_shims();
89455
89706
  var import_chalk45 = __toESM(require("chalk"));
89456
- var import_fs97 = __toESM(require("fs"));
89457
- var import_os78 = __toESM(require("os"));
89458
- var import_path96 = __toESM(require("path"));
89707
+ var import_fs99 = __toESM(require("fs"));
89708
+ var import_os79 = __toESM(require("os"));
89709
+ var import_path98 = __toESM(require("path"));
89459
89710
  function wipeSkillSessions() {
89460
89711
  try {
89461
- import_fs97.default.rmSync(import_path96.default.join(import_os78.default.homedir(), ".node9", "skill-sessions"), {
89712
+ import_fs99.default.rmSync(import_path98.default.join(import_os79.default.homedir(), ".node9", "skill-sessions"), {
89462
89713
  recursive: true,
89463
89714
  force: true
89464
89715
  });
@@ -89541,15 +89792,15 @@ function registerSkillPinCommand(program2) {
89541
89792
 
89542
89793
  // src/cli/commands/decisions.ts
89543
89794
  init_cjs_shims();
89544
- var import_fs98 = __toESM(require("fs"));
89545
- var import_os79 = __toESM(require("os"));
89546
- var import_path97 = __toESM(require("path"));
89795
+ var import_fs100 = __toESM(require("fs"));
89796
+ var import_os80 = __toESM(require("os"));
89797
+ var import_path99 = __toESM(require("path"));
89547
89798
  var import_chalk46 = __toESM(require("chalk"));
89548
- var DECISIONS_FILE2 = import_path97.default.join(import_os79.default.homedir(), ".node9", "decisions.json");
89799
+ var DECISIONS_FILE2 = import_path99.default.join(import_os80.default.homedir(), ".node9", "decisions.json");
89549
89800
  function readDecisions() {
89550
89801
  try {
89551
- if (!import_fs98.default.existsSync(DECISIONS_FILE2)) return {};
89552
- const raw = import_fs98.default.readFileSync(DECISIONS_FILE2, "utf-8");
89802
+ if (!import_fs100.default.existsSync(DECISIONS_FILE2)) return {};
89803
+ const raw = import_fs100.default.readFileSync(DECISIONS_FILE2, "utf-8");
89553
89804
  const parsed = JSON.parse(raw);
89554
89805
  const out = {};
89555
89806
  for (const [k, v] of Object.entries(parsed)) {
@@ -89561,11 +89812,11 @@ function readDecisions() {
89561
89812
  }
89562
89813
  }
89563
89814
  function writeDecisions(d) {
89564
- const dir2 = import_path97.default.dirname(DECISIONS_FILE2);
89565
- if (!import_fs98.default.existsSync(dir2)) import_fs98.default.mkdirSync(dir2, { recursive: true });
89815
+ const dir2 = import_path99.default.dirname(DECISIONS_FILE2);
89816
+ if (!import_fs100.default.existsSync(dir2)) import_fs100.default.mkdirSync(dir2, { recursive: true });
89566
89817
  const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
89567
- import_fs98.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
89568
- import_fs98.default.renameSync(tmp, DECISIONS_FILE2);
89818
+ import_fs100.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
89819
+ import_fs100.default.renameSync(tmp, DECISIONS_FILE2);
89569
89820
  }
89570
89821
  function registerDecisionsCommand(program2) {
89571
89822
  const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
@@ -89623,15 +89874,15 @@ Persistent decisions (${entries.length})
89623
89874
  // src/cli/commands/dlp.ts
89624
89875
  init_cjs_shims();
89625
89876
  var import_chalk47 = __toESM(require("chalk"));
89626
- var import_fs99 = __toESM(require("fs"));
89627
- var import_path98 = __toESM(require("path"));
89628
- var import_os80 = __toESM(require("os"));
89877
+ var import_fs101 = __toESM(require("fs"));
89878
+ var import_path100 = __toESM(require("path"));
89879
+ var import_os81 = __toESM(require("os"));
89629
89880
  init_safe_text();
89630
- var AUDIT_LOG = import_path98.default.join(import_os80.default.homedir(), ".node9", "audit.log");
89631
- var RESOLVED_FILE = import_path98.default.join(import_os80.default.homedir(), ".node9", "dlp-resolved.json");
89881
+ var AUDIT_LOG = import_path100.default.join(import_os81.default.homedir(), ".node9", "audit.log");
89882
+ var RESOLVED_FILE = import_path100.default.join(import_os81.default.homedir(), ".node9", "dlp-resolved.json");
89632
89883
  function loadResolved() {
89633
89884
  try {
89634
- const raw = JSON.parse(import_fs99.default.readFileSync(RESOLVED_FILE, "utf-8"));
89885
+ const raw = JSON.parse(import_fs101.default.readFileSync(RESOLVED_FILE, "utf-8"));
89635
89886
  return new Set(raw);
89636
89887
  } catch {
89637
89888
  return /* @__PURE__ */ new Set();
@@ -89639,13 +89890,13 @@ function loadResolved() {
89639
89890
  }
89640
89891
  function saveResolved(resolved) {
89641
89892
  try {
89642
- import_fs99.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
89893
+ import_fs101.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
89643
89894
  } catch {
89644
89895
  }
89645
89896
  }
89646
89897
  function loadDlpFindings() {
89647
- if (!import_fs99.default.existsSync(AUDIT_LOG)) return [];
89648
- return import_fs99.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
89898
+ if (!import_fs101.default.existsSync(AUDIT_LOG)) return [];
89899
+ return import_fs101.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
89649
89900
  if (!line.trim()) return [];
89650
89901
  try {
89651
89902
  const e = JSON.parse(line);
@@ -89744,15 +89995,15 @@ function registerDlpCommand(program2) {
89744
89995
  // src/cli/commands/mask.ts
89745
89996
  init_cjs_shims();
89746
89997
  var import_chalk48 = __toESM(require("chalk"));
89747
- var import_fs100 = __toESM(require("fs"));
89748
- var import_path99 = __toESM(require("path"));
89749
- var import_os81 = __toESM(require("os"));
89998
+ var import_fs102 = __toESM(require("fs"));
89999
+ var import_path101 = __toESM(require("path"));
90000
+ var import_os82 = __toESM(require("os"));
89750
90001
  init_dlp();
89751
90002
  function findJsonlFiles(dir2) {
89752
90003
  const results = [];
89753
- if (!import_fs100.default.existsSync(dir2)) return results;
89754
- for (const entry of import_fs100.default.readdirSync(dir2, { withFileTypes: true })) {
89755
- const full = import_path99.default.join(dir2, entry.name);
90004
+ if (!import_fs102.default.existsSync(dir2)) return results;
90005
+ for (const entry of import_fs102.default.readdirSync(dir2, { withFileTypes: true })) {
90006
+ const full = import_path101.default.join(dir2, entry.name);
89756
90007
  if (entry.isDirectory()) results.push(...findJsonlFiles(full));
89757
90008
  else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
89758
90009
  }
@@ -89795,7 +90046,7 @@ function redactJson(obj) {
89795
90046
  function processFile(filePath, dryRun) {
89796
90047
  let raw;
89797
90048
  try {
89798
- raw = import_fs100.default.readFileSync(filePath, "utf-8");
90049
+ raw = import_fs102.default.readFileSync(filePath, "utf-8");
89799
90050
  } catch {
89800
90051
  return { redactedLines: 0, patterns: [] };
89801
90052
  }
@@ -89827,14 +90078,14 @@ function processFile(filePath, dryRun) {
89827
90078
  }
89828
90079
  }
89829
90080
  if (!dryRun && redactedLines > 0) {
89830
- import_fs100.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
90081
+ import_fs102.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
89831
90082
  }
89832
90083
  return { redactedLines, patterns };
89833
90084
  }
89834
90085
  function processJsonFile(filePath, dryRun) {
89835
90086
  let raw;
89836
90087
  try {
89837
- raw = import_fs100.default.readFileSync(filePath, "utf-8");
90088
+ raw = import_fs102.default.readFileSync(filePath, "utf-8");
89838
90089
  } catch {
89839
90090
  return { redactedLines: 0, patterns: [] };
89840
90091
  }
@@ -89847,15 +90098,15 @@ function processJsonFile(filePath, dryRun) {
89847
90098
  const { value, modified, found } = redactJson(parsed);
89848
90099
  if (!modified) return { redactedLines: 0, patterns: [] };
89849
90100
  if (!dryRun) {
89850
- import_fs100.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
90101
+ import_fs102.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
89851
90102
  }
89852
90103
  return { redactedLines: 1, patterns: found };
89853
90104
  }
89854
90105
  function findJsonFiles(dir2) {
89855
90106
  const results = [];
89856
- if (!import_fs100.default.existsSync(dir2)) return results;
89857
- for (const entry of import_fs100.default.readdirSync(dir2, { withFileTypes: true })) {
89858
- const full = import_path99.default.join(dir2, entry.name);
90107
+ if (!import_fs102.default.existsSync(dir2)) return results;
90108
+ for (const entry of import_fs102.default.readdirSync(dir2, { withFileTypes: true })) {
90109
+ const full = import_path101.default.join(dir2, entry.name);
89859
90110
  if (entry.isDirectory()) results.push(...findJsonFiles(full));
89860
90111
  else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
89861
90112
  }
@@ -89864,9 +90115,9 @@ function findJsonFiles(dir2) {
89864
90115
  function registerMaskCommand(program2) {
89865
90116
  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) => {
89866
90117
  const dryRun = !!options.dryRun;
89867
- const home = import_os81.default.homedir();
89868
- const claudeDir = import_path99.default.join(home, ".claude", "projects");
89869
- const geminiDir = import_path99.default.join(home, ".gemini", "tmp");
90118
+ const home = import_os82.default.homedir();
90119
+ const claudeDir = import_path101.default.join(home, ".claude", "projects");
90120
+ const geminiDir = import_path101.default.join(home, ".gemini", "tmp");
89870
90121
  const allFiles = [
89871
90122
  ...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
89872
90123
  ...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
@@ -89874,7 +90125,7 @@ function registerMaskCommand(program2) {
89874
90125
  const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
89875
90126
  const filtered = cutoff ? allFiles.filter((f) => {
89876
90127
  try {
89877
- return import_fs100.default.statSync(f.path).mtime >= cutoff;
90128
+ return import_fs102.default.statSync(f.path).mtime >= cutoff;
89878
90129
  } catch {
89879
90130
  return false;
89880
90131
  }
@@ -89931,7 +90182,7 @@ function registerMaskCommand(program2) {
89931
90182
  init_blast();
89932
90183
  init_safe_text();
89933
90184
  var { version } = JSON.parse(
89934
- import_fs104.default.readFileSync(import_path103.default.join(__dirname, "../package.json"), "utf-8")
90185
+ import_fs106.default.readFileSync(import_path105.default.join(__dirname, "../package.json"), "utf-8")
89935
90186
  );
89936
90187
  var program = new import_commander.Command();
89937
90188
  program.name("node9").description("The Sudo Command for AI Agents").version(version);
@@ -90089,8 +90340,8 @@ function undoLeftoverNote() {
90089
90340
  program.command("uninstall").description("Remove all Node9 hooks and optionally delete config files").option("--purge", "Also delete ~/.node9/ directory (config, audit log, credentials)").action(async (options) => {
90090
90341
  console.log(import_chalk50.default.cyan("\n\u{1F6E1}\uFE0F Node9 Uninstall\n"));
90091
90342
  try {
90092
- const credRaw = import_fs104.default.readFileSync(
90093
- import_path103.default.join(import_os85.default.homedir(), ".node9", "credentials.json"),
90343
+ const credRaw = import_fs106.default.readFileSync(
90344
+ import_path105.default.join(import_os86.default.homedir(), ".node9", "credentials.json"),
90094
90345
  "utf-8"
90095
90346
  );
90096
90347
  const prof = JSON.parse(credRaw)[process.env.NODE9_PROFILE || "default"];
@@ -90165,7 +90416,7 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
90165
90416
  if (removed.length > 0 || refused.length > 0) {
90166
90417
  console.log(import_chalk50.default.bold("\nRemoving decoy credentials..."));
90167
90418
  for (const r of removed) {
90168
- if (r.path) console.log(import_chalk50.default.green(` \u2705 ${r.path.replace(import_os85.default.homedir(), "~")}`));
90419
+ if (r.path) console.log(import_chalk50.default.green(` \u2705 ${r.path.replace(import_os86.default.homedir(), "~")}`));
90169
90420
  }
90170
90421
  for (const r of refused) {
90171
90422
  decoysLeft.push(r.path ?? "(unknown path)");
@@ -90182,8 +90433,8 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
90182
90433
  decoysLeft = ["(the decoy registry could not be read)"];
90183
90434
  }
90184
90435
  if (options.purge) {
90185
- const node9Dir = import_path103.default.join(import_os85.default.homedir(), ".node9");
90186
- if (import_fs104.default.existsSync(node9Dir)) {
90436
+ const node9Dir = import_path105.default.join(import_os86.default.homedir(), ".node9");
90437
+ if (import_fs106.default.existsSync(node9Dir)) {
90187
90438
  const alsoSnapshots = undoLeftoverPaths().length > 0 ? ", old undo snapshots" : "";
90188
90439
  if (decoysLeft.length > 0) {
90189
90440
  console.error(import_chalk50.default.red("\n \u26A0\uFE0F Decoy credential files are still on disk:"));
@@ -90199,8 +90450,8 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
90199
90450
  default: false
90200
90451
  });
90201
90452
  if (confirmed) {
90202
- import_fs104.default.rmSync(node9Dir, { recursive: true });
90203
- if (import_fs104.default.existsSync(node9Dir)) {
90453
+ import_fs106.default.rmSync(node9Dir, { recursive: true });
90454
+ if (import_fs106.default.existsSync(node9Dir)) {
90204
90455
  console.error(
90205
90456
  import_chalk50.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
90206
90457
  );
@@ -90356,7 +90607,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
90356
90607
  });
90357
90608
  program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
90358
90609
  try {
90359
- const dashboardPath = import_path103.default.join(__dirname, "dashboard.mjs");
90610
+ const dashboardPath = import_path105.default.join(__dirname, "dashboard.mjs");
90360
90611
  const dynamicImport = new Function("id", "return import(id)");
90361
90612
  const mod = await dynamicImport(`file://${dashboardPath}`);
90362
90613
  await mod.startMonitor();
@@ -90394,14 +90645,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
90394
90645
  Run "node9 addto claude" to register it as the statusLine.`
90395
90646
  ).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
90396
90647
  if (subcommand === "debug") {
90397
- const flagFile = import_path103.default.join(import_os85.default.homedir(), ".node9", "hud-debug");
90648
+ const flagFile = import_path105.default.join(import_os86.default.homedir(), ".node9", "hud-debug");
90398
90649
  if (state === "on") {
90399
- import_fs104.default.mkdirSync(import_path103.default.dirname(flagFile), { recursive: true });
90400
- import_fs104.default.writeFileSync(flagFile, "");
90650
+ import_fs106.default.mkdirSync(import_path105.default.dirname(flagFile), { recursive: true });
90651
+ import_fs106.default.writeFileSync(flagFile, "");
90401
90652
  console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
90402
90653
  console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
90403
90654
  } else if (state === "off") {
90404
- if (import_fs104.default.existsSync(flagFile)) import_fs104.default.unlinkSync(flagFile);
90655
+ if (import_fs106.default.existsSync(flagFile)) import_fs106.default.unlinkSync(flagFile);
90405
90656
  console.log("HUD debug logging disabled.");
90406
90657
  } else {
90407
90658
  console.error("Usage: node9 hud debug on|off");
@@ -90535,9 +90786,9 @@ if (process.argv[2] !== "daemon") {
90535
90786
  const isCheckHook = process.argv[2] === "check";
90536
90787
  if (isCheckHook) {
90537
90788
  if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
90538
- const logPath = import_path103.default.join(import_os85.default.homedir(), ".node9", "hook-debug.log");
90789
+ const logPath = import_path105.default.join(import_os86.default.homedir(), ".node9", "hook-debug.log");
90539
90790
  const msg = reason instanceof Error ? reason.message : String(reason);
90540
- import_fs104.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
90791
+ import_fs106.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
90541
90792
  `);
90542
90793
  }
90543
90794
  process.exit(0);