nexus-agents 11.5.4 → 11.5.5

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 (151) hide show
  1. package/dist/{ast-rule-runner-UIBITXDJ.js → ast-rule-runner-CVDVRVAS.js} +7 -7
  2. package/dist/{child-mcp-config-EMNCNHKM.js → child-mcp-config-H5G3DK7S.js} +7 -7
  3. package/dist/{chunk-CH6IBWXH.js → chunk-356WC2D4.js} +39 -9
  4. package/dist/chunk-356WC2D4.js.map +1 -0
  5. package/dist/{chunk-TH3MSFDF.js → chunk-3RVTDYT7.js} +44 -45
  6. package/dist/{chunk-TH3MSFDF.js.map → chunk-3RVTDYT7.js.map} +1 -1
  7. package/dist/{chunk-5FYSIB3L.js → chunk-3VH6RBVJ.js} +2 -2
  8. package/dist/{chunk-DFRQP7AM.js → chunk-432FGBZR.js} +3 -3
  9. package/dist/{chunk-QBP4VHJF.js → chunk-4JCRCOOV.js} +4 -4
  10. package/dist/{chunk-O76YJOEG.js → chunk-4PNQ3OUO.js} +2 -2
  11. package/dist/{chunk-4DHC2TDC.js → chunk-5BYTGR63.js} +4 -4
  12. package/dist/{chunk-Y3A3VVGT.js → chunk-5EYCAD6W.js} +9 -8
  13. package/dist/chunk-5EYCAD6W.js.map +1 -0
  14. package/dist/{chunk-WSLPF7BX.js → chunk-5SZD2I3X.js} +4 -4
  15. package/dist/{chunk-ZDNXBCOP.js → chunk-6FHFS2QA.js} +2 -2
  16. package/dist/{chunk-WM2BE65D.js → chunk-6V4ERXGA.js} +10 -10
  17. package/dist/{chunk-4IN3DHXY.js → chunk-6YWQAEAN.js} +2 -2
  18. package/dist/{chunk-W56VP6JH.js → chunk-7P7TBPXE.js} +4 -4
  19. package/dist/{chunk-4S77S56F.js → chunk-AKNZ5SZW.js} +2 -2
  20. package/dist/{chunk-N5DHPHPE.js → chunk-AUO7FSZX.js} +2 -2
  21. package/dist/{chunk-U7HL7FGS.js → chunk-CBDUTJJC.js} +2 -2
  22. package/dist/{chunk-RUHKJC3X.js → chunk-CBN5IKTG.js} +2 -2
  23. package/dist/{chunk-HH4FMRXL.js → chunk-CYI7ZAMR.js} +19 -18
  24. package/dist/chunk-CYI7ZAMR.js.map +1 -0
  25. package/dist/{chunk-XBXLA6DJ.js → chunk-EA234IFY.js} +8 -8
  26. package/dist/{chunk-AH4Y7Z6S.js → chunk-EBMDEUH7.js} +7 -7
  27. package/dist/{chunk-V2DJZZKS.js → chunk-EFDMPXMP.js} +2 -2
  28. package/dist/{chunk-JKYOZIDM.js → chunk-FOKNFLXF.js} +2 -2
  29. package/dist/{chunk-LEPAOFIF.js → chunk-GP2SE2FW.js} +8 -8
  30. package/dist/{chunk-FYXIWH62.js → chunk-GW35PEDO.js} +2 -2
  31. package/dist/{chunk-VMGKPEVR.js → chunk-JRGPMF67.js} +7 -7
  32. package/dist/{chunk-BGELNT5F.js → chunk-JYZDA5Z7.js} +5 -5
  33. package/dist/{chunk-6MOCJOKU.js → chunk-K6OPXID6.js} +2 -2
  34. package/dist/{chunk-65ENP3HN.js → chunk-KUAYIDEG.js} +2 -2
  35. package/dist/{chunk-FGR6O454.js → chunk-LNGZKTJL.js} +3 -3
  36. package/dist/{chunk-FQFCLNYM.js → chunk-PY6GUS22.js} +2 -2
  37. package/dist/{chunk-BCC27PGX.js → chunk-Q7FEF3YH.js} +3 -3
  38. package/dist/{chunk-NKITVLTK.js → chunk-SNLDHZQ5.js} +4 -4
  39. package/dist/{chunk-CSDGNGAG.js → chunk-T6DZTVDF.js} +2 -2
  40. package/dist/{chunk-5TW3NLWA.js → chunk-TNZSALI4.js} +7 -7
  41. package/dist/chunk-TNZSALI4.js.map +1 -0
  42. package/dist/{chunk-IQYJPOMW.js → chunk-UMX44QLL.js} +4 -4
  43. package/dist/{chunk-VA247HQO.js → chunk-XJEV7JH2.js} +11 -11
  44. package/dist/{chunk-KXD7ZJWM.js → chunk-Z5NCR7DH.js} +2 -2
  45. package/dist/{chunk-6V25ZIPU.js → chunk-ZQYQZ7FQ.js} +15 -15
  46. package/dist/{cli-circuit-breaker-MBEEEQUD.js → cli-circuit-breaker-7QJ4SIGM.js} +7 -7
  47. package/dist/{cli-readiness-NQKW6M27.js → cli-readiness-6WFM5N4I.js} +10 -10
  48. package/dist/{cli-server-gateway-UQC4FDQH.js → cli-server-gateway-TA7TRBJ5.js} +16 -16
  49. package/dist/cli.js +113 -70
  50. package/dist/cli.js.map +1 -1
  51. package/dist/{composite-router-VDDTC263.js → composite-router-52ZLFXVR.js} +6 -6
  52. package/dist/{consensus-vote-KQTXJS5E.js → consensus-vote-FPSXMIFK.js} +21 -21
  53. package/dist/{context-retriever-BJIUY6QW.js → context-retriever-HTBOLH5P.js} +13 -13
  54. package/dist/{doctor-deep-LGOSW75C.js → doctor-deep-TTIMGYHS.js} +7 -7
  55. package/dist/{doctor-gateway-report-WCPLTO7X.js → doctor-gateway-report-I4AFMGUC.js} +10 -10
  56. package/dist/{doctor-live-DFGOZPZ2.js → doctor-live-E5ZMGVXF.js} +16 -16
  57. package/dist/{expert-bridge-GFO6QWXL.js → expert-bridge-F6NAPNZC.js} +8 -8
  58. package/dist/{factory-RZVZ6BLF.js → factory-7IAD2557.js} +15 -15
  59. package/dist/{factory-P45WM7Y5.js → factory-FO6ICRSI.js} +9 -9
  60. package/dist/{improvement-review-6PXKRGRU.js → improvement-review-536ZRPUI.js} +9 -9
  61. package/dist/index.js +34 -34
  62. package/dist/{init-opencode-UTUYKUJ5.js → init-opencode-46DMB7VH.js} +8 -8
  63. package/dist/{issue-triage-RUA2254S.js → issue-triage-LBR6OJQ3.js} +9 -9
  64. package/dist/{learning-persistence-X24OOBYY.js → learning-persistence-RXI2ASRC.js} +3 -3
  65. package/dist/{model-config-helpers-ZIVSTS76.js → model-config-helpers-PSOLGUS4.js} +4 -4
  66. package/dist/{openai-compat-adapter-BAHSQKIS.js → openai-compat-adapter-ARDUWHBA.js} +8 -8
  67. package/dist/{pr-reviewer-helpers-J2KQYHPB.js → pr-reviewer-helpers-YVHGQLCF.js} +7 -7
  68. package/dist/{registry-command-BCNWYA6P.js → registry-command-7FRS53FH.js} +3 -3
  69. package/dist/{repo-security-plan-OZHFTQB3.js → repo-security-plan-YINATBVX.js} +6 -6
  70. package/dist/{research-helpers-synthesize-BY7RH4B3.js → research-helpers-synthesize-VRWS6GBM.js} +8 -8
  71. package/dist/{routing-memory-TVITESTN.js → routing-memory-52ZSJBWK.js} +6 -6
  72. package/dist/{session-memory-C4R2RA4D.js → session-memory-PDVXENIX.js} +7 -7
  73. package/dist/{setup-config-Q6MJ7HWN.js → setup-config-XEAU5FMU.js} +7 -7
  74. package/dist/{setup-custom-api-GOM3HW5G.js → setup-custom-api-BTGG5HNE.js} +8 -8
  75. package/dist/setup-data-dir-FMHY5AVX.js +40 -0
  76. package/dist/{tool-memory-PHPWXWS3.js → tool-memory-VFHAQIEN.js} +10 -10
  77. package/dist/{tool-memory-registry-adapters-IIORYBCC.js → tool-memory-registry-adapters-2FUUCWAG.js} +3 -3
  78. package/dist/{unified-registry-GXELRMCT.js → unified-registry-KHXB62QQ.js} +15 -15
  79. package/dist/{weather-report-OIWO4BCH.js → weather-report-DZLWIKOZ.js} +6 -6
  80. package/package.json +1 -1
  81. package/dist/chunk-5TW3NLWA.js.map +0 -1
  82. package/dist/chunk-CH6IBWXH.js.map +0 -1
  83. package/dist/chunk-HH4FMRXL.js.map +0 -1
  84. package/dist/chunk-Y3A3VVGT.js.map +0 -1
  85. package/dist/setup-data-dir-AY6JK4P6.js +0 -40
  86. /package/dist/{ast-rule-runner-UIBITXDJ.js.map → ast-rule-runner-CVDVRVAS.js.map} +0 -0
  87. /package/dist/{child-mcp-config-EMNCNHKM.js.map → child-mcp-config-H5G3DK7S.js.map} +0 -0
  88. /package/dist/{chunk-5FYSIB3L.js.map → chunk-3VH6RBVJ.js.map} +0 -0
  89. /package/dist/{chunk-DFRQP7AM.js.map → chunk-432FGBZR.js.map} +0 -0
  90. /package/dist/{chunk-QBP4VHJF.js.map → chunk-4JCRCOOV.js.map} +0 -0
  91. /package/dist/{chunk-O76YJOEG.js.map → chunk-4PNQ3OUO.js.map} +0 -0
  92. /package/dist/{chunk-4DHC2TDC.js.map → chunk-5BYTGR63.js.map} +0 -0
  93. /package/dist/{chunk-WSLPF7BX.js.map → chunk-5SZD2I3X.js.map} +0 -0
  94. /package/dist/{chunk-ZDNXBCOP.js.map → chunk-6FHFS2QA.js.map} +0 -0
  95. /package/dist/{chunk-WM2BE65D.js.map → chunk-6V4ERXGA.js.map} +0 -0
  96. /package/dist/{chunk-4IN3DHXY.js.map → chunk-6YWQAEAN.js.map} +0 -0
  97. /package/dist/{chunk-W56VP6JH.js.map → chunk-7P7TBPXE.js.map} +0 -0
  98. /package/dist/{chunk-4S77S56F.js.map → chunk-AKNZ5SZW.js.map} +0 -0
  99. /package/dist/{chunk-N5DHPHPE.js.map → chunk-AUO7FSZX.js.map} +0 -0
  100. /package/dist/{chunk-U7HL7FGS.js.map → chunk-CBDUTJJC.js.map} +0 -0
  101. /package/dist/{chunk-RUHKJC3X.js.map → chunk-CBN5IKTG.js.map} +0 -0
  102. /package/dist/{chunk-XBXLA6DJ.js.map → chunk-EA234IFY.js.map} +0 -0
  103. /package/dist/{chunk-AH4Y7Z6S.js.map → chunk-EBMDEUH7.js.map} +0 -0
  104. /package/dist/{chunk-V2DJZZKS.js.map → chunk-EFDMPXMP.js.map} +0 -0
  105. /package/dist/{chunk-JKYOZIDM.js.map → chunk-FOKNFLXF.js.map} +0 -0
  106. /package/dist/{chunk-LEPAOFIF.js.map → chunk-GP2SE2FW.js.map} +0 -0
  107. /package/dist/{chunk-FYXIWH62.js.map → chunk-GW35PEDO.js.map} +0 -0
  108. /package/dist/{chunk-VMGKPEVR.js.map → chunk-JRGPMF67.js.map} +0 -0
  109. /package/dist/{chunk-BGELNT5F.js.map → chunk-JYZDA5Z7.js.map} +0 -0
  110. /package/dist/{chunk-6MOCJOKU.js.map → chunk-K6OPXID6.js.map} +0 -0
  111. /package/dist/{chunk-65ENP3HN.js.map → chunk-KUAYIDEG.js.map} +0 -0
  112. /package/dist/{chunk-FGR6O454.js.map → chunk-LNGZKTJL.js.map} +0 -0
  113. /package/dist/{chunk-FQFCLNYM.js.map → chunk-PY6GUS22.js.map} +0 -0
  114. /package/dist/{chunk-BCC27PGX.js.map → chunk-Q7FEF3YH.js.map} +0 -0
  115. /package/dist/{chunk-NKITVLTK.js.map → chunk-SNLDHZQ5.js.map} +0 -0
  116. /package/dist/{chunk-CSDGNGAG.js.map → chunk-T6DZTVDF.js.map} +0 -0
  117. /package/dist/{chunk-IQYJPOMW.js.map → chunk-UMX44QLL.js.map} +0 -0
  118. /package/dist/{chunk-VA247HQO.js.map → chunk-XJEV7JH2.js.map} +0 -0
  119. /package/dist/{chunk-KXD7ZJWM.js.map → chunk-Z5NCR7DH.js.map} +0 -0
  120. /package/dist/{chunk-6V25ZIPU.js.map → chunk-ZQYQZ7FQ.js.map} +0 -0
  121. /package/dist/{cli-circuit-breaker-MBEEEQUD.js.map → cli-circuit-breaker-7QJ4SIGM.js.map} +0 -0
  122. /package/dist/{cli-readiness-NQKW6M27.js.map → cli-readiness-6WFM5N4I.js.map} +0 -0
  123. /package/dist/{cli-server-gateway-UQC4FDQH.js.map → cli-server-gateway-TA7TRBJ5.js.map} +0 -0
  124. /package/dist/{composite-router-VDDTC263.js.map → composite-router-52ZLFXVR.js.map} +0 -0
  125. /package/dist/{consensus-vote-KQTXJS5E.js.map → consensus-vote-FPSXMIFK.js.map} +0 -0
  126. /package/dist/{context-retriever-BJIUY6QW.js.map → context-retriever-HTBOLH5P.js.map} +0 -0
  127. /package/dist/{doctor-deep-LGOSW75C.js.map → doctor-deep-TTIMGYHS.js.map} +0 -0
  128. /package/dist/{doctor-gateway-report-WCPLTO7X.js.map → doctor-gateway-report-I4AFMGUC.js.map} +0 -0
  129. /package/dist/{doctor-live-DFGOZPZ2.js.map → doctor-live-E5ZMGVXF.js.map} +0 -0
  130. /package/dist/{expert-bridge-GFO6QWXL.js.map → expert-bridge-F6NAPNZC.js.map} +0 -0
  131. /package/dist/{factory-P45WM7Y5.js.map → factory-7IAD2557.js.map} +0 -0
  132. /package/dist/{factory-RZVZ6BLF.js.map → factory-FO6ICRSI.js.map} +0 -0
  133. /package/dist/{improvement-review-6PXKRGRU.js.map → improvement-review-536ZRPUI.js.map} +0 -0
  134. /package/dist/{init-opencode-UTUYKUJ5.js.map → init-opencode-46DMB7VH.js.map} +0 -0
  135. /package/dist/{issue-triage-RUA2254S.js.map → issue-triage-LBR6OJQ3.js.map} +0 -0
  136. /package/dist/{learning-persistence-X24OOBYY.js.map → learning-persistence-RXI2ASRC.js.map} +0 -0
  137. /package/dist/{model-config-helpers-ZIVSTS76.js.map → model-config-helpers-PSOLGUS4.js.map} +0 -0
  138. /package/dist/{openai-compat-adapter-BAHSQKIS.js.map → openai-compat-adapter-ARDUWHBA.js.map} +0 -0
  139. /package/dist/{pr-reviewer-helpers-J2KQYHPB.js.map → pr-reviewer-helpers-YVHGQLCF.js.map} +0 -0
  140. /package/dist/{registry-command-BCNWYA6P.js.map → registry-command-7FRS53FH.js.map} +0 -0
  141. /package/dist/{repo-security-plan-OZHFTQB3.js.map → repo-security-plan-YINATBVX.js.map} +0 -0
  142. /package/dist/{research-helpers-synthesize-BY7RH4B3.js.map → research-helpers-synthesize-VRWS6GBM.js.map} +0 -0
  143. /package/dist/{routing-memory-TVITESTN.js.map → routing-memory-52ZSJBWK.js.map} +0 -0
  144. /package/dist/{session-memory-C4R2RA4D.js.map → session-memory-PDVXENIX.js.map} +0 -0
  145. /package/dist/{setup-config-Q6MJ7HWN.js.map → setup-config-XEAU5FMU.js.map} +0 -0
  146. /package/dist/{setup-custom-api-GOM3HW5G.js.map → setup-custom-api-BTGG5HNE.js.map} +0 -0
  147. /package/dist/{setup-data-dir-AY6JK4P6.js.map → setup-data-dir-FMHY5AVX.js.map} +0 -0
  148. /package/dist/{tool-memory-PHPWXWS3.js.map → tool-memory-VFHAQIEN.js.map} +0 -0
  149. /package/dist/{tool-memory-registry-adapters-IIORYBCC.js.map → tool-memory-registry-adapters-2FUUCWAG.js.map} +0 -0
  150. /package/dist/{unified-registry-GXELRMCT.js.map → unified-registry-KHXB62QQ.js.map} +0 -0
  151. /package/dist/{weather-report-OIWO4BCH.js.map → weather-report-DZLWIKOZ.js.map} +0 -0
