@node9/proxy 1.61.1 → 1.62.1

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.
Files changed (3) hide show
  1. package/dist/cli.js +973 -622
  2. package/dist/cli.mjs +967 -616
  3. package/package.json +1 -1
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,
@@ -1454,9 +1454,9 @@ function matchesPattern(text, patterns) {
1454
1454
  const withoutDotSlash = text.replace(/^\.\//, "");
1455
1455
  return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
1456
1456
  }
1457
- function getNestedValue(obj, path70) {
1457
+ function getNestedValue(obj, path71) {
1458
1458
  if (!obj || typeof obj !== "object") return null;
1459
- const segments = path70.split(".");
1459
+ const segments = path71.split(".");
1460
1460
  for (const seg of segments) {
1461
1461
  if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
1462
1462
  }
@@ -4842,10 +4842,10 @@ function getConfig(cwd) {
4842
4842
  }
4843
4843
  if (Array.isArray(mc.jailPaths)) {
4844
4844
  for (const jp of mc.jailPaths) {
4845
- const path70 = typeof jp?.path === "string" ? jp.path.trim() : "";
4846
- if (!path70) continue;
4845
+ const path71 = typeof jp?.path === "string" ? jp.path.trim() : "";
4846
+ if (!path71) continue;
4847
4847
  const verdict = jp?.verdict === "review" ? "review" : "block";
4848
- for (const r of pathRules(path70, verdict, "org-managed jail")) {
4848
+ for (const r of pathRules(path71, verdict, "org-managed jail")) {
4849
4849
  mergedPolicy.smartRules.push({ ...r, name: `org:${r.name}` });
4850
4850
  }
4851
4851
  }
@@ -17965,6 +17965,66 @@ function pickSyncIntervalMs(cloudHours, localSettings) {
17965
17965
  function effectiveSyncIntervalMs() {
17966
17966
  return pickSyncIntervalMs(readCachedSyncIntervalHours(), getConfig().settings);
17967
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
+ }
17968
18028
  function fetchCloudPolicy(apiKey, apiUrl, ifNoneMatch) {
17969
18029
  const parsed = new URL(apiUrl);
17970
18030
  const headers = {
@@ -18129,6 +18189,7 @@ async function syncOnce() {
18129
18189
  try {
18130
18190
  const result = await fetchCloudPolicy(creds.apiKey, creds.apiUrl, readCachedEtag());
18131
18191
  if (result.kind === "unchanged") {
18192
+ recordSyncHealth({ ok: true });
18132
18193
  } else {
18133
18194
  const cache = {
18134
18195
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -18142,8 +18203,19 @@ async function syncOnce() {
18142
18203
  managedConfig: extractManagedConfig(result.body)
18143
18204
  };
18144
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 {
18145
18218
  }
18146
- } catch {
18147
18219
  }
18148
18220
  if (process.env.NODE9_BLAST_DISABLE !== "1") {
18149
18221
  void pushBlastSnapshot(creds);
@@ -18319,6 +18391,7 @@ async function runCloudSync() {
18319
18391
  const result = await fetchCloudPolicy(creds.apiKey, creds.apiUrl, readCachedEtag());
18320
18392
  if (result.kind === "unchanged") {
18321
18393
  const status = getCloudSyncStatus();
18394
+ recordSyncHealth({ ok: true });
18322
18395
  maybePushBlast();
18323
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 };
18324
18397
  }
@@ -18334,11 +18407,14 @@ async function runCloudSync() {
18334
18407
  managedConfig: extractManagedConfig(result.body)
18335
18408
  };
18336
18409
  writeCache2(cache);
18410
+ recordSyncHealth({ ok: true, changed: true });
18337
18411
  maybePushBlast();
18338
18412
  return { ok: true, rules: cache.rules.length, fetchedAt: cache.fetchedAt };
18339
18413
  } catch (err2) {
18414
+ const msg = err2 instanceof Error ? err2.message : String(err2);
18415
+ recordSyncHealth({ ok: false, error: msg });
18340
18416
  maybePushBlast();
18341
- return { ok: false, reason: err2 instanceof Error ? err2.message : String(err2) };
18417
+ return { ok: false, reason: msg };
18342
18418
  }
18343
18419
  }
18344
18420
  function getCloudSyncStatus() {
@@ -18395,7 +18471,7 @@ function startForensicBroadcast() {
18395
18471
  const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
18396
18472
  recurring.unref();
18397
18473
  }
18398
- 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;
18399
18475
  var init_sync = __esm({
18400
18476
  "src/daemon/sync.ts"() {
18401
18477
  "use strict";
@@ -18433,6 +18509,10 @@ var init_sync = __esm({
18433
18509
  DEFAULT_INTERVAL_HOURS = 5;
18434
18510
  MIN_INTERVAL_SECONDS = 15;
18435
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;
18436
18516
  FORENSIC_BROADCAST_INTERVAL_MS = 3e4;
18437
18517
  FORENSIC_INITIAL_DELAY_MS = 5e3;
18438
18518
  forensicBroadcastOffsets = /* @__PURE__ */ new Map();
@@ -19047,16 +19127,61 @@ var init_hook_heal = __esm({
19047
19127
  }
19048
19128
  });
19049
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
+
19050
19168
  // src/daemon/server.ts
19051
19169
  function startDaemon() {
19052
- startCostSync();
19053
- startCloudSync();
19054
- startForensicBroadcast();
19055
- startAuditShipper();
19056
- startDlpScanner();
19057
- startMcpReconciler();
19058
- startHookHeal();
19059
- 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
+ }
19060
19185
  const internalToken = (0, import_crypto11.randomUUID)();
19061
19186
  const validToken = (req) => req.headers["x-node9-internal"] === internalToken || req.headers["x-node9-token"] === internalToken;
19062
19187
  const IDLE_TIMEOUT_MS = 12 * 60 * 60 * 1e3;
@@ -19068,7 +19193,7 @@ function startDaemon() {
19068
19193
  idleTimer = setTimeout(() => {
19069
19194
  if (autoStarted) {
19070
19195
  try {
19071
- import_fs39.default.unlinkSync(DAEMON_PID_FILE);
19196
+ import_fs40.default.unlinkSync(DAEMON_PID_FILE);
19072
19197
  } catch {
19073
19198
  }
19074
19199
  }
@@ -19213,7 +19338,7 @@ data: ${JSON.stringify(item.data)}
19213
19338
  mcpServer: entry.mcpServer
19214
19339
  });
19215
19340
  }
19216
- 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;
19217
19342
  const projectConfig = getConfig(projectCwd);
19218
19343
  const browserEnabled = projectConfig.settings.approvers?.browser !== false;
19219
19344
  const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
@@ -19505,8 +19630,8 @@ data: ${JSON.stringify(item.data)}
19505
19630
  if (!validToken(req)) return res.writeHead(403).end();
19506
19631
  const periodParam = reqUrl.searchParams.get("period") || "7d";
19507
19632
  const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
19508
- const logPath = import_path38.default.join(import_os36.default.homedir(), ".node9", "audit.log");
19509
- 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)) {
19510
19635
  res.writeHead(200, { "Content-Type": "application/json" });
19511
19636
  return res.end(
19512
19637
  JSON.stringify({
@@ -19519,7 +19644,7 @@ data: ${JSON.stringify(item.data)}
19519
19644
  );
19520
19645
  }
19521
19646
  try {
19522
- const raw = import_fs39.default.readFileSync(logPath, "utf-8");
19647
+ const raw = import_fs40.default.readFileSync(logPath, "utf-8");
19523
19648
  const allEntries = raw.split("\n").flatMap((line) => {
19524
19649
  if (!line.trim()) return [];
19525
19650
  try {
@@ -19902,14 +20027,15 @@ data: ${JSON.stringify(item.data)}
19902
20027
  server.on("error", (e) => {
19903
20028
  if (e.code === "EADDRINUSE") {
19904
20029
  try {
19905
- if (import_fs39.default.existsSync(DAEMON_PID_FILE)) {
19906
- 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"));
19907
20032
  process.kill(pid, 0);
20033
+ logDaemonStartup("port-in-use", `another daemon (pid ${pid}) owns :${DAEMON_PORT}`);
19908
20034
  return process.exit(0);
19909
20035
  }
19910
20036
  } catch {
19911
20037
  try {
19912
- import_fs39.default.unlinkSync(DAEMON_PID_FILE);
20038
+ import_fs40.default.unlinkSync(DAEMON_PID_FILE);
19913
20039
  } catch {
19914
20040
  }
19915
20041
  server.listen(DAEMON_PORT, DAEMON_HOST);
@@ -19958,6 +20084,7 @@ data: ${JSON.stringify(item.data)}
19958
20084
  });
19959
20085
  return;
19960
20086
  }
20087
+ logDaemonStartup("bind-failed", e.message);
19961
20088
  console.error(import_chalk6.default.red("\n\u{1F6D1} Node9 Daemon Error:"), e.message);
19962
20089
  process.exit(1);
19963
20090
  });
@@ -19981,14 +20108,14 @@ data: ${JSON.stringify(item.data)}
19981
20108
  }
19982
20109
  startActivitySocket();
19983
20110
  }
19984
- 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;
19985
20112
  var init_server = __esm({
19986
20113
  "src/daemon/server.ts"() {
19987
20114
  "use strict";
19988
20115
  import_http3 = __toESM(require("http"));
19989
- import_fs39 = __toESM(require("fs"));
19990
- import_path38 = __toESM(require("path"));
19991
- import_os36 = __toESM(require("os"));
20116
+ import_fs40 = __toESM(require("fs"));
20117
+ import_path39 = __toESM(require("path"));
20118
+ import_os37 = __toESM(require("os"));
19992
20119
  import_crypto11 = require("crypto");
19993
20120
  import_child_process2 = require("child_process");
19994
20121
  import_chalk6 = __toESM(require("chalk"));
@@ -20003,6 +20130,7 @@ var init_server = __esm({
20003
20130
  init_dlp_scanner();
20004
20131
  init_mcp_reconciler();
20005
20132
  init_hook_heal();
20133
+ init_startup_log();
20006
20134
  init_mcp_tools();
20007
20135
  }
20008
20136
  });
@@ -20011,8 +20139,8 @@ var init_server = __esm({
20011
20139
  function resolveNode9Binary() {
20012
20140
  try {
20013
20141
  const script = process.argv[1];
20014
- if (typeof script === "string" && import_path39.default.isAbsolute(script) && import_fs40.default.existsSync(script)) {
20015
- 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);
20016
20144
  }
20017
20145
  } catch {
20018
20146
  }
@@ -20030,11 +20158,11 @@ function xmlEscape(s) {
20030
20158
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
20031
20159
  }
20032
20160
  function launchdPlist(binaryPath) {
20033
- const logDir = import_path39.default.join(import_os37.default.homedir(), ".node9");
20161
+ const logDir = import_path40.default.join(import_os38.default.homedir(), ".node9");
20034
20162
  const nodePath = xmlEscape(process.execPath);
20035
20163
  const scriptPath = xmlEscape(binaryPath);
20036
- const outLog = xmlEscape(import_path39.default.join(logDir, "daemon.log"));
20037
- 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"));
20038
20166
  return `<?xml version="1.0" encoding="UTF-8"?>
20039
20167
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
20040
20168
  <plist version="1.0">
@@ -20067,9 +20195,9 @@ function launchdPlist(binaryPath) {
20067
20195
  `;
20068
20196
  }
20069
20197
  function installLaunchd(binaryPath) {
20070
- const dir = import_path39.default.dirname(LAUNCHD_PLIST);
20071
- if (!import_fs40.default.existsSync(dir)) import_fs40.default.mkdirSync(dir, { recursive: true });
20072
- 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");
20073
20201
  (0, import_child_process3.spawnSync)("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
20074
20202
  const r = (0, import_child_process3.spawnSync)("launchctl", ["load", "-w", LAUNCHD_PLIST], {
20075
20203
  encoding: "utf8",
@@ -20080,13 +20208,13 @@ function installLaunchd(binaryPath) {
20080
20208
  }
20081
20209
  }
20082
20210
  function uninstallLaunchd() {
20083
- if (import_fs40.default.existsSync(LAUNCHD_PLIST)) {
20211
+ if (import_fs41.default.existsSync(LAUNCHD_PLIST)) {
20084
20212
  (0, import_child_process3.spawnSync)("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
20085
- import_fs40.default.unlinkSync(LAUNCHD_PLIST);
20213
+ import_fs41.default.unlinkSync(LAUNCHD_PLIST);
20086
20214
  }
20087
20215
  }
20088
20216
  function isLaunchdInstalled() {
20089
- return import_fs40.default.existsSync(LAUNCHD_PLIST);
20217
+ return import_fs41.default.existsSync(LAUNCHD_PLIST);
20090
20218
  }
20091
20219
  function systemdUnit(binaryPath) {
20092
20220
  return `[Unit]
@@ -20105,12 +20233,12 @@ WantedBy=default.target
20105
20233
  `;
20106
20234
  }
20107
20235
  function installSystemd(binaryPath) {
20108
- if (!import_fs40.default.existsSync(SYSTEMD_UNIT_DIR)) {
20109
- 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 });
20110
20238
  }
20111
- import_fs40.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
20239
+ import_fs41.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
20112
20240
  try {
20113
- (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 });
20114
20242
  } catch {
20115
20243
  }
20116
20244
  const reload = (0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], {
@@ -20130,23 +20258,23 @@ function installSystemd(binaryPath) {
20130
20258
  }
20131
20259
  }
20132
20260
  function uninstallSystemd() {
20133
- if (import_fs40.default.existsSync(SYSTEMD_UNIT)) {
20261
+ if (import_fs41.default.existsSync(SYSTEMD_UNIT)) {
20134
20262
  (0, import_child_process3.spawnSync)("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
20135
20263
  encoding: "utf8",
20136
20264
  timeout: 5e3
20137
20265
  });
20138
20266
  (0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
20139
- import_fs40.default.unlinkSync(SYSTEMD_UNIT);
20267
+ import_fs41.default.unlinkSync(SYSTEMD_UNIT);
20140
20268
  }
20141
20269
  }
20142
20270
  function isSystemdInstalled() {
20143
- return import_fs40.default.existsSync(SYSTEMD_UNIT);
20271
+ return import_fs41.default.existsSync(SYSTEMD_UNIT);
20144
20272
  }
20145
20273
  function stopRunningDaemon() {
20146
- const pidFile = import_path39.default.join(import_os37.default.homedir(), ".node9", "daemon.pid");
20147
- 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;
20148
20276
  try {
20149
- const data = JSON.parse(import_fs40.default.readFileSync(pidFile, "utf-8"));
20277
+ const data = JSON.parse(import_fs41.default.readFileSync(pidFile, "utf-8"));
20150
20278
  const pid = data.pid;
20151
20279
  const MAX_PID2 = 4194304;
20152
20280
  if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
@@ -20166,7 +20294,7 @@ function stopRunningDaemon() {
20166
20294
  }
20167
20295
  }
20168
20296
  try {
20169
- import_fs40.default.unlinkSync(pidFile);
20297
+ import_fs41.default.unlinkSync(pidFile);
20170
20298
  } catch {
20171
20299
  }
20172
20300
  } catch {
@@ -20236,26 +20364,95 @@ function isDaemonServiceInstalled() {
20236
20364
  if (process.platform === "linux") return isSystemdInstalled();
20237
20365
  return false;
20238
20366
  }
20239
- 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;
20240
20437
  var init_service = __esm({
20241
20438
  "src/daemon/service.ts"() {
20242
20439
  "use strict";
20243
- import_fs40 = __toESM(require("fs"));
20244
- import_path39 = __toESM(require("path"));
20245
- import_os37 = __toESM(require("os"));
20440
+ import_fs41 = __toESM(require("fs"));
20441
+ import_path40 = __toESM(require("path"));
20442
+ import_os38 = __toESM(require("os"));
20246
20443
  import_child_process3 = require("child_process");
20247
20444
  LAUNCHD_LABEL = "ai.node9.daemon";
20248
- LAUNCHD_PLIST = import_path39.default.join(import_os37.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
20249
- SYSTEMD_UNIT_DIR = import_path39.default.join(import_os37.default.homedir(), ".config", "systemd", "user");
20250
- 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");
20251
20448
  }
20252
20449
  });
20253
20450
 
20254
20451
  // src/daemon/index.ts
20255
20452
  function stopDaemon() {
20256
- 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."));
20257
20454
  try {
20258
- 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"));
20259
20456
  const pid = data.pid;
20260
20457
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
20261
20458
  console.log(import_chalk7.default.gray("Cleaned up invalid PID file."));
@@ -20267,7 +20464,7 @@ function stopDaemon() {
20267
20464
  console.log(import_chalk7.default.gray("Cleaned up stale PID file."));
20268
20465
  } finally {
20269
20466
  try {
20270
- import_fs41.default.unlinkSync(DAEMON_PID_FILE);
20467
+ import_fs42.default.unlinkSync(DAEMON_PID_FILE);
20271
20468
  } catch {
20272
20469
  }
20273
20470
  }
@@ -20276,9 +20473,9 @@ function daemonStatus() {
20276
20473
  const serviceInstalled = isDaemonServiceInstalled();
20277
20474
  const serviceLabel = serviceInstalled ? import_chalk7.default.green("installed (starts on login)") : import_chalk7.default.yellow("not installed \u2014 run: node9 daemon install");
20278
20475
  let processStatus;
20279
- if (import_fs41.default.existsSync(DAEMON_PID_FILE)) {
20476
+ if (import_fs42.default.existsSync(DAEMON_PID_FILE)) {
20280
20477
  try {
20281
- 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"));
20282
20479
  const pid = data.pid;
20283
20480
  const port = data.port;
20284
20481
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
@@ -20300,11 +20497,11 @@ function daemonStatus() {
20300
20497
  console.log(` Service : ${serviceLabel}
20301
20498
  `);
20302
20499
  }
20303
- var import_fs41, import_chalk7, MAX_PID;
20500
+ var import_fs42, import_chalk7, MAX_PID;
20304
20501
  var init_daemon2 = __esm({
20305
20502
  "src/daemon/index.ts"() {
20306
20503
  "use strict";
20307
- import_fs41 = __toESM(require("fs"));
20504
+ import_fs42 = __toESM(require("fs"));
20308
20505
  import_chalk7 = __toESM(require("chalk"));
20309
20506
  init_server();
20310
20507
  init_state2();
@@ -21423,14 +21620,14 @@ var require_util = __commonJS({
21423
21620
  }
21424
21621
  const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
21425
21622
  let origin = url.origin != null ? url.origin : `${url.protocol || ""}//${url.hostname || ""}:${port}`;
21426
- let path70 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
21623
+ let path71 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
21427
21624
  if (origin[origin.length - 1] === "/") {
21428
21625
  origin = origin.slice(0, origin.length - 1);
21429
21626
  }
21430
- if (path70 && path70[0] !== "/") {
21431
- path70 = `/${path70}`;
21627
+ if (path71 && path71[0] !== "/") {
21628
+ path71 = `/${path71}`;
21432
21629
  }
21433
- return new URL(`${origin}${path70}`);
21630
+ return new URL(`${origin}${path71}`);
21434
21631
  }
21435
21632
  if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
21436
21633
  throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
@@ -22251,9 +22448,9 @@ var require_diagnostics = __commonJS({
22251
22448
  "undici:client:sendHeaders",
22252
22449
  (evt) => {
22253
22450
  const {
22254
- request: { method, path: path70, origin }
22451
+ request: { method, path: path71, origin }
22255
22452
  } = evt;
22256
- debugLog("sending request to %s %s%s", method, origin, path70);
22453
+ debugLog("sending request to %s %s%s", method, origin, path71);
22257
22454
  }
22258
22455
  );
22259
22456
  }
@@ -22271,14 +22468,14 @@ var require_diagnostics = __commonJS({
22271
22468
  "undici:request:headers",
22272
22469
  (evt) => {
22273
22470
  const {
22274
- request: { method, path: path70, origin },
22471
+ request: { method, path: path71, origin },
22275
22472
  response: { statusCode }
22276
22473
  } = evt;
22277
22474
  debugLog(
22278
22475
  "received response to %s %s%s - HTTP %d",
22279
22476
  method,
22280
22477
  origin,
22281
- path70,
22478
+ path71,
22282
22479
  statusCode
22283
22480
  );
22284
22481
  }
@@ -22287,23 +22484,23 @@ var require_diagnostics = __commonJS({
22287
22484
  "undici:request:trailers",
22288
22485
  (evt) => {
22289
22486
  const {
22290
- request: { method, path: path70, origin }
22487
+ request: { method, path: path71, origin }
22291
22488
  } = evt;
22292
- debugLog("trailers received from %s %s%s", method, origin, path70);
22489
+ debugLog("trailers received from %s %s%s", method, origin, path71);
22293
22490
  }
22294
22491
  );
22295
22492
  diagnosticsChannel.subscribe(
22296
22493
  "undici:request:error",
22297
22494
  (evt) => {
22298
22495
  const {
22299
- request: { method, path: path70, origin },
22496
+ request: { method, path: path71, origin },
22300
22497
  error
22301
22498
  } = evt;
22302
22499
  debugLog(
22303
22500
  "request to %s %s%s errored - %s",
22304
22501
  method,
22305
22502
  origin,
22306
- path70,
22503
+ path71,
22307
22504
  error.message
22308
22505
  );
22309
22506
  }
@@ -22406,7 +22603,7 @@ var require_request = __commonJS({
22406
22603
  var kHandler = /* @__PURE__ */ Symbol("handler");
22407
22604
  var Request = class {
22408
22605
  constructor(origin, {
22409
- path: path70,
22606
+ path: path71,
22410
22607
  method,
22411
22608
  body,
22412
22609
  headers,
@@ -22423,11 +22620,11 @@ var require_request = __commonJS({
22423
22620
  maxRedirections,
22424
22621
  typeOfService
22425
22622
  }, handler) {
22426
- if (typeof path70 !== "string") {
22623
+ if (typeof path71 !== "string") {
22427
22624
  throw new InvalidArgumentError("path must be a string");
22428
- } 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") {
22429
22626
  throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
22430
- } else if (invalidPathRegex.test(path70)) {
22627
+ } else if (invalidPathRegex.test(path71)) {
22431
22628
  throw new InvalidArgumentError("invalid request path");
22432
22629
  }
22433
22630
  if (typeof method !== "string") {
@@ -22502,7 +22699,7 @@ var require_request = __commonJS({
22502
22699
  this.completed = false;
22503
22700
  this.aborted = false;
22504
22701
  this.upgrade = upgrade || null;
22505
- this.path = query ? serializePathWithQuery(path70, query) : path70;
22702
+ this.path = query ? serializePathWithQuery(path71, query) : path71;
22506
22703
  this.origin = origin;
22507
22704
  this.protocol = getProtocolFromUrlString(origin);
22508
22705
  this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
@@ -27541,7 +27738,7 @@ var require_client_h1 = __commonJS({
27541
27738
  return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
27542
27739
  }
27543
27740
  function writeH1(client, request2) {
27544
- const { method, path: path70, host, upgrade, blocking, reset } = request2;
27741
+ const { method, path: path71, host, upgrade, blocking, reset } = request2;
27545
27742
  let { body, headers, contentLength } = request2;
27546
27743
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
27547
27744
  if (util.isFormDataLike(body)) {
@@ -27610,7 +27807,7 @@ var require_client_h1 = __commonJS({
27610
27807
  if (socket.setTypeOfService) {
27611
27808
  socket.setTypeOfService(request2.typeOfService);
27612
27809
  }
27613
- let header = `${method} ${path70} HTTP/1.1\r
27810
+ let header = `${method} ${path71} HTTP/1.1\r
27614
27811
  `;
27615
27812
  if (typeof host === "string") {
27616
27813
  header += `host: ${host}\r
@@ -28263,7 +28460,7 @@ var require_client_h2 = __commonJS({
28263
28460
  function writeH2(client, request2) {
28264
28461
  const requestTimeout = request2.bodyTimeout ?? client[kBodyTimeout];
28265
28462
  const session = client[kHTTP2Session];
28266
- 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;
28267
28464
  let { body } = request2;
28268
28465
  if (upgrade != null && upgrade !== "websocket") {
28269
28466
  util.errorRequest(client, request2, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
@@ -28331,7 +28528,7 @@ var require_client_h2 = __commonJS({
28331
28528
  }
28332
28529
  headers[HTTP2_HEADER_METHOD] = "CONNECT";
28333
28530
  headers[HTTP2_HEADER_PROTOCOL] = "websocket";
28334
- headers[HTTP2_HEADER_PATH] = path70;
28531
+ headers[HTTP2_HEADER_PATH] = path71;
28335
28532
  if (protocol === "ws:" || protocol === "wss:") {
28336
28533
  headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
28337
28534
  } else {
@@ -28372,7 +28569,7 @@ var require_client_h2 = __commonJS({
28372
28569
  stream.setTimeout(requestTimeout);
28373
28570
  return true;
28374
28571
  }
28375
- headers[HTTP2_HEADER_PATH] = path70;
28572
+ headers[HTTP2_HEADER_PATH] = path71;
28376
28573
  headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
28377
28574
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
28378
28575
  if (body && typeof body.read === "function") {
@@ -30674,10 +30871,10 @@ var require_proxy_agent = __commonJS({
30674
30871
  };
30675
30872
  const {
30676
30873
  origin,
30677
- path: path70 = "/",
30874
+ path: path71 = "/",
30678
30875
  headers = {}
30679
30876
  } = opts;
30680
- opts.path = origin + path70;
30877
+ opts.path = origin + path71;
30681
30878
  if (!("host" in headers) && !("Host" in headers)) {
30682
30879
  const { host } = new URL(origin);
30683
30880
  headers.host = host;
@@ -32740,20 +32937,20 @@ var require_mock_utils = __commonJS({
32740
32937
  }
32741
32938
  return normalizedQp;
32742
32939
  }
32743
- function safeUrl(path70) {
32744
- if (typeof path70 !== "string") {
32745
- return path70;
32940
+ function safeUrl(path71) {
32941
+ if (typeof path71 !== "string") {
32942
+ return path71;
32746
32943
  }
32747
- const pathSegments = path70.split("?", 3);
32944
+ const pathSegments = path71.split("?", 3);
32748
32945
  if (pathSegments.length !== 2) {
32749
- return path70;
32946
+ return path71;
32750
32947
  }
32751
32948
  const qp = new URLSearchParams(pathSegments.pop());
32752
32949
  qp.sort();
32753
32950
  return [...pathSegments, qp.toString()].join("?");
32754
32951
  }
32755
- function matchKey(mockDispatch2, { path: path70, method, body, headers }) {
32756
- const pathMatch = matchValue(mockDispatch2.path, path70);
32952
+ function matchKey(mockDispatch2, { path: path71, method, body, headers }) {
32953
+ const pathMatch = matchValue(mockDispatch2.path, path71);
32757
32954
  const methodMatch = matchValue(mockDispatch2.method, method);
32758
32955
  const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
32759
32956
  const headersMatch = matchHeaders(mockDispatch2, headers);
@@ -32778,8 +32975,8 @@ var require_mock_utils = __commonJS({
32778
32975
  const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path;
32779
32976
  const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
32780
32977
  const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
32781
- let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path70, ignoreTrailingSlash }) => {
32782
- 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);
32783
32980
  });
32784
32981
  if (matchedMockDispatches.length === 0) {
32785
32982
  throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
@@ -32818,19 +33015,19 @@ var require_mock_utils = __commonJS({
32818
33015
  mockDispatches.splice(index, 1);
32819
33016
  }
32820
33017
  }
32821
- function removeTrailingSlash(path70) {
32822
- while (path70.endsWith("/")) {
32823
- path70 = path70.slice(0, -1);
33018
+ function removeTrailingSlash(path71) {
33019
+ while (path71.endsWith("/")) {
33020
+ path71 = path71.slice(0, -1);
32824
33021
  }
32825
- if (path70.length === 0) {
32826
- path70 = "/";
33022
+ if (path71.length === 0) {
33023
+ path71 = "/";
32827
33024
  }
32828
- return path70;
33025
+ return path71;
32829
33026
  }
32830
33027
  function buildKey(opts) {
32831
- const { path: path70, method, body, headers, query } = opts;
33028
+ const { path: path71, method, body, headers, query } = opts;
32832
33029
  return {
32833
- path: path70,
33030
+ path: path71,
32834
33031
  method,
32835
33032
  body,
32836
33033
  headers,
@@ -33520,10 +33717,10 @@ var require_pending_interceptors_formatter = __commonJS({
33520
33717
  }
33521
33718
  format(pendingInterceptors) {
33522
33719
  const withPrettyHeaders = pendingInterceptors.map(
33523
- ({ method, path: path70, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
33720
+ ({ method, path: path71, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
33524
33721
  Method: method,
33525
33722
  Origin: origin,
33526
- Path: path70,
33723
+ Path: path71,
33527
33724
  "Status code": statusCode,
33528
33725
  Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
33529
33726
  Invocations: timesInvoked,
@@ -33605,9 +33802,9 @@ var require_mock_agent = __commonJS({
33605
33802
  const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
33606
33803
  const dispatchOpts = { ...opts };
33607
33804
  if (acceptNonStandardSearchParameters && dispatchOpts.path) {
33608
- const [path70, searchParams] = dispatchOpts.path.split("?");
33805
+ const [path71, searchParams] = dispatchOpts.path.split("?");
33609
33806
  const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
33610
- dispatchOpts.path = `${path70}?${normalizedSearchParams}`;
33807
+ dispatchOpts.path = `${path71}?${normalizedSearchParams}`;
33611
33808
  }
33612
33809
  return this[kAgent].dispatch(dispatchOpts, handler);
33613
33810
  }
@@ -34008,12 +34205,12 @@ var require_snapshot_recorder = __commonJS({
34008
34205
  * @return {Promise<void>} - Resolves when snapshots are loaded
34009
34206
  */
34010
34207
  async loadSnapshots(filePath) {
34011
- const path70 = filePath || this.#snapshotPath;
34012
- if (!path70) {
34208
+ const path71 = filePath || this.#snapshotPath;
34209
+ if (!path71) {
34013
34210
  throw new InvalidArgumentError("Snapshot path is required");
34014
34211
  }
34015
34212
  try {
34016
- const data = await readFile(resolve2(path70), "utf8");
34213
+ const data = await readFile(resolve2(path71), "utf8");
34017
34214
  const parsed = JSON.parse(data);
34018
34215
  if (Array.isArray(parsed)) {
34019
34216
  this.#snapshots.clear();
@@ -34027,7 +34224,7 @@ var require_snapshot_recorder = __commonJS({
34027
34224
  if (error.code === "ENOENT") {
34028
34225
  this.#snapshots.clear();
34029
34226
  } else {
34030
- throw new UndiciError(`Failed to load snapshots from ${path70}`, { cause: error });
34227
+ throw new UndiciError(`Failed to load snapshots from ${path71}`, { cause: error });
34031
34228
  }
34032
34229
  }
34033
34230
  }
@@ -34038,11 +34235,11 @@ var require_snapshot_recorder = __commonJS({
34038
34235
  * @returns {Promise<void>} - Resolves when snapshots are saved
34039
34236
  */
34040
34237
  async saveSnapshots(filePath) {
34041
- const path70 = filePath || this.#snapshotPath;
34042
- if (!path70) {
34238
+ const path71 = filePath || this.#snapshotPath;
34239
+ if (!path71) {
34043
34240
  throw new InvalidArgumentError("Snapshot path is required");
34044
34241
  }
34045
- const resolvedPath = resolve2(path70);
34242
+ const resolvedPath = resolve2(path71);
34046
34243
  await mkdir(dirname2(resolvedPath), { recursive: true });
34047
34244
  const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
34048
34245
  hash,
@@ -34667,15 +34864,15 @@ var require_redirect_handler = __commonJS({
34667
34864
  return;
34668
34865
  }
34669
34866
  const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
34670
- const path70 = search ? `${pathname}${search}` : pathname;
34671
- const redirectUrlString = `${origin}${path70}`;
34867
+ const path71 = search ? `${pathname}${search}` : pathname;
34868
+ const redirectUrlString = `${origin}${path71}`;
34672
34869
  for (const historyUrl of this.history) {
34673
34870
  if (historyUrl.toString() === redirectUrlString) {
34674
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.`);
34675
34872
  }
34676
34873
  }
34677
34874
  this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
34678
- this.opts.path = path70;
34875
+ this.opts.path = path71;
34679
34876
  this.opts.origin = origin;
34680
34877
  this.opts.query = null;
34681
34878
  }
@@ -40882,11 +41079,11 @@ var require_fetch = __commonJS({
40882
41079
  function dispatch({ body }) {
40883
41080
  const url = requestCurrentURL(request2);
40884
41081
  const agent = fetchParams.controller.dispatcher;
40885
- const path70 = url.pathname + url.search;
41082
+ const path71 = url.pathname + url.search;
40886
41083
  const hasTrailingQuestionMark = url.search.length === 0 && url.href[url.href.length - url.hash.length - 1] === "?";
40887
41084
  return new Promise((resolve2, reject) => agent.dispatch(
40888
41085
  {
40889
- path: hasTrailingQuestionMark ? `${path70}?` : path70,
41086
+ path: hasTrailingQuestionMark ? `${path71}?` : path71,
40890
41087
  origin: url.origin,
40891
41088
  method: request2.method,
40892
41089
  body: agent.isMockActive ? request2.body && (request2.body.source || request2.body.stream) : body,
@@ -41817,9 +42014,9 @@ var require_util4 = __commonJS({
41817
42014
  }
41818
42015
  }
41819
42016
  }
41820
- function validateCookiePath(path70) {
41821
- for (let i = 0; i < path70.length; ++i) {
41822
- const code = path70.charCodeAt(i);
42017
+ function validateCookiePath(path71) {
42018
+ for (let i = 0; i < path71.length; ++i) {
42019
+ const code = path71.charCodeAt(i);
41823
42020
  if (code < 32 || // exclude CTLs (0-31)
41824
42021
  code === 127 || // DEL
41825
42022
  code === 59) {
@@ -44989,11 +45186,11 @@ var require_undici = __commonJS({
44989
45186
  if (typeof opts.path !== "string") {
44990
45187
  throw new InvalidArgumentError("invalid opts.path");
44991
45188
  }
44992
- let path70 = opts.path;
45189
+ let path71 = opts.path;
44993
45190
  if (!opts.path.startsWith("/")) {
44994
- path70 = `/${path70}`;
45191
+ path71 = `/${path71}`;
44995
45192
  }
44996
- url = new URL(util.parseOrigin(url).origin + path70);
45193
+ url = new URL(util.parseOrigin(url).origin + path71);
44997
45194
  } else {
44998
45195
  if (!opts) {
44999
45196
  opts = typeof url === "object" ? url : {};
@@ -45131,20 +45328,20 @@ function getModelContextLimit(model) {
45131
45328
  return 2e5;
45132
45329
  }
45133
45330
  function readSessionUsage() {
45134
- const projectsDir = import_path66.default.join(import_os58.default.homedir(), ".claude", "projects");
45135
- 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;
45136
45333
  let latestFile = null;
45137
45334
  let latestMtime = 0;
45138
45335
  try {
45139
- for (const dir of import_fs69.default.readdirSync(projectsDir)) {
45140
- 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);
45141
45338
  try {
45142
- if (!import_fs69.default.statSync(dirPath).isDirectory()) continue;
45143
- 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)) {
45144
45341
  if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
45145
- const filePath = import_path66.default.join(dirPath, file);
45342
+ const filePath = import_path67.default.join(dirPath, file);
45146
45343
  try {
45147
- const mtime = import_fs69.default.statSync(filePath).mtimeMs;
45344
+ const mtime = import_fs70.default.statSync(filePath).mtimeMs;
45148
45345
  if (mtime > latestMtime) {
45149
45346
  latestMtime = mtime;
45150
45347
  latestFile = filePath;
@@ -45159,7 +45356,7 @@ function readSessionUsage() {
45159
45356
  }
45160
45357
  if (!latestFile) return null;
45161
45358
  try {
45162
- const lines = import_fs69.default.readFileSync(latestFile, "utf-8").split("\n");
45359
+ const lines = import_fs70.default.readFileSync(latestFile, "utf-8").split("\n");
45163
45360
  let lastModel = "";
45164
45361
  let lastInput = 0;
45165
45362
  let lastOutput = 0;
@@ -45220,7 +45417,7 @@ function formatBase(activity) {
45220
45417
  const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
45221
45418
  const icon = getIcon(activity.tool);
45222
45419
  const toolName = activity.tool.slice(0, 16).padEnd(16);
45223
- 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(), "~");
45224
45421
  const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
45225
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)}`;
45226
45423
  }
@@ -45259,9 +45456,9 @@ function renderPending(activity) {
45259
45456
  }
45260
45457
  async function ensureDaemon() {
45261
45458
  let pidPort = null;
45262
- if (import_fs69.default.existsSync(PID_FILE)) {
45459
+ if (import_fs70.default.existsSync(PID_FILE)) {
45263
45460
  try {
45264
- 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"));
45265
45462
  pidPort = port;
45266
45463
  } catch {
45267
45464
  console.error(import_chalk40.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
@@ -45417,9 +45614,9 @@ function buildRecoveryCardLines(req) {
45417
45614
  ];
45418
45615
  }
45419
45616
  function readApproversFromDisk() {
45420
- 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");
45421
45618
  try {
45422
- const raw = JSON.parse(import_fs69.default.readFileSync(configPath, "utf-8"));
45619
+ const raw = JSON.parse(import_fs70.default.readFileSync(configPath, "utf-8"));
45423
45620
  const settings = raw.settings ?? {};
45424
45621
  return settings.approvers ?? {};
45425
45622
  } catch {
@@ -45435,15 +45632,15 @@ function approverStatusLine() {
45435
45632
  return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
45436
45633
  }
45437
45634
  function toggleApprover(channel) {
45438
- 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");
45439
45636
  try {
45440
- const raw = JSON.parse(import_fs69.default.readFileSync(configPath, "utf-8"));
45637
+ const raw = JSON.parse(import_fs70.default.readFileSync(configPath, "utf-8"));
45441
45638
  const settings = raw.settings ?? {};
45442
45639
  const approvers = settings.approvers ?? {};
45443
45640
  approvers[channel] = approvers[channel] === false;
45444
45641
  settings.approvers = approvers;
45445
45642
  raw.settings = settings;
45446
- import_fs69.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
45643
+ import_fs70.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
45447
45644
  } catch (err2) {
45448
45645
  process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
45449
45646
  `);
@@ -45615,8 +45812,8 @@ async function startTail(options = {}) {
45615
45812
  }
45616
45813
  postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
45617
45814
  try {
45618
- import_fs69.default.appendFileSync(
45619
- 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"),
45620
45817
  `[tail] POST /decision failed: ${String(err2)}
45621
45818
  `
45622
45819
  );
@@ -45680,9 +45877,9 @@ async function startTail(options = {}) {
45680
45877
  };
45681
45878
  process.stdin.on("keypress", onKeypress);
45682
45879
  }
45683
- 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");
45684
45881
  try {
45685
- 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;
45686
45883
  if (unackedDlp > 0) {
45687
45884
  console.log("");
45688
45885
  console.log(
@@ -45722,7 +45919,7 @@ async function startTail(options = {}) {
45722
45919
  if (stallWarned) return;
45723
45920
  if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
45724
45921
  try {
45725
- const auditMtime = import_fs69.default.statSync(auditLog).mtimeMs;
45922
+ const auditMtime = import_fs70.default.statSync(auditLog).mtimeMs;
45726
45923
  if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
45727
45924
  console.log("");
45728
45925
  console.log(
@@ -45907,20 +46104,20 @@ async function startTail(options = {}) {
45907
46104
  process.exit(1);
45908
46105
  });
45909
46106
  }
45910
- 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;
45911
46108
  var init_tail = __esm({
45912
46109
  "src/tui/tail.ts"() {
45913
46110
  "use strict";
45914
46111
  import_http5 = __toESM(require("http"));
45915
46112
  import_chalk40 = __toESM(require("chalk"));
45916
- import_fs69 = __toESM(require("fs"));
45917
- import_os58 = __toESM(require("os"));
45918
- import_path66 = __toESM(require("path"));
46113
+ import_fs70 = __toESM(require("fs"));
46114
+ import_os60 = __toESM(require("os"));
46115
+ import_path67 = __toESM(require("path"));
45919
46116
  import_readline6 = __toESM(require("readline"));
45920
46117
  import_child_process14 = require("child_process");
45921
46118
  init_daemon2();
45922
46119
  init_daemon();
45923
- 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");
45924
46121
  ICONS = {
45925
46122
  bash: "\u{1F4BB}",
45926
46123
  shell: "\u{1F4BB}",
@@ -46042,9 +46239,9 @@ function formatTimeLeft(resetsAt) {
46042
46239
  return ` (${m}m left)`;
46043
46240
  }
46044
46241
  function safeReadJson(filePath) {
46045
- if (!import_fs70.default.existsSync(filePath)) return null;
46242
+ if (!import_fs71.default.existsSync(filePath)) return null;
46046
46243
  try {
46047
- return JSON.parse(import_fs70.default.readFileSync(filePath, "utf-8"));
46244
+ return JSON.parse(import_fs71.default.readFileSync(filePath, "utf-8"));
46048
46245
  } catch {
46049
46246
  return null;
46050
46247
  }
@@ -46065,12 +46262,12 @@ function countHooksInFile(filePath) {
46065
46262
  return Object.keys(cfg.hooks).length;
46066
46263
  }
46067
46264
  function countRulesInDir(rulesDir) {
46068
- if (!import_fs70.default.existsSync(rulesDir)) return 0;
46265
+ if (!import_fs71.default.existsSync(rulesDir)) return 0;
46069
46266
  let count = 0;
46070
46267
  try {
46071
- for (const entry of import_fs70.default.readdirSync(rulesDir, { withFileTypes: true })) {
46268
+ for (const entry of import_fs71.default.readdirSync(rulesDir, { withFileTypes: true })) {
46072
46269
  if (entry.isDirectory()) {
46073
- count += countRulesInDir(import_path67.default.join(rulesDir, entry.name));
46270
+ count += countRulesInDir(import_path68.default.join(rulesDir, entry.name));
46074
46271
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
46075
46272
  count++;
46076
46273
  }
@@ -46081,46 +46278,46 @@ function countRulesInDir(rulesDir) {
46081
46278
  }
46082
46279
  function isSamePath(a, b) {
46083
46280
  try {
46084
- return import_path67.default.resolve(a) === import_path67.default.resolve(b);
46281
+ return import_path68.default.resolve(a) === import_path68.default.resolve(b);
46085
46282
  } catch {
46086
46283
  return false;
46087
46284
  }
46088
46285
  }
46089
46286
  function countConfigs(cwd) {
46090
- const homeDir2 = import_os59.default.homedir();
46091
- const claudeDir = import_path67.default.join(homeDir2, ".claude");
46287
+ const homeDir2 = import_os61.default.homedir();
46288
+ const claudeDir = import_path68.default.join(homeDir2, ".claude");
46092
46289
  let claudeMdCount = 0;
46093
46290
  let rulesCount = 0;
46094
46291
  let hooksCount = 0;
46095
46292
  const userMcpServers = /* @__PURE__ */ new Set();
46096
46293
  const projectMcpServers = /* @__PURE__ */ new Set();
46097
- if (import_fs70.default.existsSync(import_path67.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
46098
- rulesCount += countRulesInDir(import_path67.default.join(claudeDir, "rules"));
46099
- 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");
46100
46297
  for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
46101
46298
  hooksCount += countHooksInFile(userSettings);
46102
- const userClaudeJson = import_path67.default.join(homeDir2, ".claude.json");
46299
+ const userClaudeJson = import_path68.default.join(homeDir2, ".claude.json");
46103
46300
  for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
46104
46301
  for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
46105
46302
  userMcpServers.delete(name);
46106
46303
  }
46107
46304
  if (cwd) {
46108
- if (import_fs70.default.existsSync(import_path67.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
46109
- if (import_fs70.default.existsSync(import_path67.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
46110
- 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");
46111
46308
  const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
46112
46309
  if (!overlapsUserScope) {
46113
- if (import_fs70.default.existsSync(import_path67.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
46114
- rulesCount += countRulesInDir(import_path67.default.join(projectClaudeDir, "rules"));
46115
- 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");
46116
46313
  for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
46117
46314
  hooksCount += countHooksInFile(projSettings);
46118
46315
  }
46119
- if (import_fs70.default.existsSync(import_path67.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
46120
- 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");
46121
46318
  for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
46122
46319
  hooksCount += countHooksInFile(localSettings);
46123
- const mcpJsonServers = getMcpServerNames(import_path67.default.join(cwd, ".mcp.json"));
46320
+ const mcpJsonServers = getMcpServerNames(import_path68.default.join(cwd, ".mcp.json"));
46124
46321
  const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
46125
46322
  for (const name of disabledMcpJson) mcpJsonServers.delete(name);
46126
46323
  for (const name of mcpJsonServers) projectMcpServers.add(name);
@@ -46153,12 +46350,12 @@ function readActiveShieldsHud() {
46153
46350
  return shieldsCache.value;
46154
46351
  }
46155
46352
  try {
46156
- const shieldsPath = import_path67.default.join(import_os59.default.homedir(), ".node9", "shields.json");
46157
- 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)) {
46158
46355
  shieldsCache = { value: [], ts: now };
46159
46356
  return [];
46160
46357
  }
46161
- const parsed = JSON.parse(import_fs70.default.readFileSync(shieldsPath, "utf-8"));
46358
+ const parsed = JSON.parse(import_fs71.default.readFileSync(shieldsPath, "utf-8"));
46162
46359
  if (!Array.isArray(parsed.active)) {
46163
46360
  shieldsCache = { value: [], ts: now };
46164
46361
  return [];
@@ -46260,17 +46457,17 @@ function renderContextLine(stdin) {
46260
46457
  async function main() {
46261
46458
  try {
46262
46459
  const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
46263
- 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"))) {
46264
46461
  try {
46265
- 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");
46266
46463
  const MAX_LOG_SIZE = 10 * 1024 * 1024;
46267
46464
  let size = 0;
46268
46465
  try {
46269
- size = import_fs70.default.statSync(logPath).size;
46466
+ size = import_fs71.default.statSync(logPath).size;
46270
46467
  } catch {
46271
46468
  }
46272
46469
  if (size < MAX_LOG_SIZE) {
46273
- import_fs70.default.appendFileSync(
46470
+ import_fs71.default.appendFileSync(
46274
46471
  logPath,
46275
46472
  JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
46276
46473
  );
@@ -46291,11 +46488,11 @@ async function main() {
46291
46488
  try {
46292
46489
  const cwd = stdin.cwd ?? process.cwd();
46293
46490
  for (const configPath of [
46294
- import_path67.default.join(cwd, "node9.config.json"),
46295
- 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")
46296
46493
  ]) {
46297
- if (!import_fs70.default.existsSync(configPath)) continue;
46298
- 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"));
46299
46496
  const hud = cfg.settings?.hud;
46300
46497
  if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
46301
46498
  }
@@ -46313,13 +46510,13 @@ async function main() {
46313
46510
  renderOffline();
46314
46511
  }
46315
46512
  }
46316
- 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;
46317
46514
  var init_hud = __esm({
46318
46515
  "src/cli/hud.ts"() {
46319
46516
  "use strict";
46320
- import_fs70 = __toESM(require("fs"));
46321
- import_path67 = __toESM(require("path"));
46322
- import_os59 = __toESM(require("os"));
46517
+ import_fs71 = __toESM(require("fs"));
46518
+ import_path68 = __toESM(require("path"));
46519
+ import_os61 = __toESM(require("os"));
46323
46520
  import_http6 = __toESM(require("http"));
46324
46521
  init_daemon();
46325
46522
  RESET3 = "\x1B[0m";
@@ -46441,9 +46638,9 @@ function writeCredentialsAndConfig(apiKey, opts = {}) {
46441
46638
  // src/cli.ts
46442
46639
  init_daemon2();
46443
46640
  var import_chalk41 = __toESM(require("chalk"));
46444
- var import_fs71 = __toESM(require("fs"));
46445
- var import_path68 = __toESM(require("path"));
46446
- 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"));
46447
46644
  var import_child_process15 = require("child_process");
46448
46645
  var import_prompts2 = require("@inquirer/prompts");
46449
46646
 
@@ -46630,26 +46827,48 @@ async function runProxy(targetCommand) {
46630
46827
 
46631
46828
  // src/cli/daemon-starter.ts
46632
46829
  var import_child_process5 = require("child_process");
46633
- var import_path40 = __toESM(require("path"));
46634
- 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"));
46635
46833
  init_daemon();
46834
+ init_startup_log();
46636
46835
  function isTestingMode() {
46637
46836
  return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
46638
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
+ }
46639
46857
  async function autoStartDaemonAndWait() {
46640
46858
  if (isTestingMode()) return false;
46641
- if (!import_path40.default.isAbsolute(process.argv[1])) return false;
46859
+ if (!import_path41.default.isAbsolute(process.argv[1])) return false;
46642
46860
  let resolvedArgv1;
46643
46861
  try {
46644
- resolvedArgv1 = import_fs42.default.realpathSync(process.argv[1]);
46862
+ resolvedArgv1 = import_fs43.default.realpathSync(process.argv[1]);
46645
46863
  } catch {
46646
46864
  return false;
46647
46865
  }
46648
46866
  if (!resolvedArgv1.endsWith(".js")) return false;
46867
+ const startupFd = openStartupLogFd();
46649
46868
  try {
46650
46869
  const child = (0, import_child_process5.spawn)(process.execPath, [resolvedArgv1, "daemon"], {
46651
46870
  detached: true,
46652
- stdio: "ignore",
46871
+ stdio: ["ignore", "ignore", startupFd ?? "ignore"],
46653
46872
  env: {
46654
46873
  ...process.env,
46655
46874
  NODE9_AUTO_STARTED: "1"
@@ -46662,30 +46881,41 @@ async function autoStartDaemonAndWait() {
46662
46881
  if (await isDaemonReachable()) return true;
46663
46882
  }
46664
46883
  } catch {
46884
+ } finally {
46885
+ if (startupFd !== void 0) {
46886
+ try {
46887
+ import_fs43.default.closeSync(startupFd);
46888
+ } catch {
46889
+ }
46890
+ }
46665
46891
  }
46666
46892
  return false;
46667
46893
  }
46668
46894
 
46895
+ // src/cli.ts
46896
+ init_service();
46897
+
46669
46898
  // src/cli/commands/check.ts
46670
46899
  var import_chalk9 = __toESM(require("chalk"));
46671
- var import_fs46 = __toESM(require("fs"));
46900
+ var import_fs47 = __toESM(require("fs"));
46672
46901
  var import_child_process7 = require("child_process");
46673
- var import_path44 = __toESM(require("path"));
46674
- var import_os41 = __toESM(require("os"));
46902
+ var import_path45 = __toESM(require("path"));
46903
+ var import_os43 = __toESM(require("os"));
46675
46904
  init_orchestrator();
46676
46905
  init_state();
46677
46906
  init_daemon();
46907
+ init_startup_log();
46678
46908
  init_config();
46679
46909
  init_policy();
46680
46910
 
46681
46911
  // src/undo.ts
46682
46912
  var import_child_process6 = require("child_process");
46683
46913
  var import_crypto12 = __toESM(require("crypto"));
46684
- var import_fs43 = __toESM(require("fs"));
46914
+ var import_fs44 = __toESM(require("fs"));
46685
46915
  var import_net3 = __toESM(require("net"));
46686
- var import_path41 = __toESM(require("path"));
46687
- var import_os38 = __toESM(require("os"));
46688
- 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");
46689
46919
  function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
46690
46920
  try {
46691
46921
  const payload = JSON.stringify({
@@ -46705,22 +46935,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
46705
46935
  } catch {
46706
46936
  }
46707
46937
  }
46708
- var SNAPSHOT_STACK_PATH = import_path41.default.join(import_os38.default.homedir(), ".node9", "snapshots.json");
46709
- 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");
46710
46940
  var MAX_SNAPSHOTS = 10;
46711
46941
  var GIT_TIMEOUT = 15e3;
46712
46942
  function readStack() {
46713
46943
  try {
46714
- if (import_fs43.default.existsSync(SNAPSHOT_STACK_PATH))
46715
- 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"));
46716
46946
  } catch {
46717
46947
  }
46718
46948
  return [];
46719
46949
  }
46720
46950
  function writeStack(stack) {
46721
- const dir = import_path41.default.dirname(SNAPSHOT_STACK_PATH);
46722
- if (!import_fs43.default.existsSync(dir)) import_fs43.default.mkdirSync(dir, { recursive: true });
46723
- 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));
46724
46954
  }
46725
46955
  function extractFilePath(args) {
46726
46956
  if (!args || typeof args !== "object") return null;
@@ -46740,12 +46970,12 @@ function buildArgsSummary(tool, args) {
46740
46970
  return "";
46741
46971
  }
46742
46972
  function findProjectRoot(filePath) {
46743
- let dir = import_path41.default.dirname(filePath);
46973
+ let dir = import_path42.default.dirname(filePath);
46744
46974
  while (true) {
46745
- 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"))) {
46746
46976
  return dir;
46747
46977
  }
46748
- const parent = import_path41.default.dirname(dir);
46978
+ const parent = import_path42.default.dirname(dir);
46749
46979
  if (parent === dir) return process.cwd();
46750
46980
  dir = parent;
46751
46981
  }
@@ -46753,7 +46983,7 @@ function findProjectRoot(filePath) {
46753
46983
  function normalizeCwdForHash(cwd) {
46754
46984
  let normalized;
46755
46985
  try {
46756
- normalized = import_fs43.default.realpathSync(cwd);
46986
+ normalized = import_fs44.default.realpathSync(cwd);
46757
46987
  } catch {
46758
46988
  normalized = cwd;
46759
46989
  }
@@ -46763,16 +46993,16 @@ function normalizeCwdForHash(cwd) {
46763
46993
  }
46764
46994
  function getShadowRepoDir(cwd) {
46765
46995
  const hash = import_crypto12.default.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
46766
- 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);
46767
46997
  }
46768
46998
  function cleanOrphanedIndexFiles(shadowDir) {
46769
46999
  try {
46770
47000
  const cutoff = Date.now() - 6e4;
46771
- for (const f of import_fs43.default.readdirSync(shadowDir)) {
47001
+ for (const f of import_fs44.default.readdirSync(shadowDir)) {
46772
47002
  if (f.startsWith("index_")) {
46773
- const fp = import_path41.default.join(shadowDir, f);
47003
+ const fp = import_path42.default.join(shadowDir, f);
46774
47004
  try {
46775
- 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);
46776
47006
  } catch {
46777
47007
  }
46778
47008
  }
@@ -46784,7 +47014,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
46784
47014
  const hardcoded = [".git", ".node9"];
46785
47015
  const lines = [...hardcoded, ...ignorePaths].join("\n");
46786
47016
  try {
46787
- 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");
46788
47018
  } catch {
46789
47019
  }
46790
47020
  }
@@ -46797,25 +47027,25 @@ function ensureShadowRepo(shadowDir, cwd) {
46797
47027
  timeout: 3e3
46798
47028
  });
46799
47029
  if (check.status === 0) {
46800
- const ptPath = import_path41.default.join(shadowDir, "project-path.txt");
47030
+ const ptPath = import_path42.default.join(shadowDir, "project-path.txt");
46801
47031
  try {
46802
- const stored = import_fs43.default.readFileSync(ptPath, "utf8").trim();
47032
+ const stored = import_fs44.default.readFileSync(ptPath, "utf8").trim();
46803
47033
  if (stored === normalizedCwd) return true;
46804
47034
  if (process.env.NODE9_DEBUG === "1")
46805
47035
  console.error(
46806
47036
  `[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
46807
47037
  );
46808
- import_fs43.default.rmSync(shadowDir, { recursive: true, force: true });
47038
+ import_fs44.default.rmSync(shadowDir, { recursive: true, force: true });
46809
47039
  } catch {
46810
47040
  try {
46811
- import_fs43.default.writeFileSync(ptPath, normalizedCwd, "utf8");
47041
+ import_fs44.default.writeFileSync(ptPath, normalizedCwd, "utf8");
46812
47042
  } catch {
46813
47043
  }
46814
47044
  return true;
46815
47045
  }
46816
47046
  }
46817
47047
  try {
46818
- import_fs43.default.mkdirSync(shadowDir, { recursive: true });
47048
+ import_fs44.default.mkdirSync(shadowDir, { recursive: true });
46819
47049
  } catch {
46820
47050
  }
46821
47051
  const init = (0, import_child_process6.spawnSync)("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
@@ -46824,7 +47054,7 @@ function ensureShadowRepo(shadowDir, cwd) {
46824
47054
  if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
46825
47055
  return false;
46826
47056
  }
46827
- const configFile = import_path41.default.join(shadowDir, "config");
47057
+ const configFile = import_path42.default.join(shadowDir, "config");
46828
47058
  (0, import_child_process6.spawnSync)("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
46829
47059
  timeout: 3e3
46830
47060
  });
@@ -46832,7 +47062,7 @@ function ensureShadowRepo(shadowDir, cwd) {
46832
47062
  timeout: 3e3
46833
47063
  });
46834
47064
  try {
46835
- 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");
46836
47066
  } catch {
46837
47067
  }
46838
47068
  return true;
@@ -46855,12 +47085,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
46855
47085
  let indexFile = null;
46856
47086
  try {
46857
47087
  const rawFilePath = extractFilePath(args);
46858
- const absFilePath = rawFilePath && import_path41.default.isAbsolute(rawFilePath) ? rawFilePath : null;
47088
+ const absFilePath = rawFilePath && import_path42.default.isAbsolute(rawFilePath) ? rawFilePath : null;
46859
47089
  const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
46860
47090
  const shadowDir = getShadowRepoDir(cwd);
46861
47091
  if (!ensureShadowRepo(shadowDir, cwd)) return null;
46862
47092
  writeShadowExcludes(shadowDir, ignorePaths);
46863
- indexFile = import_path41.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
47093
+ indexFile = import_path42.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
46864
47094
  const shadowEnv = {
46865
47095
  ...process.env,
46866
47096
  GIT_DIR: shadowDir,
@@ -46932,7 +47162,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
46932
47162
  writeStack(stack);
46933
47163
  const entry = stack[stack.length - 1];
46934
47164
  notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
46935
- import_fs43.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
47165
+ import_fs44.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
46936
47166
  if (shouldGc) {
46937
47167
  (0, import_child_process6.spawn)("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
46938
47168
  }
@@ -46943,7 +47173,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
46943
47173
  } finally {
46944
47174
  if (indexFile) {
46945
47175
  try {
46946
- import_fs43.default.unlinkSync(indexFile);
47176
+ import_fs44.default.unlinkSync(indexFile);
46947
47177
  } catch {
46948
47178
  }
46949
47179
  }
@@ -47019,9 +47249,9 @@ function applyUndo(hash, cwd) {
47019
47249
  timeout: GIT_TIMEOUT
47020
47250
  }).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
47021
47251
  for (const file of [...tracked, ...untracked]) {
47022
- const fullPath = import_path41.default.join(dir, file);
47023
- if (!snapshotFiles.has(file) && import_fs43.default.existsSync(fullPath)) {
47024
- 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);
47025
47255
  }
47026
47256
  }
47027
47257
  return true;
@@ -47031,12 +47261,12 @@ function applyUndo(hash, cwd) {
47031
47261
  }
47032
47262
 
47033
47263
  // src/skill-pin.ts
47034
- var import_fs44 = __toESM(require("fs"));
47035
- var import_path42 = __toESM(require("path"));
47036
- 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"));
47037
47267
  var import_crypto13 = __toESM(require("crypto"));
47038
47268
  function getPinsFilePath2() {
47039
- 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");
47040
47270
  }
47041
47271
  var MAX_FILES = 5e3;
47042
47272
  var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
@@ -47050,18 +47280,18 @@ function walkDir(root) {
47050
47280
  if (out.length >= MAX_FILES) return;
47051
47281
  let entries;
47052
47282
  try {
47053
- entries = import_fs44.default.readdirSync(dir, { withFileTypes: true });
47283
+ entries = import_fs45.default.readdirSync(dir, { withFileTypes: true });
47054
47284
  } catch {
47055
47285
  return;
47056
47286
  }
47057
47287
  entries.sort((a, b) => a.name.localeCompare(b.name));
47058
47288
  for (const entry of entries) {
47059
47289
  if (out.length >= MAX_FILES) return;
47060
- const full = import_path42.default.join(dir, entry.name);
47061
- 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;
47062
47292
  let lst;
47063
47293
  try {
47064
- lst = import_fs44.default.lstatSync(full);
47294
+ lst = import_fs45.default.lstatSync(full);
47065
47295
  } catch {
47066
47296
  continue;
47067
47297
  }
@@ -47073,7 +47303,7 @@ function walkDir(root) {
47073
47303
  if (!lst.isFile()) continue;
47074
47304
  if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
47075
47305
  try {
47076
- const buf = import_fs44.default.readFileSync(full);
47306
+ const buf = import_fs45.default.readFileSync(full);
47077
47307
  totalBytes += buf.length;
47078
47308
  out.push({ rel, hash: sha256Bytes(buf) });
47079
47309
  } catch {
@@ -47087,14 +47317,14 @@ function walkDir(root) {
47087
47317
  function hashSkillRoot(absPath) {
47088
47318
  let lst;
47089
47319
  try {
47090
- lst = import_fs44.default.lstatSync(absPath);
47320
+ lst = import_fs45.default.lstatSync(absPath);
47091
47321
  } catch {
47092
47322
  return { exists: false, contentHash: "", fileCount: 0 };
47093
47323
  }
47094
47324
  if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
47095
47325
  if (lst.isFile()) {
47096
47326
  try {
47097
- 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 };
47098
47328
  } catch {
47099
47329
  return { exists: false, contentHash: "", fileCount: 0 };
47100
47330
  }
@@ -47112,7 +47342,7 @@ function getRootKey(absPath) {
47112
47342
  function readSkillPinsSafe() {
47113
47343
  const filePath = getPinsFilePath2();
47114
47344
  try {
47115
- const raw = import_fs44.default.readFileSync(filePath, "utf-8");
47345
+ const raw = import_fs45.default.readFileSync(filePath, "utf-8");
47116
47346
  if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
47117
47347
  const parsed = JSON.parse(raw);
47118
47348
  if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
@@ -47132,10 +47362,10 @@ function readSkillPins() {
47132
47362
  }
47133
47363
  function writeSkillPins(data) {
47134
47364
  const filePath = getPinsFilePath2();
47135
- import_fs44.default.mkdirSync(import_path42.default.dirname(filePath), { recursive: true });
47365
+ import_fs45.default.mkdirSync(import_path43.default.dirname(filePath), { recursive: true });
47136
47366
  const tmp = `${filePath}.${import_crypto13.default.randomBytes(6).toString("hex")}.tmp`;
47137
- import_fs44.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
47138
- 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);
47139
47369
  }
47140
47370
  function removePin2(rootKey) {
47141
47371
  const pins = readSkillPins();
@@ -47179,36 +47409,36 @@ function verifyAndPinRoots(roots) {
47179
47409
  return { kind: "verified" };
47180
47410
  }
47181
47411
  function defaultSkillRoots(_cwd) {
47182
- 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");
47183
47413
  const roots = [];
47184
47414
  let registries;
47185
47415
  try {
47186
- registries = import_fs44.default.readdirSync(marketplaces, { withFileTypes: true });
47416
+ registries = import_fs45.default.readdirSync(marketplaces, { withFileTypes: true });
47187
47417
  } catch {
47188
47418
  return [];
47189
47419
  }
47190
47420
  for (const registry of registries) {
47191
47421
  if (!registry.isDirectory()) continue;
47192
- const pluginsDir = import_path42.default.join(marketplaces, registry.name, "plugins");
47422
+ const pluginsDir = import_path43.default.join(marketplaces, registry.name, "plugins");
47193
47423
  let plugins;
47194
47424
  try {
47195
- plugins = import_fs44.default.readdirSync(pluginsDir, { withFileTypes: true });
47425
+ plugins = import_fs45.default.readdirSync(pluginsDir, { withFileTypes: true });
47196
47426
  } catch {
47197
47427
  continue;
47198
47428
  }
47199
47429
  for (const plugin of plugins) {
47200
47430
  if (!plugin.isDirectory()) continue;
47201
- roots.push(import_path42.default.join(pluginsDir, plugin.name));
47431
+ roots.push(import_path43.default.join(pluginsDir, plugin.name));
47202
47432
  }
47203
47433
  }
47204
47434
  return roots;
47205
47435
  }
47206
47436
  function resolveUserSkillRoot(entry, cwd) {
47207
47437
  if (!entry) return null;
47208
- if (entry.startsWith("~/") || entry === "~") return import_path42.default.join(import_os39.default.homedir(), entry.slice(1));
47209
- if (import_path42.default.isAbsolute(entry)) return entry;
47210
- if (!cwd || !import_path42.default.isAbsolute(cwd)) return null;
47211
- 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);
47212
47442
  }
47213
47443
 
47214
47444
  // src/cli/commands/check.ts
@@ -47216,12 +47446,12 @@ init_dlp();
47216
47446
  init_audit();
47217
47447
 
47218
47448
  // src/review-pending.ts
47219
- var import_fs45 = __toESM(require("fs"));
47220
- var import_os40 = __toESM(require("os"));
47221
- 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"));
47222
47452
  init_hasher();
47223
47453
  function storePath() {
47224
- 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");
47225
47455
  }
47226
47456
  var TTL_MS2 = 6 * 60 * 60 * 1e3;
47227
47457
  var MAX_ENTRIES = 500;
@@ -47238,7 +47468,7 @@ function reviewCorrelationKey(payload) {
47238
47468
  }
47239
47469
  function read() {
47240
47470
  try {
47241
- const parsed = JSON.parse(import_fs45.default.readFileSync(storePath(), "utf-8"));
47471
+ const parsed = JSON.parse(import_fs46.default.readFileSync(storePath(), "utf-8"));
47242
47472
  if (parsed && Array.isArray(parsed.entries)) return parsed;
47243
47473
  } catch {
47244
47474
  }
@@ -47247,11 +47477,11 @@ function read() {
47247
47477
  function write(store) {
47248
47478
  try {
47249
47479
  const p = storePath();
47250
- const dir = import_path43.default.dirname(p);
47251
- 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 });
47252
47482
  const tmp = `${p}.${process.pid}.tmp`;
47253
- import_fs45.default.writeFileSync(tmp, JSON.stringify(store));
47254
- import_fs45.default.renameSync(tmp, p);
47483
+ import_fs46.default.writeFileSync(tmp, JSON.stringify(store));
47484
+ import_fs46.default.renameSync(tmp, p);
47255
47485
  } catch {
47256
47486
  }
47257
47487
  }
@@ -47364,9 +47594,9 @@ function registerCheckCommand(program2) {
47364
47594
  } catch (err2) {
47365
47595
  const tempConfig = getConfig();
47366
47596
  if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
47367
- 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");
47368
47598
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
47369
- import_fs46.default.appendFileSync(
47599
+ import_fs47.default.appendFileSync(
47370
47600
  logPath,
47371
47601
  `[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
47372
47602
  RAW: ${raw}
@@ -47379,14 +47609,14 @@ RAW: ${raw}
47379
47609
  const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
47380
47610
  if (process.env.NODE9_DEBUG === "1") {
47381
47611
  try {
47382
- const logPath = import_path44.default.join(import_os41.default.homedir(), ".node9", "hook-debug.log");
47383
- if (!import_fs46.default.existsSync(import_path44.default.dirname(logPath)))
47384
- 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 });
47385
47615
  const sanitized = JSON.stringify({
47386
47616
  ...payload,
47387
47617
  prompt: `<redacted, ${prompt.length} bytes>`
47388
47618
  });
47389
- import_fs46.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
47619
+ import_fs47.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
47390
47620
  `);
47391
47621
  } catch {
47392
47622
  }
@@ -47407,8 +47637,8 @@ RAW: ${raw}
47407
47637
  );
47408
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.`;
47409
47639
  try {
47410
- const ttyFd = import_fs46.default.openSync("/dev/tty", "w");
47411
- import_fs46.default.writeSync(
47640
+ const ttyFd = import_fs47.default.openSync("/dev/tty", "w");
47641
+ import_fs47.default.writeSync(
47412
47642
  ttyFd,
47413
47643
  import_chalk9.default.bgRed.white.bold(`
47414
47644
  \u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
@@ -47418,7 +47648,7 @@ RAW: ${raw}
47418
47648
 
47419
47649
  `)
47420
47650
  );
47421
- import_fs46.default.closeSync(ttyFd);
47651
+ import_fs47.default.closeSync(ttyFd);
47422
47652
  } catch {
47423
47653
  }
47424
47654
  const isCodex = agent2 === "Codex";
@@ -47437,16 +47667,17 @@ RAW: ${raw}
47437
47667
  process.exit(2);
47438
47668
  }
47439
47669
  const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
47440
- 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;
47441
47671
  const config = getConfig(safeCwdForConfig);
47442
- 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) {
47443
47674
  try {
47444
47675
  const scriptPath = process.argv[1];
47445
- if (typeof scriptPath !== "string" || !import_path44.default.isAbsolute(scriptPath))
47676
+ if (typeof scriptPath !== "string" || !import_path45.default.isAbsolute(scriptPath))
47446
47677
  throw new Error("node9: argv[1] is not an absolute path");
47447
- const resolvedScript = import_fs46.default.realpathSync(scriptPath);
47448
- const packageDist = import_fs46.default.realpathSync(import_path44.default.resolve(__dirname, "../.."));
47449
- 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)
47450
47681
  throw new Error(
47451
47682
  `node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
47452
47683
  );
@@ -47461,17 +47692,27 @@ RAW: ${raw}
47461
47692
  ]) {
47462
47693
  delete safeEnv[key];
47463
47694
  }
47464
- const d = (0, import_child_process7.spawn)(process.execPath, [scriptPath, "daemon"], {
47465
- detached: true,
47466
- stdio: "ignore",
47467
- env: { ...safeEnv, NODE9_AUTO_STARTED: "1" }
47468
- });
47469
- 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
+ }
47470
47711
  } catch (spawnErr) {
47471
- 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");
47472
47713
  const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
47473
47714
  try {
47474
- import_fs46.default.appendFileSync(
47715
+ import_fs47.default.appendFileSync(
47475
47716
  logPath,
47476
47717
  `[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
47477
47718
  `
@@ -47479,12 +47720,16 @@ RAW: ${raw}
47479
47720
  } catch {
47480
47721
  }
47481
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
+ );
47482
47727
  }
47483
47728
  if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
47484
- const logPath = import_path44.default.join(import_os41.default.homedir(), ".node9", "hook-debug.log");
47485
- if (!import_fs46.default.existsSync(import_path44.default.dirname(logPath)))
47486
- import_fs46.default.mkdirSync(import_path44.default.dirname(logPath), { recursive: true });
47487
- 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}
47488
47733
  `);
47489
47734
  }
47490
47735
  const rawToolName = sanitize2(extractToolName(payload));
@@ -47498,8 +47743,8 @@ RAW: ${raw}
47498
47743
  const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
47499
47744
  let ttyFd = null;
47500
47745
  try {
47501
- ttyFd = import_fs46.default.openSync("/dev/tty", "w");
47502
- 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");
47503
47748
  if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
47504
47749
  writeTty(import_chalk9.default.bgRed.white.bold(`
47505
47750
  \u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
@@ -47518,7 +47763,7 @@ RAW: ${raw}
47518
47763
  } finally {
47519
47764
  if (ttyFd !== null)
47520
47765
  try {
47521
- import_fs46.default.closeSync(ttyFd);
47766
+ import_fs47.default.closeSync(ttyFd);
47522
47767
  } catch {
47523
47768
  }
47524
47769
  }
@@ -47575,8 +47820,8 @@ RAW: ${raw}
47575
47820
  } catch {
47576
47821
  }
47577
47822
  try {
47578
- const ttyFd = import_fs46.default.openSync("/dev/tty", "w");
47579
- import_fs46.default.writeSync(
47823
+ const ttyFd = import_fs47.default.openSync("/dev/tty", "w");
47824
+ import_fs47.default.writeSync(
47580
47825
  ttyFd,
47581
47826
  import_chalk9.default.yellow(
47582
47827
  `
@@ -47584,7 +47829,7 @@ RAW: ${raw}
47584
47829
  `
47585
47830
  )
47586
47831
  );
47587
- import_fs46.default.closeSync(ttyFd);
47832
+ import_fs47.default.closeSync(ttyFd);
47588
47833
  } catch {
47589
47834
  }
47590
47835
  if (agent === "GitHub Copilot") {
@@ -47616,17 +47861,17 @@ RAW: ${raw}
47616
47861
  const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
47617
47862
  if (skillPinCfg.enabled && safeSessionId) {
47618
47863
  try {
47619
- const sessionsDir = import_path44.default.join(import_os41.default.homedir(), ".node9", "skill-sessions");
47620
- 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`);
47621
47866
  let flag = null;
47622
47867
  try {
47623
- flag = JSON.parse(import_fs46.default.readFileSync(flagPath, "utf-8"));
47868
+ flag = JSON.parse(import_fs47.default.readFileSync(flagPath, "utf-8"));
47624
47869
  } catch {
47625
47870
  }
47626
47871
  const writeFlag = (data2) => {
47627
47872
  try {
47628
- import_fs46.default.mkdirSync(sessionsDir, { recursive: true });
47629
- import_fs46.default.writeFileSync(
47873
+ import_fs47.default.mkdirSync(sessionsDir, { recursive: true });
47874
+ import_fs47.default.writeFileSync(
47630
47875
  flagPath,
47631
47876
  JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
47632
47877
  { mode: 384 }
@@ -47637,8 +47882,8 @@ RAW: ${raw}
47637
47882
  const sendSkillWarn = (detail, recoveryCmd) => {
47638
47883
  let ttyFd = null;
47639
47884
  try {
47640
- ttyFd = import_fs46.default.openSync("/dev/tty", "w");
47641
- 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");
47642
47887
  w(import_chalk9.default.yellow(`
47643
47888
  \u26A0\uFE0F Node9: installed skill drift detected`));
47644
47889
  w(import_chalk9.default.gray(` ${detail}`));
@@ -47653,7 +47898,7 @@ RAW: ${raw}
47653
47898
  } finally {
47654
47899
  if (ttyFd !== null)
47655
47900
  try {
47656
- import_fs46.default.closeSync(ttyFd);
47901
+ import_fs47.default.closeSync(ttyFd);
47657
47902
  } catch {
47658
47903
  }
47659
47904
  }
@@ -47669,7 +47914,7 @@ RAW: ${raw}
47669
47914
  return;
47670
47915
  }
47671
47916
  if (!flag || flag.state !== "verified" && flag.state !== "warned") {
47672
- 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;
47673
47918
  const extraRoots = skillPinCfg.roots;
47674
47919
  const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
47675
47920
  const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
@@ -47710,10 +47955,10 @@ RAW: ${raw}
47710
47955
  }
47711
47956
  try {
47712
47957
  const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
47713
- for (const name of import_fs46.default.readdirSync(sessionsDir)) {
47714
- 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);
47715
47960
  try {
47716
- 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);
47717
47962
  } catch {
47718
47963
  }
47719
47964
  }
@@ -47723,9 +47968,9 @@ RAW: ${raw}
47723
47968
  } catch (err2) {
47724
47969
  if (process.env.NODE9_DEBUG === "1") {
47725
47970
  try {
47726
- 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");
47727
47972
  const msg = err2 instanceof Error ? err2.message : String(err2);
47728
- 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}
47729
47974
  `);
47730
47975
  } catch {
47731
47976
  }
@@ -47735,7 +47980,7 @@ RAW: ${raw}
47735
47980
  if (shouldSnapshot(toolName, toolInput, config)) {
47736
47981
  await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
47737
47982
  }
47738
- 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;
47739
47984
  const askMode = resolveAskMode(agent, opts, config);
47740
47985
  const result = await authorizeHeadless(toolName, toolInput, meta, {
47741
47986
  cwd: safeCwdForAuth,
@@ -47753,12 +47998,12 @@ RAW: ${raw}
47753
47998
  }
47754
47999
  if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
47755
48000
  try {
47756
- const tty = import_fs46.default.openSync("/dev/tty", "w");
47757
- import_fs46.default.writeSync(
48001
+ const tty = import_fs47.default.openSync("/dev/tty", "w");
48002
+ import_fs47.default.writeSync(
47758
48003
  tty,
47759
48004
  import_chalk9.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
47760
48005
  );
47761
- import_fs46.default.closeSync(tty);
48006
+ import_fs47.default.closeSync(tty);
47762
48007
  } catch {
47763
48008
  }
47764
48009
  const daemonReady = await autoStartDaemonAndWait();
@@ -47785,9 +48030,9 @@ RAW: ${raw}
47785
48030
  });
47786
48031
  } catch (err2) {
47787
48032
  if (process.env.NODE9_DEBUG === "1") {
47788
- 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");
47789
48034
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
47790
- import_fs46.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
48035
+ import_fs47.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
47791
48036
  `);
47792
48037
  }
47793
48038
  process.exit(0);
@@ -47821,9 +48066,9 @@ RAW: ${raw}
47821
48066
  }
47822
48067
 
47823
48068
  // src/cli/commands/log.ts
47824
- var import_fs47 = __toESM(require("fs"));
47825
- var import_path45 = __toESM(require("path"));
47826
- 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"));
47827
48072
  init_audit();
47828
48073
  init_config();
47829
48074
  init_daemon();
@@ -47933,10 +48178,10 @@ function registerLogCommand(program2) {
47933
48178
  if (rawToolName !== tool) entry.agentToolName = rawToolName;
47934
48179
  const payloadSessionId = payload.session_id ?? payload.conversationId;
47935
48180
  if (payloadSessionId) entry.sessionId = payloadSessionId;
47936
- const logPath = import_path45.default.join(import_os42.default.homedir(), ".node9", "audit.log");
47937
- if (!import_fs47.default.existsSync(import_path45.default.dirname(logPath)))
47938
- import_fs47.default.mkdirSync(import_path45.default.dirname(logPath), { recursive: true });
47939
- 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");
47940
48185
  if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
47941
48186
  const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
47942
48187
  if (command) {
@@ -47970,7 +48215,7 @@ function registerLogCommand(program2) {
47970
48215
  }
47971
48216
  }
47972
48217
  const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
47973
- 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;
47974
48219
  const config = getConfig(safeCwd);
47975
48220
  {
47976
48221
  const toolOutput = payload.tool_response?.output;
@@ -48047,9 +48292,9 @@ function registerLogCommand(program2) {
48047
48292
  const msg = err2 instanceof Error ? err2.message : String(err2);
48048
48293
  process.stderr.write(`[Node9] audit log error: ${msg}
48049
48294
  `);
48050
- 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");
48051
48296
  try {
48052
- 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}
48053
48298
  `);
48054
48299
  } catch {
48055
48300
  }
@@ -48074,15 +48319,15 @@ function registerLogCommand(program2) {
48074
48319
 
48075
48320
  // src/cli/commands/shield.ts
48076
48321
  var import_chalk10 = __toESM(require("chalk"));
48077
- var import_fs49 = __toESM(require("fs"));
48078
- var import_path47 = __toESM(require("path"));
48079
- 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"));
48080
48325
  init_shields();
48081
48326
  init_build();
48082
48327
 
48083
48328
  // src/shields/create.ts
48084
- var import_fs48 = __toESM(require("fs"));
48085
- var import_path46 = __toESM(require("path"));
48329
+ var import_fs49 = __toESM(require("fs"));
48330
+ var import_path47 = __toESM(require("path"));
48086
48331
  init_dist();
48087
48332
  init_shields();
48088
48333
  init_audit();
@@ -48102,8 +48347,8 @@ function createShield(def, opts = {}) {
48102
48347
  error: `"${name}" is a built-in shield \u2014 choose a different name (a user shield with this name would shadow the built-in).`
48103
48348
  };
48104
48349
  }
48105
- const filePath = import_path46.default.join(USER_SHIELDS_DIR_PATH, `${name}.json`);
48106
- 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)) {
48107
48352
  return {
48108
48353
  ok: false,
48109
48354
  error: `Shield "${name}" already exists at ${filePath}. Pass --overwrite to replace it.`
@@ -48168,8 +48413,8 @@ var COMMUNITY_INDEX_URL = "https://raw.githubusercontent.com/node9ai/node9-proxy
48168
48413
  function readCloudShields() {
48169
48414
  const out = /* @__PURE__ */ new Set();
48170
48415
  try {
48171
- const file = import_path47.default.join(import_os43.default.homedir(), ".node9", "rules-cache.json");
48172
- 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"));
48173
48418
  for (const r of raw.rules ?? []) {
48174
48419
  const rule = r;
48175
48420
  const fromSource = rule.source?.startsWith("SHIELD:") ? rule.source.slice("SHIELD:".length).toLowerCase() : void 0;
@@ -48486,7 +48731,7 @@ function registerShieldCommand(program2) {
48486
48731
  if (opts.fromFile) {
48487
48732
  let raw;
48488
48733
  try {
48489
- raw = JSON.parse(import_fs49.default.readFileSync(opts.fromFile, "utf-8"));
48734
+ raw = JSON.parse(import_fs50.default.readFileSync(opts.fromFile, "utf-8"));
48490
48735
  } catch (err2) {
48491
48736
  console.error(
48492
48737
  import_chalk10.default.red(`
@@ -48606,16 +48851,33 @@ function registerConfigShowCommand(program2) {
48606
48851
 
48607
48852
  // src/cli/commands/doctor.ts
48608
48853
  var import_chalk11 = __toESM(require("chalk"));
48609
- var import_fs50 = __toESM(require("fs"));
48610
- var import_path48 = __toESM(require("path"));
48611
- 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"));
48612
48857
  var import_child_process8 = require("child_process");
48613
48858
  init_daemon();
48614
48859
  init_config();
48615
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
48616
48878
  function registerDoctorCommand(program2, version2) {
48617
48879
  program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
48618
- const homeDir2 = import_os44.default.homedir();
48880
+ const homeDir2 = import_os46.default.homedir();
48619
48881
  let failures = 0;
48620
48882
  function pass(msg) {
48621
48883
  console.log(import_chalk11.default.green(" \u2705 ") + msg);
@@ -48661,10 +48923,10 @@ function registerDoctorCommand(program2, version2) {
48661
48923
  );
48662
48924
  }
48663
48925
  section("Configuration");
48664
- const globalConfigPath = import_path48.default.join(homeDir2, ".node9", "config.json");
48665
- if (import_fs50.default.existsSync(globalConfigPath)) {
48926
+ const globalConfigPath = import_path49.default.join(homeDir2, ".node9", "config.json");
48927
+ if (import_fs51.default.existsSync(globalConfigPath)) {
48666
48928
  try {
48667
- JSON.parse(import_fs50.default.readFileSync(globalConfigPath, "utf-8"));
48929
+ JSON.parse(import_fs51.default.readFileSync(globalConfigPath, "utf-8"));
48668
48930
  pass("~/.node9/config.json found and valid");
48669
48931
  } catch {
48670
48932
  fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
@@ -48672,10 +48934,10 @@ function registerDoctorCommand(program2, version2) {
48672
48934
  } else {
48673
48935
  warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
48674
48936
  }
48675
- const projectConfigPath = import_path48.default.join(process.cwd(), "node9.config.json");
48676
- 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)) {
48677
48939
  try {
48678
- JSON.parse(import_fs50.default.readFileSync(projectConfigPath, "utf-8"));
48940
+ JSON.parse(import_fs51.default.readFileSync(projectConfigPath, "utf-8"));
48679
48941
  pass("node9.config.json found and valid (project)");
48680
48942
  } catch {
48681
48943
  fail(
@@ -48684,8 +48946,8 @@ function registerDoctorCommand(program2, version2) {
48684
48946
  );
48685
48947
  }
48686
48948
  }
48687
- const credsPath = import_path48.default.join(homeDir2, ".node9", "credentials.json");
48688
- if (import_fs50.default.existsSync(credsPath)) {
48949
+ const credsPath = import_path49.default.join(homeDir2, ".node9", "credentials.json");
48950
+ if (import_fs51.default.existsSync(credsPath)) {
48689
48951
  pass("Cloud credentials found (~/.node9/credentials.json)");
48690
48952
  } else {
48691
48953
  warn(
@@ -48725,11 +48987,31 @@ function registerDoctorCommand(program2, version2) {
48725
48987
  "Run: node9 daemon --background"
48726
48988
  );
48727
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
+ }
48728
49010
  section("Cloud audit shipping");
48729
49011
  try {
48730
49012
  const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
48731
49013
  const cfg = getConfig();
48732
- 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"));
48733
49015
  if (!creds) {
48734
49016
  warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
48735
49017
  } else if (!cfg.settings.approvers.cloud) {
@@ -48779,9 +49061,9 @@ function registerDoctorCommand(program2, version2) {
48779
49061
 
48780
49062
  // src/cli/commands/audit.ts
48781
49063
  var import_chalk12 = __toESM(require("chalk"));
48782
- var import_fs51 = __toESM(require("fs"));
48783
- var import_path49 = __toESM(require("path"));
48784
- 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"));
48785
49067
  function formatRelativeTime(timestamp) {
48786
49068
  const diff = Date.now() - new Date(timestamp).getTime();
48787
49069
  const sec = Math.floor(diff / 1e3);
@@ -48794,14 +49076,14 @@ function formatRelativeTime(timestamp) {
48794
49076
  }
48795
49077
  function registerAuditCommand(program2) {
48796
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) => {
48797
- const logPath = import_path49.default.join(import_os45.default.homedir(), ".node9", "audit.log");
48798
- 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)) {
48799
49081
  console.log(
48800
49082
  import_chalk12.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
48801
49083
  );
48802
49084
  return;
48803
49085
  }
48804
- const raw = import_fs51.default.readFileSync(logPath, "utf-8");
49086
+ const raw = import_fs52.default.readFileSync(logPath, "utf-8");
48805
49087
  const lines = raw.split("\n").filter((l) => l.trim() !== "");
48806
49088
  let entries = lines.flatMap((line) => {
48807
49089
  try {
@@ -48857,9 +49139,9 @@ function registerAuditCommand(program2) {
48857
49139
  var import_chalk13 = __toESM(require("chalk"));
48858
49140
 
48859
49141
  // src/cli/aggregate/report-audit.ts
48860
- var import_fs52 = __toESM(require("fs"));
48861
- var import_os46 = __toESM(require("os"));
48862
- 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"));
48863
49145
  init_costSync();
48864
49146
  init_litellm();
48865
49147
  init_cost_codex();
@@ -48942,8 +49224,8 @@ function getDateRange(period, now) {
48942
49224
  }
48943
49225
  }
48944
49226
  function parseAuditLog(logPath) {
48945
- if (!import_fs52.default.existsSync(logPath)) return [];
48946
- 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");
48947
49229
  return raw.split("\n").flatMap((line) => {
48948
49230
  if (!line.trim()) return [];
48949
49231
  try {
@@ -48990,25 +49272,25 @@ function freezeClaudeCost(acc) {
48990
49272
  };
48991
49273
  }
48992
49274
  function processClaudeCostProject(proj, projectsDir, start, end, acc) {
48993
- const projPath = import_path50.default.join(projectsDir, proj);
49275
+ const projPath = import_path51.default.join(projectsDir, proj);
48994
49276
  let files;
48995
49277
  try {
48996
- const stat = import_fs52.default.statSync(projPath);
49278
+ const stat = import_fs53.default.statSync(projPath);
48997
49279
  if (!stat.isDirectory()) return;
48998
- 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-"));
48999
49281
  } catch {
49000
49282
  return;
49001
49283
  }
49002
49284
  const startMs = start.getTime();
49003
49285
  for (const file of files) {
49004
- const filePath = import_path50.default.join(projPath, file);
49286
+ const filePath = import_path51.default.join(projPath, file);
49005
49287
  try {
49006
- if (import_fs52.default.statSync(filePath).mtimeMs < startMs) continue;
49288
+ if (import_fs53.default.statSync(filePath).mtimeMs < startMs) continue;
49007
49289
  } catch {
49008
49290
  continue;
49009
49291
  }
49010
49292
  try {
49011
- const raw = import_fs52.default.readFileSync(filePath, "utf-8");
49293
+ const raw = import_fs53.default.readFileSync(filePath, "utf-8");
49012
49294
  for (const line of raw.split("\n")) {
49013
49295
  if (!line.trim()) continue;
49014
49296
  let entry;
@@ -49058,10 +49340,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
49058
49340
  }
49059
49341
  function loadClaudeCost(start, end, projectsDir) {
49060
49342
  const acc = emptyClaudeCostAccumulator();
49061
- if (!import_fs52.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
49343
+ if (!import_fs53.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
49062
49344
  let dirs;
49063
49345
  try {
49064
- dirs = import_fs52.default.readdirSync(projectsDir);
49346
+ dirs = import_fs53.default.readdirSync(projectsDir);
49065
49347
  } catch {
49066
49348
  return freezeClaudeCost(acc);
49067
49349
  }
@@ -49073,7 +49355,7 @@ function loadClaudeCost(start, end, projectsDir) {
49073
49355
  function processCodexCostFile(filePath, start, end, acc) {
49074
49356
  let lines;
49075
49357
  try {
49076
- lines = import_fs52.default.readFileSync(filePath, "utf-8").split("\n");
49358
+ lines = import_fs53.default.readFileSync(filePath, "utf-8").split("\n");
49077
49359
  } catch {
49078
49360
  return;
49079
49361
  }
@@ -49128,31 +49410,31 @@ function processCodexCostFile(filePath, start, end, acc) {
49128
49410
  }
49129
49411
  function listCodexSessionFiles2(sessionsBase) {
49130
49412
  const jsonlFiles = [];
49131
- if (!import_fs52.default.existsSync(sessionsBase)) return jsonlFiles;
49413
+ if (!import_fs53.default.existsSync(sessionsBase)) return jsonlFiles;
49132
49414
  try {
49133
- for (const year of import_fs52.default.readdirSync(sessionsBase)) {
49134
- 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);
49135
49417
  try {
49136
- if (!import_fs52.default.statSync(yearPath).isDirectory()) continue;
49418
+ if (!import_fs53.default.statSync(yearPath).isDirectory()) continue;
49137
49419
  } catch {
49138
49420
  continue;
49139
49421
  }
49140
- for (const month of import_fs52.default.readdirSync(yearPath)) {
49141
- 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);
49142
49424
  try {
49143
- if (!import_fs52.default.statSync(monthPath).isDirectory()) continue;
49425
+ if (!import_fs53.default.statSync(monthPath).isDirectory()) continue;
49144
49426
  } catch {
49145
49427
  continue;
49146
49428
  }
49147
- for (const day of import_fs52.default.readdirSync(monthPath)) {
49148
- 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);
49149
49431
  try {
49150
- if (!import_fs52.default.statSync(dayPath).isDirectory()) continue;
49432
+ if (!import_fs53.default.statSync(dayPath).isDirectory()) continue;
49151
49433
  } catch {
49152
49434
  continue;
49153
49435
  }
49154
- for (const file of import_fs52.default.readdirSync(dayPath)) {
49155
- 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));
49156
49438
  }
49157
49439
  }
49158
49440
  }
@@ -49217,13 +49499,13 @@ function freezeGeminiCost(acc) {
49217
49499
  function processGeminiCostFile(filePath, projectKey, start, end, acc) {
49218
49500
  const startMs = start.getTime();
49219
49501
  try {
49220
- if (import_fs52.default.statSync(filePath).mtimeMs < startMs) return;
49502
+ if (import_fs53.default.statSync(filePath).mtimeMs < startMs) return;
49221
49503
  } catch {
49222
49504
  return;
49223
49505
  }
49224
49506
  let raw;
49225
49507
  try {
49226
- raw = import_fs52.default.readFileSync(filePath, "utf-8");
49508
+ raw = import_fs53.default.readFileSync(filePath, "utf-8");
49227
49509
  } catch {
49228
49510
  return;
49229
49511
  }
@@ -49272,30 +49554,30 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
49272
49554
  const out = [];
49273
49555
  let dirs;
49274
49556
  try {
49275
- if (!import_fs52.default.statSync(geminiTmpDir2).isDirectory()) return out;
49276
- dirs = import_fs52.default.readdirSync(geminiTmpDir2);
49557
+ if (!import_fs53.default.statSync(geminiTmpDir2).isDirectory()) return out;
49558
+ dirs = import_fs53.default.readdirSync(geminiTmpDir2);
49277
49559
  } catch {
49278
49560
  return out;
49279
49561
  }
49280
49562
  for (const proj of dirs) {
49281
- const chatsDir = import_path50.default.join(geminiTmpDir2, proj, "chats");
49563
+ const chatsDir = import_path51.default.join(geminiTmpDir2, proj, "chats");
49282
49564
  let files;
49283
49565
  try {
49284
- if (!import_fs52.default.statSync(chatsDir).isDirectory()) continue;
49285
- files = import_fs52.default.readdirSync(chatsDir);
49566
+ if (!import_fs53.default.statSync(chatsDir).isDirectory()) continue;
49567
+ files = import_fs53.default.readdirSync(chatsDir);
49286
49568
  } catch {
49287
49569
  continue;
49288
49570
  }
49289
49571
  for (const f of files) {
49290
49572
  if (!f.endsWith(".jsonl")) continue;
49291
- out.push({ projectKey: proj, file: import_path50.default.join(chatsDir, f) });
49573
+ out.push({ projectKey: proj, file: import_path51.default.join(chatsDir, f) });
49292
49574
  }
49293
49575
  }
49294
49576
  return out;
49295
49577
  }
49296
49578
  function loadGeminiCost(start, end, geminiTmpDir2) {
49297
49579
  const acc = emptyGeminiAccumulator();
49298
- if (!import_fs52.default.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
49580
+ if (!import_fs53.default.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
49299
49581
  for (const { projectKey, file } of listGeminiSessionFiles2(geminiTmpDir2)) {
49300
49582
  processGeminiCostFile(file, projectKey, start, end, acc);
49301
49583
  }
@@ -49313,11 +49595,11 @@ function dimensionOfBlock(checkedBy, ruleName) {
49313
49595
  }
49314
49596
  function aggregateReportFromAudit(period, opts = {}) {
49315
49597
  const now = opts.now ?? /* @__PURE__ */ new Date();
49316
- const auditLogPath = opts.auditLogPath ?? import_path50.default.join(import_os46.default.homedir(), ".node9", "audit.log");
49317
- const claudeProjectsDir = opts.claudeProjectsDir ?? import_path50.default.join(import_os46.default.homedir(), ".claude", "projects");
49318
- const codexSessionsDir2 = opts.codexSessionsDir ?? import_path50.default.join(import_os46.default.homedir(), ".codex", "sessions");
49319
- const geminiTmpDir2 = opts.geminiTmpDir ?? import_path50.default.join(import_os46.default.homedir(), ".gemini", "tmp");
49320
- 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);
49321
49603
  const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
49322
49604
  const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
49323
49605
  const { start, end } = getDateRange(period, now);
@@ -50108,12 +50390,14 @@ function registerDaemonCommand(program2) {
50108
50390
 
50109
50391
  // src/cli/commands/status.ts
50110
50392
  var import_chalk15 = __toESM(require("chalk"));
50111
- var import_fs53 = __toESM(require("fs"));
50112
- var import_path51 = __toESM(require("path"));
50113
- 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"));
50114
50396
  init_core();
50115
50397
  init_daemon();
50116
50398
  init_agent_wiring();
50399
+ init_sync();
50400
+ init_service();
50117
50401
  function printAgentSection(label2, hookPairs, wrapped) {
50118
50402
  console.log(import_chalk15.default.bold(` ${label2}`));
50119
50403
  for (const { name, present } of hookPairs) {
@@ -50142,6 +50426,15 @@ function registerStatusCommand(program2) {
50142
50426
  console.log("");
50143
50427
  if (creds && settings.approvers.cloud) {
50144
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
+ }
50145
50438
  } else if (creds && !settings.approvers.cloud) {
50146
50439
  console.log(
50147
50440
  import_chalk15.default.blue(" \u25CF Privacy mode \u{1F6E1}\uFE0F") + import_chalk15.default.gray(" \u2014 all decisions stay on this machine")
@@ -50159,6 +50452,16 @@ function registerStatusCommand(program2) {
50159
50452
  } else {
50160
50453
  console.log(import_chalk15.default.gray(" \u25CB Daemon stopped"));
50161
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
+ }
50162
50465
  if (settings.enableUndo) {
50163
50466
  console.log(
50164
50467
  import_chalk15.default.magenta(" \u25CF Undo Engine") + import_chalk15.default.gray(` \u2192 Auto-snapshotting Git repos on AI change`)
@@ -50167,20 +50470,20 @@ function registerStatusCommand(program2) {
50167
50470
  console.log("");
50168
50471
  const modeLabel = settings.mode === "audit" ? import_chalk15.default.blue("audit") : settings.mode === "strict" ? import_chalk15.default.red("strict") : import_chalk15.default.white("standard");
50169
50472
  console.log(` Mode: ${modeLabel}`);
50170
- const projectConfig = import_path51.default.join(process.cwd(), "node9.config.json");
50171
- 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");
50172
50475
  console.log(
50173
- ` 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")}`
50174
50477
  );
50175
50478
  console.log(
50176
- ` 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")}`
50177
50480
  );
50178
50481
  if (mergedConfig.policy.sandboxPaths.length > 0) {
50179
50482
  console.log(
50180
50483
  ` Sandbox: ${import_chalk15.default.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
50181
50484
  );
50182
50485
  }
50183
- const wiring = getAgentWiring(import_os47.default.homedir()).filter((a) => a.present);
50486
+ const wiring = getAgentWiring(import_os49.default.homedir()).filter((a) => a.present);
50184
50487
  if (wiring.length > 0) {
50185
50488
  console.log("");
50186
50489
  console.log(import_chalk15.default.bold(" Agent Wiring:"));
@@ -50215,14 +50518,15 @@ function registerStatusCommand(program2) {
50215
50518
 
50216
50519
  // src/cli/commands/init.ts
50217
50520
  var import_chalk16 = __toESM(require("chalk"));
50218
- var import_fs54 = __toESM(require("fs"));
50219
- var import_path52 = __toESM(require("path"));
50220
- 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"));
50221
50524
  var import_https6 = __toESM(require("https"));
50222
50525
  init_core();
50223
50526
  init_setup();
50224
50527
  init_shields();
50225
50528
  init_service();
50529
+ init_core();
50226
50530
  var DEFAULT_SHIELDS = ["bash-safe", "filesystem", "project-jail"];
50227
50531
  function buildTelemetryPayload(agents, firstInstall) {
50228
50532
  return {
@@ -50307,16 +50611,16 @@ function registerInitCommand(program2) {
50307
50611
  }
50308
50612
  console.log("");
50309
50613
  }
50310
- const configPath = import_path52.default.join(import_os48.default.homedir(), ".node9", "config.json");
50311
- const isFirstInstall = !import_fs54.default.existsSync(configPath);
50312
- 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) {
50313
50617
  try {
50314
- const existing = JSON.parse(import_fs54.default.readFileSync(configPath, "utf-8"));
50618
+ const existing = JSON.parse(import_fs55.default.readFileSync(configPath, "utf-8"));
50315
50619
  const settings = existing.settings ?? {};
50316
50620
  if (settings.mode !== chosenMode) {
50317
50621
  settings.mode = chosenMode;
50318
50622
  existing.settings = settings;
50319
- import_fs54.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
50623
+ import_fs55.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
50320
50624
  console.log(import_chalk16.default.green(`\u2705 Mode updated: ${chosenMode}`));
50321
50625
  } else {
50322
50626
  console.log(import_chalk16.default.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
@@ -50329,9 +50633,9 @@ function registerInitCommand(program2) {
50329
50633
  ...DEFAULT_CONFIG,
50330
50634
  settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
50331
50635
  };
50332
- const dir = import_path52.default.dirname(configPath);
50333
- if (!import_fs54.default.existsSync(dir)) import_fs54.default.mkdirSync(dir, { recursive: true });
50334
- 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");
50335
50639
  console.log(import_chalk16.default.green(`\u2705 Config created: ${configPath}`));
50336
50640
  console.log(import_chalk16.default.gray(` Mode: ${chosenMode}`));
50337
50641
  }
@@ -50383,8 +50687,13 @@ function registerInitCommand(program2) {
50383
50687
  console.log(import_chalk16.default.gray(" You can try again later with: node9 daemon install"));
50384
50688
  }
50385
50689
  }
50690
+ } else if (isDaemonServiceEnabled()) {
50691
+ console.log(import_chalk16.default.green(" \u2713 Daemon login service already installed & enabled"));
50386
50692
  } else {
50387
- 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
+ );
50388
50697
  }
50389
50698
  if (!isTestingMode()) {
50390
50699
  process.stdout.write(import_chalk16.default.dim(" Starting daemon..."));
@@ -50426,14 +50735,14 @@ function registerInitCommand(program2) {
50426
50735
 
50427
50736
  // src/cli/commands/heal.ts
50428
50737
  var import_chalk17 = __toESM(require("chalk"));
50429
- var import_fs55 = __toESM(require("fs"));
50738
+ var import_fs56 = __toESM(require("fs"));
50430
50739
  init_agent_wiring();
50431
50740
  init_setup();
50432
50741
  init_hook_baseline();
50433
50742
  var hasHookSurface = (a) => a.hooks.length > 0;
50434
50743
  function backupForHeal(file) {
50435
50744
  try {
50436
- 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`);
50437
50746
  } catch {
50438
50747
  }
50439
50748
  }
@@ -50600,7 +50909,7 @@ function registerConnectCommand(program2) {
50600
50909
  }
50601
50910
 
50602
50911
  // src/cli/commands/undo.ts
50603
- var import_path53 = __toESM(require("path"));
50912
+ var import_path54 = __toESM(require("path"));
50604
50913
  var import_chalk20 = __toESM(require("chalk"));
50605
50914
 
50606
50915
  // src/tui/undo-navigator.ts
@@ -50759,7 +51068,7 @@ function findMatchingCwd(startDir, history) {
50759
51068
  let dir = startDir;
50760
51069
  while (true) {
50761
51070
  if (cwds.has(dir)) return dir;
50762
- const parent = import_path53.default.dirname(dir);
51071
+ const parent = import_path54.default.dirname(dir);
50763
51072
  if (parent === dir) return null;
50764
51073
  dir = parent;
50765
51074
  }
@@ -51393,18 +51702,18 @@ function registerMcpGatewayCommand(program2) {
51393
51702
 
51394
51703
  // src/mcp-server/index.ts
51395
51704
  var import_readline5 = __toESM(require("readline"));
51396
- var import_fs57 = __toESM(require("fs"));
51397
- var import_os50 = __toESM(require("os"));
51398
- 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"));
51399
51708
  var import_child_process11 = require("child_process");
51400
51709
  init_core();
51401
51710
  init_daemon();
51402
51711
  init_shields();
51403
51712
 
51404
51713
  // src/auth/egress-config.ts
51405
- var import_fs56 = __toESM(require("fs"));
51406
- var import_os49 = __toESM(require("os"));
51407
- 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"));
51408
51717
  var DEFAULT_EGRESS = {
51409
51718
  enabled: false,
51410
51719
  mode: "review",
@@ -51413,12 +51722,12 @@ var DEFAULT_EGRESS = {
51413
51722
  allowPrivate: true
51414
51723
  };
51415
51724
  function egressConfigPath() {
51416
- 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");
51417
51726
  }
51418
51727
  function readEgressRawConfig() {
51419
51728
  let text;
51420
51729
  try {
51421
- text = import_fs56.default.readFileSync(egressConfigPath(), "utf8");
51730
+ text = import_fs57.default.readFileSync(egressConfigPath(), "utf8");
51422
51731
  } catch (err2) {
51423
51732
  if (err2.code === "ENOENT") return {};
51424
51733
  throw err2;
@@ -51433,8 +51742,8 @@ function readEgressRawConfig() {
51433
51742
  }
51434
51743
  function writeEgressRawConfig(config) {
51435
51744
  const p = egressConfigPath();
51436
- import_fs56.default.mkdirSync(import_path54.default.dirname(p), { recursive: true });
51437
- 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 });
51438
51747
  }
51439
51748
  function applyEgress(config, change) {
51440
51749
  const policy = config.policy = config.policy ?? {};
@@ -51819,13 +52128,13 @@ function handleStatus() {
51819
52128
  lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
51820
52129
  lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
51821
52130
  lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
51822
- const projectConfig = import_path55.default.join(process.cwd(), "node9.config.json");
51823
- 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");
51824
52133
  lines.push(
51825
- `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"}`
51826
52135
  );
51827
52136
  lines.push(
51828
- `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"}`
51829
52138
  );
51830
52139
  return lines.join("\n");
51831
52140
  }
@@ -51931,21 +52240,21 @@ function handleEgressDeny(args) {
51931
52240
  addEgressHost("deny", host);
51932
52241
  return `Denied egress to ${host} (deny always wins over allow).`;
51933
52242
  }
51934
- 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");
51935
52244
  var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
51936
52245
  function readGlobalConfigRaw() {
51937
52246
  try {
51938
- if (import_fs57.default.existsSync(GLOBAL_CONFIG_PATH)) {
51939
- 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"));
51940
52249
  }
51941
52250
  } catch {
51942
52251
  }
51943
52252
  return {};
51944
52253
  }
51945
52254
  function writeGlobalConfigRaw(data) {
51946
- const dir = import_path55.default.dirname(GLOBAL_CONFIG_PATH);
51947
- if (!import_fs57.default.existsSync(dir)) import_fs57.default.mkdirSync(dir, { recursive: true });
51948
- 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");
51949
52258
  }
51950
52259
  function handleApproverList() {
51951
52260
  const config = getConfig();
@@ -51989,9 +52298,9 @@ function handleApproverSet(args) {
51989
52298
  function handleAuditGet(args) {
51990
52299
  const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
51991
52300
  const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
51992
- const auditPath = import_path55.default.join(import_os50.default.homedir(), ".node9", "audit.log");
51993
- if (!import_fs57.default.existsSync(auditPath)) return "No audit log found.";
51994
- 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);
51995
52304
  const parsed = [];
51996
52305
  for (const line of rawLines) {
51997
52306
  try {
@@ -52365,7 +52674,7 @@ function registerTrustCommand(program2) {
52365
52674
  // src/cli/commands/mcp-pin.ts
52366
52675
  var import_chalk24 = __toESM(require("chalk"));
52367
52676
  init_mcp_pin();
52368
- var import_fs58 = __toESM(require("fs"));
52677
+ var import_fs59 = __toESM(require("fs"));
52369
52678
 
52370
52679
  // src/cli/commands/mcp-gateway-cmd.ts
52371
52680
  var import_chalk23 = __toESM(require("chalk"));
@@ -52572,7 +52881,7 @@ function registerMcpPinCommand(program2) {
52572
52881
  let repoCorrupt = false;
52573
52882
  if (found.source === "repo") {
52574
52883
  try {
52575
- const raw = import_fs58.default.readFileSync(found.path, "utf-8");
52884
+ const raw = import_fs59.default.readFileSync(found.path, "utf-8");
52576
52885
  const parsed = JSON.parse(raw);
52577
52886
  repoEntries = parsed.servers ?? {};
52578
52887
  } catch {
@@ -53072,8 +53381,8 @@ function registerPostureCommand(program2) {
53072
53381
  var import_chalk30 = __toESM(require("chalk"));
53073
53382
 
53074
53383
  // src/ci-check/fetch.ts
53075
- var import_fs59 = __toESM(require("fs"));
53076
- var import_path56 = __toESM(require("path"));
53384
+ var import_fs60 = __toESM(require("fs"));
53385
+ var import_path57 = __toESM(require("path"));
53077
53386
  var import_node_child_process = require("child_process");
53078
53387
  var import_undici = __toESM(require_undici());
53079
53388
  var cachedGhToken;
@@ -53157,7 +53466,7 @@ function parseRepoUrl(input) {
53157
53466
  function isLocalPath(input) {
53158
53467
  if (input.startsWith(".") || input.startsWith("/") || input.startsWith("~")) return true;
53159
53468
  try {
53160
- 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();
53161
53470
  } catch {
53162
53471
  return false;
53163
53472
  }
@@ -53272,10 +53581,10 @@ function readLocalTree(dir) {
53272
53581
  const files = [];
53273
53582
  const notes = [];
53274
53583
  const add = (rel) => {
53275
- const abs = import_path56.default.join(root, rel);
53584
+ const abs = import_path57.default.join(root, rel);
53276
53585
  try {
53277
- if (import_fs59.default.existsSync(abs) && import_fs59.default.statSync(abs).isFile()) {
53278
- 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") });
53279
53588
  }
53280
53589
  } catch {
53281
53590
  }
@@ -53295,7 +53604,7 @@ function readLocalTree(dir) {
53295
53604
  dirsVisited++;
53296
53605
  let entries;
53297
53606
  try {
53298
- 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 });
53299
53608
  } catch {
53300
53609
  return;
53301
53610
  }
@@ -53316,11 +53625,11 @@ function readLocalTree(dir) {
53316
53625
  `repo is large \u2014 some agent-surface files may be INCOMPLETE (capped at ${MAX_SURFACE_FILES} files / ${MAX_DIRS} dirs).`
53317
53626
  );
53318
53627
  for (const rel of matches) collect(rel);
53319
- const wfDir = import_path56.default.join(root, WORKFLOW_DIR);
53628
+ const wfDir = import_path57.default.join(root, WORKFLOW_DIR);
53320
53629
  try {
53321
- if (import_fs59.default.existsSync(wfDir)) {
53322
- for (const name of import_fs59.default.readdirSync(wfDir)) {
53323
- 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));
53324
53633
  }
53325
53634
  }
53326
53635
  } catch {
@@ -53463,6 +53772,38 @@ function collectTools(steps) {
53463
53772
  }
53464
53773
  return s;
53465
53774
  }
53775
+ function toolTokens(blob) {
53776
+ const out = [];
53777
+ let buf = "";
53778
+ let inParen = false;
53779
+ const flush = () => {
53780
+ const t = buf.replace(/[[\]"'`\r\n]/g, "").trim();
53781
+ if (t) out.push(t);
53782
+ buf = "";
53783
+ };
53784
+ for (const ch of blob) {
53785
+ if (ch === "(") inParen = true;
53786
+ else if (ch === ")") inParen = false;
53787
+ if (!inParen && (ch === "," || /\s/.test(ch))) {
53788
+ flush();
53789
+ continue;
53790
+ }
53791
+ buf += ch;
53792
+ }
53793
+ flush();
53794
+ return out;
53795
+ }
53796
+ function matchedBroadTools(blob) {
53797
+ const seen = /* @__PURE__ */ new Set();
53798
+ const out = [];
53799
+ for (const tok of toolTokens(blob)) {
53800
+ if (!BROAD_TOOL_RE.test(`,${tok},`)) continue;
53801
+ if (seen.has(tok)) continue;
53802
+ seen.add(tok);
53803
+ out.push(tok.length > 40 ? tok.slice(0, 40) + "\u2026" : tok);
53804
+ }
53805
+ return out;
53806
+ }
53466
53807
  function untrustedHeadCheckout(steps) {
53467
53808
  for (const step of steps) {
53468
53809
  if (!step.uses || !/actions\/checkout/.test(step.uses)) continue;
@@ -53593,7 +53934,7 @@ function severityFromScore(score) {
53593
53934
  if (score >= 1) return "advisory";
53594
53935
  return null;
53595
53936
  }
53596
- function analyzeWorkflow(path70, content) {
53937
+ function analyzeWorkflow(path71, content) {
53597
53938
  let raw;
53598
53939
  try {
53599
53940
  raw = (0, import_yaml.parse)(content) ?? {};
@@ -53689,7 +54030,12 @@ function analyzeWorkflow(path70, content) {
53689
54030
  if (head === "root") signals.push("checks out the untrusted PR head into the workspace root");
53690
54031
  if (head === "subdir") signals.push("checks out the untrusted PR head into an isolated subdir");
53691
54032
  if (promptUntrusted) signals.push("feeds untrusted PR/issue text to the agent");
53692
- if (broadTools) signals.push("agent has broad/write-capable tools (Bash/Write/curl/git push)");
54033
+ if (broadTools) {
54034
+ const names = matchedBroadTools(toolsBlob);
54035
+ signals.push(
54036
+ names.length ? `agent has broad/write-capable tools: ${names.map((n) => `\`${n}\``).join(", ")}` : "agent has broad/write-capable tool grants"
54037
+ );
54038
+ }
53693
54039
  if (bypassActive) signals.push('allowed_non_write_users: "*" \u2014 any user can trigger the agent');
53694
54040
  if (elevated) signals.push("elevated permissions (contents/id-token: write)");
53695
54041
  if (pat) signals.push("a static PAT is exposed to the agent (recoverable via injection)");
@@ -53714,7 +54060,7 @@ function analyzeWorkflow(path70, content) {
53714
54060
  dimension: "workflows",
53715
54061
  severity,
53716
54062
  title,
53717
- file: path70,
54063
+ file: path71,
53718
54064
  signals,
53719
54065
  mitigations: mitigations.length ? mitigations : void 0,
53720
54066
  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."
@@ -53790,7 +54136,7 @@ function evalAgentJob(job, wf, raw, untrustedTrigger, reusable) {
53790
54136
  if (reusable && !loadedGun && SEVERITY_RANK2[severity] > SEVERITY_RANK2.medium) severity = "medium";
53791
54137
  return { severity, secrets, injectable, canReadEnv };
53792
54138
  }
53793
- function analyzeWorkflowSecrets(path70, content) {
54139
+ function analyzeWorkflowSecrets(path71, content) {
53794
54140
  let raw;
53795
54141
  try {
53796
54142
  raw = (0, import_yaml.parse)(content) ?? {};
@@ -53810,7 +54156,7 @@ function analyzeWorkflowSecrets(path70, content) {
53810
54156
  dimension: "data",
53811
54157
  severity: worst.severity,
53812
54158
  title: worst.severity === "advisory" ? "Secrets reachable by the agent \u2014 hardening" : "Exfiltratable secrets reachable by an injectable agent",
53813
- file: path70,
54159
+ file: path71,
53814
54160
  signals: [
53815
54161
  `agent can reach: ${worst.secrets.map((s) => s.name).join(", ")}`,
53816
54162
  worst.injectable ? "the agent is externally triggerable (untrusted trigger, no gate)" : "gated / not externally triggerable \u2014 latent risk only",
@@ -53837,7 +54183,7 @@ function hookCommands(hooks) {
53837
54183
  }
53838
54184
  return out;
53839
54185
  }
53840
- function analyzeAgentConfig(path70, content) {
54186
+ function analyzeAgentConfig(path71, content) {
53841
54187
  let cfg;
53842
54188
  try {
53843
54189
  cfg = JSON.parse(content);
@@ -53856,7 +54202,7 @@ function analyzeAgentConfig(path70, content) {
53856
54202
  dimension: "toolRules",
53857
54203
  severity: high ? "high" : "medium",
53858
54204
  title: high ? "Agent hook runs UNPINNED/remote third-party code on every action" : "Agent hook runs third-party code in the agent hot path",
53859
- file: path70,
54205
+ file: path71,
53860
54206
  signals: [
53861
54207
  `hook command: \`${cmd.slice(0, 120)}\``,
53862
54208
  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"
@@ -53876,7 +54222,7 @@ function analyzeAgentConfig(path70, content) {
53876
54222
  dimension: "toolRules",
53877
54223
  severity: hasBackstop ? "medium" : "high",
53878
54224
  title: hasBackstop ? "Committed agent config pre-authorizes broad tools" : "Committed agent config pre-authorizes broad tools with no deny backstop",
53879
- file: path70,
54225
+ file: path71,
53880
54226
  signals: [
53881
54227
  `broad allow(s): ${broad.slice(0, 5).join(", ")}`,
53882
54228
  hasBackstop ? "a `deny` list backstops the broad allow" : "no `deny` entry covers Bash/Write/Edit \u2014 every contributor is pre-authorized for catastrophic tools"
@@ -53889,16 +54235,16 @@ function analyzeAgentConfig(path70, content) {
53889
54235
 
53890
54236
  // src/ci-check/mcp.ts
53891
54237
  init_dist();
53892
- function analyzeMcp(path70, content) {
54238
+ function analyzeMcp(path71, content) {
53893
54239
  let cfg;
53894
54240
  try {
53895
54241
  cfg = JSON.parse(content);
53896
54242
  } catch {
53897
54243
  return [];
53898
54244
  }
53899
- return analyzeMcpServers(cfg.mcpServers ?? {}, path70);
54245
+ return analyzeMcpServers(cfg.mcpServers ?? {}, path71);
53900
54246
  }
53901
- function analyzeMcpServers(servers, path70) {
54247
+ function analyzeMcpServers(servers, path71) {
53902
54248
  const findings = [];
53903
54249
  for (const [name, srv] of Object.entries(servers ?? {})) {
53904
54250
  if (!srv || srv.disabled) continue;
@@ -53909,7 +54255,7 @@ function analyzeMcpServers(servers, path70) {
53909
54255
  dimension: "mcp",
53910
54256
  severity: "medium",
53911
54257
  title: `MCP server "${name}" runs an unpinned executable`,
53912
- file: path70,
54258
+ file: path71,
53913
54259
  signals: [`\`${argv.slice(0, 120)}\` \u2014 unversioned/@latest npx`],
53914
54260
  fix: "Pin the MCP server package to an exact version so a PR (or a registry compromise) can\u2019t swap the toolchain."
53915
54261
  });
@@ -53923,7 +54269,7 @@ function analyzeMcpServers(servers, path70) {
53923
54269
  dimension: "mcp",
53924
54270
  severity: "high",
53925
54271
  title: `MCP server "${name}" has an inline credential`,
53926
- file: path70,
54272
+ file: path71,
53927
54273
  signals: [
53928
54274
  `env.${k} matches ${hit.patternName} \u2014 agent-reachable secret committed to the repo`
53929
54275
  ],
@@ -53937,7 +54283,7 @@ function analyzeMcpServers(servers, path70) {
53937
54283
 
53938
54284
  // src/ci-check/codex.ts
53939
54285
  var import_smol_toml5 = require("smol-toml");
53940
- function analyzeCodexConfig(path70, content) {
54286
+ function analyzeCodexConfig(path71, content) {
53941
54287
  let cfg;
53942
54288
  try {
53943
54289
  cfg = (0, import_smol_toml5.parse)(content);
@@ -53945,7 +54291,7 @@ function analyzeCodexConfig(path70, content) {
53945
54291
  return [];
53946
54292
  }
53947
54293
  const findings = [];
53948
- findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {}, path70));
54294
+ findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {}, path71));
53949
54295
  const sandbox = typeof cfg.sandbox_mode === "string" ? cfg.sandbox_mode : "";
53950
54296
  const approval = typeof cfg.approval_policy === "string" ? cfg.approval_policy : "";
53951
54297
  const fullAccess = /danger-full-access/i.test(sandbox);
@@ -53960,7 +54306,7 @@ function analyzeCodexConfig(path70, content) {
53960
54306
  dimension: "toolRules",
53961
54307
  severity: fullAccess ? "high" : "medium",
53962
54308
  title: fullAccess ? "Codex config grants a full-access sandbox" : "Codex config never requires approval",
53963
- file: path70,
54309
+ file: path71,
53964
54310
  signals,
53965
54311
  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.'
53966
54312
  });
@@ -54016,10 +54362,10 @@ function decodeSuspiciousBase64(text) {
54016
54362
  }
54017
54363
  return out;
54018
54364
  }
54019
- function mk(severity, title, signals, fix, path70) {
54020
- return { check: "CI-6", dimension: "instructions", severity, title, file: path70, signals, fix };
54365
+ function mk(severity, title, signals, fix, path71) {
54366
+ return { check: "CI-6", dimension: "instructions", severity, title, file: path71, signals, fix };
54021
54367
  }
54022
- function analyzeInstructionFile(path70, content) {
54368
+ function analyzeInstructionFile(path71, content) {
54023
54369
  const findings = [];
54024
54370
  const decoded = decodeSuspiciousBase64(content);
54025
54371
  if (TAG_CHARS.test(content))
@@ -54031,7 +54377,7 @@ function analyzeInstructionFile(path70, content) {
54031
54377
  "contains Unicode tag characters (U+E0000\u2013E007F) \u2014 an invisible instruction-smuggling channel with no legitimate use in text"
54032
54378
  ],
54033
54379
  "Remove the tag characters. Instruction files must be plain, reviewable text.",
54034
- path70
54380
+ path71
54035
54381
  )
54036
54382
  );
54037
54383
  if (BIDI_OVERRIDE.test(content))
@@ -54043,7 +54389,7 @@ function analyzeInstructionFile(path70, content) {
54043
54389
  "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"
54044
54390
  ],
54045
54391
  "Remove the bidi override characters.",
54046
- path70
54392
+ path71
54047
54393
  )
54048
54394
  );
54049
54395
  else if (BIDI_EMBED_ISOLATE.test(content))
@@ -54055,7 +54401,7 @@ function analyzeInstructionFile(path70, content) {
54055
54401
  "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"
54056
54402
  ],
54057
54403
  "Confirm the bidi marks are legitimate RTL formatting; remove otherwise.",
54058
- path70
54404
+ path71
54059
54405
  )
54060
54406
  );
54061
54407
  const zw = suspiciousZeroWidth(content);
@@ -54069,7 +54415,7 @@ function analyzeInstructionFile(path70, content) {
54069
54415
  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)"
54070
54416
  ],
54071
54417
  "Remove the zero-width characters. Instruction files must be plain, reviewable text.",
54072
- path70
54418
+ path71
54073
54419
  )
54074
54420
  );
54075
54421
  }
@@ -54085,7 +54431,7 @@ function analyzeInstructionFile(path70, content) {
54085
54431
  `contains a prompt-override / role-impersonation directive (\`${m[0].slice(0, 60).trim()}\`)${ovEnc ? " \u2014 concealed in a base64 blob" : ""}`
54086
54432
  ],
54087
54433
  "Remove the override text. An instruction file should not tell the agent to ignore its own rules.",
54088
- path70
54434
+ path71
54089
54435
  )
54090
54436
  );
54091
54437
  }
@@ -54097,7 +54443,7 @@ function analyzeInstructionFile(path70, content) {
54097
54443
  "Instruction directs the agent to fetch and run remote code",
54098
54444
  [`\`${fo[0].slice(0, 70).trim()}\` \u2014 fetch-and-obey, outside an install/setup section`],
54099
54445
  "Do not instruct the agent to pipe remote content into a shell; pin and vendor scripts instead.",
54100
- path70
54446
+ path71
54101
54447
  )
54102
54448
  );
54103
54449
  }
@@ -54109,7 +54455,7 @@ function analyzeInstructionFile(path70, content) {
54109
54455
  "Instruction points the agent at credential material",
54110
54456
  [`references \`${sp[0].slice(0, 50).trim()}\` \u2014 directs the agent toward secrets`],
54111
54457
  "Do not reference credential files or paths in agent instructions.",
54112
- path70
54458
+ path71
54113
54459
  )
54114
54460
  );
54115
54461
  }
@@ -54121,7 +54467,7 @@ function analyzeInstructionFile(path70, content) {
54121
54467
  "Instruction directs the agent to send data to an external endpoint",
54122
54468
  [`\`${ex[0].slice(0, 70).trim()}\` \u2014 possible exfiltration directive`],
54123
54469
  "Remove external post/upload directives from agent instructions.",
54124
- path70
54470
+ path71
54125
54471
  )
54126
54472
  );
54127
54473
  }
@@ -54421,19 +54767,19 @@ function registerEgressCommand(program2) {
54421
54767
  var import_chalk32 = __toESM(require("chalk"));
54422
54768
 
54423
54769
  // src/shields/jail.ts
54424
- var import_fs60 = __toESM(require("fs"));
54425
- var import_os51 = __toESM(require("os"));
54426
- var import_path57 = __toESM(require("path"));
54770
+ var import_fs61 = __toESM(require("fs"));
54771
+ var import_os53 = __toESM(require("os"));
54772
+ var import_path58 = __toESM(require("path"));
54427
54773
  init_build();
54428
54774
  init_shields();
54429
54775
  var USER_JAIL_SHIELD = "user-jail";
54430
54776
  function jailStorePath() {
54431
- return import_path57.default.join(import_os51.default.homedir(), ".node9", "jail-paths.json");
54777
+ return import_path58.default.join(import_os53.default.homedir(), ".node9", "jail-paths.json");
54432
54778
  }
54433
54779
  function readJailPaths() {
54434
54780
  let text;
54435
54781
  try {
54436
- text = import_fs60.default.readFileSync(jailStorePath(), "utf8");
54782
+ text = import_fs61.default.readFileSync(jailStorePath(), "utf8");
54437
54783
  } catch (err2) {
54438
54784
  if (err2.code === "ENOENT") return [];
54439
54785
  throw err2;
@@ -54451,8 +54797,8 @@ function readJailPaths() {
54451
54797
  }
54452
54798
  function writeJailPaths(paths) {
54453
54799
  const p = jailStorePath();
54454
- import_fs60.default.mkdirSync(import_path57.default.dirname(p), { recursive: true });
54455
- import_fs60.default.writeFileSync(p, JSON.stringify({ paths }, null, 2) + "\n", { mode: 384 });
54800
+ import_fs61.default.mkdirSync(import_path58.default.dirname(p), { recursive: true });
54801
+ import_fs61.default.writeFileSync(p, JSON.stringify({ paths }, null, 2) + "\n", { mode: 384 });
54456
54802
  }
54457
54803
  function addJailPath(rawPath, verdict) {
54458
54804
  const norm = rawPath.trim();
@@ -54474,14 +54820,14 @@ function removeJailPath(rawPath) {
54474
54820
  return { removed, paths: after };
54475
54821
  }
54476
54822
  function regenerateUserJail(paths) {
54477
- const file = import_path57.default.join(USER_SHIELDS_DIR_PATH, `${USER_JAIL_SHIELD}.json`);
54823
+ const file = import_path58.default.join(USER_SHIELDS_DIR_PATH, `${USER_JAIL_SHIELD}.json`);
54478
54824
  if (paths.length === 0) {
54479
54825
  const active2 = readActiveShields();
54480
54826
  if (active2.includes(USER_JAIL_SHIELD)) {
54481
54827
  writeActiveShields(active2.filter((s) => s !== USER_JAIL_SHIELD));
54482
54828
  }
54483
54829
  try {
54484
- import_fs60.default.rmSync(file, { force: true });
54830
+ import_fs61.default.rmSync(file, { force: true });
54485
54831
  } catch {
54486
54832
  }
54487
54833
  return;
@@ -54595,14 +54941,14 @@ function registerJailCommand(program2) {
54595
54941
 
54596
54942
  // src/cli/commands/sandbox.ts
54597
54943
  var import_chalk33 = __toESM(require("chalk"));
54598
- var import_fs63 = __toESM(require("fs"));
54599
- var import_path60 = __toESM(require("path"));
54944
+ var import_fs64 = __toESM(require("fs"));
54945
+ var import_path61 = __toESM(require("path"));
54600
54946
  var import_child_process13 = require("child_process");
54601
54947
  init_config();
54602
54948
 
54603
54949
  // src/sandbox/config.ts
54604
- var import_fs61 = __toESM(require("fs"));
54605
- var import_path58 = __toESM(require("path"));
54950
+ var import_fs62 = __toESM(require("fs"));
54951
+ var import_path59 = __toESM(require("path"));
54606
54952
  var import_yaml2 = require("yaml");
54607
54953
  var SANDBOX_CONFIG_FILE = "node9.sandbox.yaml";
54608
54954
  var FORBIDDEN_ENV = /* @__PURE__ */ new Set(["NODE9_API_KEY", "NODE9_API_URL"]);
@@ -54675,16 +55021,16 @@ function scaffoldSandboxYaml(agent) {
54675
55021
  return header + (0, import_yaml2.stringify)(defaultSandboxConfig(agent));
54676
55022
  }
54677
55023
  function sandboxConfigPath(cwd = process.cwd()) {
54678
- return import_path58.default.join(cwd, SANDBOX_CONFIG_FILE);
55024
+ return import_path59.default.join(cwd, SANDBOX_CONFIG_FILE);
54679
55025
  }
54680
55026
  function loadSandboxConfig(cwd = process.cwd(), fallbackAgent = "claude") {
54681
55027
  const p = sandboxConfigPath(cwd);
54682
- if (!import_fs61.default.existsSync(p)) {
55028
+ if (!import_fs62.default.existsSync(p)) {
54683
55029
  throw new Error(`sandbox: ${SANDBOX_CONFIG_FILE} not found \u2014 run \`node9 sandbox new\` first.`);
54684
55030
  }
54685
55031
  let raw;
54686
55032
  try {
54687
- raw = (0, import_yaml2.parse)(import_fs61.default.readFileSync(p, "utf-8"));
55033
+ raw = (0, import_yaml2.parse)(import_fs62.default.readFileSync(p, "utf-8"));
54688
55034
  } catch (err2) {
54689
55035
  throw new Error(
54690
55036
  `sandbox: ${SANDBOX_CONFIG_FILE} is not valid YAML \u2014 ${err2.message}`
@@ -54742,14 +55088,14 @@ function compileAllowlist(input) {
54742
55088
  init_templates();
54743
55089
 
54744
55090
  // src/sandbox/runtime.ts
54745
- var import_fs62 = __toESM(require("fs"));
54746
- var import_os52 = __toESM(require("os"));
54747
- var import_path59 = __toESM(require("path"));
55091
+ var import_fs63 = __toESM(require("fs"));
55092
+ var import_os54 = __toESM(require("os"));
55093
+ var import_path60 = __toESM(require("path"));
54748
55094
  var import_crypto14 = __toESM(require("crypto"));
54749
55095
  var import_child_process12 = require("child_process");
54750
55096
  init_templates();
54751
55097
  function sandboxDataDir(cwd = process.cwd()) {
54752
- return import_path59.default.join(cwd, ".node9", "sandbox", "data");
55098
+ return import_path60.default.join(cwd, ".node9", "sandbox", "data");
54753
55099
  }
54754
55100
  function detectEngine(engine) {
54755
55101
  const r = (0, import_child_process12.spawnSync)(engine, ["--version"], { encoding: "utf-8" });
@@ -54760,7 +55106,7 @@ function detectEngine(engine) {
54760
55106
  }
54761
55107
  function agentCredentialsMount(agent) {
54762
55108
  const rel = agent === "codex" ? ".codex/auth.json" : ".claude/.credentials.json";
54763
- return { hostPath: import_path59.default.join(import_os52.default.homedir(), rel), target: `/home/${RUN_AS_USER}/${rel}` };
55109
+ return { hostPath: import_path60.default.join(import_os54.default.homedir(), rel), target: `/home/${RUN_AS_USER}/${rel}` };
54764
55110
  }
54765
55111
  function buildRunArgs(opts) {
54766
55112
  const { config, workspaceHostPath, dataHostPath, allowlistHostPath, agentArgs } = opts;
@@ -54770,7 +55116,7 @@ function buildRunArgs(opts) {
54770
55116
  args.push("-v", `${allowlistHostPath}:${ALLOWED_DOMAINS_PATH}:ro`);
54771
55117
  if (config.node9.mountAgentCredentials) {
54772
55118
  const creds = agentCredentialsMount(config.agent);
54773
- if (import_fs62.default.existsSync(creds.hostPath)) {
55119
+ if (import_fs63.default.existsSync(creds.hostPath)) {
54774
55120
  args.push("-v", `${creds.hostPath}:${creds.target}`);
54775
55121
  }
54776
55122
  }
@@ -54788,30 +55134,30 @@ function imageContentHash(dockerfile, entrypoint) {
54788
55134
  return import_crypto14.default.createHash("sha256").update(dockerfile).update("\0").update(entrypoint).digest("hex").slice(0, 16);
54789
55135
  }
54790
55136
  function sandboxBuildDir(cwd = process.cwd()) {
54791
- return import_path59.default.join(cwd, ".node9", "sandbox", "build");
55137
+ return import_path60.default.join(cwd, ".node9", "sandbox", "build");
54792
55138
  }
54793
55139
  function writeBuildContext(cwd, dockerfile, entrypoint) {
54794
55140
  const dir = sandboxBuildDir(cwd);
54795
- import_fs62.default.mkdirSync(dir, { recursive: true });
54796
- import_fs62.default.writeFileSync(import_path59.default.join(dir, "Dockerfile"), dockerfile);
54797
- import_fs62.default.writeFileSync(import_path59.default.join(dir, "entrypoint.sh"), entrypoint);
55141
+ import_fs63.default.mkdirSync(dir, { recursive: true });
55142
+ import_fs63.default.writeFileSync(import_path60.default.join(dir, "Dockerfile"), dockerfile);
55143
+ import_fs63.default.writeFileSync(import_path60.default.join(dir, "entrypoint.sh"), entrypoint);
54798
55144
  return dir;
54799
55145
  }
54800
55146
  function writeAllowlist(cwd, hosts) {
54801
- const dir = import_path59.default.join(cwd, ".node9", "sandbox");
54802
- import_fs62.default.mkdirSync(dir, { recursive: true });
54803
- const p = import_path59.default.join(dir, "allowed-domains.txt");
54804
- import_fs62.default.writeFileSync(p, hosts.join("\n") + "\n");
55147
+ const dir = import_path60.default.join(cwd, ".node9", "sandbox");
55148
+ import_fs63.default.mkdirSync(dir, { recursive: true });
55149
+ const p = import_path60.default.join(dir, "allowed-domains.txt");
55150
+ import_fs63.default.writeFileSync(p, hosts.join("\n") + "\n");
54805
55151
  return p;
54806
55152
  }
54807
55153
  function resolveHomePath(p) {
54808
- return p.startsWith("~") ? import_path59.default.join(import_os52.default.homedir(), p.slice(1)) : import_path59.default.resolve(p);
55154
+ return p.startsWith("~") ? import_path60.default.join(import_os54.default.homedir(), p.slice(1)) : import_path60.default.resolve(p);
54809
55155
  }
54810
55156
 
54811
55157
  // src/cli/commands/sandbox.ts
54812
55158
  function seedDataDirConfig(dataDir, sandbox) {
54813
- import_fs63.default.mkdirSync(dataDir, { recursive: true });
54814
- const configPath = import_path60.default.join(dataDir, "config.json");
55159
+ import_fs64.default.mkdirSync(dataDir, { recursive: true });
55160
+ const configPath = import_path61.default.join(dataDir, "config.json");
54815
55161
  const seed = {
54816
55162
  settings: {
54817
55163
  approvers: {
@@ -54822,7 +55168,7 @@ function seedDataDirConfig(dataDir, sandbox) {
54822
55168
  }
54823
55169
  }
54824
55170
  };
54825
- import_fs63.default.writeFileSync(configPath, JSON.stringify(seed, null, 2), { mode: 384 });
55171
+ import_fs64.default.writeFileSync(configPath, JSON.stringify(seed, null, 2), { mode: 384 });
54826
55172
  }
54827
55173
  function registerSandboxCommand(program2, version2) {
54828
55174
  const node9Version2 = pinnedNode9Version(version2);
@@ -54830,13 +55176,13 @@ function registerSandboxCommand(program2, version2) {
54830
55176
  cmd.command("new").description(`Scaffold ${SANDBOX_CONFIG_FILE} in this project`).option("--agent <agent>", "claude (default) or codex", "claude").action((opts) => {
54831
55177
  const agent = opts.agent === "codex" ? "codex" : "claude";
54832
55178
  const p = sandboxConfigPath();
54833
- if (import_fs63.default.existsSync(p)) {
55179
+ if (import_fs64.default.existsSync(p)) {
54834
55180
  console.log(
54835
55181
  import_chalk33.default.yellow(` ${SANDBOX_CONFIG_FILE} already exists \u2014 leaving it untouched.`)
54836
55182
  );
54837
55183
  return;
54838
55184
  }
54839
- import_fs63.default.writeFileSync(p, scaffoldSandboxYaml(agent));
55185
+ import_fs64.default.writeFileSync(p, scaffoldSandboxYaml(agent));
54840
55186
  console.log(
54841
55187
  import_chalk33.default.green(` \u2713 wrote ${SANDBOX_CONFIG_FILE}`) + import_chalk33.default.dim(` (agent: ${agent})`)
54842
55188
  );
@@ -54876,8 +55222,8 @@ function registerSandboxCommand(program2, version2) {
54876
55222
  const buildDir = writeBuildContext(cwd, dockerfile, entrypoint);
54877
55223
  const hash = imageContentHash(dockerfile, entrypoint);
54878
55224
  const image = sandbox.runtime.image;
54879
- const hashFile = import_path60.default.join(sandboxBuildDir(cwd), ".image-hash");
54880
- const lastHash = import_fs63.default.existsSync(hashFile) ? import_fs63.default.readFileSync(hashFile, "utf-8").trim() : "";
55225
+ const hashFile = import_path61.default.join(sandboxBuildDir(cwd), ".image-hash");
55226
+ const lastHash = import_fs64.default.existsSync(hashFile) ? import_fs64.default.readFileSync(hashFile, "utf-8").trim() : "";
54881
55227
  const imageExists = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, ["image", "inspect", image], { stdio: "ignore" }).status === 0;
54882
55228
  const needBuild = sandbox.runtime.rebuild === "always" || !imageExists || sandbox.runtime.rebuild !== "never" && lastHash !== hash;
54883
55229
  if (needBuild) {
@@ -54889,7 +55235,7 @@ function registerSandboxCommand(program2, version2) {
54889
55235
  console.error(import_chalk33.default.red(" build failed."));
54890
55236
  process.exit(b.status ?? 1);
54891
55237
  }
54892
- import_fs63.default.writeFileSync(hashFile, hash);
55238
+ import_fs64.default.writeFileSync(hashFile, hash);
54893
55239
  }
54894
55240
  const dataDir = sandboxDataDir(cwd);
54895
55241
  seedDataDirConfig(dataDir, sandbox);
@@ -54903,7 +55249,7 @@ function registerSandboxCommand(program2, version2) {
54903
55249
  });
54904
55250
  if (sandbox.node9.mountAgentCredentials) {
54905
55251
  const creds = agentCredentialsMount(sandbox.agent);
54906
- if (import_fs63.default.existsSync(creds.hostPath)) {
55252
+ if (import_fs64.default.existsSync(creds.hostPath)) {
54907
55253
  console.log(import_chalk33.default.dim(` mounting ${creds.hostPath} (agent credentials, rw)`));
54908
55254
  } else {
54909
55255
  console.log(
@@ -54919,20 +55265,20 @@ function registerSandboxCommand(program2, version2) {
54919
55265
  process.exit(r.status ?? 0);
54920
55266
  });
54921
55267
  cmd.command("tail").description("Stream the sandbox's audit log (host-side)").action(() => {
54922
- const auditPath = import_path60.default.join(sandboxDataDir(), "audit.log");
54923
- if (!import_fs63.default.existsSync(auditPath)) {
55268
+ const auditPath = import_path61.default.join(sandboxDataDir(), "audit.log");
55269
+ if (!import_fs64.default.existsSync(auditPath)) {
54924
55270
  console.log(import_chalk33.default.dim(" no sandbox audit yet."));
54925
55271
  return;
54926
55272
  }
54927
55273
  (0, import_child_process13.spawnSync)("tail", ["-f", auditPath], { stdio: "inherit" });
54928
55274
  });
54929
55275
  cmd.command("logs").description("Dump the sandbox's audit log").action(() => {
54930
- const auditPath = import_path60.default.join(sandboxDataDir(), "audit.log");
54931
- if (!import_fs63.default.existsSync(auditPath)) {
55276
+ const auditPath = import_path61.default.join(sandboxDataDir(), "audit.log");
55277
+ if (!import_fs64.default.existsSync(auditPath)) {
54932
55278
  console.log(import_chalk33.default.dim(" no sandbox audit yet."));
54933
55279
  return;
54934
55280
  }
54935
- process.stdout.write(import_fs63.default.readFileSync(auditPath, "utf-8"));
55281
+ process.stdout.write(import_fs64.default.readFileSync(auditPath, "utf-8"));
54936
55282
  });
54937
55283
  cmd.command("clean").description("Remove the sandbox image, build context, and data").action(() => {
54938
55284
  const cwd = process.cwd();
@@ -54946,16 +55292,16 @@ function registerSandboxCommand(program2, version2) {
54946
55292
  stdio: "ignore"
54947
55293
  });
54948
55294
  }
54949
- import_fs63.default.rmSync(import_path60.default.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
55295
+ import_fs64.default.rmSync(import_path61.default.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
54950
55296
  console.log(import_chalk33.default.green(" \u2713 sandbox image + build + data removed."));
54951
55297
  });
54952
55298
  }
54953
55299
 
54954
55300
  // src/cli/commands/sessions.ts
54955
55301
  var import_chalk34 = __toESM(require("chalk"));
54956
- var import_fs64 = __toESM(require("fs"));
54957
- var import_path61 = __toESM(require("path"));
54958
- var import_os53 = __toESM(require("os"));
55302
+ var import_fs65 = __toESM(require("fs"));
55303
+ var import_path62 = __toESM(require("path"));
55304
+ var import_os55 = __toESM(require("os"));
54959
55305
  init_scan_summary();
54960
55306
  init_litellm();
54961
55307
  init_cost_gemini();
@@ -54976,10 +55322,10 @@ function encodeProjectPath(projectPath) {
54976
55322
  }
54977
55323
  function sessionJsonlPath(projectPath, sessionId) {
54978
55324
  const encoded = encodeProjectPath(projectPath);
54979
- return import_path61.default.join(import_os53.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
55325
+ return import_path62.default.join(import_os55.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
54980
55326
  }
54981
55327
  function projectLabel(projectPath) {
54982
- return projectPath.replace(import_os53.default.homedir(), "~");
55328
+ return projectPath.replace(import_os55.default.homedir(), "~");
54983
55329
  }
54984
55330
  function parseHistoryLines(lines) {
54985
55331
  const entries = [];
@@ -55048,10 +55394,10 @@ function parseSessionLines(lines) {
55048
55394
  return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
55049
55395
  }
55050
55396
  function loadAuditEntries(auditPath) {
55051
- const aPath = auditPath ?? import_path61.default.join(import_os53.default.homedir(), ".node9", "audit.log");
55397
+ const aPath = auditPath ?? import_path62.default.join(import_os55.default.homedir(), ".node9", "audit.log");
55052
55398
  let raw;
55053
55399
  try {
55054
- raw = import_fs64.default.readFileSync(aPath, "utf-8");
55400
+ raw = import_fs65.default.readFileSync(aPath, "utf-8");
55055
55401
  } catch {
55056
55402
  return [];
55057
55403
  }
@@ -55087,8 +55433,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
55087
55433
  return result;
55088
55434
  }
55089
55435
  function buildGeminiSessions(days, allAuditEntries) {
55090
- const tmpDir = import_path61.default.join(import_os53.default.homedir(), ".gemini", "tmp");
55091
- if (!import_fs64.default.existsSync(tmpDir)) return [];
55436
+ const tmpDir = import_path62.default.join(import_os55.default.homedir(), ".gemini", "tmp");
55437
+ if (!import_fs65.default.existsSync(tmpDir)) return [];
55092
55438
  const cutoff = days !== null ? (() => {
55093
55439
  const d = /* @__PURE__ */ new Date();
55094
55440
  d.setDate(d.getDate() - days);
@@ -55097,35 +55443,35 @@ function buildGeminiSessions(days, allAuditEntries) {
55097
55443
  })() : null;
55098
55444
  let slugDirs;
55099
55445
  try {
55100
- slugDirs = import_fs64.default.readdirSync(tmpDir);
55446
+ slugDirs = import_fs65.default.readdirSync(tmpDir);
55101
55447
  } catch {
55102
55448
  return [];
55103
55449
  }
55104
55450
  const summaries = [];
55105
55451
  for (const slug2 of slugDirs) {
55106
- const slugPath = import_path61.default.join(tmpDir, slug2);
55452
+ const slugPath = import_path62.default.join(tmpDir, slug2);
55107
55453
  try {
55108
- if (!import_fs64.default.statSync(slugPath).isDirectory()) continue;
55454
+ if (!import_fs65.default.statSync(slugPath).isDirectory()) continue;
55109
55455
  } catch {
55110
55456
  continue;
55111
55457
  }
55112
- let projectRoot = import_path61.default.join(import_os53.default.homedir(), slug2);
55458
+ let projectRoot = import_path62.default.join(import_os55.default.homedir(), slug2);
55113
55459
  try {
55114
- projectRoot = import_fs64.default.readFileSync(import_path61.default.join(slugPath, ".project_root"), "utf-8").trim();
55460
+ projectRoot = import_fs65.default.readFileSync(import_path62.default.join(slugPath, ".project_root"), "utf-8").trim();
55115
55461
  } catch {
55116
55462
  }
55117
- const chatsDir = import_path61.default.join(slugPath, "chats");
55118
- if (!import_fs64.default.existsSync(chatsDir)) continue;
55463
+ const chatsDir = import_path62.default.join(slugPath, "chats");
55464
+ if (!import_fs65.default.existsSync(chatsDir)) continue;
55119
55465
  let chatFiles;
55120
55466
  try {
55121
- chatFiles = import_fs64.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
55467
+ chatFiles = import_fs65.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
55122
55468
  } catch {
55123
55469
  continue;
55124
55470
  }
55125
55471
  for (const chatFile of chatFiles) {
55126
55472
  let raw;
55127
55473
  try {
55128
- raw = import_fs64.default.readFileSync(import_path61.default.join(chatsDir, chatFile), "utf-8");
55474
+ raw = import_fs65.default.readFileSync(import_path62.default.join(chatsDir, chatFile), "utf-8");
55129
55475
  } catch {
55130
55476
  continue;
55131
55477
  }
@@ -55205,8 +55551,8 @@ function buildGeminiSessions(days, allAuditEntries) {
55205
55551
  return summaries;
55206
55552
  }
55207
55553
  function buildCodexSessions(days, allAuditEntries) {
55208
- const sessionsBase = import_path61.default.join(import_os53.default.homedir(), ".codex", "sessions");
55209
- if (!import_fs64.default.existsSync(sessionsBase)) return [];
55554
+ const sessionsBase = import_path62.default.join(import_os55.default.homedir(), ".codex", "sessions");
55555
+ if (!import_fs65.default.existsSync(sessionsBase)) return [];
55210
55556
  const cutoff = days !== null ? (() => {
55211
55557
  const d = /* @__PURE__ */ new Date();
55212
55558
  d.setDate(d.getDate() - days);
@@ -55215,29 +55561,29 @@ function buildCodexSessions(days, allAuditEntries) {
55215
55561
  })() : null;
55216
55562
  const jsonlFiles = [];
55217
55563
  try {
55218
- for (const year of import_fs64.default.readdirSync(sessionsBase)) {
55219
- const yearPath = import_path61.default.join(sessionsBase, year);
55564
+ for (const year of import_fs65.default.readdirSync(sessionsBase)) {
55565
+ const yearPath = import_path62.default.join(sessionsBase, year);
55220
55566
  try {
55221
- if (!import_fs64.default.statSync(yearPath).isDirectory()) continue;
55567
+ if (!import_fs65.default.statSync(yearPath).isDirectory()) continue;
55222
55568
  } catch {
55223
55569
  continue;
55224
55570
  }
55225
- for (const month of import_fs64.default.readdirSync(yearPath)) {
55226
- const monthPath = import_path61.default.join(yearPath, month);
55571
+ for (const month of import_fs65.default.readdirSync(yearPath)) {
55572
+ const monthPath = import_path62.default.join(yearPath, month);
55227
55573
  try {
55228
- if (!import_fs64.default.statSync(monthPath).isDirectory()) continue;
55574
+ if (!import_fs65.default.statSync(monthPath).isDirectory()) continue;
55229
55575
  } catch {
55230
55576
  continue;
55231
55577
  }
55232
- for (const day of import_fs64.default.readdirSync(monthPath)) {
55233
- const dayPath = import_path61.default.join(monthPath, day);
55578
+ for (const day of import_fs65.default.readdirSync(monthPath)) {
55579
+ const dayPath = import_path62.default.join(monthPath, day);
55234
55580
  try {
55235
- if (!import_fs64.default.statSync(dayPath).isDirectory()) continue;
55581
+ if (!import_fs65.default.statSync(dayPath).isDirectory()) continue;
55236
55582
  } catch {
55237
55583
  continue;
55238
55584
  }
55239
- for (const file of import_fs64.default.readdirSync(dayPath)) {
55240
- if (file.endsWith(".jsonl")) jsonlFiles.push(import_path61.default.join(dayPath, file));
55585
+ for (const file of import_fs65.default.readdirSync(dayPath)) {
55586
+ if (file.endsWith(".jsonl")) jsonlFiles.push(import_path62.default.join(dayPath, file));
55241
55587
  }
55242
55588
  }
55243
55589
  }
@@ -55249,7 +55595,7 @@ function buildCodexSessions(days, allAuditEntries) {
55249
55595
  for (const filePath of jsonlFiles) {
55250
55596
  let lines;
55251
55597
  try {
55252
- lines = import_fs64.default.readFileSync(filePath, "utf-8").split("\n");
55598
+ lines = import_fs65.default.readFileSync(filePath, "utf-8").split("\n");
55253
55599
  } catch {
55254
55600
  continue;
55255
55601
  }
@@ -55335,10 +55681,10 @@ function buildCodexSessions(days, allAuditEntries) {
55335
55681
  return summaries;
55336
55682
  }
55337
55683
  function buildSessions(days, historyPath) {
55338
- const hPath = historyPath ?? import_path61.default.join(import_os53.default.homedir(), ".claude", "history.jsonl");
55684
+ const hPath = historyPath ?? import_path62.default.join(import_os55.default.homedir(), ".claude", "history.jsonl");
55339
55685
  let historyRaw = "";
55340
55686
  try {
55341
- historyRaw = import_fs64.default.readFileSync(hPath, "utf-8");
55687
+ historyRaw = import_fs65.default.readFileSync(hPath, "utf-8");
55342
55688
  } catch {
55343
55689
  }
55344
55690
  const cutoff = days !== null ? (() => {
@@ -55362,7 +55708,7 @@ function buildSessions(days, historyPath) {
55362
55708
  const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
55363
55709
  let sessionLines = [];
55364
55710
  try {
55365
- sessionLines = import_fs64.default.readFileSync(jsonlFile, "utf-8").split("\n");
55711
+ sessionLines = import_fs65.default.readFileSync(jsonlFile, "utf-8").split("\n");
55366
55712
  } catch {
55367
55713
  }
55368
55714
  const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
@@ -55756,12 +56102,12 @@ function registerSessionTaintCommand(program2) {
55756
56102
 
55757
56103
  // src/cli/commands/skill-pin.ts
55758
56104
  var import_chalk36 = __toESM(require("chalk"));
55759
- var import_fs65 = __toESM(require("fs"));
55760
- var import_os54 = __toESM(require("os"));
55761
- var import_path62 = __toESM(require("path"));
56105
+ var import_fs66 = __toESM(require("fs"));
56106
+ var import_os56 = __toESM(require("os"));
56107
+ var import_path63 = __toESM(require("path"));
55762
56108
  function wipeSkillSessions() {
55763
56109
  try {
55764
- import_fs65.default.rmSync(import_path62.default.join(import_os54.default.homedir(), ".node9", "skill-sessions"), {
56110
+ import_fs66.default.rmSync(import_path63.default.join(import_os56.default.homedir(), ".node9", "skill-sessions"), {
55765
56111
  recursive: true,
55766
56112
  force: true
55767
56113
  });
@@ -55843,15 +56189,15 @@ function registerSkillPinCommand(program2) {
55843
56189
  }
55844
56190
 
55845
56191
  // src/cli/commands/decisions.ts
55846
- var import_fs66 = __toESM(require("fs"));
55847
- var import_os55 = __toESM(require("os"));
55848
- var import_path63 = __toESM(require("path"));
56192
+ var import_fs67 = __toESM(require("fs"));
56193
+ var import_os57 = __toESM(require("os"));
56194
+ var import_path64 = __toESM(require("path"));
55849
56195
  var import_chalk37 = __toESM(require("chalk"));
55850
- var DECISIONS_FILE2 = import_path63.default.join(import_os55.default.homedir(), ".node9", "decisions.json");
56196
+ var DECISIONS_FILE2 = import_path64.default.join(import_os57.default.homedir(), ".node9", "decisions.json");
55851
56197
  function readDecisions() {
55852
56198
  try {
55853
- if (!import_fs66.default.existsSync(DECISIONS_FILE2)) return {};
55854
- const raw = import_fs66.default.readFileSync(DECISIONS_FILE2, "utf-8");
56199
+ if (!import_fs67.default.existsSync(DECISIONS_FILE2)) return {};
56200
+ const raw = import_fs67.default.readFileSync(DECISIONS_FILE2, "utf-8");
55855
56201
  const parsed = JSON.parse(raw);
55856
56202
  const out = {};
55857
56203
  for (const [k, v] of Object.entries(parsed)) {
@@ -55863,11 +56209,11 @@ function readDecisions() {
55863
56209
  }
55864
56210
  }
55865
56211
  function writeDecisions(d) {
55866
- const dir = import_path63.default.dirname(DECISIONS_FILE2);
55867
- if (!import_fs66.default.existsSync(dir)) import_fs66.default.mkdirSync(dir, { recursive: true });
56212
+ const dir = import_path64.default.dirname(DECISIONS_FILE2);
56213
+ if (!import_fs67.default.existsSync(dir)) import_fs67.default.mkdirSync(dir, { recursive: true });
55868
56214
  const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
55869
- import_fs66.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
55870
- import_fs66.default.renameSync(tmp, DECISIONS_FILE2);
56215
+ import_fs67.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
56216
+ import_fs67.default.renameSync(tmp, DECISIONS_FILE2);
55871
56217
  }
55872
56218
  function registerDecisionsCommand(program2) {
55873
56219
  const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
@@ -55924,18 +56270,18 @@ Persistent decisions (${entries.length})
55924
56270
 
55925
56271
  // src/cli/commands/dlp.ts
55926
56272
  var import_chalk38 = __toESM(require("chalk"));
55927
- var import_fs67 = __toESM(require("fs"));
55928
- var import_path64 = __toESM(require("path"));
55929
- var import_os56 = __toESM(require("os"));
55930
- var AUDIT_LOG = import_path64.default.join(import_os56.default.homedir(), ".node9", "audit.log");
55931
- var RESOLVED_FILE = import_path64.default.join(import_os56.default.homedir(), ".node9", "dlp-resolved.json");
56273
+ var import_fs68 = __toESM(require("fs"));
56274
+ var import_path65 = __toESM(require("path"));
56275
+ var import_os58 = __toESM(require("os"));
56276
+ var AUDIT_LOG = import_path65.default.join(import_os58.default.homedir(), ".node9", "audit.log");
56277
+ var RESOLVED_FILE = import_path65.default.join(import_os58.default.homedir(), ".node9", "dlp-resolved.json");
55932
56278
  var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
55933
56279
  function stripAnsi(s) {
55934
56280
  return s.replace(ANSI_RE, "");
55935
56281
  }
55936
56282
  function loadResolved() {
55937
56283
  try {
55938
- const raw = JSON.parse(import_fs67.default.readFileSync(RESOLVED_FILE, "utf-8"));
56284
+ const raw = JSON.parse(import_fs68.default.readFileSync(RESOLVED_FILE, "utf-8"));
55939
56285
  return new Set(raw);
55940
56286
  } catch {
55941
56287
  return /* @__PURE__ */ new Set();
@@ -55943,13 +56289,13 @@ function loadResolved() {
55943
56289
  }
55944
56290
  function saveResolved(resolved) {
55945
56291
  try {
55946
- import_fs67.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
56292
+ import_fs68.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
55947
56293
  } catch {
55948
56294
  }
55949
56295
  }
55950
56296
  function loadDlpFindings() {
55951
- if (!import_fs67.default.existsSync(AUDIT_LOG)) return [];
55952
- return import_fs67.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
56297
+ if (!import_fs68.default.existsSync(AUDIT_LOG)) return [];
56298
+ return import_fs68.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
55953
56299
  if (!line.trim()) return [];
55954
56300
  try {
55955
56301
  const e = JSON.parse(line);
@@ -56047,15 +56393,15 @@ function registerDlpCommand(program2) {
56047
56393
 
56048
56394
  // src/cli/commands/mask.ts
56049
56395
  var import_chalk39 = __toESM(require("chalk"));
56050
- var import_fs68 = __toESM(require("fs"));
56051
- var import_path65 = __toESM(require("path"));
56052
- var import_os57 = __toESM(require("os"));
56396
+ var import_fs69 = __toESM(require("fs"));
56397
+ var import_path66 = __toESM(require("path"));
56398
+ var import_os59 = __toESM(require("os"));
56053
56399
  init_dlp();
56054
56400
  function findJsonlFiles(dir) {
56055
56401
  const results = [];
56056
- if (!import_fs68.default.existsSync(dir)) return results;
56057
- for (const entry of import_fs68.default.readdirSync(dir, { withFileTypes: true })) {
56058
- const full = import_path65.default.join(dir, entry.name);
56402
+ if (!import_fs69.default.existsSync(dir)) return results;
56403
+ for (const entry of import_fs69.default.readdirSync(dir, { withFileTypes: true })) {
56404
+ const full = import_path66.default.join(dir, entry.name);
56059
56405
  if (entry.isDirectory()) results.push(...findJsonlFiles(full));
56060
56406
  else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
56061
56407
  }
@@ -56098,7 +56444,7 @@ function redactJson(obj) {
56098
56444
  function processFile(filePath, dryRun) {
56099
56445
  let raw;
56100
56446
  try {
56101
- raw = import_fs68.default.readFileSync(filePath, "utf-8");
56447
+ raw = import_fs69.default.readFileSync(filePath, "utf-8");
56102
56448
  } catch {
56103
56449
  return { redactedLines: 0, patterns: [] };
56104
56450
  }
@@ -56130,14 +56476,14 @@ function processFile(filePath, dryRun) {
56130
56476
  }
56131
56477
  }
56132
56478
  if (!dryRun && redactedLines > 0) {
56133
- import_fs68.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
56479
+ import_fs69.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
56134
56480
  }
56135
56481
  return { redactedLines, patterns };
56136
56482
  }
56137
56483
  function processJsonFile(filePath, dryRun) {
56138
56484
  let raw;
56139
56485
  try {
56140
- raw = import_fs68.default.readFileSync(filePath, "utf-8");
56486
+ raw = import_fs69.default.readFileSync(filePath, "utf-8");
56141
56487
  } catch {
56142
56488
  return { redactedLines: 0, patterns: [] };
56143
56489
  }
@@ -56150,15 +56496,15 @@ function processJsonFile(filePath, dryRun) {
56150
56496
  const { value, modified, found } = redactJson(parsed);
56151
56497
  if (!modified) return { redactedLines: 0, patterns: [] };
56152
56498
  if (!dryRun) {
56153
- import_fs68.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
56499
+ import_fs69.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
56154
56500
  }
56155
56501
  return { redactedLines: 1, patterns: found };
56156
56502
  }
56157
56503
  function findJsonFiles(dir) {
56158
56504
  const results = [];
56159
- if (!import_fs68.default.existsSync(dir)) return results;
56160
- for (const entry of import_fs68.default.readdirSync(dir, { withFileTypes: true })) {
56161
- const full = import_path65.default.join(dir, entry.name);
56505
+ if (!import_fs69.default.existsSync(dir)) return results;
56506
+ for (const entry of import_fs69.default.readdirSync(dir, { withFileTypes: true })) {
56507
+ const full = import_path66.default.join(dir, entry.name);
56162
56508
  if (entry.isDirectory()) results.push(...findJsonFiles(full));
56163
56509
  else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
56164
56510
  }
@@ -56167,9 +56513,9 @@ function findJsonFiles(dir) {
56167
56513
  function registerMaskCommand(program2) {
56168
56514
  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) => {
56169
56515
  const dryRun = !!options.dryRun;
56170
- const home = import_os57.default.homedir();
56171
- const claudeDir = import_path65.default.join(home, ".claude", "projects");
56172
- const geminiDir = import_path65.default.join(home, ".gemini", "tmp");
56516
+ const home = import_os59.default.homedir();
56517
+ const claudeDir = import_path66.default.join(home, ".claude", "projects");
56518
+ const geminiDir = import_path66.default.join(home, ".gemini", "tmp");
56173
56519
  const allFiles = [
56174
56520
  ...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
56175
56521
  ...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
@@ -56177,7 +56523,7 @@ function registerMaskCommand(program2) {
56177
56523
  const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
56178
56524
  const filtered = cutoff ? allFiles.filter((f) => {
56179
56525
  try {
56180
- return import_fs68.default.statSync(f.path).mtime >= cutoff;
56526
+ return import_fs69.default.statSync(f.path).mtime >= cutoff;
56181
56527
  } catch {
56182
56528
  return false;
56183
56529
  }
@@ -56233,7 +56579,7 @@ function registerMaskCommand(program2) {
56233
56579
  // src/cli.ts
56234
56580
  init_blast();
56235
56581
  var { version } = JSON.parse(
56236
- import_fs71.default.readFileSync(import_path68.default.join(__dirname, "../package.json"), "utf-8")
56582
+ import_fs72.default.readFileSync(import_path69.default.join(__dirname, "../package.json"), "utf-8")
56237
56583
  );
56238
56584
  var program = new import_commander.Command();
56239
56585
  program.name("node9").description("The Sudo Command for AI Agents").version(version);
@@ -56259,6 +56605,11 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
56259
56605
  } else {
56260
56606
  console.log(import_chalk41.default.green(`\u2705 Logged in \u2014 agent mode`));
56261
56607
  console.log(import_chalk41.default.gray(` Team policy enforced for all calls via Node9 cloud.`));
56608
+ if (!isTestingMode()) {
56609
+ const healed = ensureAutostartHealthy(!!getConfig().settings.autoStartDaemon);
56610
+ if (healed === "repaired")
56611
+ console.log(import_chalk41.default.green(` \u2713 Re-enabled daemon autostart (survives reboot)`));
56612
+ }
56262
56613
  }
56263
56614
  });
56264
56615
  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) => {
@@ -56407,15 +56758,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
56407
56758
  } catch {
56408
56759
  }
56409
56760
  if (options.purge) {
56410
- const node9Dir = import_path68.default.join(import_os60.default.homedir(), ".node9");
56411
- if (import_fs71.default.existsSync(node9Dir)) {
56761
+ const node9Dir = import_path69.default.join(import_os62.default.homedir(), ".node9");
56762
+ if (import_fs72.default.existsSync(node9Dir)) {
56412
56763
  const confirmed = await (0, import_prompts2.confirm)({
56413
56764
  message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
56414
56765
  default: false
56415
56766
  });
56416
56767
  if (confirmed) {
56417
- import_fs71.default.rmSync(node9Dir, { recursive: true });
56418
- if (import_fs71.default.existsSync(node9Dir)) {
56768
+ import_fs72.default.rmSync(node9Dir, { recursive: true });
56769
+ if (import_fs72.default.existsSync(node9Dir)) {
56419
56770
  console.error(
56420
56771
  import_chalk41.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
56421
56772
  );
@@ -56540,7 +56891,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
56540
56891
  });
56541
56892
  program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
56542
56893
  try {
56543
- const dashboardPath = import_path68.default.join(__dirname, "dashboard.mjs");
56894
+ const dashboardPath = import_path69.default.join(__dirname, "dashboard.mjs");
56544
56895
  const dynamicImport = new Function("id", "return import(id)");
56545
56896
  const mod = await dynamicImport(`file://${dashboardPath}`);
56546
56897
  await mod.startMonitor();
@@ -56578,14 +56929,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
56578
56929
  Run "node9 addto claude" to register it as the statusLine.`
56579
56930
  ).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
56580
56931
  if (subcommand === "debug") {
56581
- const flagFile = import_path68.default.join(import_os60.default.homedir(), ".node9", "hud-debug");
56932
+ const flagFile = import_path69.default.join(import_os62.default.homedir(), ".node9", "hud-debug");
56582
56933
  if (state === "on") {
56583
- import_fs71.default.mkdirSync(import_path68.default.dirname(flagFile), { recursive: true });
56584
- import_fs71.default.writeFileSync(flagFile, "");
56934
+ import_fs72.default.mkdirSync(import_path69.default.dirname(flagFile), { recursive: true });
56935
+ import_fs72.default.writeFileSync(flagFile, "");
56585
56936
  console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
56586
56937
  console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
56587
56938
  } else if (state === "off") {
56588
- if (import_fs71.default.existsSync(flagFile)) import_fs71.default.unlinkSync(flagFile);
56939
+ if (import_fs72.default.existsSync(flagFile)) import_fs72.default.unlinkSync(flagFile);
56589
56940
  console.log("HUD debug logging disabled.");
56590
56941
  } else {
56591
56942
  console.error("Usage: node9 hud debug on|off");
@@ -56708,9 +57059,9 @@ if (process.argv[2] !== "daemon") {
56708
57059
  const isCheckHook = process.argv[2] === "check";
56709
57060
  if (isCheckHook) {
56710
57061
  if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
56711
- const logPath = import_path68.default.join(import_os60.default.homedir(), ".node9", "hook-debug.log");
57062
+ const logPath = import_path69.default.join(import_os62.default.homedir(), ".node9", "hook-debug.log");
56712
57063
  const msg = reason instanceof Error ? reason.message : String(reason);
56713
- import_fs71.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
57064
+ import_fs72.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
56714
57065
  `);
56715
57066
  }
56716
57067
  process.exit(0);