@node9/proxy 2.43.0 → 2.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -805,12 +805,12 @@ function judgeInlineCode(language, code, isProtected) {
805
805
  category
806
806
  };
807
807
  }
808
- const path30 = protectedLiteral(text, isProtected);
809
- if (path30) {
808
+ const path31 = protectedLiteral(text, isProtected);
809
+ if (path31) {
810
810
  return {
811
811
  outcome: "dangerous",
812
812
  what: WHAT["reads-protected"],
813
- evidence: path30.slice(0, 60),
813
+ evidence: path31.slice(0, 60),
814
814
  category: "reads-protected"
815
815
  };
816
816
  }
@@ -2973,9 +2973,9 @@ function ruleServerMatches(rule, serverLabel) {
2973
2973
  if (rule.notServer && label2 && matchesPattern(label2, rule.notServer)) return false;
2974
2974
  return true;
2975
2975
  }
2976
- function getNestedValue(obj, path30) {
2976
+ function getNestedValue(obj, path31) {
2977
2977
  if (!obj || typeof obj !== "object") return null;
2978
- const segments2 = path30.split(".");
2978
+ const segments2 = path31.split(".");
2979
2979
  for (const seg of segments2) {
2980
2980
  if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
2981
2981
  }
@@ -3955,8 +3955,8 @@ function collectFileAccesses(tool, args, context = {}, inspection = {}) {
3955
3955
  }
3956
3956
  return out;
3957
3957
  }
3958
- function within(path30, root) {
3959
- return path30 === root || path30.startsWith(root === "/" ? "/" : root + "/");
3958
+ function within(path31, root) {
3959
+ return path31 === root || path31.startsWith(root === "/" ? "/" : root + "/");
3960
3960
  }
3961
3961
  function hits(access, paths, directories, context) {
3962
3962
  const home = context.homeDirs?.[0] ?? "~";
@@ -5344,7 +5344,10 @@ function classify(inv) {
5344
5344
  out.push({ ...f, shown: inv.shown, reason: `${f.reason}: ${inv.shown}` });
5345
5345
  };
5346
5346
  if (hooksBypass(inv)) found(HOOKS_BYPASS);
5347
- if (stagesEverything(inv)) found(STAGE_ALL);
5347
+ const staged = stagesEverything(inv);
5348
+ if (staged) {
5349
+ found(staged.ifWorkTreeTop === void 0 ? STAGE_ALL : { ...STAGE_ALL, ...staged });
5350
+ }
5348
5351
  if (inv.sub === null) {
5349
5352
  found(UNREADABLE);
5350
5353
  return out;
@@ -5405,12 +5408,35 @@ function appliedValue(env, name) {
5405
5408
  const word = f?.Stmts?.[0]?.Cmd?.Args?.[1];
5406
5409
  return word ? resolveWordLiteral(word) : null;
5407
5410
  }
5411
+ function lexicalPath(p) {
5412
+ if (/^[\\/~$]/.test(p) || /^[A-Za-z]:/.test(p)) return null;
5413
+ const parts = [];
5414
+ let climbed = false;
5415
+ for (const part of p.split(/[\\/]+/)) {
5416
+ if (part === "" || part === ".") continue;
5417
+ if (part === "..") {
5418
+ if (parts.length === 0) climbed = true;
5419
+ else parts.pop();
5420
+ } else parts.push(part);
5421
+ }
5422
+ return { parts, climbed };
5423
+ }
5424
+ function hooksPathBypasses(value) {
5425
+ if (value === null || value === void 0) return true;
5426
+ const v = value.trim();
5427
+ if (v === "" || v === "true") return true;
5428
+ const lp = lexicalPath(v);
5429
+ if (lp === null || lp.climbed || lp.parts.length === 0) return true;
5430
+ return lp.parts[0] === ".git" && lp.parts[1] !== "hooks";
5431
+ }
5408
5432
  function hooksBypass(inv) {
5409
- if (inv.config.has("core.hookspath")) return true;
5433
+ if (inv.config.has("core.hookspath") && hooksPathBypasses(inv.config.get("core.hookspath")))
5434
+ return true;
5410
5435
  for (const [name, value] of inv.env) {
5411
5436
  if (name === "GIT_CONFIG_PARAMETERS" && value !== null && /core\.hookspath/i.test(value))
5412
5437
  return true;
5413
- if (/^GIT_CONFIG_KEY_\d+$/.test(name) && value !== null && value.toLowerCase() === "core.hookspath")
5438
+ const key = /^GIT_CONFIG_KEY_(\d+)$/.exec(name);
5439
+ if (key && value !== null && value.toLowerCase() === "core.hookspath" && hooksPathBypasses(inv.env.get(`GIT_CONFIG_VALUE_${key[1]}`)))
5414
5440
  return true;
5415
5441
  }
5416
5442
  for (const name of HOOK_KILL_SWITCHES) {
@@ -5452,7 +5478,10 @@ function configWritesHooksPath(args) {
5452
5478
  }
5453
5479
  const key = args[i];
5454
5480
  if (key === null || key === void 0 || key.toLowerCase() !== "core.hookspath") return false;
5455
- return write || i + 1 < args.length;
5481
+ const unset = args.slice(0, i).some((w) => w === "--unset" || w === "--unset-all") || args[0] === "unset";
5482
+ if (unset) return true;
5483
+ if (i + 1 < args.length) return hooksPathBypasses(args[i + 1]);
5484
+ return write;
5456
5485
  }
5457
5486
  function isHookPath(word) {
5458
5487
  return /(^|[\\/])(\.git[\\/]hooks|\.husky)([\\/]|$)/.test(word);
@@ -5487,31 +5516,49 @@ function chmodDisarmsHook(args, shown) {
5487
5516
  function wholeTree(operand) {
5488
5517
  if (/^:\(top\)\.?$/.test(operand) || operand === ":/" || operand === "*") return true;
5489
5518
  if (operand.startsWith(":")) return false;
5519
+ const lp = lexicalPath(operand);
5520
+ return lp !== null && lp.parts.length === 0;
5521
+ }
5522
+ function chdirPrefix(inv) {
5523
+ const dirs = inv.chdir ?? [];
5524
+ if (dirs.length === 0) return null;
5490
5525
  const parts = [];
5491
- for (const part of operand.split("/")) {
5492
- if (!part || part === ".") continue;
5493
- if (part === "..") parts.pop();
5494
- else parts.push(part);
5526
+ for (const d of dirs) {
5527
+ if (d === null || d === "") return null;
5528
+ const lp = lexicalPath(d);
5529
+ if (lp === null || lp.climbed) return null;
5530
+ parts.push(...lp.parts);
5495
5531
  }
5496
- return parts.length === 0 && !operand.startsWith("/");
5532
+ return parts.length === 0 ? null : parts.join("/");
5497
5533
  }
5498
5534
  function stagesEverything(inv) {
5499
5535
  const sub = inv.sub?.toLowerCase();
5536
+ const prefix = chdirPrefix(inv);
5537
+ const judge = (operands2) => {
5538
+ let conditional = false;
5539
+ for (const operand of operands2) {
5540
+ if (!wholeTree(operand)) continue;
5541
+ if (prefix === null || operand.startsWith(":") || operand.startsWith("/")) return {};
5542
+ if (wholeTree(`${prefix}/${operand === "*" ? "." : operand}`)) return {};
5543
+ conditional = true;
5544
+ }
5545
+ return conditional && prefix !== null ? { ifWorkTreeTop: prefix } : null;
5546
+ };
5500
5547
  if (sub === "add") {
5501
5548
  const o = parseOptions(inv.args, "", ADD_LONG_VALUE);
5502
5549
  if (o.flags.has("-n") || o.flags.has("--dry-run") || o.flags.has("-i") || o.flags.has("--interactive") || o.flags.has("-p") || o.flags.has("--patch") || o.flags.has("-e") || o.flags.has("--edit"))
5503
- return false;
5550
+ return null;
5504
5551
  const all = o.flags.has("-A") || o.flags.has("--all") || o.flags.has("--no-ignore-removal") || o.flags.has("-u") || o.flags.has("--update");
5505
- if (all && o.operands.length === 0) return true;
5506
- return o.operands.some(wholeTree);
5552
+ if (all && o.operands.length === 0) return {};
5553
+ return judge(o.operands);
5507
5554
  }
5508
5555
  if (sub === "commit") {
5509
5556
  const o = parseOptions(inv.args, "mFCcut", COMMIT_LONG_VALUE);
5510
- if (o.flags.has("--dry-run")) return false;
5511
- if (o.flags.has("-a") || o.flags.has("--all")) return true;
5512
- return o.operands.some(wholeTree);
5557
+ if (o.flags.has("--dry-run")) return null;
5558
+ if (o.flags.has("-a") || o.flags.has("--all")) return {};
5559
+ return judge(o.operands);
5513
5560
  }
5514
- return false;
5561
+ return null;
5515
5562
  }
5516
5563
  function hookTextRunsNothing(text) {
5517
5564
  return text.split(/\r?\n/).every((line) => INERT_LINE_RE.test(line.trim()));
@@ -7167,9 +7214,9 @@ function bareToolName(toolName) {
7167
7214
  const parts = toolName.split("__");
7168
7215
  return (parts.length >= 3 ? parts.slice(2).join("__") : toolName).toLowerCase();
7169
7216
  }
7170
- function valuesAt(args, path30) {
7217
+ function valuesAt(args, path31) {
7171
7218
  let cursors = [args];
7172
- for (const rawSegment of path30.split(".")) {
7219
+ for (const rawSegment of path31.split(".")) {
7173
7220
  const isArray = rawSegment.endsWith("[]");
7174
7221
  const key = isArray ? rawSegment.slice(0, -2) : rawSegment;
7175
7222
  const next = [];
@@ -7200,8 +7247,8 @@ function extractToolDestinations(toolName, args) {
7200
7247
  try {
7201
7248
  const out = [];
7202
7249
  const paths = DESTINATION_ARGS.get(bareToolName(toolName)) ?? [];
7203
- for (const path30 of paths) {
7204
- for (const value of valuesAt(args, path30)) {
7250
+ for (const path31 of paths) {
7251
+ for (const value of valuesAt(args, path31)) {
7205
7252
  const host2 = hostOf(value);
7206
7253
  if (host2) out.push({ host: host2, binary: toolName, raw: value });
7207
7254
  }
@@ -7227,8 +7274,8 @@ function ssrfDestinationFloor(toolName, args, opts = {}) {
7227
7274
  try {
7228
7275
  const paths = DESTINATION_ARGS.get(bareToolName(toolName));
7229
7276
  if (!paths) return null;
7230
- for (const path30 of paths) {
7231
- for (const value of valuesAt(args, path30)) {
7277
+ for (const path31 of paths) {
7278
+ for (const value of valuesAt(args, path31)) {
7232
7279
  const host2 = hostOf(value);
7233
7280
  if (!host2) continue;
7234
7281
  const m = classifySsrf(host2);
@@ -7237,7 +7284,7 @@ function ssrfDestinationFloor(toolName, args, opts = {}) {
7237
7284
  const decision = ssrfFloorDecision(m, written, opts);
7238
7285
  if (decision === null) continue;
7239
7286
  const reason = decision === "review" ? ssrfDisguisedReason(m, written) : ssrfReason(m, host2);
7240
- return { ...m, argPath: path30, host: host2, reason, decision };
7287
+ return { ...m, argPath: path31, host: host2, reason, decision };
7241
7288
  }
7242
7289
  }
7243
7290
  return null;
@@ -7519,7 +7566,7 @@ async function evaluatePolicy(config, toolName, args, context = {}, hostHooks =
7519
7566
  }
7520
7567
  async function evaluatePolicyCore(config, toolName, args, context = {}, hooks = {}) {
7521
7568
  const { agent, cwd, activeEnvironment } = context;
7522
- const { checkProvenance: checkProvenance2, isTrustedHost: isTrustedHost2, isConfiguredRegistry } = hooks;
7569
+ const { checkProvenance: checkProvenance2, isTrustedHost: isTrustedHost2, isConfiguredRegistry, isGitWorkTreeTop: isGitWorkTreeTop2 } = hooks;
7523
7570
  const settingsView = catalogSettings(config);
7524
7571
  const layers = inspectionLayers(config.policy);
7525
7572
  const cv = (id) => checkValue(settingsView, id);
@@ -7673,6 +7720,8 @@ async function evaluatePolicyCore(config, toolName, args, context = {}, hooks =
7673
7720
  const action = cv(id);
7674
7721
  const finding = action === "off" ? void 0 : git.findings.find((f) => f.checkId === id);
7675
7722
  if (!finding) continue;
7723
+ if (finding.ifWorkTreeTop !== void 0 && isGitWorkTreeTop2 && cwd && !isGitWorkTreeTop2(finding.ifWorkTreeTop, cwd))
7724
+ continue;
7676
7725
  const v = applyCheckValue(action, {
7677
7726
  decision: "review",
7678
7727
  blockedByLabel: `Node9 (AST): ${finding.ruleName}`,
@@ -16301,6 +16350,7 @@ zoo`.split("\n");
16301
16350
  /** The words after `git`: global options, then the subcommand. */
16302
16351
  visitGit(rest, env, depth, viaXargs, fromAlias, shown) {
16303
16352
  const config = /* @__PURE__ */ new Map();
16353
+ const chdir = [];
16304
16354
  let i = 0;
16305
16355
  while (i < rest.length) {
16306
16356
  const w = rest[i];
@@ -16315,6 +16365,7 @@ zoo`.split("\n");
16315
16365
  i++;
16316
16366
  value = i < rest.length ? rest[i] : null;
16317
16367
  }
16368
+ if (name === "-C") chdir.push(viaXargs || (value ?? "").includes("{}") ? null : value);
16318
16369
  if (name === "-c" && value !== null) {
16319
16370
  const ceq = value.indexOf("=");
16320
16371
  const key = (ceq > 0 ? value.slice(0, ceq) : value).toLowerCase();
@@ -16331,7 +16382,7 @@ zoo`.split("\n");
16331
16382
  }
16332
16383
  const subWord = i < rest.length ? rest[i] : void 0;
16333
16384
  const args = rest.slice(i + 1);
16334
- const inv = { sub: null, args, config, env, shown };
16385
+ const inv = { sub: null, args, config, env, shown, chdir };
16335
16386
  if (subWord === void 0) {
16336
16387
  if (!viaXargs) return;
16337
16388
  this.emit(inv);
@@ -16345,16 +16396,23 @@ zoo`.split("\n");
16345
16396
  const fromConfig = config.get(`alias.${subWord.toLowerCase()}`);
16346
16397
  const alias = fromConfig !== void 0 ? fromConfig : this.aliases.get(subWord);
16347
16398
  if (alias !== void 0 && !fromAlias) {
16348
- this.expandAlias(subWord, alias, args, env, depth, 0, shown);
16399
+ this.expandAlias(subWord, alias, args, env, depth, 0, shown, chdir);
16349
16400
  return;
16350
16401
  }
16351
16402
  inv.sub = subWord;
16352
16403
  this.emit(inv);
16353
16404
  this.recordAliasDefinition(inv, env, depth);
16354
16405
  }
16355
- expandAlias(name, value, args, env, depth, level, shown) {
16406
+ expandAlias(name, value, args, env, depth, level, shown, chdir) {
16356
16407
  if (value === null) {
16357
- this.emit({ sub: null, args, config: /* @__PURE__ */ new Map(), env, shown: `${shown} (alias ${name})` });
16408
+ this.emit({
16409
+ sub: null,
16410
+ args,
16411
+ config: /* @__PURE__ */ new Map(),
16412
+ env,
16413
+ shown: `${shown} (alias ${name})`,
16414
+ chdir
16415
+ });
16358
16416
  return;
16359
16417
  }
16360
16418
  if (value.startsWith("!")) {
@@ -16368,7 +16426,16 @@ zoo`.split("\n");
16368
16426
  const nested = this.aliases.get(sub);
16369
16427
  const expandedShown = `${shown} (alias ${name} = ${value})`;
16370
16428
  if (nested !== void 0 && level < MAX_ALIAS_DEPTH) {
16371
- this.expandAlias(sub, nested, [...words.slice(1), ...args], env, depth, level + 1, shown);
16429
+ this.expandAlias(
16430
+ sub,
16431
+ nested,
16432
+ [...words.slice(1), ...args],
16433
+ env,
16434
+ depth,
16435
+ level + 1,
16436
+ shown,
16437
+ chdir
16438
+ );
16372
16439
  return;
16373
16440
  }
16374
16441
  this.emit({
@@ -16376,7 +16443,8 @@ zoo`.split("\n");
16376
16443
  args: [...words.slice(1), ...args],
16377
16444
  config: /* @__PURE__ */ new Map(),
16378
16445
  env,
16379
- shown: expandedShown
16446
+ shown: expandedShown,
16447
+ chdir
16380
16448
  });
16381
16449
  }
16382
16450
  /**
@@ -16410,7 +16478,7 @@ zoo`.split("\n");
16410
16478
  if (i + 1 >= args.length) return;
16411
16479
  const value = args[i + 1];
16412
16480
  this.aliases.set(m[1], value);
16413
- this.expandAlias(m[1], value, [], env, depth, 0, `${inv.shown}`);
16481
+ this.expandAlias(m[1], value, [], env, depth, 0, `${inv.shown}`, []);
16414
16482
  }
16415
16483
  };
16416
16484
  POSITIONAL2 = "\0positional";
@@ -18333,8 +18401,8 @@ var ConfigFileSchema = import_zod.z.object({
18333
18401
  }).strict();
18334
18402
  function formatIssues(issues) {
18335
18403
  const lines = issues.map((issue) => {
18336
- const path30 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
18337
- return ` \u2022 ${path30}: ${issue.message}`;
18404
+ const path31 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
18405
+ return ` \u2022 ${path31}: ${issue.message}`;
18338
18406
  });
18339
18407
  return `Invalid config:
18340
18408
  ${lines.join("\n")}`;
@@ -18347,9 +18415,9 @@ function prunePaths(root, paths) {
18347
18415
  const yi = y[y.length - 1];
18348
18416
  return typeof xi === "number" && typeof yi === "number" ? yi - xi : 0;
18349
18417
  });
18350
- for (const path30 of ordered) {
18418
+ for (const path31 of ordered) {
18351
18419
  let cur = root;
18352
- for (const key of path30.slice(0, -1)) {
18420
+ for (const key of path31.slice(0, -1)) {
18353
18421
  if (cur === null || typeof cur !== "object") {
18354
18422
  cur = void 0;
18355
18423
  break;
@@ -18357,7 +18425,7 @@ function prunePaths(root, paths) {
18357
18425
  cur = cur[key];
18358
18426
  }
18359
18427
  if (cur === null || typeof cur !== "object") continue;
18360
- const last = path30[path30.length - 1];
18428
+ const last = path31[path31.length - 1];
18361
18429
  if (Array.isArray(cur)) {
18362
18430
  const i = Number(last);
18363
18431
  if (Number.isInteger(i) && i >= 0 && i < cur.length) {
@@ -18393,7 +18461,7 @@ function sanitizeConfig(raw) {
18393
18461
  return issue.keys.map((k) => [...at, k]);
18394
18462
  }
18395
18463
  return [at.slice(0, -level || void 0)];
18396
- }).filter((path30) => path30.length > 0);
18464
+ }).filter((path31) => path31.length > 0);
18397
18465
  if (paths.length === 0 || !prunePaths(working, paths)) break;
18398
18466
  }
18399
18467
  if (ConfigFileSchema.safeParse(working).success) break;
@@ -19831,13 +19899,13 @@ function getConfig(cwd) {
19831
19899
  }
19832
19900
  if (Array.isArray(mc.jailPaths)) {
19833
19901
  for (const jp of mc.jailPaths) {
19834
- const path30 = typeof jp?.path === "string" ? jp.path.trim() : "";
19835
- if (!path30) continue;
19902
+ const path31 = typeof jp?.path === "string" ? jp.path.trim() : "";
19903
+ if (!path31) continue;
19836
19904
  const verdict = jp?.verdict === "review" ? "review" : "block";
19837
- for (const r of pathRules(path30, verdict, "org-managed jail")) {
19905
+ for (const r of pathRules(path31, verdict, "org-managed jail")) {
19838
19906
  mergedPolicy.smartRules.push({ ...r, name: `org:${r.name}` });
19839
19907
  }
19840
- mergedPolicy.managedJailPaths.push({ path: path30, verdict });
19908
+ mergedPolicy.managedJailPaths.push({ path: path31, verdict });
19841
19909
  }
19842
19910
  }
19843
19911
  if (Array.isArray(mc.trustedHosts)) {
@@ -20218,6 +20286,9 @@ function readCappedText(file2, maxBytes, openFlags = "r") {
20218
20286
  return r ? { text: r.bytes.toString("utf8"), truncated: r.truncated } : null;
20219
20287
  }
20220
20288
 
20289
+ // src/policy/index.ts
20290
+ var import_path13 = __toESM(require("path"));
20291
+
20221
20292
  // src/dlp.ts
20222
20293
  var import_fs6 = __toESM(require("fs"));
20223
20294
  var import_path5 = __toESM(require("path"));
@@ -21538,10 +21609,19 @@ async function evaluatePolicy2(toolName, args, agent, cwd, opts) {
21538
21609
  // reaches a long-lived in-process authorizer (the gateway) within seconds.
21539
21610
  isTrustedHost: config.policy.trustedHostsManaged ? (host2) => matchesTrustedHost(host2, config.policy.trustedHosts) : isTrustedHost,
21540
21611
  readAgentSettings,
21541
- isConfiguredRegistry: (host2, at) => configuredRegistryHosts(at).has(host2)
21612
+ isConfiguredRegistry: (host2, at) => configuredRegistryHosts(at).has(host2),
21613
+ isGitWorkTreeTop
21542
21614
  }
21543
21615
  );
21544
21616
  }
21617
+ function isGitWorkTreeTop(dir2, cwd) {
21618
+ if (!import_path13.default.isAbsolute(cwd)) return true;
21619
+ try {
21620
+ return import_fs13.default.existsSync(import_path13.default.join(import_path13.default.resolve(cwd, dir2), ".git"));
21621
+ } catch {
21622
+ return true;
21623
+ }
21624
+ }
21545
21625
  var MAX_AGENT_SETTINGS_BYTES = 256 * 1024;
21546
21626
  function readAgentSettings(absPath) {
21547
21627
  const r = readCappedText(
@@ -21557,11 +21637,11 @@ function isIgnoredTool2(toolName) {
21557
21637
 
21558
21638
  // src/auth/state.ts
21559
21639
  var import_fs14 = __toESM(require("fs"));
21560
- var import_path13 = __toESM(require("path"));
21640
+ var import_path14 = __toESM(require("path"));
21561
21641
  var import_os9 = __toESM(require("os"));
21562
21642
  init_forecast_context();
21563
- var PAUSED_FILE = import_path13.default.join(import_os9.default.homedir(), ".node9", "PAUSED");
21564
- var TRUST_FILE = import_path13.default.join(import_os9.default.homedir(), ".node9", "trust.json");
21643
+ var PAUSED_FILE = import_path14.default.join(import_os9.default.homedir(), ".node9", "PAUSED");
21644
+ var TRUST_FILE = import_path14.default.join(import_os9.default.homedir(), ".node9", "trust.json");
21565
21645
  function extractCommandPattern(toolName, args) {
21566
21646
  const lower2 = toolName.toLowerCase();
21567
21647
  if (lower2 !== "bash" && lower2 !== "execute_bash" && lower2 !== "shell") return void 0;
@@ -21638,7 +21718,7 @@ function writeTrustSession(toolName, durationMs, args) {
21638
21718
  }
21639
21719
  function getPersistentDecision(toolName) {
21640
21720
  try {
21641
- const file2 = import_path13.default.join(import_os9.default.homedir(), ".node9", "decisions.json");
21721
+ const file2 = import_path14.default.join(import_os9.default.homedir(), ".node9", "decisions.json");
21642
21722
  if (!import_fs14.default.existsSync(file2)) return null;
21643
21723
  const decisions = JSON.parse(import_fs14.default.readFileSync(file2, "utf-8"));
21644
21724
  const d = decisions[toolName];
@@ -21652,7 +21732,7 @@ function getPersistentDecision(toolName) {
21652
21732
  var import_fs15 = __toESM(require("fs"));
21653
21733
  var import_http = __toESM(require("http"));
21654
21734
  var import_net4 = __toESM(require("net"));
21655
- var import_path14 = __toESM(require("path"));
21735
+ var import_path15 = __toESM(require("path"));
21656
21736
  var import_os10 = __toESM(require("os"));
21657
21737
  init_forecast_context();
21658
21738
 
@@ -21804,7 +21884,7 @@ function recordFromLegacyWait(body, now = Date.now()) {
21804
21884
  }
21805
21885
 
21806
21886
  // src/auth/daemon.ts
21807
- var ACTIVITY_SOCKET_PATH = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path14.default.join(import_os10.default.tmpdir(), "node9-activity.sock");
21887
+ var ACTIVITY_SOCKET_PATH = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path15.default.join(import_os10.default.tmpdir(), "node9-activity.sock");
21808
21888
  function notifyActivitySocket(data) {
21809
21889
  if (forecastRun()) return Promise.resolve(false);
21810
21890
  return new Promise((resolve) => {
@@ -21849,7 +21929,7 @@ var DAEMON_HOST = "127.0.0.1";
21849
21929
  function getInternalToken() {
21850
21930
  if (forecastRun()) return null;
21851
21931
  try {
21852
- const pidFile = import_path14.default.join(import_os10.default.homedir(), ".node9", "daemon.pid");
21932
+ const pidFile = import_path15.default.join(import_os10.default.homedir(), ".node9", "daemon.pid");
21853
21933
  if (!import_fs15.default.existsSync(pidFile)) return null;
21854
21934
  const data = JSON.parse(import_fs15.default.readFileSync(pidFile, "utf-8"));
21855
21935
  process.kill(data.pid, 0);
@@ -21860,7 +21940,7 @@ function getInternalToken() {
21860
21940
  }
21861
21941
  function isDaemonRunning() {
21862
21942
  if (forecastRun()) return false;
21863
- const pidFile = import_path14.default.join(import_os10.default.homedir(), ".node9", "daemon.pid");
21943
+ const pidFile = import_path15.default.join(import_os10.default.homedir(), ".node9", "daemon.pid");
21864
21944
  if (import_fs15.default.existsSync(pidFile)) {
21865
21945
  let pid;
21866
21946
  let port;
@@ -22223,7 +22303,7 @@ var import_crypto10 = require("crypto");
22223
22303
  // src/apps/state.ts
22224
22304
  var import_fs17 = __toESM(require("fs"));
22225
22305
  var import_os12 = __toESM(require("os"));
22226
- var import_path16 = __toESM(require("path"));
22306
+ var import_path17 = __toESM(require("path"));
22227
22307
 
22228
22308
  // src/apps/catalog.ts
22229
22309
  var APP_CATALOG = [
@@ -22356,10 +22436,10 @@ init_audit();
22356
22436
 
22357
22437
  // src/daemon/mcp-tools.ts
22358
22438
  var import_fs16 = __toESM(require("fs"));
22359
- var import_path15 = __toESM(require("path"));
22439
+ var import_path16 = __toESM(require("path"));
22360
22440
  var import_os11 = __toESM(require("os"));
22361
22441
  function getMcpToolsFile() {
22362
- return import_path15.default.join(import_os11.default.homedir(), ".node9", "mcp-tools.json");
22442
+ return import_path16.default.join(import_os11.default.homedir(), ".node9", "mcp-tools.json");
22363
22443
  }
22364
22444
  function readMcpToolsConfig() {
22365
22445
  try {
@@ -22374,7 +22454,7 @@ function readMcpToolsConfig() {
22374
22454
 
22375
22455
  // src/apps/state.ts
22376
22456
  function appsFilePath(home = import_os12.default.homedir()) {
22377
- return import_path16.default.join(home, ".node9", "apps.json");
22457
+ return import_path17.default.join(home, ".node9", "apps.json");
22378
22458
  }
22379
22459
  var SIGNAL_KINDS = /* @__PURE__ */ new Set(["mcp-server", "command", "package", "env-name"]);
22380
22460
  function emptyFile() {
@@ -22478,14 +22558,14 @@ function resolveLinkedServer(label2, opts = {}) {
22478
22558
 
22479
22559
  // src/auth/orchestrator.ts
22480
22560
  var import_os21 = __toESM(require("os"));
22481
- var import_path29 = __toESM(require("path"));
22561
+ var import_path30 = __toESM(require("path"));
22482
22562
 
22483
22563
  // src/ui/native.ts
22484
22564
  var import_child_process = require("child_process");
22485
- var import_path18 = __toESM(require("path"));
22565
+ var import_path19 = __toESM(require("path"));
22486
22566
 
22487
22567
  // src/context-sniper.ts
22488
- var import_path17 = __toESM(require("path"));
22568
+ var import_path18 = __toESM(require("path"));
22489
22569
  function smartTruncate(str, maxLen = 500) {
22490
22570
  if (str.length <= maxLen) return str;
22491
22571
  const edge = Math.floor(maxLen / 2) - 3;
@@ -22553,7 +22633,7 @@ function computeRiskMetadata(args, tier, blockedByLabel, matchedField, matchedWo
22553
22633
  intent = "EDIT";
22554
22634
  if (obj.file_path) {
22555
22635
  editFilePath = String(obj.file_path);
22556
- editFileName = import_path17.default.basename(editFilePath);
22636
+ editFileName = import_path18.default.basename(editFilePath);
22557
22637
  }
22558
22638
  const result = extractContext(String(obj.new_string), matchedWord);
22559
22639
  contextSnippet = result.snippet;
@@ -22621,7 +22701,7 @@ function formatArgs(args, matchedField, matchedWord) {
22621
22701
  if (typeof parsed === "object" && !Array.isArray(parsed)) {
22622
22702
  const obj = parsed;
22623
22703
  if (obj.old_string !== void 0 && obj.new_string !== void 0) {
22624
- const file2 = obj.file_path ? import_path18.default.basename(String(obj.file_path)) : "file";
22704
+ const file2 = obj.file_path ? import_path19.default.basename(String(obj.file_path)) : "file";
22625
22705
  const oldPreview = smartTruncate(String(obj.old_string), 120);
22626
22706
  const newPreview = extractContext(String(obj.new_string), matchedWord).snippet;
22627
22707
  return {
@@ -22826,17 +22906,17 @@ end run`;
22826
22906
  // src/canary/registry.ts
22827
22907
  var import_fs19 = __toESM(require("fs"));
22828
22908
  var import_os14 = __toESM(require("os"));
22829
- var import_path20 = __toESM(require("path"));
22909
+ var import_path21 = __toESM(require("path"));
22830
22910
  init_dist();
22831
22911
 
22832
22912
  // src/shields/jail.ts
22833
22913
  var import_fs18 = __toESM(require("fs"));
22834
22914
  var import_os13 = __toESM(require("os"));
22835
- var import_path19 = __toESM(require("path"));
22915
+ var import_path20 = __toESM(require("path"));
22836
22916
  init_dist();
22837
22917
  var USER_JAIL_SHIELD = "user-jail";
22838
22918
  function jailStorePath() {
22839
- return import_path19.default.join(import_os13.default.homedir(), ".node9", "jail-paths.json");
22919
+ return import_path20.default.join(import_os13.default.homedir(), ".node9", "jail-paths.json");
22840
22920
  }
22841
22921
  function readJailPaths() {
22842
22922
  let text;
@@ -22870,7 +22950,7 @@ function findJailedPathIn(candidate, paths) {
22870
22950
 
22871
22951
  // src/canary/registry.ts
22872
22952
  function canaryStorePath() {
22873
- return import_path20.default.join(import_os14.default.homedir(), ".node9", "canaries.json");
22953
+ return import_path21.default.join(import_os14.default.homedir(), ".node9", "canaries.json");
22874
22954
  }
22875
22955
  function isRecord(x) {
22876
22956
  if (!x || typeof x !== "object") return false;
@@ -22909,7 +22989,7 @@ init_dist();
22909
22989
  // src/auth/session-script.ts
22910
22990
  var import_fs20 = __toESM(require("fs"));
22911
22991
  var import_os15 = __toESM(require("os"));
22912
- var import_path21 = __toESM(require("path"));
22992
+ var import_path22 = __toESM(require("path"));
22913
22993
  init_dist();
22914
22994
  var MAX_SCRIPT_BYTES = 64 * 1024;
22915
22995
  var MAX_RECORDED_WRITES = 32;
@@ -22941,7 +23021,7 @@ function readScriptFile(resolved) {
22941
23021
  }
22942
23022
  function absolute(p, cwd, home) {
22943
23023
  const spelled = p === "~" || p.startsWith("~/") ? home + p.slice(1) : p;
22944
- return import_path21.default.resolve(cwd, spelled);
23024
+ return import_path22.default.resolve(cwd, spelled);
22945
23025
  }
22946
23026
  async function resolveSessionScript(toolName, args, cwd, layers, deps, home = import_os15.default.homedir()) {
22947
23027
  try {
@@ -23003,11 +23083,11 @@ init_dist();
23003
23083
 
23004
23084
  // src/exposure/known-hosts.ts
23005
23085
  var import_fs22 = __toESM(require("fs"));
23006
- var import_path23 = __toESM(require("path"));
23086
+ var import_path24 = __toESM(require("path"));
23007
23087
 
23008
23088
  // src/utils/git-remotes.ts
23009
23089
  var import_fs21 = __toESM(require("fs"));
23010
- var import_path22 = __toESM(require("path"));
23090
+ var import_path23 = __toESM(require("path"));
23011
23091
  init_dist();
23012
23092
  function readSmallFile(p, max) {
23013
23093
  let fd;
@@ -23040,20 +23120,20 @@ function gitRemoteHost(url) {
23040
23120
  return null;
23041
23121
  }
23042
23122
  function findGitConfig(dir2, walkUp = true) {
23043
- let cur = import_path22.default.resolve(dir2);
23123
+ let cur = import_path23.default.resolve(dir2);
23044
23124
  for (let i = 0; i < (walkUp ? 64 : 1); i++) {
23045
- const dotGit = import_path22.default.join(cur, ".git");
23046
- const direct = readSmallFile(import_path22.default.join(dotGit, "config"), 1e6);
23125
+ const dotGit = import_path23.default.join(cur, ".git");
23126
+ const direct = readSmallFile(import_path23.default.join(dotGit, "config"), 1e6);
23047
23127
  if (direct !== null) return direct;
23048
23128
  const pointer = readSmallFile(dotGit, 4096);
23049
23129
  const m = pointer && /^gitdir:\s*(.+?)\s*$/m.exec(pointer);
23050
23130
  if (m) {
23051
- let gitDir = import_path22.default.resolve(cur, m[1]);
23052
- const common = readSmallFile(import_path22.default.join(gitDir, "commondir"), 4096);
23053
- if (common !== null) gitDir = import_path22.default.resolve(gitDir, common.trim());
23054
- return readSmallFile(import_path22.default.join(gitDir, "config"), 1e6);
23131
+ let gitDir = import_path23.default.resolve(cur, m[1]);
23132
+ const common = readSmallFile(import_path23.default.join(gitDir, "commondir"), 4096);
23133
+ if (common !== null) gitDir = import_path23.default.resolve(gitDir, common.trim());
23134
+ return readSmallFile(import_path23.default.join(gitDir, "config"), 1e6);
23055
23135
  }
23056
- const parent = import_path22.default.dirname(cur);
23136
+ const parent = import_path23.default.dirname(cur);
23057
23137
  if (parent === cur) return null;
23058
23138
  cur = parent;
23059
23139
  }
@@ -23063,12 +23143,12 @@ var cache4 = /* @__PURE__ */ new Map();
23063
23143
  function readGitRemotes(dir2, opts = {}) {
23064
23144
  if (!dir2) return [];
23065
23145
  const walkUp = opts.walkUp !== false;
23066
- const key = `${walkUp ? "up" : "at"}:${import_path22.default.resolve(dir2)}`;
23146
+ const key = `${walkUp ? "up" : "at"}:${import_path23.default.resolve(dir2)}`;
23067
23147
  const hit = cache4.get(key);
23068
23148
  if (hit) return hit;
23069
23149
  const out = [];
23070
23150
  try {
23071
- const cfg = findGitConfig(import_path22.default.resolve(dir2), walkUp);
23151
+ const cfg = findGitConfig(import_path23.default.resolve(dir2), walkUp);
23072
23152
  if (cfg !== null) {
23073
23153
  let current = null;
23074
23154
  for (const line of cfg.split(/\r?\n/)) {
@@ -23104,15 +23184,15 @@ var ECOSYSTEMS = [
23104
23184
  ];
23105
23185
  var cache5 = /* @__PURE__ */ new Map();
23106
23186
  function manifestRoot(dir2) {
23107
- let cur = import_path23.default.resolve(dir2);
23187
+ let cur = import_path24.default.resolve(dir2);
23108
23188
  for (let i = 0; i < 64; i++) {
23109
23189
  for (const [m] of ECOSYSTEMS) {
23110
23190
  try {
23111
- if (import_fs22.default.existsSync(import_path23.default.join(cur, m))) return cur;
23191
+ if (import_fs22.default.existsSync(import_path24.default.join(cur, m))) return cur;
23112
23192
  } catch {
23113
23193
  }
23114
23194
  }
23115
- const parent = import_path23.default.dirname(cur);
23195
+ const parent = import_path24.default.dirname(cur);
23116
23196
  if (parent === cur) return null;
23117
23197
  cur = parent;
23118
23198
  }
@@ -23121,7 +23201,7 @@ function manifestRoot(dir2) {
23121
23201
  function knownProjectHosts(dir2) {
23122
23202
  const empty = { hosts: /* @__PURE__ */ new Set(), repos: /* @__PURE__ */ new Set(), remotes: /* @__PURE__ */ new Map() };
23123
23203
  if (!dir2) return empty;
23124
- const key = import_path23.default.resolve(dir2);
23204
+ const key = import_path24.default.resolve(dir2);
23125
23205
  const hit = cache5.get(key);
23126
23206
  if (hit) return hit;
23127
23207
  const out = { hosts: /* @__PURE__ */ new Set(), repos: /* @__PURE__ */ new Set(), remotes: /* @__PURE__ */ new Map() };
@@ -23134,7 +23214,7 @@ function knownProjectHosts(dir2) {
23134
23214
  const root = manifestRoot(key);
23135
23215
  if (root !== null) {
23136
23216
  for (const [m, registry] of ECOSYSTEMS) {
23137
- if (import_fs22.default.existsSync(import_path23.default.join(root, m))) out.hosts.add(registry);
23217
+ if (import_fs22.default.existsSync(import_path24.default.join(root, m))) out.hosts.add(registry);
23138
23218
  }
23139
23219
  try {
23140
23220
  if (import_fs22.default.readdirSync(root).some((f) => f.endsWith(".gemspec")))
@@ -23151,7 +23231,7 @@ function knownProjectHosts(dir2) {
23151
23231
  // src/exposure/writes.ts
23152
23232
  var import_fs23 = __toESM(require("fs"));
23153
23233
  var import_os16 = __toESM(require("os"));
23154
- var import_path24 = __toESM(require("path"));
23234
+ var import_path25 = __toESM(require("path"));
23155
23235
  init_dist();
23156
23236
  var WRITE_OPS = /* @__PURE__ */ new Set(["write", "create", "remove"]);
23157
23237
  var LIFECYCLE_RE = /"(scripts|preinstall|install|postinstall|prepare|prepublish|prepublishOnly|prepack|postpack|publish|postpublish)"\s*:/;
@@ -23202,7 +23282,7 @@ function judgeWritesAfterExposure(opts) {
23202
23282
  seen.add(p);
23203
23283
  if (p === "/dev" || p.startsWith("/dev/")) continue;
23204
23284
  if (root !== null && isInside(root, p)) {
23205
- if (isAgentInstructionPath(p, root) && (import_path24.default.basename(p) !== "package.json" || packageScriptsTouched(opts.args, p, opts.shellCommand)))
23285
+ if (isAgentInstructionPath(p, root) && (import_path25.default.basename(p) !== "package.json" || packageScriptsTouched(opts.args, p, opts.shellCommand)))
23206
23286
  holds.push({ path: p, why: "agent-instruction" });
23207
23287
  continue;
23208
23288
  }
@@ -23226,7 +23306,7 @@ function judgeWritesAfterExposure(opts) {
23226
23306
  var import_crypto9 = __toESM(require("crypto"));
23227
23307
  var import_fs24 = __toESM(require("fs"));
23228
23308
  var import_os17 = __toESM(require("os"));
23229
- var import_path25 = __toESM(require("path"));
23309
+ var import_path26 = __toESM(require("path"));
23230
23310
 
23231
23311
  // src/daemon/exposure-store.ts
23232
23312
  var SESSION_EXPOSURE_TTL_MS = 4 * 60 * 60 * 1e3;
@@ -23234,11 +23314,11 @@ var SESSION_EXPOSURE_TTL_MS = 4 * 60 * 60 * 1e3;
23234
23314
  // src/exposure/marker.ts
23235
23315
  init_forecast_context();
23236
23316
  function dir() {
23237
- return import_path25.default.join(import_os17.default.homedir(), ".node9", "exposure-sessions");
23317
+ return import_path26.default.join(import_os17.default.homedir(), ".node9", "exposure-sessions");
23238
23318
  }
23239
23319
  function file(sessionId) {
23240
23320
  const id = import_crypto9.default.createHash("sha256").update(sessionId).digest("hex").slice(0, 32);
23241
- return import_path25.default.join(dir(), id);
23321
+ return import_path26.default.join(dir(), id);
23242
23322
  }
23243
23323
  function maybeSessionExposed(sessionId) {
23244
23324
  if (!sessionId) return false;
@@ -23348,11 +23428,11 @@ function sourceWord(toolName) {
23348
23428
 
23349
23429
  // src/auth/trusted-recipients.ts
23350
23430
  var import_fs26 = __toESM(require("fs"));
23351
- var import_path26 = __toESM(require("path"));
23431
+ var import_path27 = __toESM(require("path"));
23352
23432
  var import_os18 = __toESM(require("os"));
23353
23433
  init_dist();
23354
23434
  function getTrustedRecipientsPath() {
23355
- return import_path26.default.join(import_os18.default.homedir(), ".node9", "trusted-recipients.json");
23435
+ return import_path27.default.join(import_os18.default.homedir(), ".node9", "trusted-recipients.json");
23356
23436
  }
23357
23437
  function readTrustedRecipients() {
23358
23438
  try {
@@ -23365,7 +23445,7 @@ function readTrustedRecipients() {
23365
23445
  }
23366
23446
  function writeTrustedRecipients(entries) {
23367
23447
  const filePath = getTrustedRecipientsPath();
23368
- import_fs26.default.mkdirSync(import_path26.default.dirname(filePath), { recursive: true });
23448
+ import_fs26.default.mkdirSync(import_path27.default.dirname(filePath), { recursive: true });
23369
23449
  const tmp = filePath + ".node9-tmp";
23370
23450
  import_fs26.default.writeFileSync(tmp, JSON.stringify({ entries }, null, 2), { mode: 384 });
23371
23451
  import_fs26.default.renameSync(tmp, filePath);
@@ -23402,7 +23482,7 @@ init_forecast_context();
23402
23482
  // src/auth/cloud.ts
23403
23483
  var import_fs27 = __toESM(require("fs"));
23404
23484
  var import_os19 = __toESM(require("os"));
23405
- var import_path27 = __toESM(require("path"));
23485
+ var import_path28 = __toESM(require("path"));
23406
23486
  init_audit();
23407
23487
  init_dist();
23408
23488
  var CLOUD_ARRAY_KEYS = /* @__PURE__ */ new Set(["exposureDestinations", "exposureDestinationHashes"]);
@@ -23438,7 +23518,7 @@ async function initNode9SaaS(toolName, args, creds, meta, riskMetadata, agentPol
23438
23518
  let ciContext;
23439
23519
  if (process.env.CI) {
23440
23520
  try {
23441
- const ciContextPath = import_path27.default.join(import_os19.default.homedir(), ".node9", "ci-context.json");
23521
+ const ciContextPath = import_path28.default.join(import_os19.default.homedir(), ".node9", "ci-context.json");
23442
23522
  const ci = readCappedText(ciContextPath, 1e4);
23443
23523
  if (!ci) throw new Error("ci-context.json unreadable");
23444
23524
  if (ci.truncated) throw new Error("ci-context.json exceeds 10 KB");
@@ -23573,13 +23653,13 @@ async function resolveNode9SaaS(requestId, creds, approved, decidedBy) {
23573
23653
 
23574
23654
  // src/loop-detector.ts
23575
23655
  var import_fs28 = __toESM(require("fs"));
23576
- var import_path28 = __toESM(require("path"));
23656
+ var import_path29 = __toESM(require("path"));
23577
23657
  var import_os20 = __toESM(require("os"));
23578
23658
  init_dist();
23579
23659
  init_forecast_context();
23580
23660
  init_dist();
23581
23661
  function loopStateFile() {
23582
- return import_path28.default.join(import_os20.default.homedir(), ".node9", "loop-state.json");
23662
+ return import_path29.default.join(import_os20.default.homedir(), ".node9", "loop-state.json");
23583
23663
  }
23584
23664
  function readState() {
23585
23665
  try {
@@ -23593,7 +23673,7 @@ function readState() {
23593
23673
  }
23594
23674
  }
23595
23675
  function writeState(records) {
23596
- const dir2 = import_path28.default.dirname(loopStateFile());
23676
+ const dir2 = import_path29.default.dirname(loopStateFile());
23597
23677
  if (!import_fs28.default.existsSync(dir2)) import_fs28.default.mkdirSync(dir2, { recursive: true });
23598
23678
  const tmpPath = `${loopStateFile()}.${import_os20.default.hostname()}.${process.pid}.tmp`;
23599
23679
  import_fs28.default.writeFileSync(tmpPath, JSON.stringify(records));
@@ -23793,9 +23873,9 @@ function isMcpToolName(toolName) {
23793
23873
  return /^mcp__[^_](?:[^_]|_(?!_))*?__/i.test(toolName);
23794
23874
  }
23795
23875
  function absoluteUploadPath(spelled, cwd) {
23796
- const expanded = spelled === "~" || spelled.startsWith("~/") ? import_path29.default.join(import_os21.default.homedir(), spelled.slice(1)) : spelled;
23797
- if (import_path29.default.isAbsolute(expanded)) return expanded;
23798
- return cwd && import_path29.default.isAbsolute(cwd) ? import_path29.default.resolve(cwd, expanded) : expanded;
23876
+ const expanded = spelled === "~" || spelled.startsWith("~/") ? import_path30.default.join(import_os21.default.homedir(), spelled.slice(1)) : spelled;
23877
+ if (import_path30.default.isAbsolute(expanded)) return expanded;
23878
+ return cwd && import_path30.default.isAbsolute(cwd) ? import_path30.default.resolve(cwd, expanded) : expanded;
23799
23879
  }
23800
23880
  function extractFilePaths(toolName, args, shellCommand) {
23801
23881
  const paths = [];