@@ -9,15 +9,15 @@ import {
9
9
  getBuiltInAstRulesPath,
10
10
  loadRules,
11
11
  runAstQaRules
12
- } from "./chunk-FYXIWH62.js";
13
- import "./chunk-WM2BE65D.js";
12
+ } from "./chunk-GW35PEDO.js";
13
+ import "./chunk-6V4ERXGA.js";
14
14
  import "./chunk-XBEKMUTO.js";
15
- import "./chunk-5FYSIB3L.js";
16
- import "./chunk-5TW3NLWA.js";
17
- import "./chunk-RUHKJC3X.js";
15
+ import "./chunk-3VH6RBVJ.js";
16
+ import "./chunk-TNZSALI4.js";
17
+ import "./chunk-CBN5IKTG.js";
18
18
  import "./chunk-UFAK5UGH.js";
19
19
  import "./chunk-GR6WCJWY.js";
20
- import "./chunk-CH6IBWXH.js";
20
+ import "./chunk-356WC2D4.js";
21
21
  import "./chunk-6TBRXZY7.js";
22
22
  import "./chunk-SYTFRVWX.js";
23
23
  import "./chunk-MTN5VMBX.js";
@@ -34,4 +34,4 @@ export {
34
34
  loadRules,
35
35
  runAstQaRules
36
36
  };
37
- //# sourceMappingURL=ast-rule-runner-UIBITXDJ.js.map
37
+ //# sourceMappingURL=ast-rule-runner-CVDVRVAS.js.map
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  nexusMkdtempSync
3
- } from "./chunk-U7HL7FGS.js";
4
- import "./chunk-WM2BE65D.js";
3
+ } from "./chunk-CBDUTJJC.js";
4
+ import "./chunk-6V4ERXGA.js";
5
5
  import "./chunk-XBEKMUTO.js";
6
- import "./chunk-5FYSIB3L.js";
7
- import "./chunk-5TW3NLWA.js";
8
- import "./chunk-RUHKJC3X.js";
6
+ import "./chunk-3VH6RBVJ.js";
7
+ import "./chunk-TNZSALI4.js";
8
+ import "./chunk-CBN5IKTG.js";
9
9
  import "./chunk-UFAK5UGH.js";
10
10
  import {
11
11
  createLogger
12
12
  } from "./chunk-GR6WCJWY.js";
13
- import "./chunk-CH6IBWXH.js";
13
+ import "./chunk-356WC2D4.js";
14
14
  import "./chunk-6TBRXZY7.js";
15
15
  import "./chunk-SYTFRVWX.js";
16
16
  import "./chunk-MTN5VMBX.js";
@@ -81,4 +81,4 @@ async function generateMcpConfig(options) {
81
81
  export {
82
82
  generateMcpConfig
83
83
  };
84
- //# sourceMappingURL=child-mcp-config-EMNCNHKM.js.map
84
+ //# sourceMappingURL=child-mcp-config-H5G3DK7S.js.map
@@ -272,7 +272,7 @@ function detectPortableMode(cwd = process.cwd()) {
272
272
  reason: "default"
273
273
  };
274
274
  }
