@node9/proxy 1.61.0 → 1.62.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -243,8 +243,8 @@ function sanitizeConfig(raw) {
243
243
  }
244
244
  }
245
245
  const lines = result.error.issues.map((issue) => {
246
- const path70 = issue.path.length > 0 ? issue.path.join(".") : "root";
247
- return ` \u2022 ${path70}: ${issue.message}`;
246
+ const path71 = issue.path.length > 0 ? issue.path.join(".") : "root";
247
+ return ` \u2022 ${path71}: ${issue.message}`;
248
248
  });
249
249
  return {
250
250
  sanitized,
@@ -973,6 +973,91 @@ function analyzeFsOperation(command) {
973
973
  fsOpCache.set(normalized, computed);
974
974
  return computed;
975
975
  }
976
+ function isSensitiveCleanupName(p) {
977
+ const base = p.replace(/^.*[\\/]/, "");
978
+ return /^\.env(\.|$)/i.test(base) || /(?:^|[\\/])\.(?:ssh|aws|gnupg|git)(?:[\\/]|$)/i.test(p) || /\.(?:pem|key|p12|pfx|crt)$/i.test(base) || /^\.?(?:netrc|npmrc|pgpass|htpasswd)$/i.test(base) || /^id_(?:rsa|dsa|ecdsa|ed25519)/i.test(base) || /credential/i.test(p) || /secret/i.test(base);
979
+ }
980
+ function isWaivableCleanupTarget(p) {
981
+ if (/^[/~]/.test(p) || /^\$/.test(p)) return false;
982
+ if (/(?:^|[\\/])\.\.(?:[\\/]|$)/.test(p)) return false;
983
+ if (/[*?[{]/.test(p)) return false;
984
+ if (isSensitiveCleanupName(p)) return false;
985
+ return true;
986
+ }
987
+ function deriveRedirOp(sample) {
988
+ try {
989
+ const f = sharedParser.Parse(sample, "cmd");
990
+ let op = -1;
991
+ syntax.Walk(f, (node) => {
992
+ const n = node;
993
+ if (n && syntax.NodeType(n) === "Redirect" && op < 0) op = n.Op;
994
+ return true;
995
+ });
996
+ return op;
997
+ } catch {
998
+ return -1;
999
+ }
1000
+ }
1001
+ function collectSameCommandCreations(f) {
1002
+ const created = /* @__PURE__ */ new Set();
1003
+ try {
1004
+ const stmts = Array.isArray(f?.Stmts) ? f.Stmts : [];
1005
+ for (const stmt of stmts) {
1006
+ if (!stmt || !stmt.Cmd || syntax.NodeType(stmt.Cmd) !== "CallExpr") continue;
1007
+ const redirs = stmt.Redirs || [];
1008
+ if (!redirs.some((r) => r && REDIR_HEREDOC_OPS.has(r.Op))) continue;
1009
+ for (const r of redirs) {
1010
+ if (r && REDIR_TRUNCATE_OPS.has(r.Op) && r.N == null) {
1011
+ const w = resolveWordLiteral(r.Word);
1012
+ if (w) created.add(stripDotSlash(w));
1013
+ }
1014
+ }
1015
+ }
1016
+ } catch {
1017
+ return created;
1018
+ }
1019
+ return created;
1020
+ }
1021
+ function isRmCreatedInCommandCleanup(command) {
1022
+ if (!/\brm\b/.test(command)) return false;
1023
+ const f = parseShared(command);
1024
+ if (f === PARSE_FAIL) return false;
1025
+ const created = collectSameCommandCreations(f);
1026
+ if (created.size === 0) return false;
1027
+ let sawRm = false;
1028
+ let ok2 = true;
1029
+ try {
1030
+ syntax.Walk(f, (node) => {
1031
+ if (!node || !ok2) return false;
1032
+ const n = node;
1033
+ if (syntax.NodeType(n) !== "CallExpr") return true;
1034
+ const args = n.Args || [];
1035
+ const name = (resolveWordLiteral(args[0]) ?? "").toLowerCase();
1036
+ if (name !== "rm") return true;
1037
+ sawRm = true;
1038
+ const { flags, paths } = extractLiteralArgs(n);
1039
+ if (args.length - 1 > flags.length + paths.length) {
1040
+ ok2 = false;
1041
+ return false;
1042
+ }
1043
+ if (paths.length === 0) {
1044
+ ok2 = false;
1045
+ return false;
1046
+ }
1047
+ for (const p of paths) {
1048
+ const np = stripDotSlash(p);
1049
+ if (!created.has(np) || !isWaivableCleanupTarget(np)) {
1050
+ ok2 = false;
1051
+ return false;
1052
+ }
1053
+ }
1054
+ return true;
1055
+ });
1056
+ } catch {
1057
+ return false;
1058
+ }
1059
+ return sawRm && ok2;
1060
+ }
976
1061
  function analyzeFsOperationImpl(command) {
977
1062
  const f = parseShared(command);
978
1063
  if (f === PARSE_FAIL) return null;
@@ -1369,9 +1454,9 @@ function matchesPattern(text, patterns) {
1369
1454
  const withoutDotSlash = text.replace(/^\.\//, "");
1370
1455
  return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
1371
1456
  }
1372
- function getNestedValue(obj, path70) {
1457
+ function getNestedValue(obj, path71) {
1373
1458
  if (!obj || typeof obj !== "object") return null;
1374
- const segments = path70.split(".");
1459
+ const segments = path71.split(".");
1375
1460
  for (const seg of segments) {
1376
1461
  if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
1377
1462
  }
@@ -1543,8 +1628,9 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
1543
1628
  }
1544
1629
  }
1545
1630
  if (config.policy.smartRules.length > 0) {
1631
+ const rmCleanupWaiver = bashCommand !== null && isRmCreatedInCommandCleanup(bashCommand);
1546
1632
  const matches = config.policy.smartRules.filter(
1547
- (rule) => matchesPattern(toolName, rule.tool) && !(bashCommand !== null && rule.name && AST_FS_REGEX_RULES.has(rule.name)) && evaluateSmartConditions(args, rule)
1633
+ (rule) => matchesPattern(toolName, rule.tool) && !(bashCommand !== null && rule.name && AST_FS_REGEX_RULES.has(rule.name)) && !(rmCleanupWaiver && rule.name === "review-rm" && rule.verdict === "review") && evaluateSmartConditions(args, rule)
1548
1634
  );
1549
1635
  const matchedRule = resolvePinned(matches);
1550
1636
  if (matchedRule) {
@@ -2285,7 +2371,7 @@ function* stringValues(obj, depth = 0) {
2285
2371
  }
2286
2372
  for (const v of Object.values(obj)) yield* stringValues(v, depth + 1);
2287
2373
  }
2288
- var import_safe_regex2, import_mvdan_sh, import_picomatch, import_safe_regex22, import_safe_regex23, import_crypto3, MAX, UNTRUSTED_TOOLS, SIGNALS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, NET_BINARIES, VALUE_FLAGS, FS_OP_CACHE_MAX, fsOpCache, DEFAULT_EGRESS_ALLOWLIST, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, VERDICT_RANK, SQL_DML_KEYWORDS, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, LOOP_MAX_RECORDS, FINDING_TO_SIGNAL, SCAN_SIGNAL_WEIGHTS, LOOP_THRESHOLD_FOR_WASTE, COST_PER_LOOP_ITER_USD, DESTRUCTIVE_OP_RE, SENSITIVE_PATH_RE, FILE_TOOLS, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION, DEDUPE_PREVIEW_LEN, TERMINAL_ESCAPE_RE, ENGINE_VERSION;
2374
+ var import_safe_regex2, import_mvdan_sh, import_picomatch, import_safe_regex22, import_safe_regex23, import_crypto3, MAX, UNTRUSTED_TOOLS, SIGNALS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, NET_BINARIES, VALUE_FLAGS, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_HEREDOC_OPS, DEFAULT_EGRESS_ALLOWLIST, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, VERDICT_RANK, SQL_DML_KEYWORDS, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, LOOP_MAX_RECORDS, FINDING_TO_SIGNAL, SCAN_SIGNAL_WEIGHTS, LOOP_THRESHOLD_FOR_WASTE, COST_PER_LOOP_ITER_USD, DESTRUCTIVE_OP_RE, SENSITIVE_PATH_RE, FILE_TOOLS, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION, DEDUPE_PREVIEW_LEN, TERMINAL_ESCAPE_RE, ENGINE_VERSION;
2289
2375
  var init_dist = __esm({
2290
2376
  "packages/policy-engine/dist/index.mjs"() {
2291
2377
  "use strict";
@@ -2962,7 +3048,7 @@ var init_dist = __esm({
2962
3048
  "mongosh"
2963
3049
  ]);
2964
3050
  SQL_DDL_RE = /\b(DROP|TRUNCATE)\s+(TABLE|DATABASE|SCHEMA|INDEX)\b/i;
2965
- CHMOD_OPEN_PERM_TOKENS = /* @__PURE__ */ new Set(["777", "0777", "a+rwx", "+x"]);
3051
+ CHMOD_OPEN_PERM_TOKENS = /* @__PURE__ */ new Set(["777", "0777", "a+rwx"]);
2966
3052
  COMMAND_WRAPPERS = /* @__PURE__ */ new Set([
2967
3053
  "sudo",
2968
3054
  "doas",
@@ -3065,6 +3151,12 @@ var init_dist = __esm({
3065
3151
  };
3066
3152
  FS_OP_CACHE_MAX = 5e3;
3067
3153
  fsOpCache = /* @__PURE__ */ new Map();
3154
+ stripDotSlash = (p) => p.replace(/^\.\//, "");
3155
+ REDIR_TRUNCATE_OPS = /* @__PURE__ */ new Set([deriveRedirOp(">_f")]);
3156
+ REDIR_HEREDOC_OPS = /* @__PURE__ */ new Set([
3157
+ deriveRedirOp("cat <<X\nX"),
3158
+ deriveRedirOp("cat <<-X\nX")
3159
+ ]);
3068
3160
  DEFAULT_EGRESS_ALLOWLIST = [
3069
3161
  "*.github.com",
3070
3162
  "*.githubusercontent.com",
@@ -4750,10 +4842,10 @@ function getConfig(cwd) {
4750
4842
  }
4751
4843
  if (Array.isArray(mc.jailPaths)) {
4752
4844
  for (const jp of mc.jailPaths) {
4753
- const path70 = typeof jp?.path === "string" ? jp.path.trim() : "";
4754
- if (!path70) continue;
4845
+ const path71 = typeof jp?.path === "string" ? jp.path.trim() : "";
4846
+ if (!path71) continue;
4755
4847
  const verdict = jp?.verdict === "review" ? "review" : "block";
4756
- for (const r of pathRules(path70, verdict, "org-managed jail")) {
4848
+ for (const r of pathRules(path71, verdict, "org-managed jail")) {
4757
4849
  mergedPolicy.smartRules.push({ ...r, name: `org:${r.name}` });
4758
4850
  }
4759
4851
  }
@@ -17873,6 +17965,66 @@ function pickSyncIntervalMs(cloudHours, localSettings) {
17873
17965
  function effectiveSyncIntervalMs() {
17874
17966
  return pickSyncIntervalMs(readCachedSyncIntervalHours(), getConfig().settings);
17875
17967
  }
17968
+ function readSyncHealth() {
17969
+ try {
17970
+ const raw = JSON.parse(import_fs35.default.readFileSync(syncHealthFile(), "utf-8"));
17971
+ return {
17972
+ lastCheckedAt: typeof raw.lastCheckedAt === "string" ? raw.lastCheckedAt : void 0,
17973
+ lastChangedAt: typeof raw.lastChangedAt === "string" ? raw.lastChangedAt : void 0,
17974
+ lastError: typeof raw.lastError === "string" ? raw.lastError : void 0,
17975
+ lastErrorAt: typeof raw.lastErrorAt === "string" ? raw.lastErrorAt : void 0,
17976
+ consecutiveFailures: typeof raw.consecutiveFailures === "number" && raw.consecutiveFailures >= 0 ? raw.consecutiveFailures : 0
17977
+ };
17978
+ } catch {
17979
+ return { consecutiveFailures: 0 };
17980
+ }
17981
+ }
17982
+ function writeSyncHealth(h) {
17983
+ try {
17984
+ const file = syncHealthFile();
17985
+ const dir = import_path34.default.dirname(file);
17986
+ if (!import_fs35.default.existsSync(dir)) import_fs35.default.mkdirSync(dir, { recursive: true });
17987
+ const tmp = `${file}.${process.pid}.tmp`;
17988
+ import_fs35.default.writeFileSync(tmp, JSON.stringify(h, null, 2) + "\n", "utf-8");
17989
+ import_fs35.default.renameSync(tmp, file);
17990
+ } catch {
17991
+ }
17992
+ }
17993
+ function readCacheFetchedAt() {
17994
+ try {
17995
+ const raw = JSON.parse(import_fs35.default.readFileSync(rulesCacheFile(), "utf-8"));
17996
+ return typeof raw.fetchedAt === "string" ? raw.fetchedAt : void 0;
17997
+ } catch {
17998
+ return void 0;
17999
+ }
18000
+ }
18001
+ function recordSyncHealth(result) {
18002
+ const h = readSyncHealth();
18003
+ const now = (/* @__PURE__ */ new Date()).toISOString();
18004
+ if (result.ok) {
18005
+ h.lastCheckedAt = now;
18006
+ if (result.changed) h.lastChangedAt = now;
18007
+ h.consecutiveFailures = 0;
18008
+ h.lastError = void 0;
18009
+ h.lastErrorAt = void 0;
18010
+ } else {
18011
+ h.consecutiveFailures += 1;
18012
+ h.lastError = result.error;
18013
+ h.lastErrorAt = now;
18014
+ }
18015
+ writeSyncHealth(h);
18016
+ }
18017
+ function stalenessThresholdMs(intervalMs) {
18018
+ return Math.min(STALE_MAX_MS, Math.max(STALE_MIN_MS, intervalMs * STALE_FACTOR));
18019
+ }
18020
+ function isPolicyStale(nowMs = Date.now(), health) {
18021
+ const h = health ?? readSyncHealth();
18022
+ const lastKnownGood = h.lastCheckedAt ?? readCacheFetchedAt();
18023
+ if (!lastKnownGood) return false;
18024
+ const last = Date.parse(lastKnownGood);
18025
+ if (Number.isNaN(last)) return false;
18026
+ return nowMs - last > stalenessThresholdMs(effectiveSyncIntervalMs());
18027
+ }
17876
18028
  function fetchCloudPolicy(apiKey, apiUrl, ifNoneMatch) {
17877
18029
  const parsed = new URL(apiUrl);
17878
18030
  const headers = {
@@ -18037,6 +18189,7 @@ async function syncOnce() {
18037
18189
  try {
18038
18190
  const result = await fetchCloudPolicy(creds.apiKey, creds.apiUrl, readCachedEtag());
18039
18191
  if (result.kind === "unchanged") {
18192
+ recordSyncHealth({ ok: true });
18040
18193
  } else {
18041
18194
  const cache = {
18042
18195
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -18050,8 +18203,19 @@ async function syncOnce() {
18050
18203
  managedConfig: extractManagedConfig(result.body)
18051
18204
  };
18052
18205
  writeCache2(cache);
18206
+ recordSyncHealth({ ok: true, changed: true });
18207
+ }
18208
+ } catch (err2) {
18209
+ const msg = err2 instanceof Error ? err2.message : String(err2);
18210
+ recordSyncHealth({ ok: false, error: msg });
18211
+ try {
18212
+ appendToLog(HOOK_DEBUG_LOG, {
18213
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
18214
+ kind: "policy-sync-error",
18215
+ error: msg
18216
+ });
18217
+ } catch {
18053
18218
  }
18054
- } catch {
18055
18219
  }
18056
18220
  if (process.env.NODE9_BLAST_DISABLE !== "1") {
18057
18221
  void pushBlastSnapshot(creds);
@@ -18227,6 +18391,7 @@ async function runCloudSync() {
18227
18391
  const result = await fetchCloudPolicy(creds.apiKey, creds.apiUrl, readCachedEtag());
18228
18392
  if (result.kind === "unchanged") {
18229
18393
  const status = getCloudSyncStatus();
18394
+ recordSyncHealth({ ok: true });
18230
18395
  maybePushBlast();
18231
18396
  return status.cached ? { ok: true, rules: status.rules, fetchedAt: status.fetchedAt, unchanged: true } : { ok: true, rules: 0, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), unchanged: true };
18232
18397
  }
@@ -18242,11 +18407,14 @@ async function runCloudSync() {
18242
18407
  managedConfig: extractManagedConfig(result.body)
18243
18408
  };
18244
18409
  writeCache2(cache);
18410
+ recordSyncHealth({ ok: true, changed: true });
18245
18411
  maybePushBlast();
18246
18412
  return { ok: true, rules: cache.rules.length, fetchedAt: cache.fetchedAt };
18247
18413
  } catch (err2) {
18414
+ const msg = err2 instanceof Error ? err2.message : String(err2);
18415
+ recordSyncHealth({ ok: false, error: msg });
18248
18416
  maybePushBlast();
18249
- return { ok: false, reason: err2 instanceof Error ? err2.message : String(err2) };
18417
+ return { ok: false, reason: msg };
18250
18418
  }
18251
18419
  }
18252
18420
  function getCloudSyncStatus() {
@@ -18303,7 +18471,7 @@ function startForensicBroadcast() {
18303
18471
  const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
18304
18472
  recurring.unref();
18305
18473
  }
18306
- var import_fs35, import_https4, import_os32, import_path34, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL2, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_SECONDS, MAX_INTERVAL_SECONDS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
18474
+ var import_fs35, import_https4, import_os32, import_path34, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL2, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_SECONDS, MAX_INTERVAL_SECONDS, syncHealthFile, STALE_MIN_MS, STALE_MAX_MS, STALE_FACTOR, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
18307
18475
  var init_sync = __esm({
18308
18476
  "src/daemon/sync.ts"() {
18309
18477
  "use strict";
@@ -18341,6 +18509,10 @@ var init_sync = __esm({
18341
18509
  DEFAULT_INTERVAL_HOURS = 5;
18342
18510
  MIN_INTERVAL_SECONDS = 15;
18343
18511
  MAX_INTERVAL_SECONDS = 24 * 60 * 60;
18512
+ syncHealthFile = () => import_path34.default.join(import_os32.default.homedir(), ".node9", "sync-health.json");
18513
+ STALE_MIN_MS = 3 * 60 * 60 * 1e3;
18514
+ STALE_MAX_MS = 24 * 60 * 60 * 1e3;
18515
+ STALE_FACTOR = 3;
18344
18516
  FORENSIC_BROADCAST_INTERVAL_MS = 3e4;
18345
18517
  FORENSIC_INITIAL_DELAY_MS = 5e3;
18346
18518
  forensicBroadcastOffsets = /* @__PURE__ */ new Map();
@@ -18955,16 +19127,61 @@ var init_hook_heal = __esm({
18955
19127
  }
18956
19128
  });
18957
19129
 
19130
+ // src/daemon/startup-log.ts
19131
+ function openStartupLogFd() {
19132
+ try {
19133
+ const file = DAEMON_STARTUP_LOG();
19134
+ const dir = import_path38.default.dirname(file);
19135
+ if (!import_fs39.default.existsSync(dir)) import_fs39.default.mkdirSync(dir, { recursive: true });
19136
+ try {
19137
+ if (import_fs39.default.statSync(file).size > MAX_STARTUP_LOG_BYTES) import_fs39.default.truncateSync(file);
19138
+ } catch {
19139
+ }
19140
+ return import_fs39.default.openSync(file, "a");
19141
+ } catch {
19142
+ return void 0;
19143
+ }
19144
+ }
19145
+ function logDaemonStartup(kind, detail) {
19146
+ try {
19147
+ const file = DAEMON_STARTUP_LOG();
19148
+ const dir = import_path38.default.dirname(file);
19149
+ if (!import_fs39.default.existsSync(dir)) import_fs39.default.mkdirSync(dir, { recursive: true });
19150
+ const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-startup:${kind}${detail ? ` ${detail}` : ""}
19151
+ `;
19152
+ import_fs39.default.appendFileSync(file, line, "utf-8");
19153
+ } catch {
19154
+ }
19155
+ }
19156
+ var import_fs39, import_path38, import_os36, DAEMON_STARTUP_LOG, MAX_STARTUP_LOG_BYTES;
19157
+ var init_startup_log = __esm({
19158
+ "src/daemon/startup-log.ts"() {
19159
+ "use strict";
19160
+ import_fs39 = __toESM(require("fs"));
19161
+ import_path38 = __toESM(require("path"));
19162
+ import_os36 = __toESM(require("os"));
19163
+ DAEMON_STARTUP_LOG = () => import_path38.default.join(import_os36.default.homedir(), ".node9", "daemon-startup.log");
19164
+ MAX_STARTUP_LOG_BYTES = 256 * 1024;
19165
+ }
19166
+ });
19167
+
18958
19168
  // src/daemon/server.ts
18959
19169
  function startDaemon() {
18960
- startCostSync();
18961
- startCloudSync();
18962
- startForensicBroadcast();
18963
- startAuditShipper();
18964
- startDlpScanner();
18965
- startMcpReconciler();
18966
- startHookHeal();
18967
- loadInsightCounts();
19170
+ try {
19171
+ startCostSync();
19172
+ startCloudSync();
19173
+ startForensicBroadcast();
19174
+ startAuditShipper();
19175
+ startDlpScanner();
19176
+ startMcpReconciler();
19177
+ startHookHeal();
19178
+ loadInsightCounts();
19179
+ } catch (err2) {
19180
+ const stack = err2 instanceof Error ? err2.stack ?? err2.message : String(err2);
19181
+ console.error("\n\u{1F6D1} Node9 daemon startup failed:\n" + stack);
19182
+ logDaemonStartup("startup-throw", err2 instanceof Error ? err2.message : String(err2));
19183
+ process.exit(1);
19184
+ }
18968
19185
  const internalToken = (0, import_crypto11.randomUUID)();
18969
19186
  const validToken = (req) => req.headers["x-node9-internal"] === internalToken || req.headers["x-node9-token"] === internalToken;
18970
19187
  const IDLE_TIMEOUT_MS = 12 * 60 * 60 * 1e3;
@@ -18976,7 +19193,7 @@ function startDaemon() {
18976
19193
  idleTimer = setTimeout(() => {
18977
19194
  if (autoStarted) {
18978
19195
  try {
18979
- import_fs39.default.unlinkSync(DAEMON_PID_FILE);
19196
+ import_fs40.default.unlinkSync(DAEMON_PID_FILE);
18980
19197
  } catch {
18981
19198
  }
18982
19199
  }
@@ -19121,7 +19338,7 @@ data: ${JSON.stringify(item.data)}
19121
19338
  mcpServer: entry.mcpServer
19122
19339
  });
19123
19340
  }
19124
- const projectCwd = typeof cwd === "string" && import_path38.default.isAbsolute(cwd) ? cwd : void 0;
19341
+ const projectCwd = typeof cwd === "string" && import_path39.default.isAbsolute(cwd) ? cwd : void 0;
19125
19342
  const projectConfig = getConfig(projectCwd);
19126
19343
  const browserEnabled = projectConfig.settings.approvers?.browser !== false;
19127
19344
  const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
@@ -19413,8 +19630,8 @@ data: ${JSON.stringify(item.data)}
19413
19630
  if (!validToken(req)) return res.writeHead(403).end();
19414
19631
  const periodParam = reqUrl.searchParams.get("period") || "7d";
19415
19632
  const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
19416
- const logPath = import_path38.default.join(import_os36.default.homedir(), ".node9", "audit.log");
19417
- if (!import_fs39.default.existsSync(logPath)) {
19633
+ const logPath = import_path39.default.join(import_os37.default.homedir(), ".node9", "audit.log");
19634
+ if (!import_fs40.default.existsSync(logPath)) {
19418
19635
  res.writeHead(200, { "Content-Type": "application/json" });
19419
19636
  return res.end(
19420
19637
  JSON.stringify({
@@ -19427,7 +19644,7 @@ data: ${JSON.stringify(item.data)}
19427
19644
  );
19428
19645
  }
19429
19646
  try {
19430
- const raw = import_fs39.default.readFileSync(logPath, "utf-8");
19647
+ const raw = import_fs40.default.readFileSync(logPath, "utf-8");
19431
19648
  const allEntries = raw.split("\n").flatMap((line) => {
19432
19649
  if (!line.trim()) return [];
19433
19650
  try {
@@ -19810,14 +20027,15 @@ data: ${JSON.stringify(item.data)}
19810
20027
  server.on("error", (e) => {
19811
20028
  if (e.code === "EADDRINUSE") {
19812
20029
  try {
19813
- if (import_fs39.default.existsSync(DAEMON_PID_FILE)) {
19814
- const { pid } = JSON.parse(import_fs39.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
20030
+ if (import_fs40.default.existsSync(DAEMON_PID_FILE)) {
20031
+ const { pid } = JSON.parse(import_fs40.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
19815
20032
  process.kill(pid, 0);
20033
+ logDaemonStartup("port-in-use", `another daemon (pid ${pid}) owns :${DAEMON_PORT}`);
19816
20034
  return process.exit(0);
19817
20035
  }
19818
20036
  } catch {
19819
20037
  try {
19820
- import_fs39.default.unlinkSync(DAEMON_PID_FILE);
20038
+ import_fs40.default.unlinkSync(DAEMON_PID_FILE);
19821
20039
  } catch {
19822
20040
  }
19823
20041
  server.listen(DAEMON_PORT, DAEMON_HOST);
@@ -19866,6 +20084,7 @@ data: ${JSON.stringify(item.data)}
19866
20084
  });
19867
20085
  return;
19868
20086
  }
20087
+ logDaemonStartup("bind-failed", e.message);
19869
20088
  console.error(import_chalk6.default.red("\n\u{1F6D1} Node9 Daemon Error:"), e.message);
19870
20089
  process.exit(1);
19871
20090
  });
@@ -19889,14 +20108,14 @@ data: ${JSON.stringify(item.data)}
19889
20108
  }
19890
20109
  startActivitySocket();
19891
20110
  }
19892
- var import_http3, import_fs39, import_path38, import_os36, import_crypto11, import_child_process2, import_chalk6;
20111
+ var import_http3, import_fs40, import_path39, import_os37, import_crypto11, import_child_process2, import_chalk6;
19893
20112
  var init_server = __esm({
19894
20113
  "src/daemon/server.ts"() {
19895
20114
  "use strict";
19896
20115
  import_http3 = __toESM(require("http"));
19897
- import_fs39 = __toESM(require("fs"));
19898
- import_path38 = __toESM(require("path"));
19899
- import_os36 = __toESM(require("os"));
20116
+ import_fs40 = __toESM(require("fs"));
20117
+ import_path39 = __toESM(require("path"));
20118
+ import_os37 = __toESM(require("os"));
19900
20119
  import_crypto11 = require("crypto");
19901
20120
  import_child_process2 = require("child_process");
19902
20121
  import_chalk6 = __toESM(require("chalk"));
@@ -19911,6 +20130,7 @@ var init_server = __esm({
19911
20130
  init_dlp_scanner();
19912
20131
  init_mcp_reconciler();
19913
20132
  init_hook_heal();
20133
+ init_startup_log();
19914
20134
  init_mcp_tools();
19915
20135
  }
19916
20136
  });
@@ -19919,8 +20139,8 @@ var init_server = __esm({
19919
20139
  function resolveNode9Binary() {
19920
20140
  try {
19921
20141
  const script = process.argv[1];
19922
- if (typeof script === "string" && import_path39.default.isAbsolute(script) && import_fs40.default.existsSync(script)) {
19923
- return import_fs40.default.realpathSync(script);
20142
+ if (typeof script === "string" && import_path40.default.isAbsolute(script) && import_fs41.default.existsSync(script)) {
20143
+ return import_fs41.default.realpathSync(script);
19924
20144
  }
19925
20145
  } catch {
19926
20146
  }
@@ -19938,11 +20158,11 @@ function xmlEscape(s) {
19938
20158
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
19939
20159
  }
19940
20160
  function launchdPlist(binaryPath) {
19941
- const logDir = import_path39.default.join(import_os37.default.homedir(), ".node9");
20161
+ const logDir = import_path40.default.join(import_os38.default.homedir(), ".node9");
19942
20162
  const nodePath = xmlEscape(process.execPath);
19943
20163
  const scriptPath = xmlEscape(binaryPath);
19944
- const outLog = xmlEscape(import_path39.default.join(logDir, "daemon.log"));
19945
- const errLog = xmlEscape(import_path39.default.join(logDir, "daemon-error.log"));
20164
+ const outLog = xmlEscape(import_path40.default.join(logDir, "daemon.log"));
20165
+ const errLog = xmlEscape(import_path40.default.join(logDir, "daemon-error.log"));
19946
20166
  return `<?xml version="1.0" encoding="UTF-8"?>
19947
20167
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
19948
20168
  <plist version="1.0">
@@ -19975,9 +20195,9 @@ function launchdPlist(binaryPath) {
19975
20195
  `;
19976
20196
  }
19977
20197
  function installLaunchd(binaryPath) {
19978
- const dir = import_path39.default.dirname(LAUNCHD_PLIST);
19979
- if (!import_fs40.default.existsSync(dir)) import_fs40.default.mkdirSync(dir, { recursive: true });
19980
- import_fs40.default.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
20198
+ const dir = import_path40.default.dirname(LAUNCHD_PLIST);
20199
+ if (!import_fs41.default.existsSync(dir)) import_fs41.default.mkdirSync(dir, { recursive: true });
20200
+ import_fs41.default.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
19981
20201
  (0, import_child_process3.spawnSync)("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
19982
20202
  const r = (0, import_child_process3.spawnSync)("launchctl", ["load", "-w", LAUNCHD_PLIST], {
19983
20203
  encoding: "utf8",
@@ -19988,13 +20208,13 @@ function installLaunchd(binaryPath) {
19988
20208
  }
19989
20209
  }
19990
20210
  function uninstallLaunchd() {
19991
- if (import_fs40.default.existsSync(LAUNCHD_PLIST)) {
20211
+ if (import_fs41.default.existsSync(LAUNCHD_PLIST)) {
19992
20212
  (0, import_child_process3.spawnSync)("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
19993
- import_fs40.default.unlinkSync(LAUNCHD_PLIST);
20213
+ import_fs41.default.unlinkSync(LAUNCHD_PLIST);
19994
20214
  }
19995
20215
  }
19996
20216
  function isLaunchdInstalled() {
19997
- return import_fs40.default.existsSync(LAUNCHD_PLIST);
20217
+ return import_fs41.default.existsSync(LAUNCHD_PLIST);
19998
20218
  }
19999
20219
  function systemdUnit(binaryPath) {
20000
20220
  return `[Unit]
@@ -20013,12 +20233,12 @@ WantedBy=default.target
20013
20233
  `;
20014
20234
  }
20015
20235
  function installSystemd(binaryPath) {
20016
- if (!import_fs40.default.existsSync(SYSTEMD_UNIT_DIR)) {
20017
- import_fs40.default.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
20236
+ if (!import_fs41.default.existsSync(SYSTEMD_UNIT_DIR)) {
20237
+ import_fs41.default.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
20018
20238
  }
20019
- import_fs40.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
20239
+ import_fs41.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
20020
20240
  try {
20021
- (0, import_child_process3.execFileSync)("loginctl", ["enable-linger", import_os37.default.userInfo().username], { timeout: 3e3 });
20241
+ (0, import_child_process3.execFileSync)("loginctl", ["enable-linger", import_os38.default.userInfo().username], { timeout: 3e3 });
20022
20242
  } catch {
20023
20243
  }
20024
20244
  const reload = (0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], {
@@ -20038,23 +20258,23 @@ function installSystemd(binaryPath) {
20038
20258
  }
20039
20259
  }
20040
20260
  function uninstallSystemd() {
20041
- if (import_fs40.default.existsSync(SYSTEMD_UNIT)) {
20261
+ if (import_fs41.default.existsSync(SYSTEMD_UNIT)) {
20042
20262
  (0, import_child_process3.spawnSync)("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
20043
20263
  encoding: "utf8",
20044
20264
  timeout: 5e3
20045
20265
  });
20046
20266
  (0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
20047
- import_fs40.default.unlinkSync(SYSTEMD_UNIT);
20267
+ import_fs41.default.unlinkSync(SYSTEMD_UNIT);
20048
20268
  }
20049
20269
  }
20050
20270
  function isSystemdInstalled() {
20051
- return import_fs40.default.existsSync(SYSTEMD_UNIT);
20271
+ return import_fs41.default.existsSync(SYSTEMD_UNIT);
20052
20272
  }
20053
20273
  function stopRunningDaemon() {
20054
- const pidFile = import_path39.default.join(import_os37.default.homedir(), ".node9", "daemon.pid");
20055
- if (!import_fs40.default.existsSync(pidFile)) return;
20274
+ const pidFile = import_path40.default.join(import_os38.default.homedir(), ".node9", "daemon.pid");
20275
+ if (!import_fs41.default.existsSync(pidFile)) return;
20056
20276
  try {
20057
- const data = JSON.parse(import_fs40.default.readFileSync(pidFile, "utf-8"));
20277
+ const data = JSON.parse(import_fs41.default.readFileSync(pidFile, "utf-8"));
20058
20278
  const pid = data.pid;
20059
20279
  const MAX_PID2 = 4194304;
20060
20280
  if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
@@ -20074,7 +20294,7 @@ function stopRunningDaemon() {
20074
20294
  }
20075
20295
  }
20076
20296
  try {
20077
- import_fs40.default.unlinkSync(pidFile);
20297
+ import_fs41.default.unlinkSync(pidFile);
20078
20298
  } catch {
20079
20299
  }
20080
20300
  } catch {
@@ -20144,26 +20364,95 @@ function isDaemonServiceInstalled() {
20144
20364
  if (process.platform === "linux") return isSystemdInstalled();
20145
20365
  return false;
20146
20366
  }
20147
- var import_fs40, import_path39, import_os37, import_child_process3, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
20367
+ function autostartRepairDecision(opts) {
20368
+ if (!opts.autoStartDaemon) return "skip";
20369
+ if (process.platform !== "linux" && process.platform !== "darwin") return "unsupported";
20370
+ if (!opts.installed) return "skip";
20371
+ return opts.enabled ? "ok" : "repair";
20372
+ }
20373
+ function enableDaemonServiceQuiet() {
20374
+ try {
20375
+ if (process.platform === "linux") {
20376
+ const r = (0, import_child_process3.spawnSync)("systemctl", ["--user", "enable", "node9-daemon"], {
20377
+ encoding: "utf8",
20378
+ timeout: 3e3
20379
+ });
20380
+ return r.status === 0;
20381
+ }
20382
+ return process.platform === "darwin";
20383
+ } catch {
20384
+ return false;
20385
+ }
20386
+ }
20387
+ function ensureAutostartHealthy(autoStartDaemon) {
20388
+ const decision = autostartRepairDecision({
20389
+ installed: isDaemonServiceInstalled(),
20390
+ enabled: isDaemonServiceEnabled(),
20391
+ autoStartDaemon
20392
+ });
20393
+ if (decision === "repair") return enableDaemonServiceQuiet() ? "repaired" : "skipped";
20394
+ return decision === "ok" ? "ok" : decision === "unsupported" ? "unsupported" : "skipped";
20395
+ }
20396
+ function autostartAdvice(opts) {
20397
+ const installable = process.platform === "linux" || process.platform === "darwin";
20398
+ if (!opts.cloudEnabled || !installable) return null;
20399
+ const installHint = process.platform === "linux" ? "Run: systemctl --user enable --now node9-daemon (or: node9 daemon install)" : "Run: node9 daemon install";
20400
+ if (opts.installed && !opts.enabled) {
20401
+ return {
20402
+ level: "warn",
20403
+ message: "Daemon autostart is INSTALLED but DISABLED \u2014 it will NOT survive a reboot, so cloud policy can silently go stale.",
20404
+ hint: installHint
20405
+ };
20406
+ }
20407
+ if (!opts.installed) {
20408
+ return {
20409
+ level: "warn",
20410
+ message: "No daemon autostart installed \u2014 the daemon only runs when an agent happens to spawn it; cloud policy may lag.",
20411
+ hint: installHint
20412
+ };
20413
+ }
20414
+ return null;
20415
+ }
20416
+ function isDaemonServiceEnabled() {
20417
+ try {
20418
+ if (process.platform === "linux") {
20419
+ const r = (0, import_child_process3.spawnSync)("systemctl", ["--user", "is-enabled", "node9-daemon"], {
20420
+ encoding: "utf8",
20421
+ timeout: 3e3
20422
+ });
20423
+ return r.status === 0 && (r.stdout ?? "").trim() === "enabled";
20424
+ }
20425
+ if (process.platform === "darwin") {
20426
+ const r = (0, import_child_process3.spawnSync)("launchctl", ["list", LAUNCHD_LABEL], {
20427
+ encoding: "utf8",
20428
+ timeout: 3e3
20429
+ });
20430
+ return r.status === 0;
20431
+ }
20432
+ } catch {
20433
+ }
20434
+ return false;
20435
+ }
20436
+ var import_fs41, import_path40, import_os38, import_child_process3, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
20148
20437
  var init_service = __esm({
20149
20438
  "src/daemon/service.ts"() {
20150
20439
  "use strict";
20151
- import_fs40 = __toESM(require("fs"));
20152
- import_path39 = __toESM(require("path"));
20153
- import_os37 = __toESM(require("os"));
20440
+ import_fs41 = __toESM(require("fs"));
20441
+ import_path40 = __toESM(require("path"));
20442
+ import_os38 = __toESM(require("os"));
20154
20443
  import_child_process3 = require("child_process");
20155
20444
  LAUNCHD_LABEL = "ai.node9.daemon";
20156
- LAUNCHD_PLIST = import_path39.default.join(import_os37.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
20157
- SYSTEMD_UNIT_DIR = import_path39.default.join(import_os37.default.homedir(), ".config", "systemd", "user");
20158
- SYSTEMD_UNIT = import_path39.default.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
20445
+ LAUNCHD_PLIST = import_path40.default.join(import_os38.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
20446
+ SYSTEMD_UNIT_DIR = import_path40.default.join(import_os38.default.homedir(), ".config", "systemd", "user");
20447
+ SYSTEMD_UNIT = import_path40.default.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
20159
20448
  }
20160
20449
  });
20161
20450
 
20162
20451
  // src/daemon/index.ts
20163
20452
  function stopDaemon() {
20164
- if (!import_fs41.default.existsSync(DAEMON_PID_FILE)) return console.log(import_chalk7.default.yellow("Not running."));
20453
+ if (!import_fs42.default.existsSync(DAEMON_PID_FILE)) return console.log(import_chalk7.default.yellow("Not running."));
20165
20454
  try {
20166
- const data = JSON.parse(import_fs41.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
20455
+ const data = JSON.parse(import_fs42.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
20167
20456
  const pid = data.pid;
20168
20457
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
20169
20458
  console.log(import_chalk7.default.gray("Cleaned up invalid PID file."));
@@ -20175,7 +20464,7 @@ function stopDaemon() {
20175
20464
  console.log(import_chalk7.default.gray("Cleaned up stale PID file."));
20176
20465
  } finally {
20177
20466
  try {
20178
- import_fs41.default.unlinkSync(DAEMON_PID_FILE);
20467
+ import_fs42.default.unlinkSync(DAEMON_PID_FILE);
20179
20468
  } catch {
20180
20469
  }
20181
20470
  }
@@ -20184,9 +20473,9 @@ function daemonStatus() {
20184
20473
  const serviceInstalled = isDaemonServiceInstalled();
20185
20474
  const serviceLabel = serviceInstalled ? import_chalk7.default.green("installed (starts on login)") : import_chalk7.default.yellow("not installed \u2014 run: node9 daemon install");
20186
20475
  let processStatus;
20187
- if (import_fs41.default.existsSync(DAEMON_PID_FILE)) {
20476
+ if (import_fs42.default.existsSync(DAEMON_PID_FILE)) {
20188
20477
  try {
20189
- const data = JSON.parse(import_fs41.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
20478
+ const data = JSON.parse(import_fs42.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
20190
20479
  const pid = data.pid;
20191
20480
  const port = data.port;
20192
20481
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
@@ -20208,11 +20497,11 @@ function daemonStatus() {
20208
20497
  console.log(` Service : ${serviceLabel}
20209
20498
  `);
20210
20499
  }
20211
- var import_fs41, import_chalk7, MAX_PID;
20500
+ var import_fs42, import_chalk7, MAX_PID;
20212
20501
  var init_daemon2 = __esm({
20213
20502
  "src/daemon/index.ts"() {
20214
20503
  "use strict";
20215
- import_fs41 = __toESM(require("fs"));
20504
+ import_fs42 = __toESM(require("fs"));
20216
20505
  import_chalk7 = __toESM(require("chalk"));
20217
20506
  init_server();
20218
20507
  init_state2();
@@ -21331,14 +21620,14 @@ var require_util = __commonJS({
21331
21620
  }
21332
21621
  const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
21333
21622
  let origin = url.origin != null ? url.origin : `${url.protocol || ""}//${url.hostname || ""}:${port}`;
21334
- let path70 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
21623
+ let path71 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
21335
21624
  if (origin[origin.length - 1] === "/") {
21336
21625
  origin = origin.slice(0, origin.length - 1);
21337
21626
  }
21338
- if (path70 && path70[0] !== "/") {
21339
- path70 = `/${path70}`;
21627
+ if (path71 && path71[0] !== "/") {
21628
+ path71 = `/${path71}`;
21340
21629
  }
21341
- return new URL(`${origin}${path70}`);
21630
+ return new URL(`${origin}${path71}`);
21342
21631
  }
21343
21632
  if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
21344
21633
  throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
@@ -22159,9 +22448,9 @@ var require_diagnostics = __commonJS({
22159
22448
  "undici:client:sendHeaders",
22160
22449
  (evt) => {
22161
22450
  const {
22162
- request: { method, path: path70, origin }
22451
+ request: { method, path: path71, origin }
22163
22452
  } = evt;
22164
- debugLog("sending request to %s %s%s", method, origin, path70);
22453
+ debugLog("sending request to %s %s%s", method, origin, path71);
22165
22454
  }
22166
22455
  );
22167
22456
  }
@@ -22179,14 +22468,14 @@ var require_diagnostics = __commonJS({
22179
22468
  "undici:request:headers",
22180
22469
  (evt) => {
22181
22470
  const {
22182
- request: { method, path: path70, origin },
22471
+ request: { method, path: path71, origin },
22183
22472
  response: { statusCode }
22184
22473
  } = evt;
22185
22474
  debugLog(
22186
22475
  "received response to %s %s%s - HTTP %d",
22187
22476
  method,
22188
22477
  origin,
22189
- path70,
22478
+ path71,
22190
22479
  statusCode
22191
22480
  );
22192
22481
  }
@@ -22195,23 +22484,23 @@ var require_diagnostics = __commonJS({
22195
22484
  "undici:request:trailers",
22196
22485
  (evt) => {
22197
22486
  const {
22198
- request: { method, path: path70, origin }
22487
+ request: { method, path: path71, origin }
22199
22488
  } = evt;
22200
- debugLog("trailers received from %s %s%s", method, origin, path70);
22489
+ debugLog("trailers received from %s %s%s", method, origin, path71);
22201
22490
  }
22202
22491
  );
22203
22492
  diagnosticsChannel.subscribe(
22204
22493
  "undici:request:error",
22205
22494
  (evt) => {
22206
22495
  const {
22207
- request: { method, path: path70, origin },
22496
+ request: { method, path: path71, origin },
22208
22497
  error
22209
22498
  } = evt;
22210
22499
  debugLog(
22211
22500
  "request to %s %s%s errored - %s",
22212
22501
  method,
22213
22502
  origin,
22214
- path70,
22503
+ path71,
22215
22504
  error.message
22216
22505
  );
22217
22506
  }
@@ -22314,7 +22603,7 @@ var require_request = __commonJS({
22314
22603
  var kHandler = /* @__PURE__ */ Symbol("handler");
22315
22604
  var Request = class {
22316
22605
  constructor(origin, {
22317
- path: path70,
22606
+ path: path71,
22318
22607
  method,
22319
22608
  body,
22320
22609
  headers,
@@ -22331,11 +22620,11 @@ var require_request = __commonJS({
22331
22620
  maxRedirections,
22332
22621
  typeOfService
22333
22622
  }, handler) {
22334
- if (typeof path70 !== "string") {
22623
+ if (typeof path71 !== "string") {
22335
22624
  throw new InvalidArgumentError("path must be a string");
22336
- } else if (path70[0] !== "/" && !(path70.startsWith("http://") || path70.startsWith("https://")) && method !== "CONNECT") {
22625
+ } else if (path71[0] !== "/" && !(path71.startsWith("http://") || path71.startsWith("https://")) && method !== "CONNECT") {
22337
22626
  throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
22338
- } else if (invalidPathRegex.test(path70)) {
22627
+ } else if (invalidPathRegex.test(path71)) {
22339
22628
  throw new InvalidArgumentError("invalid request path");
22340
22629
  }
22341
22630
  if (typeof method !== "string") {
@@ -22410,7 +22699,7 @@ var require_request = __commonJS({
22410
22699
  this.completed = false;
22411
22700
  this.aborted = false;
22412
22701
  this.upgrade = upgrade || null;
22413
- this.path = query ? serializePathWithQuery(path70, query) : path70;
22702
+ this.path = query ? serializePathWithQuery(path71, query) : path71;
22414
22703
  this.origin = origin;
22415
22704
  this.protocol = getProtocolFromUrlString(origin);
22416
22705
  this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
@@ -27449,7 +27738,7 @@ var require_client_h1 = __commonJS({
27449
27738
  return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
27450
27739
  }
27451
27740
  function writeH1(client, request2) {
27452
- const { method, path: path70, host, upgrade, blocking, reset } = request2;
27741
+ const { method, path: path71, host, upgrade, blocking, reset } = request2;
27453
27742
  let { body, headers, contentLength } = request2;
27454
27743
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
27455
27744
  if (util.isFormDataLike(body)) {
@@ -27518,7 +27807,7 @@ var require_client_h1 = __commonJS({
27518
27807
  if (socket.setTypeOfService) {
27519
27808
  socket.setTypeOfService(request2.typeOfService);
27520
27809
  }
27521
- let header = `${method} ${path70} HTTP/1.1\r
27810
+ let header = `${method} ${path71} HTTP/1.1\r
27522
27811
  `;
27523
27812
  if (typeof host === "string") {
27524
27813
  header += `host: ${host}\r
@@ -28171,7 +28460,7 @@ var require_client_h2 = __commonJS({
28171
28460
  function writeH2(client, request2) {
28172
28461
  const requestTimeout = request2.bodyTimeout ?? client[kBodyTimeout];
28173
28462
  const session = client[kHTTP2Session];
28174
- const { method, path: path70, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2;
28463
+ const { method, path: path71, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2;
28175
28464
  let { body } = request2;
28176
28465
  if (upgrade != null && upgrade !== "websocket") {
28177
28466
  util.errorRequest(client, request2, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
@@ -28239,7 +28528,7 @@ var require_client_h2 = __commonJS({
28239
28528
  }
28240
28529
  headers[HTTP2_HEADER_METHOD] = "CONNECT";
28241
28530
  headers[HTTP2_HEADER_PROTOCOL] = "websocket";
28242
- headers[HTTP2_HEADER_PATH] = path70;
28531
+ headers[HTTP2_HEADER_PATH] = path71;
28243
28532
  if (protocol === "ws:" || protocol === "wss:") {
28244
28533
  headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
28245
28534
  } else {
@@ -28280,7 +28569,7 @@ var require_client_h2 = __commonJS({
28280
28569
  stream.setTimeout(requestTimeout);
28281
28570
  return true;
28282
28571
  }
28283
- headers[HTTP2_HEADER_PATH] = path70;
28572
+ headers[HTTP2_HEADER_PATH] = path71;
28284
28573
  headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
28285
28574
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
28286
28575
  if (body && typeof body.read === "function") {
@@ -30582,10 +30871,10 @@ var require_proxy_agent = __commonJS({
30582
30871
  };
30583
30872
  const {
30584
30873
  origin,
30585
- path: path70 = "/",
30874
+ path: path71 = "/",
30586
30875
  headers = {}
30587
30876
  } = opts;
30588
- opts.path = origin + path70;
30877
+ opts.path = origin + path71;
30589
30878
  if (!("host" in headers) && !("Host" in headers)) {
30590
30879
  const { host } = new URL(origin);
30591
30880
  headers.host = host;
@@ -32648,20 +32937,20 @@ var require_mock_utils = __commonJS({
32648
32937
  }
32649
32938
  return normalizedQp;
32650
32939
  }
32651
- function safeUrl(path70) {
32652
- if (typeof path70 !== "string") {
32653
- return path70;
32940
+ function safeUrl(path71) {
32941
+ if (typeof path71 !== "string") {
32942
+ return path71;
32654
32943
  }
32655
- const pathSegments = path70.split("?", 3);
32944
+ const pathSegments = path71.split("?", 3);
32656
32945
  if (pathSegments.length !== 2) {
32657
- return path70;
32946
+ return path71;
32658
32947
  }
32659
32948
  const qp = new URLSearchParams(pathSegments.pop());
32660
32949
  qp.sort();
32661
32950
  return [...pathSegments, qp.toString()].join("?");
32662
32951
  }
32663
- function matchKey(mockDispatch2, { path: path70, method, body, headers }) {
32664
- const pathMatch = matchValue(mockDispatch2.path, path70);
32952
+ function matchKey(mockDispatch2, { path: path71, method, body, headers }) {
32953
+ const pathMatch = matchValue(mockDispatch2.path, path71);
32665
32954
  const methodMatch = matchValue(mockDispatch2.method, method);
32666
32955
  const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
32667
32956
  const headersMatch = matchHeaders(mockDispatch2, headers);
@@ -32686,8 +32975,8 @@ var require_mock_utils = __commonJS({
32686
32975
  const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path;
32687
32976
  const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
32688
32977
  const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
32689
- let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path70, ignoreTrailingSlash }) => {
32690
- return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path70)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path70), resolvedPath);
32978
+ let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path71, ignoreTrailingSlash }) => {
32979
+ return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path71)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path71), resolvedPath);
32691
32980
  });
32692
32981
  if (matchedMockDispatches.length === 0) {
32693
32982
  throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
@@ -32726,19 +33015,19 @@ var require_mock_utils = __commonJS({
32726
33015
  mockDispatches.splice(index, 1);
32727
33016
  }
32728
33017
  }
32729
- function removeTrailingSlash(path70) {
32730
- while (path70.endsWith("/")) {
32731
- path70 = path70.slice(0, -1);
33018
+ function removeTrailingSlash(path71) {
33019
+ while (path71.endsWith("/")) {
33020
+ path71 = path71.slice(0, -1);
32732
33021
  }
32733
- if (path70.length === 0) {
32734
- path70 = "/";
33022
+ if (path71.length === 0) {
33023
+ path71 = "/";
32735
33024
  }
32736
- return path70;
33025
+ return path71;
32737
33026
  }
32738
33027
  function buildKey(opts) {
32739
- const { path: path70, method, body, headers, query } = opts;
33028
+ const { path: path71, method, body, headers, query } = opts;
32740
33029
  return {
32741
- path: path70,
33030
+ path: path71,
32742
33031
  method,
32743
33032
  body,
32744
33033
  headers,
@@ -33428,10 +33717,10 @@ var require_pending_interceptors_formatter = __commonJS({
33428
33717
  }
33429
33718
  format(pendingInterceptors) {
33430
33719
  const withPrettyHeaders = pendingInterceptors.map(
33431
- ({ method, path: path70, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
33720
+ ({ method, path: path71, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
33432
33721
  Method: method,
33433
33722
  Origin: origin,
33434
- Path: path70,
33723
+ Path: path71,
33435
33724
  "Status code": statusCode,
33436
33725
  Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
33437
33726
  Invocations: timesInvoked,
@@ -33513,9 +33802,9 @@ var require_mock_agent = __commonJS({
33513
33802
  const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
33514
33803
  const dispatchOpts = { ...opts };
33515
33804
  if (acceptNonStandardSearchParameters && dispatchOpts.path) {
33516
- const [path70, searchParams] = dispatchOpts.path.split("?");
33805
+ const [path71, searchParams] = dispatchOpts.path.split("?");
33517
33806
  const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
33518
- dispatchOpts.path = `${path70}?${normalizedSearchParams}`;
33807
+ dispatchOpts.path = `${path71}?${normalizedSearchParams}`;
33519
33808
  }
33520
33809
  return this[kAgent].dispatch(dispatchOpts, handler);
33521
33810
  }
@@ -33916,12 +34205,12 @@ var require_snapshot_recorder = __commonJS({
33916
34205
  * @return {Promise<void>} - Resolves when snapshots are loaded
33917
34206
  */
33918
34207
  async loadSnapshots(filePath) {
33919
- const path70 = filePath || this.#snapshotPath;
33920
- if (!path70) {
34208
+ const path71 = filePath || this.#snapshotPath;
34209
+ if (!path71) {
33921
34210
  throw new InvalidArgumentError("Snapshot path is required");
33922
34211
  }
33923
34212
  try {
33924
- const data = await readFile(resolve2(path70), "utf8");
34213
+ const data = await readFile(resolve2(path71), "utf8");
33925
34214
  const parsed = JSON.parse(data);
33926
34215
  if (Array.isArray(parsed)) {
33927
34216
  this.#snapshots.clear();
@@ -33935,7 +34224,7 @@ var require_snapshot_recorder = __commonJS({
33935
34224
  if (error.code === "ENOENT") {
33936
34225
  this.#snapshots.clear();
33937
34226
  } else {
33938
- throw new UndiciError(`Failed to load snapshots from ${path70}`, { cause: error });
34227
+ throw new UndiciError(`Failed to load snapshots from ${path71}`, { cause: error });
33939
34228
  }
33940
34229
  }
33941
34230
  }
@@ -33946,11 +34235,11 @@ var require_snapshot_recorder = __commonJS({
33946
34235
  * @returns {Promise<void>} - Resolves when snapshots are saved
33947
34236
  */
33948
34237
  async saveSnapshots(filePath) {
33949
- const path70 = filePath || this.#snapshotPath;
33950
- if (!path70) {
34238
+ const path71 = filePath || this.#snapshotPath;
34239
+ if (!path71) {
33951
34240
  throw new InvalidArgumentError("Snapshot path is required");
33952
34241
  }
33953
- const resolvedPath = resolve2(path70);
34242
+ const resolvedPath = resolve2(path71);
33954
34243
  await mkdir(dirname2(resolvedPath), { recursive: true });
33955
34244
  const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
33956
34245
  hash,
@@ -34575,15 +34864,15 @@ var require_redirect_handler = __commonJS({
34575
34864
  return;
34576
34865
  }
34577
34866
  const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
34578
- const path70 = search ? `${pathname}${search}` : pathname;
34579
- const redirectUrlString = `${origin}${path70}`;
34867
+ const path71 = search ? `${pathname}${search}` : pathname;
34868
+ const redirectUrlString = `${origin}${path71}`;
34580
34869
  for (const historyUrl of this.history) {
34581
34870
  if (historyUrl.toString() === redirectUrlString) {
34582
34871
  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.`);
34583
34872
  }
34584
34873
  }
34585
34874
  this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
34586
- this.opts.path = path70;
34875
+ this.opts.path = path71;
34587
34876
  this.opts.origin = origin;
34588
34877
  this.opts.query = null;
34589
34878
  }
@@ -40790,11 +41079,11 @@ var require_fetch = __commonJS({
40790
41079
  function dispatch({ body }) {
40791
41080
  const url = requestCurrentURL(request2);
40792
41081
  const agent = fetchParams.controller.dispatcher;
40793
- const path70 = url.pathname + url.search;
41082
+ const path71 = url.pathname + url.search;
40794
41083
  const hasTrailingQuestionMark = url.search.length === 0 && url.href[url.href.length - url.hash.length - 1] === "?";
40795
41084
  return new Promise((resolve2, reject) => agent.dispatch(
40796
41085
  {
40797
- path: hasTrailingQuestionMark ? `${path70}?` : path70,
41086
+ path: hasTrailingQuestionMark ? `${path71}?` : path71,
40798
41087
  origin: url.origin,
40799
41088
  method: request2.method,
40800
41089
  body: agent.isMockActive ? request2.body && (request2.body.source || request2.body.stream) : body,
@@ -41725,9 +42014,9 @@ var require_util4 = __commonJS({
41725
42014
  }
41726
42015
  }
41727
42016
  }
41728
- function validateCookiePath(path70) {
41729
- for (let i = 0; i < path70.length; ++i) {
41730
- const code = path70.charCodeAt(i);
42017
+ function validateCookiePath(path71) {
42018
+ for (let i = 0; i < path71.length; ++i) {
42019
+ const code = path71.charCodeAt(i);
41731
42020
  if (code < 32 || // exclude CTLs (0-31)
41732
42021
  code === 127 || // DEL
41733
42022
  code === 59) {
@@ -44897,11 +45186,11 @@ var require_undici = __commonJS({
44897
45186
  if (typeof opts.path !== "string") {
44898
45187
  throw new InvalidArgumentError("invalid opts.path");
44899
45188
  }
44900
- let path70 = opts.path;
45189
+ let path71 = opts.path;
44901
45190
  if (!opts.path.startsWith("/")) {
44902
- path70 = `/${path70}`;
45191
+ path71 = `/${path71}`;
44903
45192
  }
44904
- url = new URL(util.parseOrigin(url).origin + path70);
45193
+ url = new URL(util.parseOrigin(url).origin + path71);
44905
45194
  } else {
44906
45195
  if (!opts) {
44907
45196
  opts = typeof url === "object" ? url : {};
@@ -45039,20 +45328,20 @@ function getModelContextLimit(model) {
45039
45328
  return 2e5;
45040
45329
  }
45041
45330
  function readSessionUsage() {
45042
- const projectsDir = import_path66.default.join(import_os58.default.homedir(), ".claude", "projects");
45043
- if (!import_fs69.default.existsSync(projectsDir)) return null;
45331
+ const projectsDir = import_path67.default.join(import_os60.default.homedir(), ".claude", "projects");
45332
+ if (!import_fs70.default.existsSync(projectsDir)) return null;
45044
45333
  let latestFile = null;
45045
45334
  let latestMtime = 0;
45046
45335
  try {
45047
- for (const dir of import_fs69.default.readdirSync(projectsDir)) {
45048
- const dirPath = import_path66.default.join(projectsDir, dir);
45336
+ for (const dir of import_fs70.default.readdirSync(projectsDir)) {
45337
+ const dirPath = import_path67.default.join(projectsDir, dir);
45049
45338
  try {
45050
- if (!import_fs69.default.statSync(dirPath).isDirectory()) continue;
45051
- for (const file of import_fs69.default.readdirSync(dirPath)) {
45339
+ if (!import_fs70.default.statSync(dirPath).isDirectory()) continue;
45340
+ for (const file of import_fs70.default.readdirSync(dirPath)) {
45052
45341
  if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
45053
- const filePath = import_path66.default.join(dirPath, file);
45342
+ const filePath = import_path67.default.join(dirPath, file);
45054
45343
  try {
45055
- const mtime = import_fs69.default.statSync(filePath).mtimeMs;
45344
+ const mtime = import_fs70.default.statSync(filePath).mtimeMs;
45056
45345
  if (mtime > latestMtime) {
45057
45346
  latestMtime = mtime;
45058
45347
  latestFile = filePath;
@@ -45067,7 +45356,7 @@ function readSessionUsage() {
45067
45356
  }
45068
45357
  if (!latestFile) return null;
45069
45358
  try {
45070
- const lines = import_fs69.default.readFileSync(latestFile, "utf-8").split("\n");
45359
+ const lines = import_fs70.default.readFileSync(latestFile, "utf-8").split("\n");
45071
45360
  let lastModel = "";
45072
45361
  let lastInput = 0;
45073
45362
  let lastOutput = 0;
@@ -45128,7 +45417,7 @@ function formatBase(activity) {
45128
45417
  const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
45129
45418
  const icon = getIcon(activity.tool);
45130
45419
  const toolName = activity.tool.slice(0, 16).padEnd(16);
45131
- const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os58.default.homedir(), "~");
45420
+ const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os60.default.homedir(), "~");
45132
45421
  const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
45133
45422
  return `${import_chalk40.default.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${import_chalk40.default.white.bold(toolName)} ${import_chalk40.default.dim(argsPreview)}`;
45134
45423
  }
@@ -45167,9 +45456,9 @@ function renderPending(activity) {
45167
45456
  }
45168
45457
  async function ensureDaemon() {
45169
45458
  let pidPort = null;
45170
- if (import_fs69.default.existsSync(PID_FILE)) {
45459
+ if (import_fs70.default.existsSync(PID_FILE)) {
45171
45460
  try {
45172
- const { port } = JSON.parse(import_fs69.default.readFileSync(PID_FILE, "utf-8"));
45461
+ const { port } = JSON.parse(import_fs70.default.readFileSync(PID_FILE, "utf-8"));
45173
45462
  pidPort = port;
45174
45463
  } catch {
45175
45464
  console.error(import_chalk40.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
@@ -45325,9 +45614,9 @@ function buildRecoveryCardLines(req) {
45325
45614
  ];
45326
45615
  }
45327
45616
  function readApproversFromDisk() {
45328
- const configPath = import_path66.default.join(import_os58.default.homedir(), ".node9", "config.json");
45617
+ const configPath = import_path67.default.join(import_os60.default.homedir(), ".node9", "config.json");
45329
45618
  try {
45330
- const raw = JSON.parse(import_fs69.default.readFileSync(configPath, "utf-8"));
45619
+ const raw = JSON.parse(import_fs70.default.readFileSync(configPath, "utf-8"));
45331
45620
  const settings = raw.settings ?? {};
45332
45621
  return settings.approvers ?? {};
45333
45622
  } catch {
@@ -45343,15 +45632,15 @@ function approverStatusLine() {
45343
45632
  return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
45344
45633
  }
45345
45634
  function toggleApprover(channel) {
45346
- const configPath = import_path66.default.join(import_os58.default.homedir(), ".node9", "config.json");
45635
+ const configPath = import_path67.default.join(import_os60.default.homedir(), ".node9", "config.json");
45347
45636
  try {
45348
- const raw = JSON.parse(import_fs69.default.readFileSync(configPath, "utf-8"));
45637
+ const raw = JSON.parse(import_fs70.default.readFileSync(configPath, "utf-8"));
45349
45638
  const settings = raw.settings ?? {};
45350
45639
  const approvers = settings.approvers ?? {};
45351
45640
  approvers[channel] = approvers[channel] === false;
45352
45641
  settings.approvers = approvers;
45353
45642
  raw.settings = settings;
45354
- import_fs69.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
45643
+ import_fs70.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
45355
45644
  } catch (err2) {
45356
45645
  process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
45357
45646
  `);
@@ -45523,8 +45812,8 @@ async function startTail(options = {}) {
45523
45812
  }
45524
45813
  postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
45525
45814
  try {
45526
- import_fs69.default.appendFileSync(
45527
- import_path66.default.join(import_os58.default.homedir(), ".node9", "hook-debug.log"),
45815
+ import_fs70.default.appendFileSync(
45816
+ import_path67.default.join(import_os60.default.homedir(), ".node9", "hook-debug.log"),
45528
45817
  `[tail] POST /decision failed: ${String(err2)}
45529
45818
  `
45530
45819
  );
@@ -45588,9 +45877,9 @@ async function startTail(options = {}) {
45588
45877
  };
45589
45878
  process.stdin.on("keypress", onKeypress);
45590
45879
  }
45591
- const auditLog = import_path66.default.join(import_os58.default.homedir(), ".node9", "audit.log");
45880
+ const auditLog = import_path67.default.join(import_os60.default.homedir(), ".node9", "audit.log");
45592
45881
  try {
45593
- const unackedDlp = import_fs69.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
45882
+ const unackedDlp = import_fs70.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
45594
45883
  if (unackedDlp > 0) {
45595
45884
  console.log("");
45596
45885
  console.log(
@@ -45630,7 +45919,7 @@ async function startTail(options = {}) {
45630
45919
  if (stallWarned) return;
45631
45920
  if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
45632
45921
  try {
45633
- const auditMtime = import_fs69.default.statSync(auditLog).mtimeMs;
45922
+ const auditMtime = import_fs70.default.statSync(auditLog).mtimeMs;
45634
45923
  if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
45635
45924
  console.log("");
45636
45925
  console.log(
@@ -45815,20 +46104,20 @@ async function startTail(options = {}) {
45815
46104
  process.exit(1);
45816
46105
  });
45817
46106
  }
45818
- var import_http5, import_chalk40, import_fs69, import_os58, import_path66, import_readline6, import_child_process14, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
46107
+ var import_http5, import_chalk40, import_fs70, import_os60, import_path67, import_readline6, import_child_process14, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
45819
46108
  var init_tail = __esm({
45820
46109
  "src/tui/tail.ts"() {
45821
46110
  "use strict";
45822
46111
  import_http5 = __toESM(require("http"));
45823
46112
  import_chalk40 = __toESM(require("chalk"));
45824
- import_fs69 = __toESM(require("fs"));
45825
- import_os58 = __toESM(require("os"));
45826
- import_path66 = __toESM(require("path"));
46113
+ import_fs70 = __toESM(require("fs"));
46114
+ import_os60 = __toESM(require("os"));
46115
+ import_path67 = __toESM(require("path"));
45827
46116
  import_readline6 = __toESM(require("readline"));
45828
46117
  import_child_process14 = require("child_process");
45829
46118
  init_daemon2();
45830
46119
  init_daemon();
45831
- PID_FILE = import_path66.default.join(import_os58.default.homedir(), ".node9", "daemon.pid");
46120
+ PID_FILE = import_path67.default.join(import_os60.default.homedir(), ".node9", "daemon.pid");
45832
46121
  ICONS = {
45833
46122
  bash: "\u{1F4BB}",
45834
46123
  shell: "\u{1F4BB}",
@@ -45950,9 +46239,9 @@ function formatTimeLeft(resetsAt) {
45950
46239
  return ` (${m}m left)`;
45951
46240
  }
45952
46241
  function safeReadJson(filePath) {
45953
- if (!import_fs70.default.existsSync(filePath)) return null;
46242
+ if (!import_fs71.default.existsSync(filePath)) return null;
45954
46243
  try {
45955
- return JSON.parse(import_fs70.default.readFileSync(filePath, "utf-8"));
46244
+ return JSON.parse(import_fs71.default.readFileSync(filePath, "utf-8"));
45956
46245
  } catch {
45957
46246
  return null;
45958
46247
  }
@@ -45973,12 +46262,12 @@ function countHooksInFile(filePath) {
45973
46262
  return Object.keys(cfg.hooks).length;
45974
46263
  }
45975
46264
  function countRulesInDir(rulesDir) {
45976
- if (!import_fs70.default.existsSync(rulesDir)) return 0;
46265
+ if (!import_fs71.default.existsSync(rulesDir)) return 0;
45977
46266
  let count = 0;
45978
46267
  try {
45979
- for (const entry of import_fs70.default.readdirSync(rulesDir, { withFileTypes: true })) {
46268
+ for (const entry of import_fs71.default.readdirSync(rulesDir, { withFileTypes: true })) {
45980
46269
  if (entry.isDirectory()) {
45981
- count += countRulesInDir(import_path67.default.join(rulesDir, entry.name));
46270
+ count += countRulesInDir(import_path68.default.join(rulesDir, entry.name));
45982
46271
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
45983
46272
  count++;
45984
46273
  }
@@ -45989,46 +46278,46 @@ function countRulesInDir(rulesDir) {
45989
46278
  }
45990
46279
  function isSamePath(a, b) {
45991
46280
  try {
45992
- return import_path67.default.resolve(a) === import_path67.default.resolve(b);
46281
+ return import_path68.default.resolve(a) === import_path68.default.resolve(b);
45993
46282
  } catch {
45994
46283
  return false;
45995
46284
  }
45996
46285
  }
45997
46286
  function countConfigs(cwd) {
45998
- const homeDir2 = import_os59.default.homedir();
45999
- const claudeDir = import_path67.default.join(homeDir2, ".claude");
46287
+ const homeDir2 = import_os61.default.homedir();
46288
+ const claudeDir = import_path68.default.join(homeDir2, ".claude");
46000
46289
  let claudeMdCount = 0;
46001
46290
  let rulesCount = 0;
46002
46291
  let hooksCount = 0;
46003
46292
  const userMcpServers = /* @__PURE__ */ new Set();
46004
46293
  const projectMcpServers = /* @__PURE__ */ new Set();
46005
- if (import_fs70.default.existsSync(import_path67.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
46006
- rulesCount += countRulesInDir(import_path67.default.join(claudeDir, "rules"));
46007
- const userSettings = import_path67.default.join(claudeDir, "settings.json");
46294
+ if (import_fs71.default.existsSync(import_path68.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
46295
+ rulesCount += countRulesInDir(import_path68.default.join(claudeDir, "rules"));
46296
+ const userSettings = import_path68.default.join(claudeDir, "settings.json");
46008
46297
  for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
46009
46298
  hooksCount += countHooksInFile(userSettings);
46010
- const userClaudeJson = import_path67.default.join(homeDir2, ".claude.json");
46299
+ const userClaudeJson = import_path68.default.join(homeDir2, ".claude.json");
46011
46300
  for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
46012
46301
  for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
46013
46302
  userMcpServers.delete(name);
46014
46303
  }
46015
46304
  if (cwd) {
46016
- if (import_fs70.default.existsSync(import_path67.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
46017
- if (import_fs70.default.existsSync(import_path67.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
46018
- const projectClaudeDir = import_path67.default.join(cwd, ".claude");
46305
+ if (import_fs71.default.existsSync(import_path68.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
46306
+ if (import_fs71.default.existsSync(import_path68.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
46307
+ const projectClaudeDir = import_path68.default.join(cwd, ".claude");
46019
46308
  const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
46020
46309
  if (!overlapsUserScope) {
46021
- if (import_fs70.default.existsSync(import_path67.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
46022
- rulesCount += countRulesInDir(import_path67.default.join(projectClaudeDir, "rules"));
46023
- const projSettings = import_path67.default.join(projectClaudeDir, "settings.json");
46310
+ if (import_fs71.default.existsSync(import_path68.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
46311
+ rulesCount += countRulesInDir(import_path68.default.join(projectClaudeDir, "rules"));
46312
+ const projSettings = import_path68.default.join(projectClaudeDir, "settings.json");
46024
46313
  for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
46025
46314
  hooksCount += countHooksInFile(projSettings);
46026
46315
  }
46027
- if (import_fs70.default.existsSync(import_path67.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
46028
- const localSettings = import_path67.default.join(projectClaudeDir, "settings.local.json");
46316
+ if (import_fs71.default.existsSync(import_path68.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
46317
+ const localSettings = import_path68.default.join(projectClaudeDir, "settings.local.json");
46029
46318
  for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
46030
46319
  hooksCount += countHooksInFile(localSettings);
46031
- const mcpJsonServers = getMcpServerNames(import_path67.default.join(cwd, ".mcp.json"));
46320
+ const mcpJsonServers = getMcpServerNames(import_path68.default.join(cwd, ".mcp.json"));
46032
46321
  const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
46033
46322
  for (const name of disabledMcpJson) mcpJsonServers.delete(name);
46034
46323
  for (const name of mcpJsonServers) projectMcpServers.add(name);
@@ -46061,12 +46350,12 @@ function readActiveShieldsHud() {
46061
46350
  return shieldsCache.value;
46062
46351
  }
46063
46352
  try {
46064
- const shieldsPath = import_path67.default.join(import_os59.default.homedir(), ".node9", "shields.json");
46065
- if (!import_fs70.default.existsSync(shieldsPath)) {
46353
+ const shieldsPath = import_path68.default.join(import_os61.default.homedir(), ".node9", "shields.json");
46354
+ if (!import_fs71.default.existsSync(shieldsPath)) {
46066
46355
  shieldsCache = { value: [], ts: now };
46067
46356
  return [];
46068
46357
  }
46069
- const parsed = JSON.parse(import_fs70.default.readFileSync(shieldsPath, "utf-8"));
46358
+ const parsed = JSON.parse(import_fs71.default.readFileSync(shieldsPath, "utf-8"));
46070
46359
  if (!Array.isArray(parsed.active)) {
46071
46360
  shieldsCache = { value: [], ts: now };
46072
46361
  return [];
@@ -46168,17 +46457,17 @@ function renderContextLine(stdin) {
46168
46457
  async function main() {
46169
46458
  try {
46170
46459
  const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
46171
- if (import_fs70.default.existsSync(import_path67.default.join(import_os59.default.homedir(), ".node9", "hud-debug"))) {
46460
+ if (import_fs71.default.existsSync(import_path68.default.join(import_os61.default.homedir(), ".node9", "hud-debug"))) {
46172
46461
  try {
46173
- const logPath = import_path67.default.join(import_os59.default.homedir(), ".node9", "hud-debug.log");
46462
+ const logPath = import_path68.default.join(import_os61.default.homedir(), ".node9", "hud-debug.log");
46174
46463
  const MAX_LOG_SIZE = 10 * 1024 * 1024;
46175
46464
  let size = 0;
46176
46465
  try {
46177
- size = import_fs70.default.statSync(logPath).size;
46466
+ size = import_fs71.default.statSync(logPath).size;
46178
46467
  } catch {
46179
46468
  }
46180
46469
  if (size < MAX_LOG_SIZE) {
46181
- import_fs70.default.appendFileSync(
46470
+ import_fs71.default.appendFileSync(
46182
46471
  logPath,
46183
46472
  JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
46184
46473
  );
@@ -46199,11 +46488,11 @@ async function main() {
46199
46488
  try {
46200
46489
  const cwd = stdin.cwd ?? process.cwd();
46201
46490
  for (const configPath of [
46202
- import_path67.default.join(cwd, "node9.config.json"),
46203
- import_path67.default.join(import_os59.default.homedir(), ".node9", "config.json")
46491
+ import_path68.default.join(cwd, "node9.config.json"),
46492
+ import_path68.default.join(import_os61.default.homedir(), ".node9", "config.json")
46204
46493
  ]) {
46205
- if (!import_fs70.default.existsSync(configPath)) continue;
46206
- const cfg = JSON.parse(import_fs70.default.readFileSync(configPath, "utf-8"));
46494
+ if (!import_fs71.default.existsSync(configPath)) continue;
46495
+ const cfg = JSON.parse(import_fs71.default.readFileSync(configPath, "utf-8"));
46207
46496
  const hud = cfg.settings?.hud;
46208
46497
  if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
46209
46498
  }
@@ -46221,13 +46510,13 @@ async function main() {
46221
46510
  renderOffline();
46222
46511
  }
46223
46512
  }
46224
- var import_fs70, import_path67, import_os59, import_http6, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
46513
+ var import_fs71, import_path68, import_os61, import_http6, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
46225
46514
  var init_hud = __esm({
46226
46515
  "src/cli/hud.ts"() {
46227
46516
  "use strict";
46228
- import_fs70 = __toESM(require("fs"));
46229
- import_path67 = __toESM(require("path"));
46230
- import_os59 = __toESM(require("os"));
46517
+ import_fs71 = __toESM(require("fs"));
46518
+ import_path68 = __toESM(require("path"));
46519
+ import_os61 = __toESM(require("os"));
46231
46520
  import_http6 = __toESM(require("http"));
46232
46521
  init_daemon();
46233
46522
  RESET3 = "\x1B[0m";
@@ -46349,9 +46638,9 @@ function writeCredentialsAndConfig(apiKey, opts = {}) {
46349
46638
  // src/cli.ts
46350
46639
  init_daemon2();
46351
46640
  var import_chalk41 = __toESM(require("chalk"));
46352
- var import_fs71 = __toESM(require("fs"));
46353
- var import_path68 = __toESM(require("path"));
46354
- var import_os60 = __toESM(require("os"));
46641
+ var import_fs72 = __toESM(require("fs"));
46642
+ var import_path69 = __toESM(require("path"));
46643
+ var import_os62 = __toESM(require("os"));
46355
46644
  var import_child_process15 = require("child_process");
46356
46645
  var import_prompts2 = require("@inquirer/prompts");
46357
46646
 
@@ -46538,26 +46827,48 @@ async function runProxy(targetCommand) {
46538
46827
 
46539
46828
  // src/cli/daemon-starter.ts
46540
46829
  var import_child_process5 = require("child_process");
46541
- var import_path40 = __toESM(require("path"));
46542
- var import_fs42 = __toESM(require("fs"));
46830
+ var import_path41 = __toESM(require("path"));
46831
+ var import_fs43 = __toESM(require("fs"));
46832
+ var import_os39 = __toESM(require("os"));
46543
46833
  init_daemon();
46834
+ init_startup_log();
46544
46835
  function isTestingMode() {
46545
46836
  return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
46546
46837
  }
46838
+ var SKIP_STAMP = () => import_path41.default.join(import_os39.default.homedir(), ".node9", ".autostart-skip-stamp");
46839
+ var SKIP_THROTTLE_MS = 60 * 60 * 1e3;
46840
+ function logAutostartSkipThrottled(reason) {
46841
+ try {
46842
+ const stamp = SKIP_STAMP();
46843
+ try {
46844
+ if (Date.now() - import_fs43.default.statSync(stamp).mtimeMs < SKIP_THROTTLE_MS) return;
46845
+ } catch {
46846
+ }
46847
+ import_fs43.default.writeFileSync(stamp, "", "utf-8");
46848
+ import_fs43.default.appendFileSync(
46849
+ import_path41.default.join(import_os39.default.homedir(), ".node9", "hook-debug.log"),
46850
+ `[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-skip: ${reason}
46851
+ `,
46852
+ "utf-8"
46853
+ );
46854
+ } catch {
46855
+ }
46856
+ }
46547
46857
  async function autoStartDaemonAndWait() {
46548
46858
  if (isTestingMode()) return false;
46549
- if (!import_path40.default.isAbsolute(process.argv[1])) return false;
46859
+ if (!import_path41.default.isAbsolute(process.argv[1])) return false;
46550
46860
  let resolvedArgv1;
46551
46861
  try {
46552
- resolvedArgv1 = import_fs42.default.realpathSync(process.argv[1]);
46862
+ resolvedArgv1 = import_fs43.default.realpathSync(process.argv[1]);
46553
46863
  } catch {
46554
46864
  return false;
46555
46865
  }
46556
46866
  if (!resolvedArgv1.endsWith(".js")) return false;
46867
+ const startupFd = openStartupLogFd();
46557
46868
  try {
46558
46869
  const child = (0, import_child_process5.spawn)(process.execPath, [resolvedArgv1, "daemon"], {
46559
46870
  detached: true,
46560
- stdio: "ignore",
46871
+ stdio: ["ignore", "ignore", startupFd ?? "ignore"],
46561
46872
  env: {
46562
46873
  ...process.env,
46563
46874
  NODE9_AUTO_STARTED: "1"
@@ -46570,30 +46881,41 @@ async function autoStartDaemonAndWait() {
46570
46881
  if (await isDaemonReachable()) return true;
46571
46882
  }
46572
46883
  } catch {
46884
+ } finally {
46885
+ if (startupFd !== void 0) {
46886
+ try {
46887
+ import_fs43.default.closeSync(startupFd);
46888
+ } catch {
46889
+ }
46890
+ }
46573
46891
  }
46574
46892
  return false;
46575
46893
  }
46576
46894
 
46895
+ // src/cli.ts
46896
+ init_service();
46897
+
46577
46898
  // src/cli/commands/check.ts
46578
46899
  var import_chalk9 = __toESM(require("chalk"));
46579
- var import_fs46 = __toESM(require("fs"));
46900
+ var import_fs47 = __toESM(require("fs"));
46580
46901
  var import_child_process7 = require("child_process");
46581
- var import_path44 = __toESM(require("path"));
46582
- var import_os41 = __toESM(require("os"));
46902
+ var import_path45 = __toESM(require("path"));
46903
+ var import_os43 = __toESM(require("os"));
46583
46904
  init_orchestrator();
46584
46905
  init_state();
46585
46906
  init_daemon();
46907
+ init_startup_log();
46586
46908
  init_config();
46587
46909
  init_policy();
46588
46910
 
46589
46911
  // src/undo.ts
46590
46912
  var import_child_process6 = require("child_process");
46591
46913
  var import_crypto12 = __toESM(require("crypto"));
46592
- var import_fs43 = __toESM(require("fs"));
46914
+ var import_fs44 = __toESM(require("fs"));
46593
46915
  var import_net3 = __toESM(require("net"));
46594
- var import_path41 = __toESM(require("path"));
46595
- var import_os38 = __toESM(require("os"));
46596
- var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path41.default.join(import_os38.default.tmpdir(), "node9-activity.sock");
46916
+ var import_path42 = __toESM(require("path"));
46917
+ var import_os40 = __toESM(require("os"));
46918
+ var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path42.default.join(import_os40.default.tmpdir(), "node9-activity.sock");
46597
46919
  function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
46598
46920
  try {
46599
46921
  const payload = JSON.stringify({
@@ -46613,22 +46935,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
46613
46935
  } catch {
46614
46936
  }
46615
46937
  }
46616
- var SNAPSHOT_STACK_PATH = import_path41.default.join(import_os38.default.homedir(), ".node9", "snapshots.json");
46617
- var UNDO_LATEST_PATH = import_path41.default.join(import_os38.default.homedir(), ".node9", "undo_latest.txt");
46938
+ var SNAPSHOT_STACK_PATH = import_path42.default.join(import_os40.default.homedir(), ".node9", "snapshots.json");
46939
+ var UNDO_LATEST_PATH = import_path42.default.join(import_os40.default.homedir(), ".node9", "undo_latest.txt");
46618
46940
  var MAX_SNAPSHOTS = 10;
46619
46941
  var GIT_TIMEOUT = 15e3;
46620
46942
  function readStack() {
46621
46943
  try {
46622
- if (import_fs43.default.existsSync(SNAPSHOT_STACK_PATH))
46623
- return JSON.parse(import_fs43.default.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
46944
+ if (import_fs44.default.existsSync(SNAPSHOT_STACK_PATH))
46945
+ return JSON.parse(import_fs44.default.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
46624
46946
  } catch {
46625
46947
  }
46626
46948
  return [];
46627
46949
  }
46628
46950
  function writeStack(stack) {
46629
- const dir = import_path41.default.dirname(SNAPSHOT_STACK_PATH);
46630
- if (!import_fs43.default.existsSync(dir)) import_fs43.default.mkdirSync(dir, { recursive: true });
46631
- import_fs43.default.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
46951
+ const dir = import_path42.default.dirname(SNAPSHOT_STACK_PATH);
46952
+ if (!import_fs44.default.existsSync(dir)) import_fs44.default.mkdirSync(dir, { recursive: true });
46953
+ import_fs44.default.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
46632
46954
  }
46633
46955
  function extractFilePath(args) {
46634
46956
  if (!args || typeof args !== "object") return null;
@@ -46648,12 +46970,12 @@ function buildArgsSummary(tool, args) {
46648
46970
  return "";
46649
46971
  }
46650
46972
  function findProjectRoot(filePath) {
46651
- let dir = import_path41.default.dirname(filePath);
46973
+ let dir = import_path42.default.dirname(filePath);
46652
46974
  while (true) {
46653
- if (import_fs43.default.existsSync(import_path41.default.join(dir, ".git")) || import_fs43.default.existsSync(import_path41.default.join(dir, "package.json"))) {
46975
+ if (import_fs44.default.existsSync(import_path42.default.join(dir, ".git")) || import_fs44.default.existsSync(import_path42.default.join(dir, "package.json"))) {
46654
46976
  return dir;
46655
46977
  }
46656
- const parent = import_path41.default.dirname(dir);
46978
+ const parent = import_path42.default.dirname(dir);
46657
46979
  if (parent === dir) return process.cwd();
46658
46980
  dir = parent;
46659
46981
  }
@@ -46661,7 +46983,7 @@ function findProjectRoot(filePath) {
46661
46983
  function normalizeCwdForHash(cwd) {
46662
46984
  let normalized;
46663
46985
  try {
46664
- normalized = import_fs43.default.realpathSync(cwd);
46986
+ normalized = import_fs44.default.realpathSync(cwd);
46665
46987
  } catch {
46666
46988
  normalized = cwd;
46667
46989
  }
@@ -46671,16 +46993,16 @@ function normalizeCwdForHash(cwd) {
46671
46993
  }
46672
46994
  function getShadowRepoDir(cwd) {
46673
46995
  const hash = import_crypto12.default.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
46674
- return import_path41.default.join(import_os38.default.homedir(), ".node9", "snapshots", hash);
46996
+ return import_path42.default.join(import_os40.default.homedir(), ".node9", "snapshots", hash);
46675
46997
  }
46676
46998
  function cleanOrphanedIndexFiles(shadowDir) {
46677
46999
  try {
46678
47000
  const cutoff = Date.now() - 6e4;
46679
- for (const f of import_fs43.default.readdirSync(shadowDir)) {
47001
+ for (const f of import_fs44.default.readdirSync(shadowDir)) {
46680
47002
  if (f.startsWith("index_")) {
46681
- const fp = import_path41.default.join(shadowDir, f);
47003
+ const fp = import_path42.default.join(shadowDir, f);
46682
47004
  try {
46683
- if (import_fs43.default.statSync(fp).mtimeMs < cutoff) import_fs43.default.unlinkSync(fp);
47005
+ if (import_fs44.default.statSync(fp).mtimeMs < cutoff) import_fs44.default.unlinkSync(fp);
46684
47006
  } catch {
46685
47007
  }
46686
47008
  }
@@ -46692,7 +47014,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
46692
47014
  const hardcoded = [".git", ".node9"];
46693
47015
  const lines = [...hardcoded, ...ignorePaths].join("\n");
46694
47016
  try {
46695
- import_fs43.default.writeFileSync(import_path41.default.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
47017
+ import_fs44.default.writeFileSync(import_path42.default.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
46696
47018
  } catch {
46697
47019
  }
46698
47020
  }
@@ -46705,25 +47027,25 @@ function ensureShadowRepo(shadowDir, cwd) {
46705
47027
  timeout: 3e3
46706
47028
  });
46707
47029
  if (check.status === 0) {
46708
- const ptPath = import_path41.default.join(shadowDir, "project-path.txt");
47030
+ const ptPath = import_path42.default.join(shadowDir, "project-path.txt");
46709
47031
  try {
46710
- const stored = import_fs43.default.readFileSync(ptPath, "utf8").trim();
47032
+ const stored = import_fs44.default.readFileSync(ptPath, "utf8").trim();
46711
47033
  if (stored === normalizedCwd) return true;
46712
47034
  if (process.env.NODE9_DEBUG === "1")
46713
47035
  console.error(
46714
47036
  `[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
46715
47037
  );
46716
- import_fs43.default.rmSync(shadowDir, { recursive: true, force: true });
47038
+ import_fs44.default.rmSync(shadowDir, { recursive: true, force: true });
46717
47039
  } catch {
46718
47040
  try {
46719
- import_fs43.default.writeFileSync(ptPath, normalizedCwd, "utf8");
47041
+ import_fs44.default.writeFileSync(ptPath, normalizedCwd, "utf8");
46720
47042
  } catch {
46721
47043
  }
46722
47044
  return true;
46723
47045
  }
46724
47046
  }
46725
47047
  try {
46726
- import_fs43.default.mkdirSync(shadowDir, { recursive: true });
47048
+ import_fs44.default.mkdirSync(shadowDir, { recursive: true });
46727
47049
  } catch {
46728
47050
  }
46729
47051
  const init = (0, import_child_process6.spawnSync)("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
@@ -46732,7 +47054,7 @@ function ensureShadowRepo(shadowDir, cwd) {
46732
47054
  if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
46733
47055
  return false;
46734
47056
  }
46735
- const configFile = import_path41.default.join(shadowDir, "config");
47057
+ const configFile = import_path42.default.join(shadowDir, "config");
46736
47058
  (0, import_child_process6.spawnSync)("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
46737
47059
  timeout: 3e3
46738
47060
  });
@@ -46740,7 +47062,7 @@ function ensureShadowRepo(shadowDir, cwd) {
46740
47062
  timeout: 3e3
46741
47063
  });
46742
47064
  try {
46743
- import_fs43.default.writeFileSync(import_path41.default.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
47065
+ import_fs44.default.writeFileSync(import_path42.default.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
46744
47066
  } catch {
46745
47067
  }
46746
47068
  return true;
@@ -46763,12 +47085,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
46763
47085
  let indexFile = null;
46764
47086
  try {
46765
47087
  const rawFilePath = extractFilePath(args);
46766
- const absFilePath = rawFilePath && import_path41.default.isAbsolute(rawFilePath) ? rawFilePath : null;
47088
+ const absFilePath = rawFilePath && import_path42.default.isAbsolute(rawFilePath) ? rawFilePath : null;
46767
47089
  const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
46768
47090
  const shadowDir = getShadowRepoDir(cwd);
46769
47091
  if (!ensureShadowRepo(shadowDir, cwd)) return null;
46770
47092
  writeShadowExcludes(shadowDir, ignorePaths);
46771
- indexFile = import_path41.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
47093
+ indexFile = import_path42.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
46772
47094
  const shadowEnv = {
46773
47095
  ...process.env,
46774
47096
  GIT_DIR: shadowDir,
@@ -46840,7 +47162,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
46840
47162
  writeStack(stack);
46841
47163
  const entry = stack[stack.length - 1];
46842
47164
  notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
46843
- import_fs43.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
47165
+ import_fs44.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
46844
47166
  if (shouldGc) {
46845
47167
  (0, import_child_process6.spawn)("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
46846
47168
  }
@@ -46851,7 +47173,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
46851
47173
  } finally {
46852
47174
  if (indexFile) {
46853
47175
  try {
46854
- import_fs43.default.unlinkSync(indexFile);
47176
+ import_fs44.default.unlinkSync(indexFile);
46855
47177
  } catch {
46856
47178
  }
46857
47179
  }
@@ -46927,9 +47249,9 @@ function applyUndo(hash, cwd) {
46927
47249
  timeout: GIT_TIMEOUT
46928
47250
  }).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
46929
47251
  for (const file of [...tracked, ...untracked]) {
46930
- const fullPath = import_path41.default.join(dir, file);
46931
- if (!snapshotFiles.has(file) && import_fs43.default.existsSync(fullPath)) {
46932
- import_fs43.default.unlinkSync(fullPath);
47252
+ const fullPath = import_path42.default.join(dir, file);
47253
+ if (!snapshotFiles.has(file) && import_fs44.default.existsSync(fullPath)) {
47254
+ import_fs44.default.unlinkSync(fullPath);
46933
47255
  }
46934
47256
  }
46935
47257
  return true;
@@ -46939,12 +47261,12 @@ function applyUndo(hash, cwd) {
46939
47261
  }
46940
47262
 
46941
47263
  // src/skill-pin.ts
46942
- var import_fs44 = __toESM(require("fs"));
46943
- var import_path42 = __toESM(require("path"));
46944
- var import_os39 = __toESM(require("os"));
47264
+ var import_fs45 = __toESM(require("fs"));
47265
+ var import_path43 = __toESM(require("path"));
47266
+ var import_os41 = __toESM(require("os"));
46945
47267
  var import_crypto13 = __toESM(require("crypto"));
46946
47268
  function getPinsFilePath2() {
46947
- return import_path42.default.join(import_os39.default.homedir(), ".node9", "skill-pins.json");
47269
+ return import_path43.default.join(import_os41.default.homedir(), ".node9", "skill-pins.json");
46948
47270
  }
46949
47271
  var MAX_FILES = 5e3;
46950
47272
  var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
@@ -46958,18 +47280,18 @@ function walkDir(root) {
46958
47280
  if (out.length >= MAX_FILES) return;
46959
47281
  let entries;
46960
47282
  try {
46961
- entries = import_fs44.default.readdirSync(dir, { withFileTypes: true });
47283
+ entries = import_fs45.default.readdirSync(dir, { withFileTypes: true });
46962
47284
  } catch {
46963
47285
  return;
46964
47286
  }
46965
47287
  entries.sort((a, b) => a.name.localeCompare(b.name));
46966
47288
  for (const entry of entries) {
46967
47289
  if (out.length >= MAX_FILES) return;
46968
- const full = import_path42.default.join(dir, entry.name);
46969
- const rel = relDir ? import_path42.default.posix.join(relDir, entry.name) : entry.name;
47290
+ const full = import_path43.default.join(dir, entry.name);
47291
+ const rel = relDir ? import_path43.default.posix.join(relDir, entry.name) : entry.name;
46970
47292
  let lst;
46971
47293
  try {
46972
- lst = import_fs44.default.lstatSync(full);
47294
+ lst = import_fs45.default.lstatSync(full);
46973
47295
  } catch {
46974
47296
  continue;
46975
47297
  }
@@ -46981,7 +47303,7 @@ function walkDir(root) {
46981
47303
  if (!lst.isFile()) continue;
46982
47304
  if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
46983
47305
  try {
46984
- const buf = import_fs44.default.readFileSync(full);
47306
+ const buf = import_fs45.default.readFileSync(full);
46985
47307
  totalBytes += buf.length;
46986
47308
  out.push({ rel, hash: sha256Bytes(buf) });
46987
47309
  } catch {
@@ -46995,14 +47317,14 @@ function walkDir(root) {
46995
47317
  function hashSkillRoot(absPath) {
46996
47318
  let lst;
46997
47319
  try {
46998
- lst = import_fs44.default.lstatSync(absPath);
47320
+ lst = import_fs45.default.lstatSync(absPath);
46999
47321
  } catch {
47000
47322
  return { exists: false, contentHash: "", fileCount: 0 };
47001
47323
  }
47002
47324
  if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
47003
47325
  if (lst.isFile()) {
47004
47326
  try {
47005
- return { exists: true, contentHash: sha256Bytes(import_fs44.default.readFileSync(absPath)), fileCount: 1 };
47327
+ return { exists: true, contentHash: sha256Bytes(import_fs45.default.readFileSync(absPath)), fileCount: 1 };
47006
47328
  } catch {
47007
47329
  return { exists: false, contentHash: "", fileCount: 0 };
47008
47330
  }
@@ -47020,7 +47342,7 @@ function getRootKey(absPath) {
47020
47342
  function readSkillPinsSafe() {
47021
47343
  const filePath = getPinsFilePath2();
47022
47344
  try {
47023
- const raw = import_fs44.default.readFileSync(filePath, "utf-8");
47345
+ const raw = import_fs45.default.readFileSync(filePath, "utf-8");
47024
47346
  if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
47025
47347
  const parsed = JSON.parse(raw);
47026
47348
  if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
@@ -47040,10 +47362,10 @@ function readSkillPins() {
47040
47362
  }
47041
47363
  function writeSkillPins(data) {
47042
47364
  const filePath = getPinsFilePath2();
47043
- import_fs44.default.mkdirSync(import_path42.default.dirname(filePath), { recursive: true });
47365
+ import_fs45.default.mkdirSync(import_path43.default.dirname(filePath), { recursive: true });
47044
47366
  const tmp = `${filePath}.${import_crypto13.default.randomBytes(6).toString("hex")}.tmp`;
47045
- import_fs44.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
47046
- import_fs44.default.renameSync(tmp, filePath);
47367
+ import_fs45.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
47368
+ import_fs45.default.renameSync(tmp, filePath);
47047
47369
  }
47048
47370
  function removePin2(rootKey) {
47049
47371
  const pins = readSkillPins();
@@ -47087,36 +47409,36 @@ function verifyAndPinRoots(roots) {
47087
47409
  return { kind: "verified" };
47088
47410
  }
47089
47411
  function defaultSkillRoots(_cwd) {
47090
- const marketplaces = import_path42.default.join(import_os39.default.homedir(), ".claude", "plugins", "marketplaces");
47412
+ const marketplaces = import_path43.default.join(import_os41.default.homedir(), ".claude", "plugins", "marketplaces");
47091
47413
  const roots = [];
47092
47414
  let registries;
47093
47415
  try {
47094
- registries = import_fs44.default.readdirSync(marketplaces, { withFileTypes: true });
47416
+ registries = import_fs45.default.readdirSync(marketplaces, { withFileTypes: true });
47095
47417
  } catch {
47096
47418
  return [];
47097
47419
  }
47098
47420
  for (const registry of registries) {
47099
47421
  if (!registry.isDirectory()) continue;
47100
- const pluginsDir = import_path42.default.join(marketplaces, registry.name, "plugins");
47422
+ const pluginsDir = import_path43.default.join(marketplaces, registry.name, "plugins");
47101
47423
  let plugins;
47102
47424
  try {
47103
- plugins = import_fs44.default.readdirSync(pluginsDir, { withFileTypes: true });
47425
+ plugins = import_fs45.default.readdirSync(pluginsDir, { withFileTypes: true });
47104
47426
  } catch {
47105
47427
  continue;
47106
47428
  }
47107
47429
  for (const plugin of plugins) {
47108
47430
  if (!plugin.isDirectory()) continue;
47109
- roots.push(import_path42.default.join(pluginsDir, plugin.name));
47431
+ roots.push(import_path43.default.join(pluginsDir, plugin.name));
47110
47432
  }
47111
47433
  }
47112
47434
  return roots;
47113
47435
  }
47114
47436
  function resolveUserSkillRoot(entry, cwd) {
47115
47437
  if (!entry) return null;
47116
- if (entry.startsWith("~/") || entry === "~") return import_path42.default.join(import_os39.default.homedir(), entry.slice(1));
47117
- if (import_path42.default.isAbsolute(entry)) return entry;
47118
- if (!cwd || !import_path42.default.isAbsolute(cwd)) return null;
47119
- return import_path42.default.join(cwd, entry);
47438
+ if (entry.startsWith("~/") || entry === "~") return import_path43.default.join(import_os41.default.homedir(), entry.slice(1));
47439
+ if (import_path43.default.isAbsolute(entry)) return entry;
47440
+ if (!cwd || !import_path43.default.isAbsolute(cwd)) return null;
47441
+ return import_path43.default.join(cwd, entry);
47120
47442
  }
47121
47443
 
47122
47444
  // src/cli/commands/check.ts
@@ -47124,12 +47446,12 @@ init_dlp();
47124
47446
  init_audit();
47125
47447
 
47126
47448
  // src/review-pending.ts
47127
- var import_fs45 = __toESM(require("fs"));
47128
- var import_os40 = __toESM(require("os"));
47129
- var import_path43 = __toESM(require("path"));
47449
+ var import_fs46 = __toESM(require("fs"));
47450
+ var import_os42 = __toESM(require("os"));
47451
+ var import_path44 = __toESM(require("path"));
47130
47452
  init_hasher();
47131
47453
  function storePath() {
47132
- return process.env.NODE9_PENDING_STORE || import_path43.default.join(import_os40.default.homedir(), ".node9", "pending-reviews.json");
47454
+ return process.env.NODE9_PENDING_STORE || import_path44.default.join(import_os42.default.homedir(), ".node9", "pending-reviews.json");
47133
47455
  }
47134
47456
  var TTL_MS2 = 6 * 60 * 60 * 1e3;
47135
47457
  var MAX_ENTRIES = 500;
@@ -47146,7 +47468,7 @@ function reviewCorrelationKey(payload) {
47146
47468
  }
47147
47469
  function read() {
47148
47470
  try {
47149
- const parsed = JSON.parse(import_fs45.default.readFileSync(storePath(), "utf-8"));
47471
+ const parsed = JSON.parse(import_fs46.default.readFileSync(storePath(), "utf-8"));
47150
47472
  if (parsed && Array.isArray(parsed.entries)) return parsed;
47151
47473
  } catch {
47152
47474
  }
@@ -47155,11 +47477,11 @@ function read() {
47155
47477
  function write(store) {
47156
47478
  try {
47157
47479
  const p = storePath();
47158
- const dir = import_path43.default.dirname(p);
47159
- if (!import_fs45.default.existsSync(dir)) import_fs45.default.mkdirSync(dir, { recursive: true });
47480
+ const dir = import_path44.default.dirname(p);
47481
+ if (!import_fs46.default.existsSync(dir)) import_fs46.default.mkdirSync(dir, { recursive: true });
47160
47482
  const tmp = `${p}.${process.pid}.tmp`;
47161
- import_fs45.default.writeFileSync(tmp, JSON.stringify(store));
47162
- import_fs45.default.renameSync(tmp, p);
47483
+ import_fs46.default.writeFileSync(tmp, JSON.stringify(store));
47484
+ import_fs46.default.renameSync(tmp, p);
47163
47485
  } catch {
47164
47486
  }
47165
47487
  }
@@ -47272,9 +47594,9 @@ function registerCheckCommand(program2) {
47272
47594
  } catch (err2) {
47273
47595
  const tempConfig = getConfig();
47274
47596
  if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
47275
- const logPath = import_path44.default.join(import_os41.default.homedir(), ".node9", "hook-debug.log");
47597
+ const logPath = import_path45.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log");
47276
47598
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
47277
- import_fs46.default.appendFileSync(
47599
+ import_fs47.default.appendFileSync(
47278
47600
  logPath,
47279
47601
  `[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
47280
47602
  RAW: ${raw}
@@ -47287,14 +47609,14 @@ RAW: ${raw}
47287
47609
  const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
47288
47610
  if (process.env.NODE9_DEBUG === "1") {
47289
47611
  try {
47290
- const logPath = import_path44.default.join(import_os41.default.homedir(), ".node9", "hook-debug.log");
47291
- if (!import_fs46.default.existsSync(import_path44.default.dirname(logPath)))
47292
- import_fs46.default.mkdirSync(import_path44.default.dirname(logPath), { recursive: true });
47612
+ const logPath = import_path45.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log");
47613
+ if (!import_fs47.default.existsSync(import_path45.default.dirname(logPath)))
47614
+ import_fs47.default.mkdirSync(import_path45.default.dirname(logPath), { recursive: true });
47293
47615
  const sanitized = JSON.stringify({
47294
47616
  ...payload,
47295
47617
  prompt: `<redacted, ${prompt.length} bytes>`
47296
47618
  });
47297
- import_fs46.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
47619
+ import_fs47.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
47298
47620
  `);
47299
47621
  } catch {
47300
47622
  }
@@ -47315,8 +47637,8 @@ RAW: ${raw}
47315
47637
  );
47316
47638
  const reason = `\u{1F6A8} Node9 DLP: ${dlpMatch.patternName} detected in prompt (${dlpMatch.redactedSample}). Prompt was not submitted \u2014 remove the credential and try again.`;
47317
47639
  try {
47318
- const ttyFd = import_fs46.default.openSync("/dev/tty", "w");
47319
- import_fs46.default.writeSync(
47640
+ const ttyFd = import_fs47.default.openSync("/dev/tty", "w");
47641
+ import_fs47.default.writeSync(
47320
47642
  ttyFd,
47321
47643
  import_chalk9.default.bgRed.white.bold(`
47322
47644
  \u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
@@ -47326,7 +47648,7 @@ RAW: ${raw}
47326
47648
 
47327
47649
  `)
47328
47650
  );
47329
- import_fs46.default.closeSync(ttyFd);
47651
+ import_fs47.default.closeSync(ttyFd);
47330
47652
  } catch {
47331
47653
  }
47332
47654
  const isCodex = agent2 === "Codex";
@@ -47345,16 +47667,17 @@ RAW: ${raw}
47345
47667
  process.exit(2);
47346
47668
  }
47347
47669
  const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
47348
- const safeCwdForConfig = typeof payloadCwd === "string" && import_path44.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
47670
+ const safeCwdForConfig = typeof payloadCwd === "string" && import_path45.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
47349
47671
  const config = getConfig(safeCwdForConfig);
47350
- if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
47672
+ const daemonDown = !isDaemonRunning();
47673
+ if (config.settings.autoStartDaemon && daemonDown && !process.env.NODE9_NO_AUTO_DAEMON) {
47351
47674
  try {
47352
47675
  const scriptPath = process.argv[1];
47353
- if (typeof scriptPath !== "string" || !import_path44.default.isAbsolute(scriptPath))
47676
+ if (typeof scriptPath !== "string" || !import_path45.default.isAbsolute(scriptPath))
47354
47677
  throw new Error("node9: argv[1] is not an absolute path");
47355
- const resolvedScript = import_fs46.default.realpathSync(scriptPath);
47356
- const packageDist = import_fs46.default.realpathSync(import_path44.default.resolve(__dirname, "../.."));
47357
- if (!resolvedScript.startsWith(packageDist + import_path44.default.sep) && resolvedScript !== packageDist)
47678
+ const resolvedScript = import_fs47.default.realpathSync(scriptPath);
47679
+ const packageDist = import_fs47.default.realpathSync(import_path45.default.resolve(__dirname, "../.."));
47680
+ if (!resolvedScript.startsWith(packageDist + import_path45.default.sep) && resolvedScript !== packageDist)
47358
47681
  throw new Error(
47359
47682
  `node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
47360
47683
  );
@@ -47369,17 +47692,27 @@ RAW: ${raw}
47369
47692
  ]) {
47370
47693
  delete safeEnv[key];
47371
47694
  }
47372
- const d = (0, import_child_process7.spawn)(process.execPath, [scriptPath, "daemon"], {
47373
- detached: true,
47374
- stdio: "ignore",
47375
- env: { ...safeEnv, NODE9_AUTO_STARTED: "1" }
47376
- });
47377
- d.unref();
47695
+ const startupFd = openStartupLogFd();
47696
+ try {
47697
+ const d = (0, import_child_process7.spawn)(process.execPath, [scriptPath, "daemon"], {
47698
+ detached: true,
47699
+ stdio: ["ignore", "ignore", startupFd ?? "ignore"],
47700
+ env: { ...safeEnv, NODE9_AUTO_STARTED: "1" }
47701
+ });
47702
+ d.unref();
47703
+ } finally {
47704
+ if (startupFd !== void 0) {
47705
+ try {
47706
+ import_fs47.default.closeSync(startupFd);
47707
+ } catch {
47708
+ }
47709
+ }
47710
+ }
47378
47711
  } catch (spawnErr) {
47379
- const logPath = import_path44.default.join(import_os41.default.homedir(), ".node9", "hook-debug.log");
47712
+ const logPath = import_path45.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log");
47380
47713
  const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
47381
47714
  try {
47382
- import_fs46.default.appendFileSync(
47715
+ import_fs47.default.appendFileSync(
47383
47716
  logPath,
47384
47717
  `[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
47385
47718
  `
@@ -47387,12 +47720,16 @@ RAW: ${raw}
47387
47720
  } catch {
47388
47721
  }
47389
47722
  }
47723
+ } else if (daemonDown && !isTestingMode()) {
47724
+ logAutostartSkipThrottled(
47725
+ !config.settings.autoStartDaemon ? "autoStartDaemon=false" : process.env.NODE9_NO_AUTO_DAEMON ? "NODE9_NO_AUTO_DAEMON" : "unknown"
47726
+ );
47390
47727
  }
47391
47728
  if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
47392
- const logPath = import_path44.default.join(import_os41.default.homedir(), ".node9", "hook-debug.log");
47393
- if (!import_fs46.default.existsSync(import_path44.default.dirname(logPath)))
47394
- import_fs46.default.mkdirSync(import_path44.default.dirname(logPath), { recursive: true });
47395
- import_fs46.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
47729
+ const logPath = import_path45.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log");
47730
+ if (!import_fs47.default.existsSync(import_path45.default.dirname(logPath)))
47731
+ import_fs47.default.mkdirSync(import_path45.default.dirname(logPath), { recursive: true });
47732
+ import_fs47.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
47396
47733
  `);
47397
47734
  }
47398
47735
  const rawToolName = sanitize2(extractToolName(payload));
@@ -47406,8 +47743,8 @@ RAW: ${raw}
47406
47743
  const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
47407
47744
  let ttyFd = null;
47408
47745
  try {
47409
- ttyFd = import_fs46.default.openSync("/dev/tty", "w");
47410
- const writeTty = (line) => import_fs46.default.writeSync(ttyFd, line + "\n");
47746
+ ttyFd = import_fs47.default.openSync("/dev/tty", "w");
47747
+ const writeTty = (line) => import_fs47.default.writeSync(ttyFd, line + "\n");
47411
47748
  if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
47412
47749
  writeTty(import_chalk9.default.bgRed.white.bold(`
47413
47750
  \u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
@@ -47426,7 +47763,7 @@ RAW: ${raw}
47426
47763
  } finally {
47427
47764
  if (ttyFd !== null)
47428
47765
  try {
47429
- import_fs46.default.closeSync(ttyFd);
47766
+ import_fs47.default.closeSync(ttyFd);
47430
47767
  } catch {
47431
47768
  }
47432
47769
  }
@@ -47483,8 +47820,8 @@ RAW: ${raw}
47483
47820
  } catch {
47484
47821
  }
47485
47822
  try {
47486
- const ttyFd = import_fs46.default.openSync("/dev/tty", "w");
47487
- import_fs46.default.writeSync(
47823
+ const ttyFd = import_fs47.default.openSync("/dev/tty", "w");
47824
+ import_fs47.default.writeSync(
47488
47825
  ttyFd,
47489
47826
  import_chalk9.default.yellow(
47490
47827
  `
@@ -47492,7 +47829,7 @@ RAW: ${raw}
47492
47829
  `
47493
47830
  )
47494
47831
  );
47495
- import_fs46.default.closeSync(ttyFd);
47832
+ import_fs47.default.closeSync(ttyFd);
47496
47833
  } catch {
47497
47834
  }
47498
47835
  if (agent === "GitHub Copilot") {
@@ -47524,17 +47861,17 @@ RAW: ${raw}
47524
47861
  const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
47525
47862
  if (skillPinCfg.enabled && safeSessionId) {
47526
47863
  try {
47527
- const sessionsDir = import_path44.default.join(import_os41.default.homedir(), ".node9", "skill-sessions");
47528
- const flagPath = import_path44.default.join(sessionsDir, `${safeSessionId}.json`);
47864
+ const sessionsDir = import_path45.default.join(import_os43.default.homedir(), ".node9", "skill-sessions");
47865
+ const flagPath = import_path45.default.join(sessionsDir, `${safeSessionId}.json`);
47529
47866
  let flag = null;
47530
47867
  try {
47531
- flag = JSON.parse(import_fs46.default.readFileSync(flagPath, "utf-8"));
47868
+ flag = JSON.parse(import_fs47.default.readFileSync(flagPath, "utf-8"));
47532
47869
  } catch {
47533
47870
  }
47534
47871
  const writeFlag = (data2) => {
47535
47872
  try {
47536
- import_fs46.default.mkdirSync(sessionsDir, { recursive: true });
47537
- import_fs46.default.writeFileSync(
47873
+ import_fs47.default.mkdirSync(sessionsDir, { recursive: true });
47874
+ import_fs47.default.writeFileSync(
47538
47875
  flagPath,
47539
47876
  JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
47540
47877
  { mode: 384 }
@@ -47545,8 +47882,8 @@ RAW: ${raw}
47545
47882
  const sendSkillWarn = (detail, recoveryCmd) => {
47546
47883
  let ttyFd = null;
47547
47884
  try {
47548
- ttyFd = import_fs46.default.openSync("/dev/tty", "w");
47549
- const w = (line) => import_fs46.default.writeSync(ttyFd, line + "\n");
47885
+ ttyFd = import_fs47.default.openSync("/dev/tty", "w");
47886
+ const w = (line) => import_fs47.default.writeSync(ttyFd, line + "\n");
47550
47887
  w(import_chalk9.default.yellow(`
47551
47888
  \u26A0\uFE0F Node9: installed skill drift detected`));
47552
47889
  w(import_chalk9.default.gray(` ${detail}`));
@@ -47561,7 +47898,7 @@ RAW: ${raw}
47561
47898
  } finally {
47562
47899
  if (ttyFd !== null)
47563
47900
  try {
47564
- import_fs46.default.closeSync(ttyFd);
47901
+ import_fs47.default.closeSync(ttyFd);
47565
47902
  } catch {
47566
47903
  }
47567
47904
  }
@@ -47577,7 +47914,7 @@ RAW: ${raw}
47577
47914
  return;
47578
47915
  }
47579
47916
  if (!flag || flag.state !== "verified" && flag.state !== "warned") {
47580
- const absoluteCwd = typeof payloadCwd === "string" && import_path44.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
47917
+ const absoluteCwd = typeof payloadCwd === "string" && import_path45.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
47581
47918
  const extraRoots = skillPinCfg.roots;
47582
47919
  const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
47583
47920
  const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
@@ -47618,10 +47955,10 @@ RAW: ${raw}
47618
47955
  }
47619
47956
  try {
47620
47957
  const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
47621
- for (const name of import_fs46.default.readdirSync(sessionsDir)) {
47622
- const p = import_path44.default.join(sessionsDir, name);
47958
+ for (const name of import_fs47.default.readdirSync(sessionsDir)) {
47959
+ const p = import_path45.default.join(sessionsDir, name);
47623
47960
  try {
47624
- if (import_fs46.default.statSync(p).mtimeMs < cutoff) import_fs46.default.unlinkSync(p);
47961
+ if (import_fs47.default.statSync(p).mtimeMs < cutoff) import_fs47.default.unlinkSync(p);
47625
47962
  } catch {
47626
47963
  }
47627
47964
  }
@@ -47631,9 +47968,9 @@ RAW: ${raw}
47631
47968
  } catch (err2) {
47632
47969
  if (process.env.NODE9_DEBUG === "1") {
47633
47970
  try {
47634
- const dbg = import_path44.default.join(import_os41.default.homedir(), ".node9", "hook-debug.log");
47971
+ const dbg = import_path45.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log");
47635
47972
  const msg = err2 instanceof Error ? err2.message : String(err2);
47636
- import_fs46.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
47973
+ import_fs47.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
47637
47974
  `);
47638
47975
  } catch {
47639
47976
  }
@@ -47643,7 +47980,7 @@ RAW: ${raw}
47643
47980
  if (shouldSnapshot(toolName, toolInput, config)) {
47644
47981
  await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
47645
47982
  }
47646
- const safeCwdForAuth = typeof payloadCwd === "string" && import_path44.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
47983
+ const safeCwdForAuth = typeof payloadCwd === "string" && import_path45.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
47647
47984
  const askMode = resolveAskMode(agent, opts, config);
47648
47985
  const result = await authorizeHeadless(toolName, toolInput, meta, {
47649
47986
  cwd: safeCwdForAuth,
@@ -47661,12 +47998,12 @@ RAW: ${raw}
47661
47998
  }
47662
47999
  if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
47663
48000
  try {
47664
- const tty = import_fs46.default.openSync("/dev/tty", "w");
47665
- import_fs46.default.writeSync(
48001
+ const tty = import_fs47.default.openSync("/dev/tty", "w");
48002
+ import_fs47.default.writeSync(
47666
48003
  tty,
47667
48004
  import_chalk9.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
47668
48005
  );
47669
- import_fs46.default.closeSync(tty);
48006
+ import_fs47.default.closeSync(tty);
47670
48007
  } catch {
47671
48008
  }
47672
48009
  const daemonReady = await autoStartDaemonAndWait();
@@ -47693,9 +48030,9 @@ RAW: ${raw}
47693
48030
  });
47694
48031
  } catch (err2) {
47695
48032
  if (process.env.NODE9_DEBUG === "1") {
47696
- const logPath = import_path44.default.join(import_os41.default.homedir(), ".node9", "hook-debug.log");
48033
+ const logPath = import_path45.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log");
47697
48034
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
47698
- import_fs46.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
48035
+ import_fs47.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
47699
48036
  `);
47700
48037
  }
47701
48038
  process.exit(0);
@@ -47729,9 +48066,9 @@ RAW: ${raw}
47729
48066
  }
47730
48067
 
47731
48068
  // src/cli/commands/log.ts
47732
- var import_fs47 = __toESM(require("fs"));
47733
- var import_path45 = __toESM(require("path"));
47734
- var import_os42 = __toESM(require("os"));
48069
+ var import_fs48 = __toESM(require("fs"));
48070
+ var import_path46 = __toESM(require("path"));
48071
+ var import_os44 = __toESM(require("os"));
47735
48072
  init_audit();
47736
48073
  init_config();
47737
48074
  init_daemon();
@@ -47841,10 +48178,10 @@ function registerLogCommand(program2) {
47841
48178
  if (rawToolName !== tool) entry.agentToolName = rawToolName;
47842
48179
  const payloadSessionId = payload.session_id ?? payload.conversationId;
47843
48180
  if (payloadSessionId) entry.sessionId = payloadSessionId;
47844
- const logPath = import_path45.default.join(import_os42.default.homedir(), ".node9", "audit.log");
47845
- if (!import_fs47.default.existsSync(import_path45.default.dirname(logPath)))
47846
- import_fs47.default.mkdirSync(import_path45.default.dirname(logPath), { recursive: true });
47847
- import_fs47.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
48181
+ const logPath = import_path46.default.join(import_os44.default.homedir(), ".node9", "audit.log");
48182
+ if (!import_fs48.default.existsSync(import_path46.default.dirname(logPath)))
48183
+ import_fs48.default.mkdirSync(import_path46.default.dirname(logPath), { recursive: true });
48184
+ import_fs48.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
47848
48185
  if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
47849
48186
  const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
47850
48187
  if (command) {
@@ -47878,7 +48215,7 @@ function registerLogCommand(program2) {
47878
48215
  }
47879
48216
  }
47880
48217
  const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
47881
- const safeCwd = typeof payloadCwd === "string" && import_path45.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
48218
+ const safeCwd = typeof payloadCwd === "string" && import_path46.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
47882
48219
  const config = getConfig(safeCwd);
47883
48220
  {
47884
48221
  const toolOutput = payload.tool_response?.output;
@@ -47955,9 +48292,9 @@ function registerLogCommand(program2) {
47955
48292
  const msg = err2 instanceof Error ? err2.message : String(err2);
47956
48293
  process.stderr.write(`[Node9] audit log error: ${msg}
47957
48294
  `);
47958
- const debugPath = import_path45.default.join(import_os42.default.homedir(), ".node9", "hook-debug.log");
48295
+ const debugPath = import_path46.default.join(import_os44.default.homedir(), ".node9", "hook-debug.log");
47959
48296
  try {
47960
- import_fs47.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
48297
+ import_fs48.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
47961
48298
  `);
47962
48299
  } catch {
47963
48300
  }
@@ -47982,15 +48319,15 @@ function registerLogCommand(program2) {
47982
48319
 
47983
48320
  // src/cli/commands/shield.ts
47984
48321
  var import_chalk10 = __toESM(require("chalk"));
47985
- var import_fs49 = __toESM(require("fs"));
47986
- var import_path47 = __toESM(require("path"));
47987
- var import_os43 = __toESM(require("os"));
48322
+ var import_fs50 = __toESM(require("fs"));
48323
+ var import_path48 = __toESM(require("path"));
48324
+ var import_os45 = __toESM(require("os"));
47988
48325
  init_shields();
47989
48326
  init_build();
47990
48327
 
47991
48328
  // src/shields/create.ts
47992
- var import_fs48 = __toESM(require("fs"));
47993
- var import_path46 = __toESM(require("path"));
48329
+ var import_fs49 = __toESM(require("fs"));
48330
+ var import_path47 = __toESM(require("path"));
47994
48331
  init_dist();
47995
48332
  init_shields();
47996
48333
  init_audit();
@@ -48010,8 +48347,8 @@ function createShield(def, opts = {}) {
48010
48347
  error: `"${name}" is a built-in shield \u2014 choose a different name (a user shield with this name would shadow the built-in).`
48011
48348
  };
48012
48349
  }
48013
- const filePath = import_path46.default.join(USER_SHIELDS_DIR_PATH, `${name}.json`);
48014
- if (!opts.overwrite && import_fs48.default.existsSync(filePath)) {
48350
+ const filePath = import_path47.default.join(USER_SHIELDS_DIR_PATH, `${name}.json`);
48351
+ if (!opts.overwrite && import_fs49.default.existsSync(filePath)) {
48015
48352
  return {
48016
48353
  ok: false,
48017
48354
  error: `Shield "${name}" already exists at ${filePath}. Pass --overwrite to replace it.`
@@ -48076,8 +48413,8 @@ var COMMUNITY_INDEX_URL = "https://raw.githubusercontent.com/node9ai/node9-proxy
48076
48413
  function readCloudShields() {
48077
48414
  const out = /* @__PURE__ */ new Set();
48078
48415
  try {
48079
- const file = import_path47.default.join(import_os43.default.homedir(), ".node9", "rules-cache.json");
48080
- const raw = JSON.parse(import_fs49.default.readFileSync(file, "utf-8"));
48416
+ const file = import_path48.default.join(import_os45.default.homedir(), ".node9", "rules-cache.json");
48417
+ const raw = JSON.parse(import_fs50.default.readFileSync(file, "utf-8"));
48081
48418
  for (const r of raw.rules ?? []) {
48082
48419
  const rule = r;
48083
48420
  const fromSource = rule.source?.startsWith("SHIELD:") ? rule.source.slice("SHIELD:".length).toLowerCase() : void 0;
@@ -48394,7 +48731,7 @@ function registerShieldCommand(program2) {
48394
48731
  if (opts.fromFile) {
48395
48732
  let raw;
48396
48733
  try {
48397
- raw = JSON.parse(import_fs49.default.readFileSync(opts.fromFile, "utf-8"));
48734
+ raw = JSON.parse(import_fs50.default.readFileSync(opts.fromFile, "utf-8"));
48398
48735
  } catch (err2) {
48399
48736
  console.error(
48400
48737
  import_chalk10.default.red(`
@@ -48514,16 +48851,33 @@ function registerConfigShowCommand(program2) {
48514
48851
 
48515
48852
  // src/cli/commands/doctor.ts
48516
48853
  var import_chalk11 = __toESM(require("chalk"));
48517
- var import_fs50 = __toESM(require("fs"));
48518
- var import_path48 = __toESM(require("path"));
48519
- var import_os44 = __toESM(require("os"));
48854
+ var import_fs51 = __toESM(require("fs"));
48855
+ var import_path49 = __toESM(require("path"));
48856
+ var import_os46 = __toESM(require("os"));
48520
48857
  var import_child_process8 = require("child_process");
48521
48858
  init_daemon();
48522
48859
  init_config();
48523
48860
  init_agent_wiring();
48861
+ init_sync();
48862
+ init_service();
48863
+
48864
+ // src/lib/relative-time.ts
48865
+ function agoLabel(iso, now = Date.now()) {
48866
+ const ms = now - new Date(iso).getTime();
48867
+ if (!Number.isFinite(ms) || ms < 0) return "just now";
48868
+ const min = Math.floor(ms / 6e4);
48869
+ if (min < 1) return "just now";
48870
+ if (min < 60) return `${min} min ago`;
48871
+ const hr = Math.floor(min / 60);
48872
+ if (hr < 24) return `${hr} hour${hr === 1 ? "" : "s"} ago`;
48873
+ const d = Math.floor(hr / 24);
48874
+ return `${d} day${d === 1 ? "" : "s"} ago`;
48875
+ }
48876
+
48877
+ // src/cli/commands/doctor.ts
48524
48878
  function registerDoctorCommand(program2, version2) {
48525
48879
  program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
48526
- const homeDir2 = import_os44.default.homedir();
48880
+ const homeDir2 = import_os46.default.homedir();
48527
48881
  let failures = 0;
48528
48882
  function pass(msg) {
48529
48883
  console.log(import_chalk11.default.green(" \u2705 ") + msg);
@@ -48569,10 +48923,10 @@ function registerDoctorCommand(program2, version2) {
48569
48923
  );
48570
48924
  }
48571
48925
  section("Configuration");
48572
- const globalConfigPath = import_path48.default.join(homeDir2, ".node9", "config.json");
48573
- if (import_fs50.default.existsSync(globalConfigPath)) {
48926
+ const globalConfigPath = import_path49.default.join(homeDir2, ".node9", "config.json");
48927
+ if (import_fs51.default.existsSync(globalConfigPath)) {
48574
48928
  try {
48575
- JSON.parse(import_fs50.default.readFileSync(globalConfigPath, "utf-8"));
48929
+ JSON.parse(import_fs51.default.readFileSync(globalConfigPath, "utf-8"));
48576
48930
  pass("~/.node9/config.json found and valid");
48577
48931
  } catch {
48578
48932
  fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
@@ -48580,10 +48934,10 @@ function registerDoctorCommand(program2, version2) {
48580
48934
  } else {
48581
48935
  warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
48582
48936
  }
48583
- const projectConfigPath = import_path48.default.join(process.cwd(), "node9.config.json");
48584
- if (import_fs50.default.existsSync(projectConfigPath)) {
48937
+ const projectConfigPath = import_path49.default.join(process.cwd(), "node9.config.json");
48938
+ if (import_fs51.default.existsSync(projectConfigPath)) {
48585
48939
  try {
48586
- JSON.parse(import_fs50.default.readFileSync(projectConfigPath, "utf-8"));
48940
+ JSON.parse(import_fs51.default.readFileSync(projectConfigPath, "utf-8"));
48587
48941
  pass("node9.config.json found and valid (project)");
48588
48942
  } catch {
48589
48943
  fail(
@@ -48592,8 +48946,8 @@ function registerDoctorCommand(program2, version2) {
48592
48946
  );
48593
48947
  }
48594
48948
  }
48595
- const credsPath = import_path48.default.join(homeDir2, ".node9", "credentials.json");
48596
- if (import_fs50.default.existsSync(credsPath)) {
48949
+ const credsPath = import_path49.default.join(homeDir2, ".node9", "credentials.json");
48950
+ if (import_fs51.default.existsSync(credsPath)) {
48597
48951
  pass("Cloud credentials found (~/.node9/credentials.json)");
48598
48952
  } else {
48599
48953
  warn(
@@ -48633,11 +48987,31 @@ function registerDoctorCommand(program2, version2) {
48633
48987
  "Run: node9 daemon --background"
48634
48988
  );
48635
48989
  }
48990
+ const autostart = autostartAdvice({
48991
+ installed: isDaemonServiceInstalled(),
48992
+ enabled: isDaemonServiceEnabled(),
48993
+ cloudEnabled: !!getConfig().settings.approvers?.cloud
48994
+ });
48995
+ if (autostart) warn(autostart.message, autostart.hint);
48996
+ if (import_fs51.default.existsSync(import_path49.default.join(import_os46.default.homedir(), ".node9", "credentials.json")) && getConfig().settings.approvers?.cloud) {
48997
+ section("Policy sync");
48998
+ const health = readSyncHealth();
48999
+ if (isPolicyStale(Date.now(), health)) {
49000
+ const when = health.lastCheckedAt ? `last reached the cloud ${agoLabel(health.lastCheckedAt)}` : "never reached the cloud";
49001
+ const fails = health.consecutiveFailures > 0 ? ` (${health.consecutiveFailures} consecutive failure${health.consecutiveFailures === 1 ? "" : "s"}${health.lastError ? `: ${health.lastError}` : ""})` : "";
49002
+ warn(
49003
+ `Cloud policy is STALE \u2014 ${when}${fails}. The cached policy is still enforced, but changes from the dashboard are not reaching this machine.`,
49004
+ "Run: node9 policy sync (and ensure the daemon autostarts: systemctl --user enable --now node9-daemon)"
49005
+ );
49006
+ } else if (health.lastCheckedAt) {
49007
+ pass(`Cloud policy fresh \u2014 last synced ${agoLabel(health.lastCheckedAt)}`);
49008
+ }
49009
+ }
48636
49010
  section("Cloud audit shipping");
48637
49011
  try {
48638
49012
  const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
48639
49013
  const cfg = getConfig();
48640
- const creds = import_fs50.default.existsSync(import_path48.default.join(import_os44.default.homedir(), ".node9", "credentials.json"));
49014
+ const creds = import_fs51.default.existsSync(import_path49.default.join(import_os46.default.homedir(), ".node9", "credentials.json"));
48641
49015
  if (!creds) {
48642
49016
  warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
48643
49017
  } else if (!cfg.settings.approvers.cloud) {
@@ -48687,9 +49061,9 @@ function registerDoctorCommand(program2, version2) {
48687
49061
 
48688
49062
  // src/cli/commands/audit.ts
48689
49063
  var import_chalk12 = __toESM(require("chalk"));
48690
- var import_fs51 = __toESM(require("fs"));
48691
- var import_path49 = __toESM(require("path"));
48692
- var import_os45 = __toESM(require("os"));
49064
+ var import_fs52 = __toESM(require("fs"));
49065
+ var import_path50 = __toESM(require("path"));
49066
+ var import_os47 = __toESM(require("os"));
48693
49067
  function formatRelativeTime(timestamp) {
48694
49068
  const diff = Date.now() - new Date(timestamp).getTime();
48695
49069
  const sec = Math.floor(diff / 1e3);
@@ -48702,14 +49076,14 @@ function formatRelativeTime(timestamp) {
48702
49076
  }
48703
49077
  function registerAuditCommand(program2) {
48704
49078
  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) => {
48705
- const logPath = import_path49.default.join(import_os45.default.homedir(), ".node9", "audit.log");
48706
- if (!import_fs51.default.existsSync(logPath)) {
49079
+ const logPath = import_path50.default.join(import_os47.default.homedir(), ".node9", "audit.log");
49080
+ if (!import_fs52.default.existsSync(logPath)) {
48707
49081
  console.log(
48708
49082
  import_chalk12.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
48709
49083
  );
48710
49084
  return;
48711
49085
  }
48712
- const raw = import_fs51.default.readFileSync(logPath, "utf-8");
49086
+ const raw = import_fs52.default.readFileSync(logPath, "utf-8");
48713
49087
  const lines = raw.split("\n").filter((l) => l.trim() !== "");
48714
49088
  let entries = lines.flatMap((line) => {
48715
49089
  try {
@@ -48765,9 +49139,9 @@ function registerAuditCommand(program2) {
48765
49139
  var import_chalk13 = __toESM(require("chalk"));
48766
49140
 
48767
49141
  // src/cli/aggregate/report-audit.ts
48768
- var import_fs52 = __toESM(require("fs"));
48769
- var import_os46 = __toESM(require("os"));
48770
- var import_path50 = __toESM(require("path"));
49142
+ var import_fs53 = __toESM(require("fs"));
49143
+ var import_os48 = __toESM(require("os"));
49144
+ var import_path51 = __toESM(require("path"));
48771
49145
  init_costSync();
48772
49146
  init_litellm();
48773
49147
  init_cost_codex();
@@ -48850,8 +49224,8 @@ function getDateRange(period, now) {
48850
49224
  }
48851
49225
  }
48852
49226
  function parseAuditLog(logPath) {
48853
- if (!import_fs52.default.existsSync(logPath)) return [];
48854
- const raw = import_fs52.default.readFileSync(logPath, "utf-8");
49227
+ if (!import_fs53.default.existsSync(logPath)) return [];
49228
+ const raw = import_fs53.default.readFileSync(logPath, "utf-8");
48855
49229
  return raw.split("\n").flatMap((line) => {
48856
49230
  if (!line.trim()) return [];
48857
49231
  try {
@@ -48898,25 +49272,25 @@ function freezeClaudeCost(acc) {
48898
49272
  };
48899
49273
  }
48900
49274
  function processClaudeCostProject(proj, projectsDir, start, end, acc) {
48901
- const projPath = import_path50.default.join(projectsDir, proj);
49275
+ const projPath = import_path51.default.join(projectsDir, proj);
48902
49276
  let files;
48903
49277
  try {
48904
- const stat = import_fs52.default.statSync(projPath);
49278
+ const stat = import_fs53.default.statSync(projPath);
48905
49279
  if (!stat.isDirectory()) return;
48906
- files = import_fs52.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
49280
+ files = import_fs53.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
48907
49281
  } catch {
48908
49282
  return;
48909
49283
  }
48910
49284
  const startMs = start.getTime();
48911
49285
  for (const file of files) {
48912
- const filePath = import_path50.default.join(projPath, file);
49286
+ const filePath = import_path51.default.join(projPath, file);
48913
49287
  try {
48914
- if (import_fs52.default.statSync(filePath).mtimeMs < startMs) continue;
49288
+ if (import_fs53.default.statSync(filePath).mtimeMs < startMs) continue;
48915
49289
  } catch {
48916
49290
  continue;
48917
49291
  }
48918
49292
  try {
48919
- const raw = import_fs52.default.readFileSync(filePath, "utf-8");
49293
+ const raw = import_fs53.default.readFileSync(filePath, "utf-8");
48920
49294
  for (const line of raw.split("\n")) {
48921
49295
  if (!line.trim()) continue;
48922
49296
  let entry;
@@ -48966,10 +49340,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
48966
49340
  }
48967
49341
  function loadClaudeCost(start, end, projectsDir) {
48968
49342
  const acc = emptyClaudeCostAccumulator();
48969
- if (!import_fs52.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
49343
+ if (!import_fs53.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
48970
49344
  let dirs;
48971
49345
  try {
48972
- dirs = import_fs52.default.readdirSync(projectsDir);
49346
+ dirs = import_fs53.default.readdirSync(projectsDir);
48973
49347
  } catch {
48974
49348
  return freezeClaudeCost(acc);
48975
49349
  }
@@ -48981,7 +49355,7 @@ function loadClaudeCost(start, end, projectsDir) {
48981
49355
  function processCodexCostFile(filePath, start, end, acc) {
48982
49356
  let lines;
48983
49357
  try {
48984
- lines = import_fs52.default.readFileSync(filePath, "utf-8").split("\n");
49358
+ lines = import_fs53.default.readFileSync(filePath, "utf-8").split("\n");
48985
49359
  } catch {
48986
49360
  return;
48987
49361
  }
@@ -49036,31 +49410,31 @@ function processCodexCostFile(filePath, start, end, acc) {
49036
49410
  }
49037
49411
  function listCodexSessionFiles2(sessionsBase) {
49038
49412
  const jsonlFiles = [];
49039
- if (!import_fs52.default.existsSync(sessionsBase)) return jsonlFiles;
49413
+ if (!import_fs53.default.existsSync(sessionsBase)) return jsonlFiles;
49040
49414
  try {
49041
- for (const year of import_fs52.default.readdirSync(sessionsBase)) {
49042
- const yearPath = import_path50.default.join(sessionsBase, year);
49415
+ for (const year of import_fs53.default.readdirSync(sessionsBase)) {
49416
+ const yearPath = import_path51.default.join(sessionsBase, year);
49043
49417
  try {
49044
- if (!import_fs52.default.statSync(yearPath).isDirectory()) continue;
49418
+ if (!import_fs53.default.statSync(yearPath).isDirectory()) continue;
49045
49419
  } catch {
49046
49420
  continue;
49047
49421
  }
49048
- for (const month of import_fs52.default.readdirSync(yearPath)) {
49049
- const monthPath = import_path50.default.join(yearPath, month);
49422
+ for (const month of import_fs53.default.readdirSync(yearPath)) {
49423
+ const monthPath = import_path51.default.join(yearPath, month);
49050
49424
  try {
49051
- if (!import_fs52.default.statSync(monthPath).isDirectory()) continue;
49425
+ if (!import_fs53.default.statSync(monthPath).isDirectory()) continue;
49052
49426
  } catch {
49053
49427
  continue;
49054
49428
  }
49055
- for (const day of import_fs52.default.readdirSync(monthPath)) {
49056
- const dayPath = import_path50.default.join(monthPath, day);
49429
+ for (const day of import_fs53.default.readdirSync(monthPath)) {
49430
+ const dayPath = import_path51.default.join(monthPath, day);
49057
49431
  try {
49058
- if (!import_fs52.default.statSync(dayPath).isDirectory()) continue;
49432
+ if (!import_fs53.default.statSync(dayPath).isDirectory()) continue;
49059
49433
  } catch {
49060
49434
  continue;
49061
49435
  }
49062
- for (const file of import_fs52.default.readdirSync(dayPath)) {
49063
- if (file.endsWith(".jsonl")) jsonlFiles.push(import_path50.default.join(dayPath, file));
49436
+ for (const file of import_fs53.default.readdirSync(dayPath)) {
49437
+ if (file.endsWith(".jsonl")) jsonlFiles.push(import_path51.default.join(dayPath, file));
49064
49438
  }
49065
49439
  }
49066
49440
  }
@@ -49125,13 +49499,13 @@ function freezeGeminiCost(acc) {
49125
49499
  function processGeminiCostFile(filePath, projectKey, start, end, acc) {
49126
49500
  const startMs = start.getTime();
49127
49501
  try {
49128
- if (import_fs52.default.statSync(filePath).mtimeMs < startMs) return;
49502
+ if (import_fs53.default.statSync(filePath).mtimeMs < startMs) return;
49129
49503
  } catch {
49130
49504
  return;
49131
49505
  }
49132
49506
  let raw;
49133
49507
  try {
49134
- raw = import_fs52.default.readFileSync(filePath, "utf-8");
49508
+ raw = import_fs53.default.readFileSync(filePath, "utf-8");
49135
49509
  } catch {
49136
49510
  return;
49137
49511
  }
@@ -49180,30 +49554,30 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
49180
49554
  const out = [];
49181
49555
  let dirs;
49182
49556
  try {
49183
- if (!import_fs52.default.statSync(geminiTmpDir2).isDirectory()) return out;
49184
- dirs = import_fs52.default.readdirSync(geminiTmpDir2);
49557
+ if (!import_fs53.default.statSync(geminiTmpDir2).isDirectory()) return out;
49558
+ dirs = import_fs53.default.readdirSync(geminiTmpDir2);
49185
49559
  } catch {
49186
49560
  return out;
49187
49561
  }
49188
49562
  for (const proj of dirs) {
49189
- const chatsDir = import_path50.default.join(geminiTmpDir2, proj, "chats");
49563
+ const chatsDir = import_path51.default.join(geminiTmpDir2, proj, "chats");
49190
49564
  let files;
49191
49565
  try {
49192
- if (!import_fs52.default.statSync(chatsDir).isDirectory()) continue;
49193
- files = import_fs52.default.readdirSync(chatsDir);
49566
+ if (!import_fs53.default.statSync(chatsDir).isDirectory()) continue;
49567
+ files = import_fs53.default.readdirSync(chatsDir);
49194
49568
  } catch {
49195
49569
  continue;
49196
49570
  }
49197
49571
  for (const f of files) {
49198
49572
  if (!f.endsWith(".jsonl")) continue;
49199
- out.push({ projectKey: proj, file: import_path50.default.join(chatsDir, f) });
49573
+ out.push({ projectKey: proj, file: import_path51.default.join(chatsDir, f) });
49200
49574
  }
49201
49575
  }
49202
49576
  return out;
49203
49577
  }
49204
49578
  function loadGeminiCost(start, end, geminiTmpDir2) {
49205
49579
  const acc = emptyGeminiAccumulator();
49206
- if (!import_fs52.default.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
49580
+ if (!import_fs53.default.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
49207
49581
  for (const { projectKey, file } of listGeminiSessionFiles2(geminiTmpDir2)) {
49208
49582
  processGeminiCostFile(file, projectKey, start, end, acc);
49209
49583
  }
@@ -49221,11 +49595,11 @@ function dimensionOfBlock(checkedBy, ruleName) {
49221
49595
  }
49222
49596
  function aggregateReportFromAudit(period, opts = {}) {
49223
49597
  const now = opts.now ?? /* @__PURE__ */ new Date();
49224
- const auditLogPath = opts.auditLogPath ?? import_path50.default.join(import_os46.default.homedir(), ".node9", "audit.log");
49225
- const claudeProjectsDir = opts.claudeProjectsDir ?? import_path50.default.join(import_os46.default.homedir(), ".claude", "projects");
49226
- const codexSessionsDir2 = opts.codexSessionsDir ?? import_path50.default.join(import_os46.default.homedir(), ".codex", "sessions");
49227
- const geminiTmpDir2 = opts.geminiTmpDir ?? import_path50.default.join(import_os46.default.homedir(), ".gemini", "tmp");
49228
- const hasAuditFile = import_fs52.default.existsSync(auditLogPath);
49598
+ const auditLogPath = opts.auditLogPath ?? import_path51.default.join(import_os48.default.homedir(), ".node9", "audit.log");
49599
+ const claudeProjectsDir = opts.claudeProjectsDir ?? import_path51.default.join(import_os48.default.homedir(), ".claude", "projects");
49600
+ const codexSessionsDir2 = opts.codexSessionsDir ?? import_path51.default.join(import_os48.default.homedir(), ".codex", "sessions");
49601
+ const geminiTmpDir2 = opts.geminiTmpDir ?? import_path51.default.join(import_os48.default.homedir(), ".gemini", "tmp");
49602
+ const hasAuditFile = import_fs53.default.existsSync(auditLogPath);
49229
49603
  const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
49230
49604
  const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
49231
49605
  const { start, end } = getDateRange(period, now);
@@ -50016,12 +50390,14 @@ function registerDaemonCommand(program2) {
50016
50390
 
50017
50391
  // src/cli/commands/status.ts
50018
50392
  var import_chalk15 = __toESM(require("chalk"));
50019
- var import_fs53 = __toESM(require("fs"));
50020
- var import_path51 = __toESM(require("path"));
50021
- var import_os47 = __toESM(require("os"));
50393
+ var import_fs54 = __toESM(require("fs"));
50394
+ var import_path52 = __toESM(require("path"));
50395
+ var import_os49 = __toESM(require("os"));
50022
50396
  init_core();
50023
50397
  init_daemon();
50024
50398
  init_agent_wiring();
50399
+ init_sync();
50400
+ init_service();
50025
50401
  function printAgentSection(label2, hookPairs, wrapped) {
50026
50402
  console.log(import_chalk15.default.bold(` ${label2}`));
50027
50403
  for (const { name, present } of hookPairs) {
@@ -50050,6 +50426,15 @@ function registerStatusCommand(program2) {
50050
50426
  console.log("");
50051
50427
  if (creds && settings.approvers.cloud) {
50052
50428
  console.log(import_chalk15.default.green(" \u25CF Agent mode") + import_chalk15.default.gray(" \u2014 cloud team policy enforced"));
50429
+ const health = readSyncHealth();
50430
+ if (isPolicyStale(Date.now(), health)) {
50431
+ const when = health.lastCheckedAt ? `last synced ${agoLabel(health.lastCheckedAt)}` : "never synced";
50432
+ const fails = health.consecutiveFailures > 0 ? ` \xB7 ${health.consecutiveFailures} failed attempt${health.consecutiveFailures === 1 ? "" : "s"}${health.lastError ? ` (${health.lastError})` : ""}` : "";
50433
+ console.log(import_chalk15.default.yellow(" \u26A0 Policy sync STALE") + import_chalk15.default.gray(` \u2014 ${when}${fails}`));
50434
+ console.log(import_chalk15.default.gray(" the cached policy is still enforced \u2014 run: node9 doctor"));
50435
+ } else if (health.lastCheckedAt) {
50436
+ console.log(import_chalk15.default.gray(` \u21B3 policy synced ${agoLabel(health.lastCheckedAt)}`));
50437
+ }
50053
50438
  } else if (creds && !settings.approvers.cloud) {
50054
50439
  console.log(
50055
50440
  import_chalk15.default.blue(" \u25CF Privacy mode \u{1F6E1}\uFE0F") + import_chalk15.default.gray(" \u2014 all decisions stay on this machine")
@@ -50067,6 +50452,16 @@ function registerStatusCommand(program2) {
50067
50452
  } else {
50068
50453
  console.log(import_chalk15.default.gray(" \u25CB Daemon stopped"));
50069
50454
  }
50455
+ const autostart = autostartAdvice({
50456
+ installed: isDaemonServiceInstalled(),
50457
+ enabled: isDaemonServiceEnabled(),
50458
+ cloudEnabled: !!(creds && settings.approvers.cloud)
50459
+ });
50460
+ if (autostart) {
50461
+ console.log(
50462
+ import_chalk15.default.yellow(" \u26A0 daemon autostart not active") + import_chalk15.default.gray(" \u2014 won't survive reboot; run: node9 doctor")
50463
+ );
50464
+ }
50070
50465
  if (settings.enableUndo) {
50071
50466
  console.log(
50072
50467
  import_chalk15.default.magenta(" \u25CF Undo Engine") + import_chalk15.default.gray(` \u2192 Auto-snapshotting Git repos on AI change`)
@@ -50075,20 +50470,20 @@ function registerStatusCommand(program2) {
50075
50470
  console.log("");
50076
50471
  const modeLabel = settings.mode === "audit" ? import_chalk15.default.blue("audit") : settings.mode === "strict" ? import_chalk15.default.red("strict") : import_chalk15.default.white("standard");
50077
50472
  console.log(` Mode: ${modeLabel}`);
50078
- const projectConfig = import_path51.default.join(process.cwd(), "node9.config.json");
50079
- const globalConfig = import_path51.default.join(import_os47.default.homedir(), ".node9", "config.json");
50473
+ const projectConfig = import_path52.default.join(process.cwd(), "node9.config.json");
50474
+ const globalConfig = import_path52.default.join(import_os49.default.homedir(), ".node9", "config.json");
50080
50475
  console.log(
50081
- ` Local: ${import_fs53.default.existsSync(projectConfig) ? import_chalk15.default.green("Active (node9.config.json)") : import_chalk15.default.gray("Not present")}`
50476
+ ` Local: ${import_fs54.default.existsSync(projectConfig) ? import_chalk15.default.green("Active (node9.config.json)") : import_chalk15.default.gray("Not present")}`
50082
50477
  );
50083
50478
  console.log(
50084
- ` Global: ${import_fs53.default.existsSync(globalConfig) ? import_chalk15.default.green("Active (~/.node9/config.json)") : import_chalk15.default.gray("Not present")}`
50479
+ ` Global: ${import_fs54.default.existsSync(globalConfig) ? import_chalk15.default.green("Active (~/.node9/config.json)") : import_chalk15.default.gray("Not present")}`
50085
50480
  );
50086
50481
  if (mergedConfig.policy.sandboxPaths.length > 0) {
50087
50482
  console.log(
50088
50483
  ` Sandbox: ${import_chalk15.default.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
50089
50484
  );
50090
50485
  }
50091
- const wiring = getAgentWiring(import_os47.default.homedir()).filter((a) => a.present);
50486
+ const wiring = getAgentWiring(import_os49.default.homedir()).filter((a) => a.present);
50092
50487
  if (wiring.length > 0) {
50093
50488
  console.log("");
50094
50489
  console.log(import_chalk15.default.bold(" Agent Wiring:"));
@@ -50123,14 +50518,15 @@ function registerStatusCommand(program2) {
50123
50518
 
50124
50519
  // src/cli/commands/init.ts
50125
50520
  var import_chalk16 = __toESM(require("chalk"));
50126
- var import_fs54 = __toESM(require("fs"));
50127
- var import_path52 = __toESM(require("path"));
50128
- var import_os48 = __toESM(require("os"));
50521
+ var import_fs55 = __toESM(require("fs"));
50522
+ var import_path53 = __toESM(require("path"));
50523
+ var import_os50 = __toESM(require("os"));
50129
50524
  var import_https6 = __toESM(require("https"));
50130
50525
  init_core();
50131
50526
  init_setup();
50132
50527
  init_shields();
50133
50528
  init_service();
50529
+ init_core();
50134
50530
  var DEFAULT_SHIELDS = ["bash-safe", "filesystem", "project-jail"];
50135
50531
  function buildTelemetryPayload(agents, firstInstall) {
50136
50532
  return {
@@ -50215,16 +50611,16 @@ function registerInitCommand(program2) {
50215
50611
  }
50216
50612
  console.log("");
50217
50613
  }
50218
- const configPath = import_path52.default.join(import_os48.default.homedir(), ".node9", "config.json");
50219
- const isFirstInstall = !import_fs54.default.existsSync(configPath);
50220
- if (import_fs54.default.existsSync(configPath) && !options.force) {
50614
+ const configPath = import_path53.default.join(import_os50.default.homedir(), ".node9", "config.json");
50615
+ const isFirstInstall = !import_fs55.default.existsSync(configPath);
50616
+ if (import_fs55.default.existsSync(configPath) && !options.force) {
50221
50617
  try {
50222
- const existing = JSON.parse(import_fs54.default.readFileSync(configPath, "utf-8"));
50618
+ const existing = JSON.parse(import_fs55.default.readFileSync(configPath, "utf-8"));
50223
50619
  const settings = existing.settings ?? {};
50224
50620
  if (settings.mode !== chosenMode) {
50225
50621
  settings.mode = chosenMode;
50226
50622
  existing.settings = settings;
50227
- import_fs54.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
50623
+ import_fs55.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
50228
50624
  console.log(import_chalk16.default.green(`\u2705 Mode updated: ${chosenMode}`));
50229
50625
  } else {
50230
50626
  console.log(import_chalk16.default.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
@@ -50237,9 +50633,9 @@ function registerInitCommand(program2) {
50237
50633
  ...DEFAULT_CONFIG,
50238
50634
  settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
50239
50635
  };
50240
- const dir = import_path52.default.dirname(configPath);
50241
- if (!import_fs54.default.existsSync(dir)) import_fs54.default.mkdirSync(dir, { recursive: true });
50242
- import_fs54.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
50636
+ const dir = import_path53.default.dirname(configPath);
50637
+ if (!import_fs55.default.existsSync(dir)) import_fs55.default.mkdirSync(dir, { recursive: true });
50638
+ import_fs55.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
50243
50639
  console.log(import_chalk16.default.green(`\u2705 Config created: ${configPath}`));
50244
50640
  console.log(import_chalk16.default.gray(` Mode: ${chosenMode}`));
50245
50641
  }
@@ -50291,8 +50687,13 @@ function registerInitCommand(program2) {
50291
50687
  console.log(import_chalk16.default.gray(" You can try again later with: node9 daemon install"));
50292
50688
  }
50293
50689
  }
50690
+ } else if (isDaemonServiceEnabled()) {
50691
+ console.log(import_chalk16.default.green(" \u2713 Daemon login service already installed & enabled"));
50294
50692
  } else {
50295
- console.log(import_chalk16.default.green(" \u2713 Daemon login service already installed"));
50693
+ const healed = ensureAutostartHealthy(!!getConfig().settings.autoStartDaemon);
50694
+ console.log(
50695
+ healed === "repaired" ? import_chalk16.default.green(" \u2713 Re-enabled daemon login service (was installed but disabled)") : import_chalk16.default.gray(" \xB7 Daemon login service is disabled (autostart off) \u2014 left as-is")
50696
+ );
50296
50697
  }
50297
50698
  if (!isTestingMode()) {
50298
50699
  process.stdout.write(import_chalk16.default.dim(" Starting daemon..."));
@@ -50334,14 +50735,14 @@ function registerInitCommand(program2) {
50334
50735
 
50335
50736
  // src/cli/commands/heal.ts
50336
50737
  var import_chalk17 = __toESM(require("chalk"));
50337
- var import_fs55 = __toESM(require("fs"));
50738
+ var import_fs56 = __toESM(require("fs"));
50338
50739
  init_agent_wiring();
50339
50740
  init_setup();
50340
50741
  init_hook_baseline();
50341
50742
  var hasHookSurface = (a) => a.hooks.length > 0;
50342
50743
  function backupForHeal(file) {
50343
50744
  try {
50344
- if (file && import_fs55.default.existsSync(file)) import_fs55.default.copyFileSync(file, `${file}.node9-heal-bak`);
50745
+ if (file && import_fs56.default.existsSync(file)) import_fs56.default.copyFileSync(file, `${file}.node9-heal-bak`);
50345
50746
  } catch {
50346
50747
  }
50347
50748
  }
@@ -50508,7 +50909,7 @@ function registerConnectCommand(program2) {
50508
50909
  }
50509
50910
 
50510
50911
  // src/cli/commands/undo.ts
50511
- var import_path53 = __toESM(require("path"));
50912
+ var import_path54 = __toESM(require("path"));
50512
50913
  var import_chalk20 = __toESM(require("chalk"));
50513
50914
 
50514
50915
  // src/tui/undo-navigator.ts
@@ -50667,7 +51068,7 @@ function findMatchingCwd(startDir, history) {
50667
51068
  let dir = startDir;
50668
51069
  while (true) {
50669
51070
  if (cwds.has(dir)) return dir;
50670
- const parent = import_path53.default.dirname(dir);
51071
+ const parent = import_path54.default.dirname(dir);
50671
51072
  if (parent === dir) return null;
50672
51073
  dir = parent;
50673
51074
  }
@@ -50835,7 +51236,7 @@ function normalizeClientName(name) {
50835
51236
  const sanitized = sanitize4(name).slice(0, 40);
50836
51237
  return sanitized.length > 0 ? sanitized : void 0;
50837
51238
  }
50838
- function reportPinMismatchToCloud(serverKey, agent) {
51239
+ function reportPinMismatchToCloud(serverKey, serverLabel, agent) {
50839
51240
  try {
50840
51241
  const creds = getCredentials();
50841
51242
  if (!creds) return;
@@ -50844,18 +51245,18 @@ function reportPinMismatchToCloud(serverKey, agent) {
50844
51245
  { serverKey, reason: "tool-pin-mismatch" },
50845
51246
  "mcp-pin-mismatch",
50846
51247
  creds,
50847
- { mcpServer: serverKey, agent },
51248
+ { mcpServer: serverLabel, agent },
50848
51249
  void 0,
50849
51250
  false,
50850
51251
  {
50851
51252
  ruleName: "MCP tool definitions changed (possible rug pull)",
50852
- ruleDescription: `The MCP server "${serverKey}" changed its tool definitions since they were pinned. This can indicate a supply-chain attack (tool poisoning). The session was quarantined. Review with: node9 mcp pin update ${serverKey}`
51253
+ ruleDescription: `The MCP server "${serverLabel}" changed its tool definitions since they were pinned. This can indicate a supply-chain attack (tool poisoning). The session was quarantined. Review with: node9 mcp pin update ${serverKey}`
50853
51254
  }
50854
51255
  );
50855
51256
  } catch {
50856
51257
  }
50857
51258
  }
50858
- function reportInventoryToCloud(serverKey, toolCount, agent) {
51259
+ function reportInventoryToCloud(serverKey, serverLabel, toolCount, agent) {
50859
51260
  try {
50860
51261
  const creds = getCredentials();
50861
51262
  if (!creds) return;
@@ -50864,7 +51265,7 @@ function reportInventoryToCloud(serverKey, toolCount, agent) {
50864
51265
  { serverKey, toolCount },
50865
51266
  "mcp-discovered",
50866
51267
  creds,
50867
- { mcpServer: serverKey, agent },
51268
+ { mcpServer: serverLabel, agent },
50868
51269
  void 0,
50869
51270
  false,
50870
51271
  { mcpToolCount: toolCount }
@@ -50872,7 +51273,7 @@ function reportInventoryToCloud(serverKey, toolCount, agent) {
50872
51273
  } catch {
50873
51274
  }
50874
51275
  }
50875
- function reportLargeResponseToCloud(serverKey, responseBytes, agent) {
51276
+ function reportLargeResponseToCloud(serverKey, serverLabel, responseBytes, agent) {
50876
51277
  try {
50877
51278
  const creds = getCredentials();
50878
51279
  if (!creds) return;
@@ -50881,7 +51282,7 @@ function reportLargeResponseToCloud(serverKey, responseBytes, agent) {
50881
51282
  { serverKey, responseBytes },
50882
51283
  "mcp-large-response",
50883
51284
  creds,
50884
- { mcpServer: serverKey, agent },
51285
+ { mcpServer: serverLabel, agent },
50885
51286
  void 0,
50886
51287
  false,
50887
51288
  { mcpResponseBytes: responseBytes }
@@ -51118,7 +51519,12 @@ async function runMcpGateway(upstreamCommand, configName) {
51118
51519
  const currentHash = hashToolDefinitions(tools);
51119
51520
  const pinStatus = checkPin(serverKey, currentHash, gatewayCwd);
51120
51521
  const token = getInternalToken();
51121
- reportInventoryToCloud(serverKey, tools.length, clientName);
51522
+ reportInventoryToCloud(
51523
+ serverKey,
51524
+ resolveServerLabel("", serverKey, upstreamCommand, configName),
51525
+ tools.length,
51526
+ clientName
51527
+ );
51122
51528
  if (isDaemonRunning() && process.env.NODE9_TESTING !== "1") {
51123
51529
  const toolSummary = tools.map((t) => ({ name: t.name, description: t.description }));
51124
51530
  fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/mcp/discovered`, {
@@ -51190,7 +51596,11 @@ async function runMcpGateway(upstreamCommand, configName) {
51190
51596
  console.error(import_chalk21.default.red(" Session quarantined \u2014 all tool calls blocked."));
51191
51597
  console.error(import_chalk21.default.yellow(` Run: node9 mcp pin update ${serverKey}
51192
51598
  `));
51193
- reportPinMismatchToCloud(serverKey, clientName);
51599
+ reportPinMismatchToCloud(
51600
+ serverKey,
51601
+ resolveServerLabel("", serverKey, upstreamCommand, configName),
51602
+ clientName
51603
+ );
51194
51604
  const errorResponse = {
51195
51605
  jsonrpc: "2.0",
51196
51606
  id: parsed.id,
@@ -51236,7 +51646,12 @@ async function runMcpGateway(upstreamCommand, configName) {
51236
51646
  `\u26A1 Node9: Large MCP response from '${toolName}' (${(line.length / 1024).toFixed(0)}KB) \u2014 context window enlarged`
51237
51647
  )
51238
51648
  );
51239
- reportLargeResponseToCloud(serverKey, line.length, clientName);
51649
+ reportLargeResponseToCloud(
51650
+ serverKey,
51651
+ resolveServerLabel("", serverKey, upstreamCommand, configName),
51652
+ line.length,
51653
+ clientName
51654
+ );
51240
51655
  if (isDaemonRunning() && process.env.NODE9_TESTING !== "1") {
51241
51656
  const token = getInternalToken();
51242
51657
  fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/mcp/large-response`, {
@@ -51287,18 +51702,18 @@ function registerMcpGatewayCommand(program2) {
51287
51702
 
51288
51703
  // src/mcp-server/index.ts
51289
51704
  var import_readline5 = __toESM(require("readline"));
51290
- var import_fs57 = __toESM(require("fs"));
51291
- var import_os50 = __toESM(require("os"));
51292
- var import_path55 = __toESM(require("path"));
51705
+ var import_fs58 = __toESM(require("fs"));
51706
+ var import_os52 = __toESM(require("os"));
51707
+ var import_path56 = __toESM(require("path"));
51293
51708
  var import_child_process11 = require("child_process");
51294
51709
  init_core();
51295
51710
  init_daemon();
51296
51711
  init_shields();
51297
51712
 
51298
51713
  // src/auth/egress-config.ts
51299
- var import_fs56 = __toESM(require("fs"));
51300
- var import_os49 = __toESM(require("os"));
51301
- var import_path54 = __toESM(require("path"));
51714
+ var import_fs57 = __toESM(require("fs"));
51715
+ var import_os51 = __toESM(require("os"));
51716
+ var import_path55 = __toESM(require("path"));
51302
51717
  var DEFAULT_EGRESS = {
51303
51718
  enabled: false,
51304
51719
  mode: "review",
@@ -51307,12 +51722,12 @@ var DEFAULT_EGRESS = {
51307
51722
  allowPrivate: true
51308
51723
  };
51309
51724
  function egressConfigPath() {
51310
- return import_path54.default.join(import_os49.default.homedir(), ".node9", "config.json");
51725
+ return import_path55.default.join(import_os51.default.homedir(), ".node9", "config.json");
51311
51726
  }
51312
51727
  function readEgressRawConfig() {
51313
51728
  let text;
51314
51729
  try {
51315
- text = import_fs56.default.readFileSync(egressConfigPath(), "utf8");
51730
+ text = import_fs57.default.readFileSync(egressConfigPath(), "utf8");
51316
51731
  } catch (err2) {
51317
51732
  if (err2.code === "ENOENT") return {};
51318
51733
  throw err2;
@@ -51327,8 +51742,8 @@ function readEgressRawConfig() {
51327
51742
  }
51328
51743
  function writeEgressRawConfig(config) {
51329
51744
  const p = egressConfigPath();
51330
- import_fs56.default.mkdirSync(import_path54.default.dirname(p), { recursive: true });
51331
- import_fs56.default.writeFileSync(p, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
51745
+ import_fs57.default.mkdirSync(import_path55.default.dirname(p), { recursive: true });
51746
+ import_fs57.default.writeFileSync(p, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
51332
51747
  }
51333
51748
  function applyEgress(config, change) {
51334
51749
  const policy = config.policy = config.policy ?? {};
@@ -51713,13 +52128,13 @@ function handleStatus() {
51713
52128
  lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
51714
52129
  lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
51715
52130
  lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
51716
- const projectConfig = import_path55.default.join(process.cwd(), "node9.config.json");
51717
- const globalConfig = import_path55.default.join(import_os50.default.homedir(), ".node9", "config.json");
52131
+ const projectConfig = import_path56.default.join(process.cwd(), "node9.config.json");
52132
+ const globalConfig = import_path56.default.join(import_os52.default.homedir(), ".node9", "config.json");
51718
52133
  lines.push(
51719
- `Project config (node9.config.json): ${import_fs57.default.existsSync(projectConfig) ? "present" : "not found"}`
52134
+ `Project config (node9.config.json): ${import_fs58.default.existsSync(projectConfig) ? "present" : "not found"}`
51720
52135
  );
51721
52136
  lines.push(
51722
- `Global config (~/.node9/config.json): ${import_fs57.default.existsSync(globalConfig) ? "present" : "not found"}`
52137
+ `Global config (~/.node9/config.json): ${import_fs58.default.existsSync(globalConfig) ? "present" : "not found"}`
51723
52138
  );
51724
52139
  return lines.join("\n");
51725
52140
  }
@@ -51825,21 +52240,21 @@ function handleEgressDeny(args) {
51825
52240
  addEgressHost("deny", host);
51826
52241
  return `Denied egress to ${host} (deny always wins over allow).`;
51827
52242
  }
51828
- var GLOBAL_CONFIG_PATH = import_path55.default.join(import_os50.default.homedir(), ".node9", "config.json");
52243
+ var GLOBAL_CONFIG_PATH = import_path56.default.join(import_os52.default.homedir(), ".node9", "config.json");
51829
52244
  var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
51830
52245
  function readGlobalConfigRaw() {
51831
52246
  try {
51832
- if (import_fs57.default.existsSync(GLOBAL_CONFIG_PATH)) {
51833
- return JSON.parse(import_fs57.default.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
52247
+ if (import_fs58.default.existsSync(GLOBAL_CONFIG_PATH)) {
52248
+ return JSON.parse(import_fs58.default.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
51834
52249
  }
51835
52250
  } catch {
51836
52251
  }
51837
52252
  return {};
51838
52253
  }
51839
52254
  function writeGlobalConfigRaw(data) {
51840
- const dir = import_path55.default.dirname(GLOBAL_CONFIG_PATH);
51841
- if (!import_fs57.default.existsSync(dir)) import_fs57.default.mkdirSync(dir, { recursive: true });
51842
- import_fs57.default.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
52255
+ const dir = import_path56.default.dirname(GLOBAL_CONFIG_PATH);
52256
+ if (!import_fs58.default.existsSync(dir)) import_fs58.default.mkdirSync(dir, { recursive: true });
52257
+ import_fs58.default.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
51843
52258
  }
51844
52259
  function handleApproverList() {
51845
52260
  const config = getConfig();
@@ -51883,9 +52298,9 @@ function handleApproverSet(args) {
51883
52298
  function handleAuditGet(args) {
51884
52299
  const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
51885
52300
  const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
51886
- const auditPath = import_path55.default.join(import_os50.default.homedir(), ".node9", "audit.log");
51887
- if (!import_fs57.default.existsSync(auditPath)) return "No audit log found.";
51888
- const rawLines = import_fs57.default.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
52301
+ const auditPath = import_path56.default.join(import_os52.default.homedir(), ".node9", "audit.log");
52302
+ if (!import_fs58.default.existsSync(auditPath)) return "No audit log found.";
52303
+ const rawLines = import_fs58.default.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
51889
52304
  const parsed = [];
51890
52305
  for (const line of rawLines) {
51891
52306
  try {
@@ -52259,7 +52674,7 @@ function registerTrustCommand(program2) {
52259
52674
  // src/cli/commands/mcp-pin.ts
52260
52675
  var import_chalk24 = __toESM(require("chalk"));
52261
52676
  init_mcp_pin();
52262
- var import_fs58 = __toESM(require("fs"));
52677
+ var import_fs59 = __toESM(require("fs"));
52263
52678
 
52264
52679
  // src/cli/commands/mcp-gateway-cmd.ts
52265
52680
  var import_chalk23 = __toESM(require("chalk"));
@@ -52466,7 +52881,7 @@ function registerMcpPinCommand(program2) {
52466
52881
  let repoCorrupt = false;
52467
52882
  if (found.source === "repo") {
52468
52883
  try {
52469
- const raw = import_fs58.default.readFileSync(found.path, "utf-8");
52884
+ const raw = import_fs59.default.readFileSync(found.path, "utf-8");
52470
52885
  const parsed = JSON.parse(raw);
52471
52886
  repoEntries = parsed.servers ?? {};
52472
52887
  } catch {
@@ -52966,8 +53381,8 @@ function registerPostureCommand(program2) {
52966
53381
  var import_chalk30 = __toESM(require("chalk"));
52967
53382
 
52968
53383
  // src/ci-check/fetch.ts
52969
- var import_fs59 = __toESM(require("fs"));
52970
- var import_path56 = __toESM(require("path"));
53384
+ var import_fs60 = __toESM(require("fs"));
53385
+ var import_path57 = __toESM(require("path"));
52971
53386
  var import_node_child_process = require("child_process");
52972
53387
  var import_undici = __toESM(require_undici());
52973
53388
  var cachedGhToken;
@@ -53051,7 +53466,7 @@ function parseRepoUrl(input) {
53051
53466
  function isLocalPath(input) {
53052
53467
  if (input.startsWith(".") || input.startsWith("/") || input.startsWith("~")) return true;
53053
53468
  try {
53054
- return import_fs59.default.existsSync(input) && import_fs59.default.statSync(input).isDirectory();
53469
+ return import_fs60.default.existsSync(input) && import_fs60.default.statSync(input).isDirectory();
53055
53470
  } catch {
53056
53471
  return false;
53057
53472
  }
@@ -53166,10 +53581,10 @@ function readLocalTree(dir) {
53166
53581
  const files = [];
53167
53582
  const notes = [];
53168
53583
  const add = (rel) => {
53169
- const abs = import_path56.default.join(root, rel);
53584
+ const abs = import_path57.default.join(root, rel);
53170
53585
  try {
53171
- if (import_fs59.default.existsSync(abs) && import_fs59.default.statSync(abs).isFile()) {
53172
- files.push({ path: rel, content: import_fs59.default.readFileSync(abs, "utf8") });
53586
+ if (import_fs60.default.existsSync(abs) && import_fs60.default.statSync(abs).isFile()) {
53587
+ files.push({ path: rel, content: import_fs60.default.readFileSync(abs, "utf8") });
53173
53588
  }
53174
53589
  } catch {
53175
53590
  }
@@ -53189,7 +53604,7 @@ function readLocalTree(dir) {
53189
53604
  dirsVisited++;
53190
53605
  let entries;
53191
53606
  try {
53192
- entries = import_fs59.default.readdirSync(import_path56.default.join(root, relDir), { withFileTypes: true });
53607
+ entries = import_fs60.default.readdirSync(import_path57.default.join(root, relDir), { withFileTypes: true });
53193
53608
  } catch {
53194
53609
  return;
53195
53610
  }
@@ -53210,11 +53625,11 @@ function readLocalTree(dir) {
53210
53625
  `repo is large \u2014 some agent-surface files may be INCOMPLETE (capped at ${MAX_SURFACE_FILES} files / ${MAX_DIRS} dirs).`
53211
53626
  );
53212
53627
  for (const rel of matches) collect(rel);
53213
- const wfDir = import_path56.default.join(root, WORKFLOW_DIR);
53628
+ const wfDir = import_path57.default.join(root, WORKFLOW_DIR);
53214
53629
  try {
53215
- if (import_fs59.default.existsSync(wfDir)) {
53216
- for (const name of import_fs59.default.readdirSync(wfDir)) {
53217
- if (/\.ya?ml$/.test(name)) add(import_path56.default.join(WORKFLOW_DIR, name));
53630
+ if (import_fs60.default.existsSync(wfDir)) {
53631
+ for (const name of import_fs60.default.readdirSync(wfDir)) {
53632
+ if (/\.ya?ml$/.test(name)) add(import_path57.default.join(WORKFLOW_DIR, name));
53218
53633
  }
53219
53634
  }
53220
53635
  } catch {
@@ -53487,7 +53902,7 @@ function severityFromScore(score) {
53487
53902
  if (score >= 1) return "advisory";
53488
53903
  return null;
53489
53904
  }
53490
- function analyzeWorkflow(path70, content) {
53905
+ function analyzeWorkflow(path71, content) {
53491
53906
  let raw;
53492
53907
  try {
53493
53908
  raw = (0, import_yaml.parse)(content) ?? {};
@@ -53608,7 +54023,7 @@ function analyzeWorkflow(path70, content) {
53608
54023
  dimension: "workflows",
53609
54024
  severity,
53610
54025
  title,
53611
- file: path70,
54026
+ file: path71,
53612
54027
  signals,
53613
54028
  mitigations: mitigations.length ? mitigations : void 0,
53614
54029
  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) \u2014 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 \u2014 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."
@@ -53684,7 +54099,7 @@ function evalAgentJob(job, wf, raw, untrustedTrigger, reusable) {
53684
54099
  if (reusable && !loadedGun && SEVERITY_RANK2[severity] > SEVERITY_RANK2.medium) severity = "medium";
53685
54100
  return { severity, secrets, injectable, canReadEnv };
53686
54101
  }
53687
- function analyzeWorkflowSecrets(path70, content) {
54102
+ function analyzeWorkflowSecrets(path71, content) {
53688
54103
  let raw;
53689
54104
  try {
53690
54105
  raw = (0, import_yaml.parse)(content) ?? {};
@@ -53704,7 +54119,7 @@ function analyzeWorkflowSecrets(path70, content) {
53704
54119
  dimension: "data",
53705
54120
  severity: worst.severity,
53706
54121
  title: worst.severity === "advisory" ? "Secrets reachable by the agent \u2014 hardening" : "Exfiltratable secrets reachable by an injectable agent",
53707
- file: path70,
54122
+ file: path71,
53708
54123
  signals: [
53709
54124
  `agent can reach: ${worst.secrets.map((s) => s.name).join(", ")}`,
53710
54125
  worst.injectable ? "the agent is externally triggerable (untrusted trigger, no gate)" : "gated / not externally triggerable \u2014 latent risk only",
@@ -53731,7 +54146,7 @@ function hookCommands(hooks) {
53731
54146
  }
53732
54147
  return out;
53733
54148
  }
53734
- function analyzeAgentConfig(path70, content) {
54149
+ function analyzeAgentConfig(path71, content) {
53735
54150
  let cfg;
53736
54151
  try {
53737
54152
  cfg = JSON.parse(content);
@@ -53750,7 +54165,7 @@ function analyzeAgentConfig(path70, content) {
53750
54165
  dimension: "toolRules",
53751
54166
  severity: high ? "high" : "medium",
53752
54167
  title: high ? "Agent hook runs UNPINNED/remote third-party code on every action" : "Agent hook runs third-party code in the agent hot path",
53753
- file: path70,
54168
+ file: path71,
53754
54169
  signals: [
53755
54170
  `hook command: \`${cmd.slice(0, 120)}\``,
53756
54171
  remoteExec ? "fetch-and-run (curl|wget / pipe-to-shell) \u2014 unpinnable remote code execution on every contributor" : unpinned ? "unpinned \u2014 a compromised/yanked package = code execution on every contributor" : "pinned, but still a standing supply-chain dependency in the agent hot path"
@@ -53770,7 +54185,7 @@ function analyzeAgentConfig(path70, content) {
53770
54185
  dimension: "toolRules",
53771
54186
  severity: hasBackstop ? "medium" : "high",
53772
54187
  title: hasBackstop ? "Committed agent config pre-authorizes broad tools" : "Committed agent config pre-authorizes broad tools with no deny backstop",
53773
- file: path70,
54188
+ file: path71,
53774
54189
  signals: [
53775
54190
  `broad allow(s): ${broad.slice(0, 5).join(", ")}`,
53776
54191
  hasBackstop ? "a `deny` list backstops the broad allow" : "no `deny` entry covers Bash/Write/Edit \u2014 every contributor is pre-authorized for catastrophic tools"
@@ -53783,16 +54198,16 @@ function analyzeAgentConfig(path70, content) {
53783
54198
 
53784
54199
  // src/ci-check/mcp.ts
53785
54200
  init_dist();
53786
- function analyzeMcp(path70, content) {
54201
+ function analyzeMcp(path71, content) {
53787
54202
  let cfg;
53788
54203
  try {
53789
54204
  cfg = JSON.parse(content);
53790
54205
  } catch {
53791
54206
  return [];
53792
54207
  }
53793
- return analyzeMcpServers(cfg.mcpServers ?? {}, path70);
54208
+ return analyzeMcpServers(cfg.mcpServers ?? {}, path71);
53794
54209
  }
53795
- function analyzeMcpServers(servers, path70) {
54210
+ function analyzeMcpServers(servers, path71) {
53796
54211
  const findings = [];
53797
54212
  for (const [name, srv] of Object.entries(servers ?? {})) {
53798
54213
  if (!srv || srv.disabled) continue;
@@ -53803,7 +54218,7 @@ function analyzeMcpServers(servers, path70) {
53803
54218
  dimension: "mcp",
53804
54219
  severity: "medium",
53805
54220
  title: `MCP server "${name}" runs an unpinned executable`,
53806
- file: path70,
54221
+ file: path71,
53807
54222
  signals: [`\`${argv.slice(0, 120)}\` \u2014 unversioned/@latest npx`],
53808
54223
  fix: "Pin the MCP server package to an exact version so a PR (or a registry compromise) can\u2019t swap the toolchain."
53809
54224
  });
@@ -53817,7 +54232,7 @@ function analyzeMcpServers(servers, path70) {
53817
54232
  dimension: "mcp",
53818
54233
  severity: "high",
53819
54234
  title: `MCP server "${name}" has an inline credential`,
53820
- file: path70,
54235
+ file: path71,
53821
54236
  signals: [
53822
54237
  `env.${k} matches ${hit.patternName} \u2014 agent-reachable secret committed to the repo`
53823
54238
  ],
@@ -53831,7 +54246,7 @@ function analyzeMcpServers(servers, path70) {
53831
54246
 
53832
54247
  // src/ci-check/codex.ts
53833
54248
  var import_smol_toml5 = require("smol-toml");
53834
- function analyzeCodexConfig(path70, content) {
54249
+ function analyzeCodexConfig(path71, content) {
53835
54250
  let cfg;
53836
54251
  try {
53837
54252
  cfg = (0, import_smol_toml5.parse)(content);
@@ -53839,7 +54254,7 @@ function analyzeCodexConfig(path70, content) {
53839
54254
  return [];
53840
54255
  }
53841
54256
  const findings = [];
53842
- findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {}, path70));
54257
+ findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {}, path71));
53843
54258
  const sandbox = typeof cfg.sandbox_mode === "string" ? cfg.sandbox_mode : "";
53844
54259
  const approval = typeof cfg.approval_policy === "string" ? cfg.approval_policy : "";
53845
54260
  const fullAccess = /danger-full-access/i.test(sandbox);
@@ -53854,7 +54269,7 @@ function analyzeCodexConfig(path70, content) {
53854
54269
  dimension: "toolRules",
53855
54270
  severity: fullAccess ? "high" : "medium",
53856
54271
  title: fullAccess ? "Codex config grants a full-access sandbox" : "Codex config never requires approval",
53857
- file: path70,
54272
+ file: path71,
53858
54273
  signals,
53859
54274
  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.'
53860
54275
  });
@@ -53910,10 +54325,10 @@ function decodeSuspiciousBase64(text) {
53910
54325
  }
53911
54326
  return out;
53912
54327
  }
53913
- function mk(severity, title, signals, fix, path70) {
53914
- return { check: "CI-6", dimension: "instructions", severity, title, file: path70, signals, fix };
54328
+ function mk(severity, title, signals, fix, path71) {
54329
+ return { check: "CI-6", dimension: "instructions", severity, title, file: path71, signals, fix };
53915
54330
  }
53916
- function analyzeInstructionFile(path70, content) {
54331
+ function analyzeInstructionFile(path71, content) {
53917
54332
  const findings = [];
53918
54333
  const decoded = decodeSuspiciousBase64(content);
53919
54334
  if (TAG_CHARS.test(content))
@@ -53925,7 +54340,7 @@ function analyzeInstructionFile(path70, content) {
53925
54340
  "contains Unicode tag characters (U+E0000\u2013E007F) \u2014 an invisible instruction-smuggling channel with no legitimate use in text"
53926
54341
  ],
53927
54342
  "Remove the tag characters. Instruction files must be plain, reviewable text.",
53928
- path70
54343
+ path71
53929
54344
  )
53930
54345
  );
53931
54346
  if (BIDI_OVERRIDE.test(content))
@@ -53937,7 +54352,7 @@ function analyzeInstructionFile(path70, content) {
53937
54352
  "contains a bidi override (U+202D/U+202E) \u2014 a Trojan-Source technique that visually reorders text so a human reads something different from what the agent parses"
53938
54353
  ],
53939
54354
  "Remove the bidi override characters.",
53940
- path70
54355
+ path71
53941
54356
  )
53942
54357
  );
53943
54358
  else if (BIDI_EMBED_ISOLATE.test(content))
@@ -53949,7 +54364,7 @@ function analyzeInstructionFile(path70, content) {
53949
54364
  "contains bidi embed/isolate characters (U+202A\u2013202C / U+2066\u20132069) \u2014 legitimate in right-to-left text, but confirm they are not being used to hide or reorder instructions"
53950
54365
  ],
53951
54366
  "Confirm the bidi marks are legitimate RTL formatting; remove otherwise.",
53952
- path70
54367
+ path71
53953
54368
  )
53954
54369
  );
53955
54370
  const zw = suspiciousZeroWidth(content);
@@ -53963,7 +54378,7 @@ function analyzeInstructionFile(path70, content) {
53963
54378
  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 \u2014 a concealment technique (hides text from human review while the agent reads it as contiguous)"
53964
54379
  ],
53965
54380
  "Remove the zero-width characters. Instruction files must be plain, reviewable text.",
53966
- path70
54381
+ path71
53967
54382
  )
53968
54383
  );
53969
54384
  }
@@ -53979,7 +54394,7 @@ function analyzeInstructionFile(path70, content) {
53979
54394
  `contains a prompt-override / role-impersonation directive (\`${m[0].slice(0, 60).trim()}\`)${ovEnc ? " \u2014 concealed in a base64 blob" : ""}`
53980
54395
  ],
53981
54396
  "Remove the override text. An instruction file should not tell the agent to ignore its own rules.",
53982
- path70
54397
+ path71
53983
54398
  )
53984
54399
  );
53985
54400
  }
@@ -53991,7 +54406,7 @@ function analyzeInstructionFile(path70, content) {
53991
54406
  "Instruction directs the agent to fetch and run remote code",
53992
54407
  [`\`${fo[0].slice(0, 70).trim()}\` \u2014 fetch-and-obey, outside an install/setup section`],
53993
54408
  "Do not instruct the agent to pipe remote content into a shell; pin and vendor scripts instead.",
53994
- path70
54409
+ path71
53995
54410
  )
53996
54411
  );
53997
54412
  }
@@ -54003,7 +54418,7 @@ function analyzeInstructionFile(path70, content) {
54003
54418
  "Instruction points the agent at credential material",
54004
54419
  [`references \`${sp[0].slice(0, 50).trim()}\` \u2014 directs the agent toward secrets`],
54005
54420
  "Do not reference credential files or paths in agent instructions.",
54006
- path70
54421
+ path71
54007
54422
  )
54008
54423
  );
54009
54424
  }
@@ -54015,7 +54430,7 @@ function analyzeInstructionFile(path70, content) {
54015
54430
  "Instruction directs the agent to send data to an external endpoint",
54016
54431
  [`\`${ex[0].slice(0, 70).trim()}\` \u2014 possible exfiltration directive`],
54017
54432
  "Remove external post/upload directives from agent instructions.",
54018
- path70
54433
+ path71
54019
54434
  )
54020
54435
  );
54021
54436
  }
@@ -54315,19 +54730,19 @@ function registerEgressCommand(program2) {
54315
54730
  var import_chalk32 = __toESM(require("chalk"));
54316
54731
 
54317
54732
  // src/shields/jail.ts
54318
- var import_fs60 = __toESM(require("fs"));
54319
- var import_os51 = __toESM(require("os"));
54320
- var import_path57 = __toESM(require("path"));
54733
+ var import_fs61 = __toESM(require("fs"));
54734
+ var import_os53 = __toESM(require("os"));
54735
+ var import_path58 = __toESM(require("path"));
54321
54736
  init_build();
54322
54737
  init_shields();
54323
54738
  var USER_JAIL_SHIELD = "user-jail";
54324
54739
  function jailStorePath() {
54325
- return import_path57.default.join(import_os51.default.homedir(), ".node9", "jail-paths.json");
54740
+ return import_path58.default.join(import_os53.default.homedir(), ".node9", "jail-paths.json");
54326
54741
  }
54327
54742
  function readJailPaths() {
54328
54743
  let text;
54329
54744
  try {
54330
- text = import_fs60.default.readFileSync(jailStorePath(), "utf8");
54745
+ text = import_fs61.default.readFileSync(jailStorePath(), "utf8");
54331
54746
  } catch (err2) {
54332
54747
  if (err2.code === "ENOENT") return [];
54333
54748
  throw err2;
@@ -54345,8 +54760,8 @@ function readJailPaths() {
54345
54760
  }
54346
54761
  function writeJailPaths(paths) {
54347
54762
  const p = jailStorePath();
54348
- import_fs60.default.mkdirSync(import_path57.default.dirname(p), { recursive: true });
54349
- import_fs60.default.writeFileSync(p, JSON.stringify({ paths }, null, 2) + "\n", { mode: 384 });
54763
+ import_fs61.default.mkdirSync(import_path58.default.dirname(p), { recursive: true });
54764
+ import_fs61.default.writeFileSync(p, JSON.stringify({ paths }, null, 2) + "\n", { mode: 384 });
54350
54765
  }
54351
54766
  function addJailPath(rawPath, verdict) {
54352
54767
  const norm = rawPath.trim();
@@ -54368,14 +54783,14 @@ function removeJailPath(rawPath) {
54368
54783
  return { removed, paths: after };
54369
54784
  }
54370
54785
  function regenerateUserJail(paths) {
54371
- const file = import_path57.default.join(USER_SHIELDS_DIR_PATH, `${USER_JAIL_SHIELD}.json`);
54786
+ const file = import_path58.default.join(USER_SHIELDS_DIR_PATH, `${USER_JAIL_SHIELD}.json`);
54372
54787
  if (paths.length === 0) {
54373
54788
  const active2 = readActiveShields();
54374
54789
  if (active2.includes(USER_JAIL_SHIELD)) {
54375
54790
  writeActiveShields(active2.filter((s) => s !== USER_JAIL_SHIELD));
54376
54791
  }
54377
54792
  try {
54378
- import_fs60.default.rmSync(file, { force: true });
54793
+ import_fs61.default.rmSync(file, { force: true });
54379
54794
  } catch {
54380
54795
  }
54381
54796
  return;
@@ -54489,14 +54904,14 @@ function registerJailCommand(program2) {
54489
54904
 
54490
54905
  // src/cli/commands/sandbox.ts
54491
54906
  var import_chalk33 = __toESM(require("chalk"));
54492
- var import_fs63 = __toESM(require("fs"));
54493
- var import_path60 = __toESM(require("path"));
54907
+ var import_fs64 = __toESM(require("fs"));
54908
+ var import_path61 = __toESM(require("path"));
54494
54909
  var import_child_process13 = require("child_process");
54495
54910
  init_config();
54496
54911
 
54497
54912
  // src/sandbox/config.ts
54498
- var import_fs61 = __toESM(require("fs"));
54499
- var import_path58 = __toESM(require("path"));
54913
+ var import_fs62 = __toESM(require("fs"));
54914
+ var import_path59 = __toESM(require("path"));
54500
54915
  var import_yaml2 = require("yaml");
54501
54916
  var SANDBOX_CONFIG_FILE = "node9.sandbox.yaml";
54502
54917
  var FORBIDDEN_ENV = /* @__PURE__ */ new Set(["NODE9_API_KEY", "NODE9_API_URL"]);
@@ -54569,16 +54984,16 @@ function scaffoldSandboxYaml(agent) {
54569
54984
  return header + (0, import_yaml2.stringify)(defaultSandboxConfig(agent));
54570
54985
  }
54571
54986
  function sandboxConfigPath(cwd = process.cwd()) {
54572
- return import_path58.default.join(cwd, SANDBOX_CONFIG_FILE);
54987
+ return import_path59.default.join(cwd, SANDBOX_CONFIG_FILE);
54573
54988
  }
54574
54989
  function loadSandboxConfig(cwd = process.cwd(), fallbackAgent = "claude") {
54575
54990
  const p = sandboxConfigPath(cwd);
54576
- if (!import_fs61.default.existsSync(p)) {
54991
+ if (!import_fs62.default.existsSync(p)) {
54577
54992
  throw new Error(`sandbox: ${SANDBOX_CONFIG_FILE} not found \u2014 run \`node9 sandbox new\` first.`);
54578
54993
  }
54579
54994
  let raw;
54580
54995
  try {
54581
- raw = (0, import_yaml2.parse)(import_fs61.default.readFileSync(p, "utf-8"));
54996
+ raw = (0, import_yaml2.parse)(import_fs62.default.readFileSync(p, "utf-8"));
54582
54997
  } catch (err2) {
54583
54998
  throw new Error(
54584
54999
  `sandbox: ${SANDBOX_CONFIG_FILE} is not valid YAML \u2014 ${err2.message}`
@@ -54636,14 +55051,14 @@ function compileAllowlist(input) {
54636
55051
  init_templates();
54637
55052
 
54638
55053
  // src/sandbox/runtime.ts
54639
- var import_fs62 = __toESM(require("fs"));
54640
- var import_os52 = __toESM(require("os"));
54641
- var import_path59 = __toESM(require("path"));
55054
+ var import_fs63 = __toESM(require("fs"));
55055
+ var import_os54 = __toESM(require("os"));
55056
+ var import_path60 = __toESM(require("path"));
54642
55057
  var import_crypto14 = __toESM(require("crypto"));
54643
55058
  var import_child_process12 = require("child_process");
54644
55059
  init_templates();
54645
55060
  function sandboxDataDir(cwd = process.cwd()) {
54646
- return import_path59.default.join(cwd, ".node9", "sandbox", "data");
55061
+ return import_path60.default.join(cwd, ".node9", "sandbox", "data");
54647
55062
  }
54648
55063
  function detectEngine(engine) {
54649
55064
  const r = (0, import_child_process12.spawnSync)(engine, ["--version"], { encoding: "utf-8" });
@@ -54654,7 +55069,7 @@ function detectEngine(engine) {
54654
55069
  }
54655
55070
  function agentCredentialsMount(agent) {
54656
55071
  const rel = agent === "codex" ? ".codex/auth.json" : ".claude/.credentials.json";
54657
- return { hostPath: import_path59.default.join(import_os52.default.homedir(), rel), target: `/home/${RUN_AS_USER}/${rel}` };
55072
+ return { hostPath: import_path60.default.join(import_os54.default.homedir(), rel), target: `/home/${RUN_AS_USER}/${rel}` };
54658
55073
  }
54659
55074
  function buildRunArgs(opts) {
54660
55075
  const { config, workspaceHostPath, dataHostPath, allowlistHostPath, agentArgs } = opts;
@@ -54664,7 +55079,7 @@ function buildRunArgs(opts) {
54664
55079
  args.push("-v", `${allowlistHostPath}:${ALLOWED_DOMAINS_PATH}:ro`);
54665
55080
  if (config.node9.mountAgentCredentials) {
54666
55081
  const creds = agentCredentialsMount(config.agent);
54667
- if (import_fs62.default.existsSync(creds.hostPath)) {
55082
+ if (import_fs63.default.existsSync(creds.hostPath)) {
54668
55083
  args.push("-v", `${creds.hostPath}:${creds.target}`);
54669
55084
  }
54670
55085
  }
@@ -54682,30 +55097,30 @@ function imageContentHash(dockerfile, entrypoint) {
54682
55097
  return import_crypto14.default.createHash("sha256").update(dockerfile).update("\0").update(entrypoint).digest("hex").slice(0, 16);
54683
55098
  }
54684
55099
  function sandboxBuildDir(cwd = process.cwd()) {
54685
- return import_path59.default.join(cwd, ".node9", "sandbox", "build");
55100
+ return import_path60.default.join(cwd, ".node9", "sandbox", "build");
54686
55101
  }
54687
55102
  function writeBuildContext(cwd, dockerfile, entrypoint) {
54688
55103
  const dir = sandboxBuildDir(cwd);
54689
- import_fs62.default.mkdirSync(dir, { recursive: true });
54690
- import_fs62.default.writeFileSync(import_path59.default.join(dir, "Dockerfile"), dockerfile);
54691
- import_fs62.default.writeFileSync(import_path59.default.join(dir, "entrypoint.sh"), entrypoint);
55104
+ import_fs63.default.mkdirSync(dir, { recursive: true });
55105
+ import_fs63.default.writeFileSync(import_path60.default.join(dir, "Dockerfile"), dockerfile);
55106
+ import_fs63.default.writeFileSync(import_path60.default.join(dir, "entrypoint.sh"), entrypoint);
54692
55107
  return dir;
54693
55108
  }
54694
55109
  function writeAllowlist(cwd, hosts) {
54695
- const dir = import_path59.default.join(cwd, ".node9", "sandbox");
54696
- import_fs62.default.mkdirSync(dir, { recursive: true });
54697
- const p = import_path59.default.join(dir, "allowed-domains.txt");
54698
- import_fs62.default.writeFileSync(p, hosts.join("\n") + "\n");
55110
+ const dir = import_path60.default.join(cwd, ".node9", "sandbox");
55111
+ import_fs63.default.mkdirSync(dir, { recursive: true });
55112
+ const p = import_path60.default.join(dir, "allowed-domains.txt");
55113
+ import_fs63.default.writeFileSync(p, hosts.join("\n") + "\n");
54699
55114
  return p;
54700
55115
  }
54701
55116
  function resolveHomePath(p) {
54702
- return p.startsWith("~") ? import_path59.default.join(import_os52.default.homedir(), p.slice(1)) : import_path59.default.resolve(p);
55117
+ return p.startsWith("~") ? import_path60.default.join(import_os54.default.homedir(), p.slice(1)) : import_path60.default.resolve(p);
54703
55118
  }
54704
55119
 
54705
55120
  // src/cli/commands/sandbox.ts
54706
55121
  function seedDataDirConfig(dataDir, sandbox) {
54707
- import_fs63.default.mkdirSync(dataDir, { recursive: true });
54708
- const configPath = import_path60.default.join(dataDir, "config.json");
55122
+ import_fs64.default.mkdirSync(dataDir, { recursive: true });
55123
+ const configPath = import_path61.default.join(dataDir, "config.json");
54709
55124
  const seed = {
54710
55125
  settings: {
54711
55126
  approvers: {
@@ -54716,7 +55131,7 @@ function seedDataDirConfig(dataDir, sandbox) {
54716
55131
  }
54717
55132
  }
54718
55133
  };
54719
- import_fs63.default.writeFileSync(configPath, JSON.stringify(seed, null, 2), { mode: 384 });
55134
+ import_fs64.default.writeFileSync(configPath, JSON.stringify(seed, null, 2), { mode: 384 });
54720
55135
  }
54721
55136
  function registerSandboxCommand(program2, version2) {
54722
55137
  const node9Version2 = pinnedNode9Version(version2);
@@ -54724,13 +55139,13 @@ function registerSandboxCommand(program2, version2) {
54724
55139
  cmd.command("new").description(`Scaffold ${SANDBOX_CONFIG_FILE} in this project`).option("--agent <agent>", "claude (default) or codex", "claude").action((opts) => {
54725
55140
  const agent = opts.agent === "codex" ? "codex" : "claude";
54726
55141
  const p = sandboxConfigPath();
54727
- if (import_fs63.default.existsSync(p)) {
55142
+ if (import_fs64.default.existsSync(p)) {
54728
55143
  console.log(
54729
55144
  import_chalk33.default.yellow(` ${SANDBOX_CONFIG_FILE} already exists \u2014 leaving it untouched.`)
54730
55145
  );
54731
55146
  return;
54732
55147
  }
54733
- import_fs63.default.writeFileSync(p, scaffoldSandboxYaml(agent));
55148
+ import_fs64.default.writeFileSync(p, scaffoldSandboxYaml(agent));
54734
55149
  console.log(
54735
55150
  import_chalk33.default.green(` \u2713 wrote ${SANDBOX_CONFIG_FILE}`) + import_chalk33.default.dim(` (agent: ${agent})`)
54736
55151
  );
@@ -54770,8 +55185,8 @@ function registerSandboxCommand(program2, version2) {
54770
55185
  const buildDir = writeBuildContext(cwd, dockerfile, entrypoint);
54771
55186
  const hash = imageContentHash(dockerfile, entrypoint);
54772
55187
  const image = sandbox.runtime.image;
54773
- const hashFile = import_path60.default.join(sandboxBuildDir(cwd), ".image-hash");
54774
- const lastHash = import_fs63.default.existsSync(hashFile) ? import_fs63.default.readFileSync(hashFile, "utf-8").trim() : "";
55188
+ const hashFile = import_path61.default.join(sandboxBuildDir(cwd), ".image-hash");
55189
+ const lastHash = import_fs64.default.existsSync(hashFile) ? import_fs64.default.readFileSync(hashFile, "utf-8").trim() : "";
54775
55190
  const imageExists = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, ["image", "inspect", image], { stdio: "ignore" }).status === 0;
54776
55191
  const needBuild = sandbox.runtime.rebuild === "always" || !imageExists || sandbox.runtime.rebuild !== "never" && lastHash !== hash;
54777
55192
  if (needBuild) {
@@ -54783,7 +55198,7 @@ function registerSandboxCommand(program2, version2) {
54783
55198
  console.error(import_chalk33.default.red(" build failed."));
54784
55199
  process.exit(b.status ?? 1);
54785
55200
  }
54786
- import_fs63.default.writeFileSync(hashFile, hash);
55201
+ import_fs64.default.writeFileSync(hashFile, hash);
54787
55202
  }
54788
55203
  const dataDir = sandboxDataDir(cwd);
54789
55204
  seedDataDirConfig(dataDir, sandbox);
@@ -54797,7 +55212,7 @@ function registerSandboxCommand(program2, version2) {
54797
55212
  });
54798
55213
  if (sandbox.node9.mountAgentCredentials) {
54799
55214
  const creds = agentCredentialsMount(sandbox.agent);
54800
- if (import_fs63.default.existsSync(creds.hostPath)) {
55215
+ if (import_fs64.default.existsSync(creds.hostPath)) {
54801
55216
  console.log(import_chalk33.default.dim(` mounting ${creds.hostPath} (agent credentials, rw)`));
54802
55217
  } else {
54803
55218
  console.log(
@@ -54813,20 +55228,20 @@ function registerSandboxCommand(program2, version2) {
54813
55228
  process.exit(r.status ?? 0);
54814
55229
  });
54815
55230
  cmd.command("tail").description("Stream the sandbox's audit log (host-side)").action(() => {
54816
- const auditPath = import_path60.default.join(sandboxDataDir(), "audit.log");
54817
- if (!import_fs63.default.existsSync(auditPath)) {
55231
+ const auditPath = import_path61.default.join(sandboxDataDir(), "audit.log");
55232
+ if (!import_fs64.default.existsSync(auditPath)) {
54818
55233
  console.log(import_chalk33.default.dim(" no sandbox audit yet."));
54819
55234
  return;
54820
55235
  }
54821
55236
  (0, import_child_process13.spawnSync)("tail", ["-f", auditPath], { stdio: "inherit" });
54822
55237
  });
54823
55238
  cmd.command("logs").description("Dump the sandbox's audit log").action(() => {
54824
- const auditPath = import_path60.default.join(sandboxDataDir(), "audit.log");
54825
- if (!import_fs63.default.existsSync(auditPath)) {
55239
+ const auditPath = import_path61.default.join(sandboxDataDir(), "audit.log");
55240
+ if (!import_fs64.default.existsSync(auditPath)) {
54826
55241
  console.log(import_chalk33.default.dim(" no sandbox audit yet."));
54827
55242
  return;
54828
55243
  }
54829
- process.stdout.write(import_fs63.default.readFileSync(auditPath, "utf-8"));
55244
+ process.stdout.write(import_fs64.default.readFileSync(auditPath, "utf-8"));
54830
55245
  });
54831
55246
  cmd.command("clean").description("Remove the sandbox image, build context, and data").action(() => {
54832
55247
  const cwd = process.cwd();
@@ -54840,16 +55255,16 @@ function registerSandboxCommand(program2, version2) {
54840
55255
  stdio: "ignore"
54841
55256
  });
54842
55257
  }
54843
- import_fs63.default.rmSync(import_path60.default.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
55258
+ import_fs64.default.rmSync(import_path61.default.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
54844
55259
  console.log(import_chalk33.default.green(" \u2713 sandbox image + build + data removed."));
54845
55260
  });
54846
55261
  }
54847
55262
 
54848
55263
  // src/cli/commands/sessions.ts
54849
55264
  var import_chalk34 = __toESM(require("chalk"));
54850
- var import_fs64 = __toESM(require("fs"));
54851
- var import_path61 = __toESM(require("path"));
54852
- var import_os53 = __toESM(require("os"));
55265
+ var import_fs65 = __toESM(require("fs"));
55266
+ var import_path62 = __toESM(require("path"));
55267
+ var import_os55 = __toESM(require("os"));
54853
55268
  init_scan_summary();
54854
55269
  init_litellm();
54855
55270
  init_cost_gemini();
@@ -54870,10 +55285,10 @@ function encodeProjectPath(projectPath) {
54870
55285
  }
54871
55286
  function sessionJsonlPath(projectPath, sessionId) {
54872
55287
  const encoded = encodeProjectPath(projectPath);
54873
- return import_path61.default.join(import_os53.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
55288
+ return import_path62.default.join(import_os55.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
54874
55289
  }
54875
55290
  function projectLabel(projectPath) {
54876
- return projectPath.replace(import_os53.default.homedir(), "~");
55291
+ return projectPath.replace(import_os55.default.homedir(), "~");
54877
55292
  }
54878
55293
  function parseHistoryLines(lines) {
54879
55294
  const entries = [];
@@ -54942,10 +55357,10 @@ function parseSessionLines(lines) {
54942
55357
  return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
54943
55358
  }
54944
55359
  function loadAuditEntries(auditPath) {
54945
- const aPath = auditPath ?? import_path61.default.join(import_os53.default.homedir(), ".node9", "audit.log");
55360
+ const aPath = auditPath ?? import_path62.default.join(import_os55.default.homedir(), ".node9", "audit.log");
54946
55361
  let raw;
54947
55362
  try {
54948
- raw = import_fs64.default.readFileSync(aPath, "utf-8");
55363
+ raw = import_fs65.default.readFileSync(aPath, "utf-8");
54949
55364
  } catch {
54950
55365
  return [];
54951
55366
  }
@@ -54981,8 +55396,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
54981
55396
  return result;
54982
55397
  }
54983
55398
  function buildGeminiSessions(days, allAuditEntries) {
54984
- const tmpDir = import_path61.default.join(import_os53.default.homedir(), ".gemini", "tmp");
54985
- if (!import_fs64.default.existsSync(tmpDir)) return [];
55399
+ const tmpDir = import_path62.default.join(import_os55.default.homedir(), ".gemini", "tmp");
55400
+ if (!import_fs65.default.existsSync(tmpDir)) return [];
54986
55401
  const cutoff = days !== null ? (() => {
54987
55402
  const d = /* @__PURE__ */ new Date();
54988
55403
  d.setDate(d.getDate() - days);
@@ -54991,35 +55406,35 @@ function buildGeminiSessions(days, allAuditEntries) {
54991
55406
  })() : null;
54992
55407
  let slugDirs;
54993
55408
  try {
54994
- slugDirs = import_fs64.default.readdirSync(tmpDir);
55409
+ slugDirs = import_fs65.default.readdirSync(tmpDir);
54995
55410
  } catch {
54996
55411
  return [];
54997
55412
  }
54998
55413
  const summaries = [];
54999
55414
  for (const slug2 of slugDirs) {
55000
- const slugPath = import_path61.default.join(tmpDir, slug2);
55415
+ const slugPath = import_path62.default.join(tmpDir, slug2);
55001
55416
  try {
55002
- if (!import_fs64.default.statSync(slugPath).isDirectory()) continue;
55417
+ if (!import_fs65.default.statSync(slugPath).isDirectory()) continue;
55003
55418
  } catch {
55004
55419
  continue;
55005
55420
  }
55006
- let projectRoot = import_path61.default.join(import_os53.default.homedir(), slug2);
55421
+ let projectRoot = import_path62.default.join(import_os55.default.homedir(), slug2);
55007
55422
  try {
55008
- projectRoot = import_fs64.default.readFileSync(import_path61.default.join(slugPath, ".project_root"), "utf-8").trim();
55423
+ projectRoot = import_fs65.default.readFileSync(import_path62.default.join(slugPath, ".project_root"), "utf-8").trim();
55009
55424
  } catch {
55010
55425
  }
55011
- const chatsDir = import_path61.default.join(slugPath, "chats");
55012
- if (!import_fs64.default.existsSync(chatsDir)) continue;
55426
+ const chatsDir = import_path62.default.join(slugPath, "chats");
55427
+ if (!import_fs65.default.existsSync(chatsDir)) continue;
55013
55428
  let chatFiles;
55014
55429
  try {
55015
- chatFiles = import_fs64.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
55430
+ chatFiles = import_fs65.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
55016
55431
  } catch {
55017
55432
  continue;
55018
55433
  }
55019
55434
  for (const chatFile of chatFiles) {
55020
55435
  let raw;
55021
55436
  try {
55022
- raw = import_fs64.default.readFileSync(import_path61.default.join(chatsDir, chatFile), "utf-8");
55437
+ raw = import_fs65.default.readFileSync(import_path62.default.join(chatsDir, chatFile), "utf-8");
55023
55438
  } catch {
55024
55439
  continue;
55025
55440
  }
@@ -55099,8 +55514,8 @@ function buildGeminiSessions(days, allAuditEntries) {
55099
55514
  return summaries;
55100
55515
  }
55101
55516
  function buildCodexSessions(days, allAuditEntries) {
55102
- const sessionsBase = import_path61.default.join(import_os53.default.homedir(), ".codex", "sessions");
55103
- if (!import_fs64.default.existsSync(sessionsBase)) return [];
55517
+ const sessionsBase = import_path62.default.join(import_os55.default.homedir(), ".codex", "sessions");
55518
+ if (!import_fs65.default.existsSync(sessionsBase)) return [];
55104
55519
  const cutoff = days !== null ? (() => {
55105
55520
  const d = /* @__PURE__ */ new Date();
55106
55521
  d.setDate(d.getDate() - days);
@@ -55109,29 +55524,29 @@ function buildCodexSessions(days, allAuditEntries) {
55109
55524
  })() : null;
55110
55525
  const jsonlFiles = [];
55111
55526
  try {
55112
- for (const year of import_fs64.default.readdirSync(sessionsBase)) {
55113
- const yearPath = import_path61.default.join(sessionsBase, year);
55527
+ for (const year of import_fs65.default.readdirSync(sessionsBase)) {
55528
+ const yearPath = import_path62.default.join(sessionsBase, year);
55114
55529
  try {
55115
- if (!import_fs64.default.statSync(yearPath).isDirectory()) continue;
55530
+ if (!import_fs65.default.statSync(yearPath).isDirectory()) continue;
55116
55531
  } catch {
55117
55532
  continue;
55118
55533
  }
55119
- for (const month of import_fs64.default.readdirSync(yearPath)) {
55120
- const monthPath = import_path61.default.join(yearPath, month);
55534
+ for (const month of import_fs65.default.readdirSync(yearPath)) {
55535
+ const monthPath = import_path62.default.join(yearPath, month);
55121
55536
  try {
55122
- if (!import_fs64.default.statSync(monthPath).isDirectory()) continue;
55537
+ if (!import_fs65.default.statSync(monthPath).isDirectory()) continue;
55123
55538
  } catch {
55124
55539
  continue;
55125
55540
  }
55126
- for (const day of import_fs64.default.readdirSync(monthPath)) {
55127
- const dayPath = import_path61.default.join(monthPath, day);
55541
+ for (const day of import_fs65.default.readdirSync(monthPath)) {
55542
+ const dayPath = import_path62.default.join(monthPath, day);
55128
55543
  try {
55129
- if (!import_fs64.default.statSync(dayPath).isDirectory()) continue;
55544
+ if (!import_fs65.default.statSync(dayPath).isDirectory()) continue;
55130
55545
  } catch {
55131
55546
  continue;
55132
55547
  }
55133
- for (const file of import_fs64.default.readdirSync(dayPath)) {
55134
- if (file.endsWith(".jsonl")) jsonlFiles.push(import_path61.default.join(dayPath, file));
55548
+ for (const file of import_fs65.default.readdirSync(dayPath)) {
55549
+ if (file.endsWith(".jsonl")) jsonlFiles.push(import_path62.default.join(dayPath, file));
55135
55550
  }
55136
55551
  }
55137
55552
  }
@@ -55143,7 +55558,7 @@ function buildCodexSessions(days, allAuditEntries) {
55143
55558
  for (const filePath of jsonlFiles) {
55144
55559
  let lines;
55145
55560
  try {
55146
- lines = import_fs64.default.readFileSync(filePath, "utf-8").split("\n");
55561
+ lines = import_fs65.default.readFileSync(filePath, "utf-8").split("\n");
55147
55562
  } catch {
55148
55563
  continue;
55149
55564
  }
@@ -55229,10 +55644,10 @@ function buildCodexSessions(days, allAuditEntries) {
55229
55644
  return summaries;
55230
55645
  }
55231
55646
  function buildSessions(days, historyPath) {
55232
- const hPath = historyPath ?? import_path61.default.join(import_os53.default.homedir(), ".claude", "history.jsonl");
55647
+ const hPath = historyPath ?? import_path62.default.join(import_os55.default.homedir(), ".claude", "history.jsonl");
55233
55648
  let historyRaw = "";
55234
55649
  try {
55235
- historyRaw = import_fs64.default.readFileSync(hPath, "utf-8");
55650
+ historyRaw = import_fs65.default.readFileSync(hPath, "utf-8");
55236
55651
  } catch {
55237
55652
  }
55238
55653
  const cutoff = days !== null ? (() => {
@@ -55256,7 +55671,7 @@ function buildSessions(days, historyPath) {
55256
55671
  const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
55257
55672
  let sessionLines = [];
55258
55673
  try {
55259
- sessionLines = import_fs64.default.readFileSync(jsonlFile, "utf-8").split("\n");
55674
+ sessionLines = import_fs65.default.readFileSync(jsonlFile, "utf-8").split("\n");
55260
55675
  } catch {
55261
55676
  }
55262
55677
  const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
@@ -55650,12 +56065,12 @@ function registerSessionTaintCommand(program2) {
55650
56065
 
55651
56066
  // src/cli/commands/skill-pin.ts
55652
56067
  var import_chalk36 = __toESM(require("chalk"));
55653
- var import_fs65 = __toESM(require("fs"));
55654
- var import_os54 = __toESM(require("os"));
55655
- var import_path62 = __toESM(require("path"));
56068
+ var import_fs66 = __toESM(require("fs"));
56069
+ var import_os56 = __toESM(require("os"));
56070
+ var import_path63 = __toESM(require("path"));
55656
56071
  function wipeSkillSessions() {
55657
56072
  try {
55658
- import_fs65.default.rmSync(import_path62.default.join(import_os54.default.homedir(), ".node9", "skill-sessions"), {
56073
+ import_fs66.default.rmSync(import_path63.default.join(import_os56.default.homedir(), ".node9", "skill-sessions"), {
55659
56074
  recursive: true,
55660
56075
  force: true
55661
56076
  });
@@ -55737,15 +56152,15 @@ function registerSkillPinCommand(program2) {
55737
56152
  }
55738
56153
 
55739
56154
  // src/cli/commands/decisions.ts
55740
- var import_fs66 = __toESM(require("fs"));
55741
- var import_os55 = __toESM(require("os"));
55742
- var import_path63 = __toESM(require("path"));
56155
+ var import_fs67 = __toESM(require("fs"));
56156
+ var import_os57 = __toESM(require("os"));
56157
+ var import_path64 = __toESM(require("path"));
55743
56158
  var import_chalk37 = __toESM(require("chalk"));
55744
- var DECISIONS_FILE2 = import_path63.default.join(import_os55.default.homedir(), ".node9", "decisions.json");
56159
+ var DECISIONS_FILE2 = import_path64.default.join(import_os57.default.homedir(), ".node9", "decisions.json");
55745
56160
  function readDecisions() {
55746
56161
  try {
55747
- if (!import_fs66.default.existsSync(DECISIONS_FILE2)) return {};
55748
- const raw = import_fs66.default.readFileSync(DECISIONS_FILE2, "utf-8");
56162
+ if (!import_fs67.default.existsSync(DECISIONS_FILE2)) return {};
56163
+ const raw = import_fs67.default.readFileSync(DECISIONS_FILE2, "utf-8");
55749
56164
  const parsed = JSON.parse(raw);
55750
56165
  const out = {};
55751
56166
  for (const [k, v] of Object.entries(parsed)) {
@@ -55757,11 +56172,11 @@ function readDecisions() {
55757
56172
  }
55758
56173
  }
55759
56174
  function writeDecisions(d) {
55760
- const dir = import_path63.default.dirname(DECISIONS_FILE2);
55761
- if (!import_fs66.default.existsSync(dir)) import_fs66.default.mkdirSync(dir, { recursive: true });
56175
+ const dir = import_path64.default.dirname(DECISIONS_FILE2);
56176
+ if (!import_fs67.default.existsSync(dir)) import_fs67.default.mkdirSync(dir, { recursive: true });
55762
56177
  const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
55763
- import_fs66.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
55764
- import_fs66.default.renameSync(tmp, DECISIONS_FILE2);
56178
+ import_fs67.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
56179
+ import_fs67.default.renameSync(tmp, DECISIONS_FILE2);
55765
56180
  }
55766
56181
  function registerDecisionsCommand(program2) {
55767
56182
  const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
@@ -55818,18 +56233,18 @@ Persistent decisions (${entries.length})
55818
56233
 
55819
56234
  // src/cli/commands/dlp.ts
55820
56235
  var import_chalk38 = __toESM(require("chalk"));
55821
- var import_fs67 = __toESM(require("fs"));
55822
- var import_path64 = __toESM(require("path"));
55823
- var import_os56 = __toESM(require("os"));
55824
- var AUDIT_LOG = import_path64.default.join(import_os56.default.homedir(), ".node9", "audit.log");
55825
- var RESOLVED_FILE = import_path64.default.join(import_os56.default.homedir(), ".node9", "dlp-resolved.json");
56236
+ var import_fs68 = __toESM(require("fs"));
56237
+ var import_path65 = __toESM(require("path"));
56238
+ var import_os58 = __toESM(require("os"));
56239
+ var AUDIT_LOG = import_path65.default.join(import_os58.default.homedir(), ".node9", "audit.log");
56240
+ var RESOLVED_FILE = import_path65.default.join(import_os58.default.homedir(), ".node9", "dlp-resolved.json");
55826
56241
  var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
55827
56242
  function stripAnsi(s) {
55828
56243
  return s.replace(ANSI_RE, "");
55829
56244
  }
55830
56245
  function loadResolved() {
55831
56246
  try {
55832
- const raw = JSON.parse(import_fs67.default.readFileSync(RESOLVED_FILE, "utf-8"));
56247
+ const raw = JSON.parse(import_fs68.default.readFileSync(RESOLVED_FILE, "utf-8"));
55833
56248
  return new Set(raw);
55834
56249
  } catch {
55835
56250
  return /* @__PURE__ */ new Set();
@@ -55837,13 +56252,13 @@ function loadResolved() {
55837
56252
  }
55838
56253
  function saveResolved(resolved) {
55839
56254
  try {
55840
- import_fs67.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
56255
+ import_fs68.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
55841
56256
  } catch {
55842
56257
  }
55843
56258
  }
55844
56259
  function loadDlpFindings() {
55845
- if (!import_fs67.default.existsSync(AUDIT_LOG)) return [];
55846
- return import_fs67.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
56260
+ if (!import_fs68.default.existsSync(AUDIT_LOG)) return [];
56261
+ return import_fs68.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
55847
56262
  if (!line.trim()) return [];
55848
56263
  try {
55849
56264
  const e = JSON.parse(line);
@@ -55941,15 +56356,15 @@ function registerDlpCommand(program2) {
55941
56356
 
55942
56357
  // src/cli/commands/mask.ts
55943
56358
  var import_chalk39 = __toESM(require("chalk"));
55944
- var import_fs68 = __toESM(require("fs"));
55945
- var import_path65 = __toESM(require("path"));
55946
- var import_os57 = __toESM(require("os"));
56359
+ var import_fs69 = __toESM(require("fs"));
56360
+ var import_path66 = __toESM(require("path"));
56361
+ var import_os59 = __toESM(require("os"));
55947
56362
  init_dlp();
55948
56363
  function findJsonlFiles(dir) {
55949
56364
  const results = [];
55950
- if (!import_fs68.default.existsSync(dir)) return results;
55951
- for (const entry of import_fs68.default.readdirSync(dir, { withFileTypes: true })) {
55952
- const full = import_path65.default.join(dir, entry.name);
56365
+ if (!import_fs69.default.existsSync(dir)) return results;
56366
+ for (const entry of import_fs69.default.readdirSync(dir, { withFileTypes: true })) {
56367
+ const full = import_path66.default.join(dir, entry.name);
55953
56368
  if (entry.isDirectory()) results.push(...findJsonlFiles(full));
55954
56369
  else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
55955
56370
  }
@@ -55992,7 +56407,7 @@ function redactJson(obj) {
55992
56407
  function processFile(filePath, dryRun) {
55993
56408
  let raw;
55994
56409
  try {
55995
- raw = import_fs68.default.readFileSync(filePath, "utf-8");
56410
+ raw = import_fs69.default.readFileSync(filePath, "utf-8");
55996
56411
  } catch {
55997
56412
  return { redactedLines: 0, patterns: [] };
55998
56413
  }
@@ -56024,14 +56439,14 @@ function processFile(filePath, dryRun) {
56024
56439
  }
56025
56440
  }
56026
56441
  if (!dryRun && redactedLines > 0) {
56027
- import_fs68.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
56442
+ import_fs69.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
56028
56443
  }
56029
56444
  return { redactedLines, patterns };
56030
56445
  }
56031
56446
  function processJsonFile(filePath, dryRun) {
56032
56447
  let raw;
56033
56448
  try {
56034
- raw = import_fs68.default.readFileSync(filePath, "utf-8");
56449
+ raw = import_fs69.default.readFileSync(filePath, "utf-8");
56035
56450
  } catch {
56036
56451
  return { redactedLines: 0, patterns: [] };
56037
56452
  }
@@ -56044,15 +56459,15 @@ function processJsonFile(filePath, dryRun) {
56044
56459
  const { value, modified, found } = redactJson(parsed);
56045
56460
  if (!modified) return { redactedLines: 0, patterns: [] };
56046
56461
  if (!dryRun) {
56047
- import_fs68.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
56462
+ import_fs69.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
56048
56463
  }
56049
56464
  return { redactedLines: 1, patterns: found };
56050
56465
  }
56051
56466
  function findJsonFiles(dir) {
56052
56467
  const results = [];
56053
- if (!import_fs68.default.existsSync(dir)) return results;
56054
- for (const entry of import_fs68.default.readdirSync(dir, { withFileTypes: true })) {
56055
- const full = import_path65.default.join(dir, entry.name);
56468
+ if (!import_fs69.default.existsSync(dir)) return results;
56469
+ for (const entry of import_fs69.default.readdirSync(dir, { withFileTypes: true })) {
56470
+ const full = import_path66.default.join(dir, entry.name);
56056
56471
  if (entry.isDirectory()) results.push(...findJsonFiles(full));
56057
56472
  else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
56058
56473
  }
@@ -56061,9 +56476,9 @@ function findJsonFiles(dir) {
56061
56476
  function registerMaskCommand(program2) {
56062
56477
  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) => {
56063
56478
  const dryRun = !!options.dryRun;
56064
- const home = import_os57.default.homedir();
56065
- const claudeDir = import_path65.default.join(home, ".claude", "projects");
56066
- const geminiDir = import_path65.default.join(home, ".gemini", "tmp");
56479
+ const home = import_os59.default.homedir();
56480
+ const claudeDir = import_path66.default.join(home, ".claude", "projects");
56481
+ const geminiDir = import_path66.default.join(home, ".gemini", "tmp");
56067
56482
  const allFiles = [
56068
56483
  ...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
56069
56484
  ...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
@@ -56071,7 +56486,7 @@ function registerMaskCommand(program2) {
56071
56486
  const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
56072
56487
  const filtered = cutoff ? allFiles.filter((f) => {
56073
56488
  try {
56074
- return import_fs68.default.statSync(f.path).mtime >= cutoff;
56489
+ return import_fs69.default.statSync(f.path).mtime >= cutoff;
56075
56490
  } catch {
56076
56491
  return false;
56077
56492
  }
@@ -56127,7 +56542,7 @@ function registerMaskCommand(program2) {
56127
56542
  // src/cli.ts
56128
56543
  init_blast();
56129
56544
  var { version } = JSON.parse(
56130
- import_fs71.default.readFileSync(import_path68.default.join(__dirname, "../package.json"), "utf-8")
56545
+ import_fs72.default.readFileSync(import_path69.default.join(__dirname, "../package.json"), "utf-8")
56131
56546
  );
56132
56547
  var program = new import_commander.Command();
56133
56548
  program.name("node9").description("The Sudo Command for AI Agents").version(version);
@@ -56153,6 +56568,11 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
56153
56568
  } else {
56154
56569
  console.log(import_chalk41.default.green(`\u2705 Logged in \u2014 agent mode`));
56155
56570
  console.log(import_chalk41.default.gray(` Team policy enforced for all calls via Node9 cloud.`));
56571
+ if (!isTestingMode()) {
56572
+ const healed = ensureAutostartHealthy(!!getConfig().settings.autoStartDaemon);
56573
+ if (healed === "repaired")
56574
+ console.log(import_chalk41.default.green(` \u2713 Re-enabled daemon autostart (survives reboot)`));
56575
+ }
56156
56576
  }
56157
56577
  });
56158
56578
  program.command("signup").description("Create your node9 account / open the dashboard in your browser").option("--login", "Open the login page instead of signup").action((options) => {
@@ -56301,15 +56721,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
56301
56721
  } catch {
56302
56722
  }
56303
56723
  if (options.purge) {
56304
- const node9Dir = import_path68.default.join(import_os60.default.homedir(), ".node9");
56305
- if (import_fs71.default.existsSync(node9Dir)) {
56724
+ const node9Dir = import_path69.default.join(import_os62.default.homedir(), ".node9");
56725
+ if (import_fs72.default.existsSync(node9Dir)) {
56306
56726
  const confirmed = await (0, import_prompts2.confirm)({
56307
56727
  message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
56308
56728
  default: false
56309
56729
  });
56310
56730
  if (confirmed) {
56311
- import_fs71.default.rmSync(node9Dir, { recursive: true });
56312
- if (import_fs71.default.existsSync(node9Dir)) {
56731
+ import_fs72.default.rmSync(node9Dir, { recursive: true });
56732
+ if (import_fs72.default.existsSync(node9Dir)) {
56313
56733
  console.error(
56314
56734
  import_chalk41.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
56315
56735
  );
@@ -56434,7 +56854,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
56434
56854
  });
56435
56855
  program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
56436
56856
  try {
56437
- const dashboardPath = import_path68.default.join(__dirname, "dashboard.mjs");
56857
+ const dashboardPath = import_path69.default.join(__dirname, "dashboard.mjs");
56438
56858
  const dynamicImport = new Function("id", "return import(id)");
56439
56859
  const mod = await dynamicImport(`file://${dashboardPath}`);
56440
56860
  await mod.startMonitor();
@@ -56472,14 +56892,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
56472
56892
  Run "node9 addto claude" to register it as the statusLine.`
56473
56893
  ).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
56474
56894
  if (subcommand === "debug") {
56475
- const flagFile = import_path68.default.join(import_os60.default.homedir(), ".node9", "hud-debug");
56895
+ const flagFile = import_path69.default.join(import_os62.default.homedir(), ".node9", "hud-debug");
56476
56896
  if (state === "on") {
56477
- import_fs71.default.mkdirSync(import_path68.default.dirname(flagFile), { recursive: true });
56478
- import_fs71.default.writeFileSync(flagFile, "");
56897
+ import_fs72.default.mkdirSync(import_path69.default.dirname(flagFile), { recursive: true });
56898
+ import_fs72.default.writeFileSync(flagFile, "");
56479
56899
  console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
56480
56900
  console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
56481
56901
  } else if (state === "off") {
56482
- if (import_fs71.default.existsSync(flagFile)) import_fs71.default.unlinkSync(flagFile);
56902
+ if (import_fs72.default.existsSync(flagFile)) import_fs72.default.unlinkSync(flagFile);
56483
56903
  console.log("HUD debug logging disabled.");
56484
56904
  } else {
56485
56905
  console.error("Usage: node9 hud debug on|off");
@@ -56602,9 +57022,9 @@ if (process.argv[2] !== "daemon") {
56602
57022
  const isCheckHook = process.argv[2] === "check";
56603
57023
  if (isCheckHook) {
56604
57024
  if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
56605
- const logPath = import_path68.default.join(import_os60.default.homedir(), ".node9", "hook-debug.log");
57025
+ const logPath = import_path69.default.join(import_os62.default.homedir(), ".node9", "hook-debug.log");
56606
57026
  const msg = reason instanceof Error ? reason.message : String(reason);
56607
- import_fs71.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
57027
+ import_fs72.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
56608
57028
  `);
56609
57029
  }
56610
57030
  process.exit(0);