275
- function applyPortableMode(cwd = process.cwd()) {
275
+ function applyPortableMode(cwd = process.cwd(), options = {}) {
276
276
  if (DETECTED) return;
277
277
  DETECTED = true;
278
278
  const result = detectPortableMode(cwd);
@@ -286,7 +286,14 @@ function applyPortableMode(cwd = process.cwd()) {
286
286
  }
287
287
  process.env["NEXUS_DATA_DIR"] = result.dataDir;
288
288
  if (isInsideGitRepo(cwd)) {
289
- ensureGitignored(cwd, ".nexus-agents/");
289
+ if (options.dryRun === true) {
290
+ process.stderr.write(
291
+ `[portable-mode] Would add '.nexus-agents/' to ${join2(cwd, ".gitignore")}.
292
+ `
293
+ );
294
+ } else {
295
+ ensureGitignored(cwd, ".nexus-agents/");
296
+ }
290
297
  }
291
298
  }
292
299
  function isInsideGitRepo(cwd) {
@@ -395,10 +402,11 @@ function getNexusRepoDir(options = {}) {
395
402
  const found = activeWorkspaceRoot ?? findRepoRoot(process.cwd());
396
403
  if (found === null) return null;
397
404
  const root = options.mainCheckout === true ? resolveMainCheckoutRoot(found) : found;
398
- maybeAutoGitignore(root);
405
+ maybeAutoGitignore(root, options.readOnly);
399
406
  return join3(root, ".nexus-agents");
400
407
  }
401
- function maybeAutoGitignore(repoRoot) {
408
+ function maybeAutoGitignore(repoRoot, readOnly = false) {
409
+ if (readOnly) return;
402
410
  if (!parseBoolEnv("NEXUS_GITIGNORE_AUTO", true)) return;
403
411
  if (gitignoredRoots.has(repoRoot)) return;
404
412
  gitignoredRoots.add(repoRoot);
@@ -419,6 +427,21 @@ function isHomedirBaseWritable() {
419
427
  }
420
428
  return homedirWritable;
421
429
  }
430
+ function isHomedirBaseWritableReadOnly() {
431
+ let target = getNexusDataDir();
432
+ try {
433
+ while (!existsSync4(target)) {
434
+ const parent = dirname2(target);
435
+ if (parent === target) return false;
436
+ target = parent;
437
+ }
438
+ if (!statSync3(target).isDirectory()) return false;
439
+ accessSync2(target, fsConstants.W_OK | fsConstants.X_OK);
440
+ return true;
441
+ } catch {
442
+ return false;
443
+ }
444
+ }
422
445
  function announceCrossRepoFallback(subdir, repoPath) {
423
446
  if (announcedFallbacks.has(subdir)) return;
424
447
  announcedFallbacks.add(subdir);
@@ -428,18 +451,24 @@ function announceCrossRepoFallback(subdir, repoPath) {
428
451
  );
429
452
  }
430
453
  function nexusDataPath(...segments) {
454
+ return resolveNexusDataPath(segments, false);
455
+ }
456
+ function previewNexusDataPath(...segments) {
457
+ return resolveNexusDataPath(segments, true);
458
+ }
459
+ function resolveNexusDataPath(segments, readOnly) {
431
460
  const first = segments[0];
432
461
  if (first !== void 0 && PER_REPO_SUBDIRS.has(first)) {
433
- const repoDir = getNexusRepoDir({ mainCheckout: MAIN_CHECKOUT_SUBDIRS.has(first) });
462
+ const repoDir = getNexusRepoDir({ mainCheckout: MAIN_CHECKOUT_SUBDIRS.has(first), readOnly });
434
463
  if (repoDir !== null) {
435
464
  return join3(repoDir, ...segments);
436
465
  }
437
466
  }
438
- if (first !== void 0 && !isHomedirBaseWritable()) {
439
- const repoDir = getNexusRepoDir();
467
+ if (first !== void 0 && !(readOnly ? isHomedirBaseWritableReadOnly() : isHomedirBaseWritable())) {
468
+ const repoDir = getNexusRepoDir({ readOnly });
440
469
  if (repoDir !== null) {
441
470
  const fallbackPath = join3(repoDir, ...segments);
442
- announceCrossRepoFallback(first, fallbackPath);
471
+ if (!readOnly) announceCrossRepoFallback(first, fallbackPath);
443
472
  return fallbackPath;
444
473
  }
445
474
  }
@@ -504,9 +533,10 @@ export {
504
533
  getActiveWorkspaceRoot,
505
534
  getNexusRepoDir,
506
535
  nexusDataPath,
536
+ previewNexusDataPath,
507
537
  nexusDataPathEnsure,
508
538
  nexusSharedPath,
509
539
  getPerRepoSubdirs,
510
540
  sessionsDbPath
511
541
  };
512
- //# sourceMappingURL=chunk-CH6IBWXH.js.map
542
+ //# sourceMappingURL=chunk-356WC2D4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config/sandbox-detection.ts","../src/config/defaults-env.ts","../src/config/nexus-data-dir.ts","../src/config/repo-root-detection.ts","../src/config/portable-mode.ts"],"sourcesContent":["/**\n * Sandbox detection (#2501, child 1 of epic #2500).\n *\n * nexus-agents needs to know whether it's running inside a host-provided\n * sandbox (Docker Desktop Sandbox + OpenCode, Codex sandbox, locked-down\n * CI runner) so it can adjust behaviour:\n *\n * - default `NEXUS_DATA_DIR` to the multi-repo root rather than `~/...`\n * - skip CLI subprocess detection (binaries aren't there)\n * - fail-fast when the gateway is unreachable instead of degrading\n * - suppress diagnostics that don't apply\n *\n * The signal is **explicit**: the image author (Dockerfile, devcontainer,\n * harness wrapper) sets `NEXUS_SANDBOX=<flavor>`. The flavor string is\n * for diagnostics + per-flavor branching (`docker-opencode`, `codex`,\n * `claude-code`, `ci-restricted`, …); presence is the on/off signal.\n *\n * A heuristic check runs alongside for verification — if `NEXUS_SANDBOX`\n * claims `docker-opencode` but `/.dockerenv` is missing, that's a\n * misconfiguration worth surfacing to the operator.\n *\n * @module config/sandbox-detection\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\n\n/**\n * Heuristic detection result. Independent from the explicit\n * `NEXUS_SANDBOX` env var; produced by inspecting filesystem markers.\n */\nexport type SandboxHeuristic = 'docker' | 'podman' | 'unknown' | null;\n\nexport interface SandboxInfo {\n /**\n * True iff `NEXUS_SANDBOX` is set + non-empty. The explicit signal\n * the rest of the codebase keys off — never `true` by heuristic alone.\n */\n readonly active: boolean;\n /**\n * Operator-supplied flavor string, e.g. `docker-opencode`. Undefined\n * when `active === false` or the env var is empty.\n */\n readonly flavor: string | undefined;\n /**\n * Multi-repo root the user mounted. From `NEXUS_SANDBOX_ROOT`. Undefined\n * when unset; consumers that need a default substitute `/`.\n */\n readonly root: string | undefined;\n /**\n * Independent heuristic match — `null` when we couldn't run the check,\n * `'unknown'` when ran but no marker matched. Used by `doctor` to flag\n * mismatches between the explicit signal and the runtime environment.\n */\n readonly heuristicMatch: SandboxHeuristic;\n}\n\n/**\n * Detect whether nexus-agents is running inside a host-provided sandbox.\n * Pure read of env + filesystem; no caching (cheap enough to recompute,\n * and tests routinely mutate process.env).\n */\nexport function detectSandbox(): SandboxInfo {\n const flavorRaw = process.env['NEXUS_SANDBOX']?.trim();\n const flavor = flavorRaw !== undefined && flavorRaw !== '' ? flavorRaw : undefined;\n const active = flavor !== undefined;\n\n const rootRaw = process.env['NEXUS_SANDBOX_ROOT']?.trim();\n const root = rootRaw !== undefined && rootRaw !== '' ? rootRaw : undefined;\n\n return {\n active,\n flavor,\n root,\n heuristicMatch: detectContainerHeuristic(),\n };\n}\n\n/**\n * Look for filesystem markers indicating a container runtime. Used as a\n * cross-check against the explicit `NEXUS_SANDBOX` signal.\n *\n * Order of checks:\n * 1. `/.dockerenv` (Docker)\n * 2. `/run/.containerenv` (Podman)\n * 3. `/proc/1/cgroup` containing `docker` or `containerd` strings\n *\n * Returns `null` when none of the checks could run (non-Linux host with\n * no `/proc`, sandbox blocks `existsSync`, etc.) — distinct from\n * `'unknown'` (checks ran, no marker matched) so the doctor message can\n * differentiate \"we couldn't tell\" from \"we checked, no container\".\n */\nfunction detectContainerHeuristic(): SandboxHeuristic {\n try {\n if (existsSync('/.dockerenv')) return 'docker';\n if (existsSync('/run/.containerenv')) return 'podman';\n if (existsSync('/proc/1/cgroup')) {\n const cgroup = readFileSync('/proc/1/cgroup', 'utf8');\n if (/\\bdocker\\b/.test(cgroup)) return 'docker';\n if (/\\bcontainerd\\b/.test(cgroup)) return 'docker';\n }\n return 'unknown';\n } catch {\n return null;\n }\n}\n","/**\n * Environment Variable Override Helpers\n *\n * Provides utilities for reading configuration from environment variables\n * with type-safe fallbacks to defaults.\n *\n * @module config/defaults-env\n */\n\nimport type { ToolRateLimitConfig } from './defaults-types.js';\n\n// ============================================================================\n// Environment Variable Parsers\n// ============================================================================\n\n/**\n * Parses an integer from an environment variable with fallback.\n */\nexport function parseIntEnv(envKey: string, fallback: number): number {\n const envValue = process.env[envKey];\n if (envValue === undefined) {\n return fallback;\n }\n const parsed = parseInt(envValue, 10);\n return isNaN(parsed) || parsed <= 0 ? fallback : parsed;\n}\n\n/**\n * Parses a float from an environment variable with fallback.\n */\nexport function parseFloatEnv(envKey: string, fallback: number): number {\n const envValue = process.env[envKey];\n if (envValue === undefined) {\n return fallback;\n }\n const parsed = parseFloat(envValue);\n return isNaN(parsed) || !isFinite(parsed) ? fallback : parsed;\n}\n\n/**\n * Parses a boolean flag value with fallback — the ONE accept-set for every\n * `NEXUS_*` boolean flag (#5155): `true`/`1` are truthy, `false`/`0` are\n * falsy, case-insensitively. Any other value (including `yes`/`no`/`on`/`off`\n * and the empty string) returns the fallback; `config/env-schema.ts`\n * (`boolLooseStr`) reports those at startup so the fallback is never silent.\n *\n * Pure so consumers that read an injected env object rather than\n * `process.env` (e.g. `cli-adapters/subprocess-env.ts`) share the same set.\n */\nexport function parseBoolValue(value: string | undefined, fallback: boolean): boolean {\n const normalized = value?.toLowerCase();\n if (normalized === undefined) {\n return fallback;\n }\n if (normalized === 'true' || normalized === '1') return true;\n if (normalized === 'false' || normalized === '0') return false;\n return fallback;\n}\n\n/**\n * Parses a boolean from an environment variable with fallback.\n * Delegates to {@link parseBoolValue}: only 'true'/'1' are truthy,\n * 'false'/'0' are falsy (case-insensitive); any other value returns the fallback.\n */\nexport function parseBoolEnv(envKey: string, fallback: boolean): boolean {\n return parseBoolValue(process.env[envKey], fallback);\n}\n\n// ============================================================================\n// Config Getter Types (for lazy initialization)\n// ============================================================================\n\n// The hand-written TimeoutDefaultsConst interface that lived here was removed\n// in #4939 with its last consumer (createGetTimeout); the exported type of the\n// same name is `typeof DEFAULTS.TIMEOUT_DEFAULTS` in config/defaults.ts.\n\n/** Tool rate limits type from DEFAULTS object */\nexport interface ToolRateLimitsConst {\n readonly orchestrate: ToolRateLimitConfig;\n readonly delegate: ToolRateLimitConfig;\n readonly workflow: ToolRateLimitConfig;\n readonly expert: ToolRateLimitConfig;\n}\n\n// ============================================================================\n// Config Getter Factory Functions\n// ============================================================================\n\n// createGetTimeout removed in #4939. It built `NEXUS_TIMEOUT_<KEY>` names at\n// runtime for a getter (getTimeout) with zero production callers, so the four\n// registered names — NEXUS_TIMEOUT_{CLI,API,WORKFLOW,MCP} — were read by nothing\n// that runs. Same class as the removals below.\n//\n// createGetWorkerConfig removed in #2977. createGetRetryConfig,\n// createGetRateLimitConfig and createGetCircuitBreakerConfig removed in #5903\n// for the same reason: their twelve NEXUS_* variables were registered,\n// documented and echoed back by `config get` as `Source: (env)`, and read by\n// nothing that runs. The rate limiter takes `enabled` from the config file\n// (`cli-server-tools.ts`), retry builds DEFAULT_RETRY_CONFIG from the static\n// DEFAULTS (`adapters/retry.ts`), and the production circuit breakers carry\n// their own config. See the comment in config/defaults.ts.\n\n/**\n * Creates a tool rate limit getter function bound to the DEFAULTS object.\n */\nexport function createGetToolRateLimit(\n toolRateLimits: ToolRateLimitsConst\n): (tool: keyof ToolRateLimitsConst) => ToolRateLimitConfig {\n return (tool: keyof ToolRateLimitsConst): ToolRateLimitConfig => {\n return toolRateLimits[tool];\n };\n}\n\n// createGetEnvVarDocumentation removed in #4939: its last remaining table was\n// the four NEXUS_TIMEOUT_* rows, all of which named unread variables.\n","/**\n * Nexus runtime data directory resolver (#2302, child of #2301).\n *\n * Returns the absolute path under which nexus-agents stores runtime state.\n * Two categories of state exist (epic #2872, vote #2876):\n *\n * - **Per-repo** state (sessions, checkpoints, traces, runs, audit,\n * pipeline, tasks) — tied to the work happening in a specific codebase.\n * When `NEXUS_REPO_PREFERRED=1` is set and the caller is inside a git\n * repo, these resolve to `<repo-root>/.nexus-agents/<subdir>/`.\n * - **Cross-repo** state (learning, voting, memory, weather, research,\n * auth, usage, models manifest) — accumulates across the operator's\n * whole workflow. Always resolves to `~/.nexus-agents/<subdir>/` so the\n * learning/routing feedback loop from #1389 / #1407 keeps working.\n *\n * Resolution order (first match wins):\n * 1. `NEXUS_DATA_DIR` env var if set + non-empty. Wins for both categories\n * — the operator's explicit choice overrides the split.\n * 2. Sandbox-mode default (#2501): when `NEXUS_SANDBOX` is set, use\n * `${NEXUS_SANDBOX_ROOT ?? '/'}/.nexus-agents`. Sandboxed deployments\n * typically mount a multi-repo root; state goes there, shared across\n * repo subfolders rather than buried inside one.\n * 3. Per-repo subdirs (when a repo root is known AND `NEXUS_REPO_PREFERRED`\n * is not explicitly `'0'`): `<repo-root>/.nexus-agents/<subdir>/`. The\n * repo root is the active workspace root when one has been set via\n * `setActiveWorkspaceRoot()` (the MCP server derives it from the client's\n * declared `roots`, MCP spec — see #3991), otherwise `findRepoRoot(cwd)`.\n * The active-root path exists because a globally-installed MCP server runs\n * with `process.cwd()` outside the repo, so cwd-based detection would\n * wrongly route per-repo state to homedir. Auto-adds `.nexus-agents/` to\n * the repo's `.gitignore` on first resolution (fail-closed).\n * 4. Cross-repo subdirs when `~/.nexus-agents/` is unwritable AND we're\n * in a repo: per-repo fallback at `<repo-root>/.nexus-agents/<subdir>/`\n * with one-time stderr announce. Issue #2888 — gives sandbox users\n * a working `research/`, `memory/`, etc. without env-var wrangling\n * while preserving the vote #2876 default for normal-machine users.\n * 5. `<homedir>/.nexus-agents` (cross-repo state on normal machines,\n * plus everything when not in a git repo or when\n * `NEXUS_REPO_PREFERRED=0`).\n *\n * `NEXUS_REPO_PREFERRED` defaults **ON** as of this release per vote\n * #2876. Escape hatches preserved:\n * - `NEXUS_REPO_PREFERRED=0` — fully opt out (homedir for everything).\n * - `NEXUS_DATA_DIR=~/.nexus-agents` — explicit override wins over\n * the tier and the categorization both.\n * - `nexus-agents migrate` (#2879) — relocate existing homedir state\n * into `<repo>/.nexus-agents/` before flipping in production.\n *\n * @module config/nexus-data-dir\n */\n\nimport {\n accessSync,\n constants as fsConstants,\n copyFileSync,\n existsSync,\n mkdirSync,\n realpathSync,\n renameSync,\n statSync,\n unlinkSync,\n} from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, isAbsolute, join, resolve } from 'node:path';\n\nimport { detectSandbox } from './sandbox-detection.js';\nimport { findRepoRoot, resolveMainCheckoutRoot } from './repo-root-detection.js';\nimport { ensureGitignored } from './portable-mode.js';\nimport { parseBoolEnv } from './defaults-env.js';\n\n/**\n * Subdirs scoped to a single repo's work (per the epic #2872 vote).\n * When `NEXUS_REPO_PREFERRED=1` and the caller is inside a git repo, these\n * route to `<repo-root>/.nexus-agents/`; otherwise homedir. The complement\n * (everything not in this set) always goes to homedir so cross-project\n * learning state stays intact.\n *\n * Source-of-truth for the categorization: vote #2876 conditions + audit\n * thread on epic #2872. Adding a new entry here is the appropriate way to\n * mark new state as per-repo — do that as a deliberate decision, not by\n * default.\n */\nconst PER_REPO_SUBDIRS: ReadonlySet<string> = new Set([\n // Scratch space for short-lived work (worktrees, prompt files, MCP configs).\n // Per-repo because a throwaway worktree of repo A is meaningless to repo B,\n // and because containing it here keeps it inside the already-gitignored\n // `.nexus-agents/` tree instead of accumulating in a shared `/tmp` nobody\n // reaps. A full `/tmp` is not a theoretical problem: it silently broke this\n // repo's own test suite, with ~1,100 files failing to COLLECT and zero\n // assertion failures, which reads like a code fault and is not one.\n 'tmp',\n 'sessions',\n 'checkpoints',\n 'traces',\n 'runs',\n 'audit',\n 'pipeline',\n 'tasks',\n // Async-mode job results (#3042 / epic #2631). Tied to work happening\n // in a specific codebase — a job dispatched on repo A shouldn't be\n // polled-against on repo B, which would happen if jobs/ were homedir-scoped.\n 'jobs',\n // CI health-check events (#3076 / #3084). Per-repo because outages\n // reported via `ci_health_check({ repo })` are repo-correlated; a wedge\n // on repo A's queue does not predict repo B's health.\n 'ci-health',\n // Governance artifacts — the runtime authentic-vote-record ledger\n // (`governance/vote-records.jsonl`, #3897/#3927/#3991). Per-repo because a\n // promotion proposal is scoped to the codebase being changed; with\n // `NEXUS_REPO_PREFERRED=1` (default) these route to\n // `<repo>/.nexus-agents/governance/` (gitignored), and to\n // `~/.nexus-agents/governance/` otherwise (global / non-repo install). This\n // is DISTINCT from the committed `<repo>/governance/vote-records.jsonl`\n // ledger the promotion gate reads — that artifact is reached only via the\n // explicit `NEXUS_VOTE_RECORDS_PATH` override (#3991).\n 'governance',\n]);\n\n/**\n * Per-repo subdirs that belong to the MAIN checkout even when the caller runs\n * inside a linked git worktree (#6531). A worktree is reaped when its work\n * lands; a governance record written into `<worktree>/.nexus-agents/` went with\n * it, while the CLI reported it written. Everything else per-repo stays\n * worktree-local: a quick panel chose governance-only (option B, 2-1) over\n * routing all per-repo state, to keep parallel worktrees' scratch, sessions and\n * jobs isolated. Must be a subset of {@link PER_REPO_SUBDIRS}.\n */\nconst MAIN_CHECKOUT_SUBDIRS: ReadonlySet<string> = new Set(['governance']);\n\n/** Returns the absolute path to the nexus-agents data directory. */\nexport function getNexusDataDir(): string {\n const fromEnv = process.env['NEXUS_DATA_DIR']?.trim();\n if (fromEnv !== undefined && fromEnv !== '') {\n return resolve(fromEnv);\n }\n const sandbox = detectSandbox();\n if (sandbox.active) {\n return resolve(sandbox.root ?? '/', '.nexus-agents');\n }\n return join(homedir(), '.nexus-agents');\n}\n\n/**\n * No-op kept for source-compatibility with consumers that called this\n * earlier in development. The resolver is no longer cached, so resetting\n * is unnecessary. Kept exported (rather than removed) to avoid breaking\n * imports in tests that may have already adopted it.\n */\nexport function resetNexusDataDirCache(): void {\n // intentionally empty — see module docstring\n}\n\n/**\n * Tracks per-process state for the auto-gitignore wiring: we only need\n * to (a) probe + append to `.gitignore` once per repo, and (b) bail\n * cleanly if the operator has explicitly silenced the auto-add via\n * `NEXUS_GITIGNORE_AUTO=false`. Reset in tests via the helper below.\n */\nconst gitignoredRoots = new Set<string>();\n\n/** Test helper — clears the auto-gitignore \"already did this\" memo. */\nexport function _resetGitignoreMemoForTests(): void {\n gitignoredRoots.clear();\n}\n\n/**\n * Active workspace root, when known from a source more authoritative than\n * `process.cwd()`. Set by the MCP server (#3991) from the client's declared\n * `roots` (MCP spec) once the initialize handshake completes, because a\n * globally-installed server runs with cwd OUTSIDE the repo being worked on —\n * so cwd-based repo detection would route per-repo `.nexus-agents` state to\n * homedir instead of `<repo>/.nexus-agents/`. CLI / in-repo callers never set\n * this, so they keep resolving via `findRepoRoot(cwd)` exactly as before.\n */\nlet activeWorkspaceRoot: string | undefined;\n\n/**\n * Records the active workspace root for repo-scoped data resolution. The\n * value is cross-trust-boundary input (it arrives over the MCP transport from\n * the client), so it is validated before use: resolved to an absolute path,\n * canonicalized via `realpathSync` (defeats symlink games), and required to\n * be an existing directory. Returns `true` when accepted, `false` when the\n * value is empty/invalid (in which case the previous root is left untouched).\n * Passing `null`/empty explicitly clears any previously-set root.\n */\nexport function setActiveWorkspaceRoot(root: string | null | undefined): boolean {\n const trimmed = root?.trim();\n if (trimmed === undefined || trimmed === '') {\n activeWorkspaceRoot = undefined;\n return false;\n }\n try {\n const canonical = realpathSync(resolve(trimmed));\n if (!isAbsolute(canonical) || !statSync(canonical).isDirectory()) return false;\n activeWorkspaceRoot = canonical;\n return true;\n } catch {\n // Nonexistent path, permission error, or broken symlink — reject and keep\n // whatever was set before so a bad late signal can't corrupt resolution.\n return false;\n }\n}\n\n/** Returns the active workspace root if one has been set, else `undefined`. */\nexport function getActiveWorkspaceRoot(): string | undefined {\n return activeWorkspaceRoot;\n}\n\n/** Test helper — clears the active workspace root memo. */\nexport function _resetActiveWorkspaceRootForTests(): void {\n activeWorkspaceRoot = undefined;\n}\n\n/**\n * Returns the repo-scoped `.nexus-agents/` directory if all of the\n * following hold: `NEXUS_REPO_PREFERRED` is NOT explicitly `'0'` (it\n * defaults ON as of vote #2876), `NEXUS_DATA_DIR` is not explicitly set\n * (explicit override always wins), no sandbox is active, and a repo root is\n * known — either the active workspace root (set via\n * `setActiveWorkspaceRoot()`) or an ancestor `.git` found by\n * `findRepoRoot(cwd)`.\n *\n * Side effect: on the first successful resolution per process per repo,\n * appends `.nexus-agents/` to the repo's `.gitignore` if not already\n * present. The operator can silence this with the boolean\n * `NEXUS_GITIGNORE_AUTO` set to `false`/`0` (e.g. on CI runners with a\n * frozen working tree).\n *\n * `options.mainCheckout` (#6531): when the root found is a linked git\n * worktree, return the `.nexus-agents/` of the MAIN checkout it belongs to\n * (see `resolveMainCheckoutRoot`), so the state outlives the worktree.\n * `options.readOnly` suppresses gitignore edits and their memo updates.\n *\n * Returns `null` when any precondition fails; callers fall back to\n * `getNexusDataDir()` (homedir).\n */\nexport function getNexusRepoDir(\n options: { readonly mainCheckout?: boolean; readonly readOnly?: boolean } = {}\n): string | null {\n if (!parseBoolEnv('NEXUS_REPO_PREFERRED', true)) return null;\n const fromEnv = process.env['NEXUS_DATA_DIR']?.trim();\n if (fromEnv !== undefined && fromEnv !== '') return null;\n if (detectSandbox().active) return null;\n // Prefer the MCP-client-declared workspace root (#3991) when the server has\n // set it; fall back to walking up from cwd for CLI / in-repo callers.\n const found = activeWorkspaceRoot ?? findRepoRoot(process.cwd());\n if (found === null) return null;\n // #6531: `mainCheckout` maps a linked worktree to the checkout it belongs to.\n const root = options.mainCheckout === true ? resolveMainCheckoutRoot(found) : found;\n maybeAutoGitignore(root, options.readOnly);\n return join(root, '.nexus-agents');\n}\n\n/**\n * Best-effort fail-closed wiring: once per process per repo, ensure\n * `.nexus-agents/` is in `<repo>/.gitignore`. Silenced via the boolean\n * `NEXUS_GITIGNORE_AUTO=false` (or `0`; default on — #5155). Failures are\n * non-fatal — the helper logs to stderr and continues.\n */\nfunction maybeAutoGitignore(repoRoot: string, readOnly: boolean = false): void {\n if (readOnly) return;\n if (!parseBoolEnv('NEXUS_GITIGNORE_AUTO', true)) return;\n if (gitignoredRoots.has(repoRoot)) return;\n gitignoredRoots.add(repoRoot);\n // Only attempt when the repo root looks real — avoid spamming stderr\n // from temp-dir test fixtures that race the lifecycle.\n if (!existsSync(repoRoot)) return;\n ensureGitignored(repoRoot, '.nexus-agents/');\n}\n\n/**\n * Per-process memo: was the homedir base directory found writable on first\n * probe? Used to short-circuit the sandbox-fallback decision in\n * `nexusDataPath()` without spending a syscall on every call.\n */\nlet homedirWritable: boolean | undefined;\n\n/** Per-process memo: have we already announced a fallback for this subdir? */\nconst announcedFallbacks = new Set<string>();\n\n/** Test helper — clears the homedir-writability + announcement memos. */\nexport function _resetWritabilityMemoForTests(): void {\n homedirWritable = undefined;\n announcedFallbacks.clear();\n}\n\n/**\n * Returns true if `getNexusDataDir()` resolves to a writable location. Probed\n * once per process and memo'd — flips the sandbox-fallback on/off for\n * cross-repo subdirs. `mkdirSync(recursive: true)` is the safest probe\n * because it both creates the dir if missing and surfaces ENOENT/EACCES\n * issues at the same point. Failures here are non-fatal — they just route\n * cross-repo state to the per-repo fallback (issue #2888).\n */\nfunction isHomedirBaseWritable(): boolean {\n if (homedirWritable !== undefined) return homedirWritable;\n const base = getNexusDataDir();\n try {\n mkdirSync(base, { recursive: true });\n accessSync(base, fsConstants.W_OK);\n homedirWritable = true;\n } catch {\n homedirWritable = false;\n }\n return homedirWritable;\n}\n\n/** Check the existing base or nearest parent without creating it or caching a preview. */\nfunction isHomedirBaseWritableReadOnly(): boolean {\n let target = getNexusDataDir();\n try {\n while (!existsSync(target)) {\n const parent = dirname(target);\n if (parent === target) return false;\n target = parent;\n }\n if (!statSync(target).isDirectory()) return false;\n accessSync(target, fsConstants.W_OK | fsConstants.X_OK);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Emit a one-time stderr warning when a cross-repo subdir falls back to\n * the per-repo location. Operators in sandboxes get a clear signal about\n * what happened without per-call noise.\n */\nfunction announceCrossRepoFallback(subdir: string, repoPath: string): void {\n if (announcedFallbacks.has(subdir)) return;\n announcedFallbacks.add(subdir);\n process.stderr.write(\n `[nexus] ${subdir}: homedir ~/.nexus-agents is not writable; ` +\n `using per-repo fallback at ${repoPath}. See docs/guides/SANDBOXED-USAGE.md.\\n`\n );\n}\n\n/**\n * Returns a path joined under the appropriate data directory for the\n * given subdir.\n *\n * Routing decision (first match wins):\n * 1. **Per-repo subdir + in a repo + `NEXUS_REPO_PREFERRED` not '0'** →\n * `<repo>/.nexus-agents/<subdir>/...`. Standard behavior since #2884.\n * 2. **Cross-repo subdir + homedir unwritable + in a repo** →\n * `<repo>/.nexus-agents/<subdir>/...` as a sandbox-friendly fallback\n * (issue #2888). Emits a one-time stderr warning per subdir.\n * 3. **Otherwise** → `<homedir>/.nexus-agents/<subdir>/...`. If homedir\n * is also unwritable, the actual write will surface the error.\n *\n * Existing callers don't need to change — the routing decision is driven\n * by the first segment, not by caller-declared intent.\n */\nexport function nexusDataPath(...segments: string[]): string {\n return resolveNexusDataPath(segments, false);\n}\n\n/** Resolve planned data paths without mkdir, gitignore edits, or resolver memo changes. */\nexport function previewNexusDataPath(...segments: string[]): string {\n return resolveNexusDataPath(segments, true);\n}\n\n/** Shared routing keeps setup previews consistent with runtime state placement. */\nfunction resolveNexusDataPath(segments: string[], readOnly: boolean): string {\n const first = segments[0];\n\n // Tier 1: per-repo subdir + repo-preferred default.\n if (first !== undefined && PER_REPO_SUBDIRS.has(first)) {\n const repoDir = getNexusRepoDir({ mainCheckout: MAIN_CHECKOUT_SUBDIRS.has(first), readOnly });\n if (repoDir !== null) {\n return join(repoDir, ...segments);\n }\n }\n\n // Tier 2: cross-repo subdir but homedir isn't reachable. Fall back to\n // the per-repo location if we're in a repo, so sandbox users get a\n // working `research/`, `memory/`, etc. without manual env-var setup.\n // Vote #2876 preserved: this only fires when homedir is physically\n // unreachable; normal-machine users see no change.\n if (\n first !== undefined &&\n !(readOnly ? isHomedirBaseWritableReadOnly() : isHomedirBaseWritable())\n ) {\n const repoDir = getNexusRepoDir({ readOnly });\n if (repoDir !== null) {\n const fallbackPath = join(repoDir, ...segments);\n if (!readOnly) announceCrossRepoFallback(first, fallbackPath);\n return fallbackPath;\n }\n // No repo to fall back to AND homedir unreachable — return the\n // homedir path anyway. The caller's eventual write will surface\n // the underlying EACCES/ENOENT, which is the right error to show\n // because the environment is genuinely broken at that point.\n }\n\n return join(getNexusDataDir(), ...segments);\n}\n\n/**\n * Like `nexusDataPath()` but eagerly creates the parent directory so\n * callers don't have to remember `mkdirSync(dirname(p), { recursive: true })`\n * before every write. Issue #2890. Use when the returned path will be\n * written to immediately; for read-only resolution prefer `nexusDataPath()`.\n *\n * If the call resolves to a directory (single segment or no segments),\n * the target IS the resolved path. If it resolves to a file (multiple\n * segments), the target is its parent.\n */\nexport function nexusDataPathEnsure(...segments: string[]): string {\n const resolved = nexusDataPath(...segments);\n const target = segments.length > 1 ? dirname(resolved) : resolved;\n mkdirSync(target, { recursive: true });\n return resolved;\n}\n\n/**\n * Explicitly homedir-scoped path. Use this in code that handles\n * cross-project state (routing memory, model registry cache, auth,\n * research catalog) where you want a hard guarantee that the resolver\n * never routes per-repo, even if a new subdir gets accidentally added\n * to the `PER_REPO_SUBDIRS` allowlist later.\n */\nexport function nexusSharedPath(...segments: string[]): string {\n return join(getNexusDataDir(), ...segments);\n}\n\n/**\n * Returns the read-only categorization used by `nexusDataPath()`.\n * Exposed for tests and for tooling that wants to introspect which\n * subdirs are per-repo (e.g. the `nexus-agents migrate` command).\n */\nexport function getPerRepoSubdirs(): ReadonlySet<string> {\n return PER_REPO_SUBDIRS;\n}\n\n/** Per-process memo — the legacy session-DB relocation runs at most once. */\nlet legacySessionsDbMigrated = false;\n\n/** Test helper — clears the session-DB migration \"already did this\" memo. */\nexport function _resetSessionsDbMigrationMemoForTests(): void {\n legacySessionsDbMigrated = false;\n}\n\n/** SQLite sidecar suffixes that must travel with the main DB file. */\nconst SQLITE_SIDECAR_SUFFIXES = ['', '-wal', '-shm', '-journal'] as const;\n\n/**\n * Resolves the session-database path, performing a one-time relocation\n * of any pre-#2902 database on the first call per process.\n *\n * The session DB is per-repo episodic state and belongs in the\n * `sessions/` bucket alongside the session journals — vote #2876\n * categorized `sessions/` as per-repo, and issue #2902 (consensus\n * 3/3) extended that to the DB. Before #2902 the DB resolved via\n * `nexusDataPath('sessions.db')`; because `sessions.db` is not a\n * per-repo first segment, that landed cross-repo at\n * `~/.nexus-agents/sessions.db`, so a DB started in one repo leaked\n * into every other repo.\n *\n * If a legacy DB exists at the old location and none exists at the\n * new one, the legacy file (and any SQLite sidecars) is moved so\n * existing session history is preserved rather than silently\n * orphaned. The move is best-effort: a failure leaves the legacy DB\n * untouched for manual recovery and the caller gets a fresh DB at the\n * new path. `NEXUS_DATA_DIR` / `NEXUS_REPO_PREFERRED` / the\n * `NEXUS_SESSIONS_DB` override all sit upstream of this resolver.\n */\nexport function sessionsDbPath(): string {\n const target = nexusDataPath('sessions', 'sessions.db');\n if (!legacySessionsDbMigrated) {\n legacySessionsDbMigrated = true;\n migrateLegacySessionsDb(target);\n }\n return target;\n}\n\n/** One-time relocation of a pre-#2902 session DB. Best-effort — see `sessionsDbPath`. */\nfunction migrateLegacySessionsDb(target: string): void {\n const legacy = nexusDataPath('sessions.db'); // pre-#2902 resolution\n if (legacy === target || !existsSync(legacy) || existsSync(target)) return;\n try {\n mkdirSync(dirname(target), { recursive: true });\n for (const suffix of SQLITE_SIDECAR_SUFFIXES) {\n const from = `${legacy}${suffix}`;\n if (existsSync(from)) moveFile(from, `${target}${suffix}`);\n }\n } catch {\n // Best-effort — a migration failure must never break session storage.\n }\n}\n\n/** Moves a file, falling back to copy+unlink across a filesystem boundary. */\nfunction moveFile(from: string, to: string): void {\n try {\n renameSync(from, to);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'EXDEV') throw err;\n copyFileSync(from, to);\n unlinkSync(from);\n }\n}\n","/**\n * Repo-root detection — walks upward from a starting directory looking for\n * `.git` so callers can scope state to the current git repo. Built for\n * epic #2872 (issue #2882) to support the per-repo `.nexus-agents/` data\n * directory ratified by vote #2876.\n *\n * Defenses adopted:\n * - Walks upward but stops at filesystem root (no infinite loop on\n * symlinks-to-self).\n * - Stops at filesystem boundary (different `stat.dev`) — refuses to\n * escape across mount points. Prevents a sandboxed workdir from\n * resolving a `.git` on the host filesystem.\n * - Detects git worktrees: `.git` may be a *file* containing\n * `gitdir: <path>` rather than a directory.\n * - Realpath's the final root and rejects results that escape the\n * starting cwd by symlink.\n *\n * Deferred (tracked separately; not blocking #2882):\n * - CVE-2022-24765-style ownership check (refuse `.git` owned by a\n * different uid than the running process). The git CLI added\n * `safe.directory` for this; we don't have a comparable allowlist\n * surface yet. In CI the heuristic is too noisy to be useful\n * (runners often clone as a different uid than the workload).\n * File-system isolation (the `stat.dev` check above) covers the\n * bulk of the attack class.\n *\n * @module config/repo-root-detection\n */\n\nimport { execFileSync } from 'node:child_process';\nimport { existsSync, readFileSync, realpathSync, statSync } from 'node:fs';\nimport { dirname, isAbsolute, join, resolve } from 'node:path';\n\n/**\n * Walks upward from `start` looking for `.git` (file or directory).\n * Returns the absolute path to the directory containing it, or `null`.\n *\n * Worktrees: a `.git` file (not dir) with contents `gitdir: <path>` is\n * still recognised as marking the repo root. The pointed-to gitdir is\n * NOT followed — we just need the worktree's own root.\n *\n * Filesystem boundary: stops walking if the next ancestor lives on a\n * different filesystem (different `stat.dev`). This prevents a workdir\n * mounted inside a sandbox from finding a host-side `.git`.\n */\nexport function findRepoRoot(start: string): string | null {\n if (!isAbsolute(start)) {\n start = resolve(start);\n }\n\n let current: string;\n try {\n current = realpathSync(start);\n } catch {\n return null;\n }\n\n let startDev: number | undefined;\n try {\n startDev = statSync(current).dev;\n } catch {\n return null;\n }\n\n // Walk up. Depth cap is paranoid but bounds the loop on pathological\n // symlinks even though realpathSync above should already prevent cycles.\n for (let i = 0; i < 64; i++) {\n if (isRepoRoot(current)) {\n return current;\n }\n const parent = dirname(current);\n if (parent === current) {\n // Hit filesystem root.\n return null;\n }\n try {\n if (statSync(parent).dev !== startDev) {\n // Crossed a mount point; refuse to escape.\n return null;\n }\n } catch {\n return null;\n }\n current = parent;\n }\n return null;\n}\n\n/** True iff `dir/.git` exists as a directory or a git-worktree marker file. */\nexport function isRepoRoot(dir: string): boolean {\n const gitPath = `${dir}/.git`;\n if (!existsSync(gitPath)) return false;\n try {\n const st = statSync(gitPath);\n if (st.isDirectory()) return true;\n if (st.isFile()) {\n // Worktree: first line should be `gitdir: <path>`.\n const head = readFileSync(gitPath, 'utf-8').slice(0, 256);\n return head.startsWith('gitdir:');\n }\n } catch {\n return false;\n }\n return false;\n}\n\n/** Upper bound on a git metadata file read; real ones are one short line. */\nconst MAX_GIT_METADATA_BYTES = 4096;\n\n/** First line of a small file, trimmed; undefined when absent, oversized or empty. */\nfunction readGitMetadataLine(path: string): string | undefined {\n try {\n if (!statSync(path).isFile() || statSync(path).size > MAX_GIT_METADATA_BYTES) return undefined;\n const line = readFileSync(path, 'utf-8').split('\\n')[0]?.trim();\n return line === undefined || line === '' ? undefined : line;\n } catch {\n return undefined;\n }\n}\n\n/** realpath, or undefined when the path does not resolve. */\nfunction realpathOrUndefined(path: string): string | undefined {\n try {\n return realpathSync(path);\n } catch {\n return undefined;\n }\n}\n\n/** Bound on each git call; a hung git must not hang data-dir resolution. */\nconst GIT_TIMEOUT_MS = 5_000;\n\n/**\n * Run git and return trimmed stdout, or undefined on any failure (git absent,\n * not a repository, unset config key, timeout). `GIT_*` variables are dropped\n * so an inherited `GIT_DIR`/`GIT_WORK_TREE` cannot answer for a different\n * repository than the one asked about.\n */\nfunction gitOutput(args: readonly string[]): string | undefined {\n const env = Object.fromEntries(\n Object.entries(process.env).filter(([key]) => !key.startsWith('GIT_'))\n );\n try {\n const out = execFileSync('git', [...args], {\n encoding: 'utf-8',\n stdio: ['ignore', 'pipe', 'ignore'],\n timeout: GIT_TIMEOUT_MS,\n env,\n }).trim();\n return out === '' ? undefined : out;\n } catch {\n return undefined;\n }\n}\n\n/** git's common dir for the repository at `dir`, realpath'd. */\nfunction gitCommonDir(dir: string): string | undefined {\n const common = gitOutput(['-C', dir, 'rev-parse', '--path-format=absolute', '--git-common-dir']);\n return common === undefined ? undefined : realpathOrUndefined(common);\n}\n\n/**\n * The MAIN checkout that a linked worktree belongs to, or `repoRoot` itself\n * (#6531).\n *\n * `findRepoRoot` deliberately stops at a worktree's own root; this is the one\n * extra hop for state that must outlive the worktree. Every decision is git's\n * own answer (#6548 review), not a name heuristic:\n *\n * 1. Only a LINKED worktree moves: `repoRoot/.git` is a file whose admin dir\n * sits at `<common>/worktrees/<name>` and whose `gitdir` file points BACK\n * at this worktree (git writes it inside the main repository, not the\n * worktree — the guard against a forged marker redirecting writes, possibly\n * across a mount boundary). A submodule or `--separate-git-dir` checkout\n * also has a `.git` file, but no back-reference: it is a main checkout.\n * 2. `<common>` is `git rev-parse --git-common-dir`.\n * 3. `core.bare` in `<common>/config` → no main checkout; keep `repoRoot`.\n * 4. `core.worktree` set → that is the main checkout (a submodule: its common\n * dir is `<super>/.git/modules/<name>`). Otherwise the candidate is\n * `<common>`'s parent (the standard layout).\n * 5. The candidate is accepted only if git, run there, reports the same common\n * dir AND the candidate as its top level. A `--separate-git-dir` clone\n * records no path back to its checkout (git's own `worktree list` names the\n * git dir), so its worktrees fail here and keep their own root.\n */\nexport function resolveMainCheckoutRoot(repoRoot: string): string {\n const adminDir = backReferencedAdminDir(repoRoot);\n if (adminDir === undefined) return repoRoot;\n const commonDir = gitCommonDir(repoRoot);\n if (commonDir === undefined || dirname(adminDir) !== join(commonDir, 'worktrees')) {\n return repoRoot;\n }\n return mainCheckoutOf(commonDir) ?? repoRoot;\n}\n\n/**\n * The admin dir a worktree's `.git` marker names, only when that admin dir's\n * `gitdir` file points back at the same marker; undefined otherwise.\n */\nfunction backReferencedAdminDir(repoRoot: string): string | undefined {\n const dotGit = join(repoRoot, '.git');\n const target = readGitMetadataLine(dotGit)\n ?.match(/^gitdir:\\s*(.+)$/)?.[1]\n ?.trim();\n if (target === undefined) return undefined;\n const adminDir = resolveGitPath(repoRoot, target);\n if (adminDir === undefined) return undefined;\n const backRef = readGitMetadataLine(join(adminDir, 'gitdir'));\n if (backRef === undefined) return undefined;\n const pointsBack = resolveGitPath(adminDir, backRef) === realpathOrUndefined(dotGit);\n return pointsBack ? adminDir : undefined;\n}\n\n/** Resolve a git metadata path the way git does: relative to `base`, then realpath. */\nfunction resolveGitPath(base: string, value: string): string | undefined {\n return realpathOrUndefined(isAbsolute(value) ? value : resolve(base, value));\n}\n\n/** The checkout whose git dir is `commonDir`, per git; undefined when there is none. */\nfunction mainCheckoutOf(commonDir: string): string | undefined {\n const config = join(commonDir, 'config');\n if (gitOutput(['config', '--file', config, '--bool', '--get', 'core.bare']) === 'true') {\n return undefined;\n }\n const worktree = gitOutput(['config', '--file', config, '--get', 'core.worktree']);\n const candidate = realpathOrUndefined(\n worktree === undefined ? dirname(commonDir) : resolveUnder(commonDir, worktree)\n );\n if (candidate === undefined || gitCommonDir(candidate) !== commonDir) return undefined;\n const topLevel = gitOutput(['-C', candidate, 'rev-parse', '--show-toplevel']);\n if (topLevel === undefined || realpathOrUndefined(topLevel) !== candidate) return undefined;\n return candidate;\n}\n\n/** `value` resolved against `base` unless already absolute (core.worktree semantics). */\nfunction resolveUnder(base: string, value: string): string {\n return isAbsolute(value) ? value : resolve(base, value);\n}\n","/**\n * portable-mode — auto-detect sandboxed execution environments and\n * redirect nexus-agents data to a workspace-local directory.\n *\n * The existing `getNexusDataDir()` already respects `NEXUS_DATA_DIR` and\n * `NEXUS_PORTABLE_MODE`. This module wires up the *auto-detection* path\n * so operators running inside a Docker / restricted-FS / sandboxed\n * environment don't have to set the env vars manually — nexus-agents\n * notices and announces the flip.\n *\n * Source: Issue #2471 (epic #2467 child).\n *\n * Detection rules (first match wins):\n * 1. `NEXUS_DATA_DIR` already set → respect, no auto-detect\n * 2. `NEXUS_PORTABLE_MODE=0` → operator opted out, no auto-detect\n * 3. `NEXUS_PORTABLE_MODE=1` → portable mode, no detection needed\n * 4. Heuristic: home directory not writable\n * 5. Heuristic: container env vars set (KUBERNETES_SERVICE_HOST,\n * DOCKER_CONTAINER, ECS_CONTAINER_METADATA_URI, SANDBOX, etc.)\n *\n * When portable mode fires:\n * - Sets `process.env.NEXUS_DATA_DIR` to `<cwd>/.nexus-agents`\n * - Announces once on stderr (subsequent calls are silent)\n * - If cwd is a git repo, appends `.nexus-agents/` to .gitignore\n *\n * To force off: `NEXUS_PORTABLE_MODE=0`. To force on without heuristics:\n * `NEXUS_PORTABLE_MODE=1`. To override target dir: `NEXUS_DATA_DIR=...`.\n */\n\nimport { accessSync, constants, existsSync, readFileSync, appendFileSync, statSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join, resolve } from 'node:path';\n\n/** Container / sandbox environment variables that strongly imply portable mode. */\nconst SANDBOX_ENV_VARS: readonly string[] = [\n 'KUBERNETES_SERVICE_HOST',\n 'DOCKER_CONTAINER',\n 'ECS_CONTAINER_METADATA_URI',\n 'ECS_CONTAINER_METADATA_URI_V4',\n 'SANDBOX',\n 'NEXUS_SANDBOX',\n];\n\nlet DETECTED = false;\n\ninterface DetectionResult {\n readonly portable: boolean;\n readonly dataDir: string;\n readonly reason:\n 'env-data-dir' | 'env-opt-out' | 'env-opt-in' | 'home-unwritable' | 'container-env' | 'default';\n}\n\nfunction isHomeWritable(): boolean {\n try {\n const home = homedir();\n if (!existsSync(home)) return false;\n accessSync(home, constants.W_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction inSandboxEnv(): boolean {\n for (const v of SANDBOX_ENV_VARS) {\n const val = process.env[v];\n if (val !== undefined && val !== '') return true;\n }\n return false;\n}\n\n/**\n * The operator-declared sandbox root, when set (#5026).\n *\n * Read directly rather than through `detectSandbox()` to keep this module free\n * of imports — it runs as a side effect of `cli-log-bootstrap` before anything\n * else loads.\n */\nfunction sandboxRootFromEnv(): string | undefined {\n const raw = process.env['NEXUS_SANDBOX_ROOT']?.trim();\n return raw !== undefined && raw !== '' ? resolve(raw) : undefined;\n}\n\nfunction checkExplicitEnv(cwd: string): DetectionResult | null {\n const fromEnv = process.env['NEXUS_DATA_DIR']?.trim();\n if (fromEnv !== undefined && fromEnv !== '') {\n return { portable: false, dataDir: resolve(fromEnv), reason: 'env-data-dir' };\n }\n const portableEnv = process.env['NEXUS_PORTABLE_MODE'];\n if (portableEnv === '0' || portableEnv === 'false') {\n return { portable: false, dataDir: join(homedir(), '.nexus-agents'), reason: 'env-opt-out' };\n }\n if (portableEnv === '1' || portableEnv === 'true') {\n return { portable: true, dataDir: join(cwd, '.nexus-agents'), reason: 'env-opt-in' };\n }\n return null;\n}\n\nfunction checkHeuristics(cwd: string): DetectionResult | null {\n if (!isHomeWritable()) {\n return { portable: true, dataDir: join(cwd, '.nexus-agents'), reason: 'home-unwritable' };\n }\n if (inSandboxEnv()) {\n // #5026: prefer an explicitly declared sandbox root over cwd. `NEXUS_SANDBOX`\n // is one of SANDBOX_ENV_VARS, so setting it makes this heuristic fire and\n // stamp `NEXUS_DATA_DIR = <cwd>/.nexus-agents` — which then short-circuits\n // `getNexusDataDir`'s own sandbox branch (`nexus-data-dir.ts:124-127`)\n // before it can honour `NEXUS_SANDBOX_ROOT`. The documented purpose of that\n // variable (\"default NEXUS_DATA_DIR to the multi-repo root\") therefore never\n // happened, and state fragmented per working directory across a multi-repo\n // mount. `doctor`'s dataDirInsideRepo check exists to detect exactly that\n // layout and reports it as operator misconfiguration.\n const declaredRoot = sandboxRootFromEnv();\n return {\n portable: true,\n dataDir: join(declaredRoot ?? cwd, '.nexus-agents'),\n reason: 'container-env',\n };\n }\n return null;\n}\n\n/**\n * Decide whether to flip nexus-agents to portable mode and what data dir\n * to use. Pure function; no side effects beyond reading env + filesystem.\n */\nexport function detectPortableMode(cwd: string = process.cwd()): DetectionResult {\n return (\n checkExplicitEnv(cwd) ??\n checkHeuristics(cwd) ?? {\n portable: false,\n dataDir: join(homedir(), '.nexus-agents'),\n reason: 'default',\n }\n );\n}\n\n/**\n * Apply detected portable mode at process startup. Idempotent (subsequent\n * calls are no-ops). Announces on stderr once when the auto-detection\n * heuristic triggers — env-opt-in/out doesn't announce because the\n * operator already knows.\n */\nexport function applyPortableMode(\n cwd: string = process.cwd(),\n options: { readonly dryRun?: boolean } = {}\n): void {\n if (DETECTED) return;\n DETECTED = true;\n\n const result = detectPortableMode(cwd);\n\n // No env, no heuristic match — nothing to do.\n if (!result.portable) return;\n\n // The heuristic-driven cases announce; explicit opt-in is silent.\n if (result.reason === 'home-unwritable' || result.reason === 'container-env') {\n process.stderr.write(\n `[portable-mode] Sandbox detected (${result.reason}). Using ${result.dataDir} for all nexus-agents data.\\n` +\n ` Set NEXUS_PORTABLE_MODE=0 to override; see docs/guides/SANDBOXED-USAGE.md\\n`\n );\n }\n\n process.env['NEXUS_DATA_DIR'] = result.dataDir;\n\n if (isInsideGitRepo(cwd)) {\n if (options.dryRun === true) {\n process.stderr.write(\n `[portable-mode] Would add '.nexus-agents/' to ${join(cwd, '.gitignore')}.\\n`\n );\n } else {\n ensureGitignored(cwd, '.nexus-agents/');\n }\n }\n}\n\nfunction isInsideGitRepo(cwd: string): boolean {\n try {\n const gitDir = join(cwd, '.git');\n return existsSync(gitDir) && statSync(gitDir).isDirectory();\n } catch {\n return false;\n }\n}\n\n/**\n * Append `entry` to `<cwd>/.gitignore` if not already present. Stderr\n * announce on the first append. Exported because the repo-preferred\n * resolver in `nexus-data-dir.ts` reuses the same auto-gitignore behavior\n * when `<repo>/.nexus-agents/` becomes the active data dir (epic #2872).\n */\nexport function ensureGitignored(cwd: string, entry: string): void {\n const path = join(cwd, '.gitignore');\n try {\n const existing = existsSync(path) ? readFileSync(path, 'utf-8') : '';\n const lines = existing.split('\\n').map((l) => l.trim());\n if (lines.includes(entry) || lines.includes(entry.replace(/\\/$/, ''))) return;\n const sep = existing.length > 0 && !existing.endsWith('\\n') ? '\\n' : '';\n appendFileSync(path, `${sep}${entry}\\n`, 'utf-8');\n process.stderr.write(\n `[portable-mode] Added '${entry}' to ${path} so nexus-agents data is gitignored.\\n`\n );\n } catch (e: unknown) {\n // Non-fatal — operator can add the line themselves.\n const msg = e instanceof Error ? e.message : String(e);\n process.stderr.write(\n `[portable-mode] Could not auto-update ${path} (${msg}). Add '${entry}' manually if you don't want nexus-agents data tracked by git.\\n`\n );\n }\n}\n\n/** Test-only reset of the once-only state. */\nexport function _resetDetectedForTests(): void {\n DETECTED = false;\n}\n"],"mappings":"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","names":["accessSync","existsSync","realpathSync","statSync","homedir","dirname","isAbsolute","join","resolve","existsSync","readFileSync","existsSync","readFileSync","statSync","join","resolve","resolve","join","homedir","realpathSync","resolve","isAbsolute","statSync","join","existsSync","accessSync","existsSync","dirname","statSync","join","existsSync","dirname"]}
@@ -5,7 +5,7 @@ import {
5
5
  } from "./chunk-Z2AAMUNG.js";
6
6
  import {
7
7
  executeExpert
8
- } from "./chunk-XBXLA6DJ.js";
8
+ } from "./chunk-EA234IFY.js";
9
9
  import {
10
10
  JobStatusSchema,
11
11
  RawFindingSchema,
@@ -58,11 +58,11 @@ import {
58
58
  updateStage,
59
59
  withFileLock,
60
60
  writeJobCancelled
61
- } from "./chunk-6V25ZIPU.js";
61
+ } from "./chunk-ZQYQZ7FQ.js";
62
62
  import {
63
63
  normalizeTopicToCanonical,
64
64
  synthesizeResearch
65
- } from "./chunk-FGR6O454.js";
65
+ } from "./chunk-LNGZKTJL.js";
66
66
  import {
67
67
  IssueTriage,
68
68
  createAuditTrail,
@@ -71,13 +71,13 @@ import {
71
71
  createGraphAuditBridge,
72
72
  emitPipelinePolicyEvent,
73
73
  readActionRefusal
74
- } from "./chunk-4DHC2TDC.js";
74
+ } from "./chunk-5BYTGR63.js";
75
75
  import {
76
76
  sanitizeInput
77
77
  } from "./chunk-773AZVR3.js";
78
78
  import {
79
79
  withPrerequisite
80
- } from "./chunk-NKITVLTK.js";
80
+ } from "./chunk-SNLDHZQ5.js";
81
81
  import {
82
82
  NOOP_NOTIFIER,
83
83
  RateLimiter,
@@ -105,7 +105,7 @@ import {
105
105
  toolSuccess,
106
106
  withProgressHeartbeat,
107
107
  wrapToolWithTimeout
108
- } from "./chunk-IQYJPOMW.js";
108
+ } from "./chunk-UMX44QLL.js";
109
109
  import {
110
110
  generateSecurityPlan
111
111
  } from "./chunk-6ZTMMN2N.js";
@@ -152,18 +152,18 @@ import {
152
152
  parseRegistry,
153
153
  sourceExistsInRegistry,
154
154
  summarizeContextForPrompt
155
- } from "./chunk-AH4Y7Z6S.js";
155
+ } from "./chunk-EBMDEUH7.js";
156
156
  import {
157
157
  REGISTRY_PATH,
158
158
  getProjectRoot,
159
159
  loadPapersRegistry,
160
160
  loadTechniquesRegistry,
161
161
  resolveRegistryRoot
162
- } from "./chunk-BCC27PGX.js";
162
+ } from "./chunk-Q7FEF3YH.js";
163
163
  import {
164
164
  getTokenEnvVars,
165
165
  resolveToken
166
- } from "./chunk-N5DHPHPE.js";
166
+ } from "./chunk-AUO7FSZX.js";
167
167
  import {
168
168
  DEFAULT_RELEVANCE_CONFIG,
169
169
  MemoryImportance,
@@ -171,7 +171,7 @@ import {
171
171
  calculateTextJaccardSimilarity,
172
172
  getToolMemory,
173
173
  memoryTrustTierTag
174
- } from "./chunk-Y3A3VVGT.js";
174
+ } from "./chunk-5EYCAD6W.js";
175
175
  import {
176
176
  EXTERNAL_CONTENT_TRUST_TIER,
177
177
  resolveContentTrustProvenance,
@@ -187,7 +187,7 @@ import {
187
187
  import {
188
188
  DEFAULT_TASK_TTL_MS,
189
189
  clampTaskTtl
190
- } from "./chunk-HH4FMRXL.js";
190
+ } from "./chunk-CYI7ZAMR.js";
191
191
  import {
192
192
  allOf,
193
193
  anyOf
@@ -196,7 +196,7 @@ import {
196
196
  VERSION,
197
197
  createRequestContext,
198
198
  measuredTrustTier
199
- } from "./chunk-O76YJOEG.js";
199
+ } from "./chunk-4PNQ3OUO.js";
200
200
  import {
201
201
  BWRAP_READ_ONLY_ARGS,
202
202
  CliDetectionCache,
@@ -208,23 +208,23 @@ import {
208
208
  getGlobalEventBus,
209
209
  getGlobalRegistry,
210
210
  isAbsentSeat
211
- } from "./chunk-VA247HQO.js";
211
+ } from "./chunk-XJEV7JH2.js";
212
212
  import {
213
213
  ensureGatewayDiscovered,
214
214
  getAvailabilityCache,
215
215
  getCliForModelId,
216
216
  resolveFallback
217
- } from "./chunk-W56VP6JH.js";
217
+ } from "./chunk-7P7TBPXE.js";
218
218
  import {
219
219
  DEFAULTS
220
- } from "./chunk-4S77S56F.js";
220
+ } from "./chunk-AKNZ5SZW.js";
221
221
  import {
222
222
  DEFAULT_EXECUTION_MODE,
223
223
  DEFAULT_TOOL_RATE_LIMITS
224
224
  } from "./chunk-TYLE7Z2S.js";
225
225
  import {
226
226
  getNexusTmpDir
227
- } from "./chunk-U7HL7FGS.js";
227
+ } from "./chunk-CBDUTJJC.js";
228
228
  import {
229
229
  BaseAdapter,
230
230
  createStream,
@@ -232,10 +232,10 @@ import {
232
232
  parseGatewayExtraHeaders,
233
233
  requireApiKey,
234
234
  validateApiKeyPresence
235
- } from "./chunk-WSLPF7BX.js";
235
+ } from "./chunk-5SZD2I3X.js";
236
236
  import {
237
237
  createSessionMemory
238
- } from "./chunk-FQFCLNYM.js";
238
+ } from "./chunk-PY6GUS22.js";
239
239
  import {
240
240
  TrustTierSchema
241
241
  } from "./chunk-CJKHQ6MV.js";
@@ -249,14 +249,14 @@ import {
249
249
  terminateProcessTree,
250
250
  trackProcessTree,
251
251
  withTimeout
252
- } from "./chunk-VMGKPEVR.js";
252
+ } from "./chunk-JRGPMF67.js";
253
253
  import {
254
254
  generateHyphenId,
255
255
  generateUUID
256
- } from "./chunk-KXD7ZJWM.js";
256
+ } from "./chunk-Z5NCR7DH.js";
257
257
  import {
258
258
  getDefaultCliCircuitBreakerRegistry
259
- } from "./chunk-ZDNXBCOP.js";
259
+ } from "./chunk-6FHFS2QA.js";
260
260
  import {
261
261
  sanitizeErrorDetails
262
262
  } from "./chunk-7LKX7AUQ.js";
@@ -354,7 +354,7 @@ import {
354
354
  toExpertTaskAnalysisResult,
355
355
  truncateWithInfo,
356
356
  withStep
357
- } from "./chunk-WM2BE65D.js";
357
+ } from "./chunk-6V4ERXGA.js";
358
358
  import {
359
359
  SUPPORTED_EXTENSIONS
360
360
  } from "./chunk-XBEKMUTO.js";
@@ -369,18 +369,18 @@ import {
369
369
  lookupInTreeCapability,
370
370
  modelSupportsAll,
371
371
  resolveOwnerCli
372
- } from "./chunk-5FYSIB3L.js";
372
+ } from "./chunk-3VH6RBVJ.js";
373
373
  import {
374
374
  deriveEntry,
375
375
  getDefaultRegistry,
376
376
  resolveModelIdentity,
377
377
  resolveModelIdentitySync
378
- } from "./chunk-5TW3NLWA.js";
378
+ } from "./chunk-TNZSALI4.js";
379
379
  import {
380
380
  ensureLearningDir,
381
381
  getMetaOutcomesFile,
382
382
  isPersistenceEnabled
383
- } from "./chunk-RUHKJC3X.js";
383
+ } from "./chunk-CBN5IKTG.js";
384
384
  import {
385
385
  TRACE_ID_MAX_LENGTH,
386
386
  accessModeSignal,
@@ -405,7 +405,7 @@ import {
405
405
  nexusDataPathEnsure,
406
406
  parseBoolEnv,
407
407
  setActiveWorkspaceRoot
408
- } from "./chunk-CH6IBWXH.js";
408
+ } from "./chunk-356WC2D4.js";
409
409
  import {
410
410
  AGENT_ROUTER_TIMEOUTS,
411
411
  API_TIMEOUTS,
@@ -29770,7 +29770,7 @@ function execIdFields(executionId) {
29770
29770
  async function populateUnifiedContextOnState(state, options) {
29771
29771
  const taskCandidate = state["task"];
29772
29772
  if (typeof taskCandidate !== "string" || taskCandidate === "") return;
29773
- const { getContextForTask: getContextForTask2, inferTaskCategory: inferTaskCategory2 } = await import("./context-retriever-BJIUY6QW.js");
29773
+ const { getContextForTask: getContextForTask2, inferTaskCategory: inferTaskCategory2 } = await import("./context-retriever-HTBOLH5P.js");
29774
29774
  const category = inferTaskCategory2(taskCandidate);
29775
29775
  const executionId = options?.executionId;
29776
29776
  const execFields = execIdFields(executionId);
@@ -46285,7 +46285,7 @@ async function tryIssueTriage(task) {
46285
46285
  try {
46286
46286
  const issueMatch = task.match(/github\.com\/([^/]+\/[^/]+)\/issues\/(\d+)/);
46287
46287
  if (issueMatch === null) return null;
46288
- const { createIssueTriage } = await import("./issue-triage-RUA2254S.js");
46288
+ const { createIssueTriage } = await import("./issue-triage-LBR6OJQ3.js");
46289
46289
  const triage = createIssueTriage();
46290
46290
  const owner = issueMatch[1] ?? "";
46291
46291
  const num2 = issueMatch[2] ?? "";
@@ -46313,7 +46313,7 @@ var VALID_TEMPLATES = /* @__PURE__ */ new Set([
46313
46313
  ]);
46314
46314
  async function classifyWithLLM(task) {
46315
46315
  try {
46316
- const { executeExpert: executeExpert2 } = await import("./expert-bridge-GFO6QWXL.js");
46316
+ const { executeExpert: executeExpert2 } = await import("./expert-bridge-F6NAPNZC.js");
46317
46317
  const prompt = [
46318
46318
  "Classify this task into exactly one pipeline template.",
46319
46319
  "Templates: dev (implementation/bug fix/refactor), research (investigate/evaluate/compare),",
@@ -46682,7 +46682,7 @@ function buildVotingInput(plan, config) {
46682
46682
  }
46683
46683
  async function executeSingleVote(plan, config, log) {
46684
46684
  try {
46685
- const { executeVoting } = await import("./consensus-vote-KQTXJS5E.js");
46685
+ const { executeVoting } = await import("./consensus-vote-FPSXMIFK.js");
46686
46686
  const input = buildVotingInput(plan, config);
46687
46687
  const result = await executeVoting(input, log);
46688
46688
  return parseVotingResult(result);
@@ -48280,8 +48280,8 @@ var memoryInitPromise = null;
48280
48280
  async function initPipelineMemory() {
48281
48281
  if (cachedMemory !== null) return cachedMemory;
48282
48282
  try {
48283
- const { createSessionMemory: createSessionMemory2 } = await import("./session-memory-C4R2RA4D.js");
48284
- const { getLearningDir } = await import("./learning-persistence-X24OOBYY.js");
48283
+ const { createSessionMemory: createSessionMemory2 } = await import("./session-memory-PDVXENIX.js");
48284
+ const { getLearningDir } = await import("./learning-persistence-RXI2ASRC.js");
48285
48285
  const mem = createSessionMemory2(getLearningDir());
48286
48286
  mem.startSession(`pipeline-${String(getTimeProvider().now())}`);
48287
48287
  cachedMemory = {
@@ -48342,7 +48342,7 @@ function recordRoutingExperience(category, success, durationMs, tokensUsed = 0,
48342
48342
  callRecord(routingMemoryCache);
48343
48343
  return;
48344
48344
  }
48345
- routingMemoryInitPromise ??= import("./routing-memory-TVITESTN.js").then(({ createRoutingMemory }) => {
48345
+ routingMemoryInitPromise ??= import("./routing-memory-52ZSJBWK.js").then(({ createRoutingMemory }) => {
48346
48346
  routingMemoryCache ??= createRoutingMemory();
48347
48347
  return routingMemoryCache;
48348
48348
  }).catch((error) => {
@@ -48577,7 +48577,7 @@ function createVoteStage({ config, startStage }) {
48577
48577
  const strategy = config.votingStrategy ?? "higher_order";
48578
48578
  await postProgress(config, "Vote", `Running consensus with ${strategy} strategy...`);
48579
48579
  try {
48580
- const { executeVoting } = await import("./consensus-vote-KQTXJS5E.js");
48580
+ const { executeVoting } = await import("./consensus-vote-FPSXMIFK.js");
48581
48581
  const proposal = buildVoteProposal(plan, research);
48582
48582
  const votingResult = await executeVoting(
48583
48583
  {
@@ -50257,7 +50257,7 @@ ${text}` : "";
50257
50257
  }
50258
50258
  async function getWeatherContext() {
50259
50259
  try {
50260
- const { generateWeatherReport: generateWeatherReport2 } = await import("./weather-report-OIWO4BCH.js");
50260
+ const { generateWeatherReport: generateWeatherReport2 } = await import("./weather-report-DZLWIKOZ.js");
50261
50261
  const report = generateWeatherReport2({ includeAdaptive: true });
50262
50262
  const mappings = "recommendedMappings" in report ? report.recommendedMappings : [];
50263
50263
  if (!Array.isArray(mappings) || mappings.length === 0) return "";
@@ -50275,8 +50275,8 @@ ${lines}
50275
50275
  }
50276
50276
  async function getMemoryContext(task) {
50277
50277
  try {
50278
- const { createSessionMemory: createSessionMemory2 } = await import("./session-memory-C4R2RA4D.js");
50279
- const { getLearningDir } = await import("./learning-persistence-X24OOBYY.js");
50278
+ const { createSessionMemory: createSessionMemory2 } = await import("./session-memory-PDVXENIX.js");
50279
+ const { getLearningDir } = await import("./learning-persistence-RXI2ASRC.js");
50280
50280
  const memory = createSessionMemory2(getLearningDir(), { maxLearningsInContext: 10 });
50281
50281
  const learnings = memory.searchLearnings(task.slice(0, 200));
50282
50282
  if (learnings.length === 0) return "";
@@ -50998,7 +50998,7 @@ async function searchCodebaseForTask(task) {
50998
50998
  }
50999
50999
  async function queryResearchRegistry(task) {
51000
51000
  try {
51001
- const { synthesizeResearch: synthesizeResearch2 } = await import("./research-helpers-synthesize-BY7RH4B3.js");
51001
+ const { synthesizeResearch: synthesizeResearch2 } = await import("./research-helpers-synthesize-VRWS6GBM.js");
51002
51002
  const topic = task.split(/[.!?\n]/).filter((s) => s.trim().length > 10)[0]?.trim();
51003
51003
  if (topic === void 0) return null;
51004
51004
  const result = await synthesizeResearch2(topic.slice(0, 50));
@@ -51069,7 +51069,7 @@ function createScanStageWrapper() {
51069
51069
  try {
51070
51070
  const slug = ctx.task.match(/([a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+)/)?.[1];
51071
51071
  if (slug !== void 0) {
51072
- const { generateSecurityPlan: generateSecurityPlan2 } = await import("./repo-security-plan-OZHFTQB3.js");
51072
+ const { generateSecurityPlan: generateSecurityPlan2 } = await import("./repo-security-plan-YINATBVX.js");
51073
51073
  const plan = await generateSecurityPlan2({ repo: slug, maxScanners: 10 });
51074
51074
  const recs = plan.recommendations.slice(0, 5).map((r) => `${r.priority}: ${r.displayName} (${r.category})`).join("; ");
51075
51075
  return output(PIPELINE_STATE_KEYS.FINDINGS, recs, getTimeProvider().now() - start, true);
@@ -53390,7 +53390,6 @@ function initializeAuth(config, logger59) {
53390
53390
  }
53391
53391
 
53392
53392
  // src/cli-server-audit.ts
53393
- var DEFAULT_AUDIT_DIR = nexusDataPath("audit");
53394
53393
  var DEFAULT_AUDIT_FILE_PREFIX = "audit";
53395
53394
  function initializeAuditLogger(securityConfig, logger59) {
53396
53395
  if (securityConfig?.audit?.enabled !== true) {
@@ -53398,7 +53397,7 @@ function initializeAuditLogger(securityConfig, logger59) {
53398
53397
  return null;
53399
53398
  }
53400
53399
  const auditConfig = securityConfig.audit;
53401
- const logDir = auditConfig.logDir ?? DEFAULT_AUDIT_DIR;
53400
+ const logDir = auditConfig.logDir ?? nexusDataPath("audit");
53402
53401
  const auditLogger = createAuditLogger(
53403
53402
  {
53404
53403
  logDir,
@@ -55017,7 +55016,7 @@ var GitHubTaskTracker = class {
55017
55016
  cachedProvider = null;
55018
55017
  async getProvider() {
55019
55018
  if (this.cachedProvider !== null) return this.cachedProvider;
55020
- const { createScmProvider } = await import("./factory-P45WM7Y5.js");
55019
+ const { createScmProvider } = await import("./factory-FO6ICRSI.js");
55021
55020
  const result = await createScmProvider({ repo: this.config.repo ?? "" });
55022
55021
  if (!result.ok) throw new Error(`SCM provider error: ${result.error.message}`);
55023
55022
  this.cachedProvider = result.value;
@@ -56098,7 +56097,7 @@ function withCatalogueCaveat(report) {
56098
56097
  var GATEWAY_TRANSPORT = "gateway";
56099
56098
  var GATEWAY_API_ARM = "api:custom-openai";
56100
56099
  async function gatewaySource(apiArm) {
56101
- const { discoverModels, readOpenAICompatEnv } = await import("./openai-compat-adapter-BAHSQKIS.js");
56100
+ const { discoverModels, readOpenAICompatEnv } = await import("./openai-compat-adapter-ARDUWHBA.js");
56102
56101
  const config = readOpenAICompatEnv();
56103
56102
  if (config !== null) {
56104
56103
  return {
@@ -56117,7 +56116,7 @@ async function gatewaySource(apiArm) {
56117
56116
  }
56118
56117
  async function defaultSources(includeOpenRouter, adaptersFactory) {
56119
56118
  const adapters = new Map(
56120
- adaptersFactory !== void 0 ? adaptersFactory() : (await import("./factory-RZVZ6BLF.js")).createAllAdapters()
56119
+ adaptersFactory !== void 0 ? adaptersFactory() : (await import("./factory-7IAD2557.js")).createAllAdapters()
56121
56120
  );
56122
56121
  const apiArm = adapters.get(GATEWAY_API_ARM);
56123
56122
  adapters.delete(GATEWAY_API_ARM);
@@ -59474,4 +59473,4 @@ export {
59474
59473
  initializeSandbox,
59475
59474
  getSandboxMode
59476
59475
  };
59477
- //# sourceMappingURL=chunk-TH3MSFDF.js.map
59476
+ //# sourceMappingURL=chunk-3RVTDYT7.js.map