nexus-agents 2.81.3 → 2.82.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.
Files changed (109) hide show
  1. package/dist/{child-mcp-config-LLLRMOTQ.js → child-mcp-config-BMSYR7VV.js} +2 -2
  2. package/dist/{chunk-ERWTZSAR.js → chunk-2R5UUBGA.js} +2 -2
  3. package/dist/{chunk-BMNWUPJO.js → chunk-2SQXJQTA.js} +3 -3
  4. package/dist/{chunk-755EZIUF.js → chunk-4XNVJS5A.js} +924 -376
  5. package/dist/{chunk-755EZIUF.js.map → chunk-4XNVJS5A.js.map} +1 -1
  6. package/dist/{chunk-LJIB6TNE.js → chunk-7VNVDFD5.js} +3 -13
  7. package/dist/{chunk-LJIB6TNE.js.map → chunk-7VNVDFD5.js.map} +1 -1
  8. package/dist/{chunk-PUSFT342.js → chunk-BL5IBHEY.js} +3 -3
  9. package/dist/{chunk-Q27M6KHP.js → chunk-C7P2HLJX.js} +4 -4
  10. package/dist/{chunk-P4W7PV6L.js → chunk-FTT2IYYX.js} +123 -96
  11. package/dist/chunk-FTT2IYYX.js.map +1 -0
  12. package/dist/{chunk-UZCDHAY3.js → chunk-G2DZBEMU.js} +2 -2
  13. package/dist/{chunk-WZGCVCRQ.js → chunk-GNG7URCR.js} +2 -2
  14. package/dist/{chunk-RLQZOEMX.js → chunk-HJUHDPXJ.js} +3 -3
  15. package/dist/{chunk-SVKH6ASN.js → chunk-HMXQKDUV.js} +36 -24
  16. package/dist/chunk-HMXQKDUV.js.map +1 -0
  17. package/dist/{chunk-PV3OEDLO.js → chunk-HVZ52LOL.js} +2 -2
  18. package/dist/{chunk-EKLY4LBJ.js → chunk-JM3R267Z.js} +28 -15
  19. package/dist/chunk-JM3R267Z.js.map +1 -0
  20. package/dist/{chunk-M66MYHBT.js → chunk-NTLJ3INA.js} +2 -2
  21. package/dist/{chunk-T7RGD5JW.js → chunk-OYDJ3C4N.js} +3 -3
  22. package/dist/{chunk-UTL2SFIN.js → chunk-PZESEBD3.js} +2 -2
  23. package/dist/{chunk-LIEFKEAO.js → chunk-QHL4KGNB.js} +2 -2
  24. package/dist/{chunk-WLAQXITV.js → chunk-S36LIUV2.js} +12 -23
  25. package/dist/chunk-S36LIUV2.js.map +1 -0
  26. package/dist/{chunk-YLYT7GSG.js → chunk-SBZVRH4S.js} +2 -2
  27. package/dist/{chunk-V2KWEIV5.js → chunk-SHWGK7X6.js} +9 -60
  28. package/dist/chunk-SHWGK7X6.js.map +1 -0
  29. package/dist/{chunk-6YQCLEHL.js → chunk-SXL744NF.js} +2 -2
  30. package/dist/{chunk-4OPS2AUD.js → chunk-TXIUCEFT.js} +4 -4
  31. package/dist/chunk-TXIUCEFT.js.map +1 -0
  32. package/dist/{chunk-PZEE6T5Y.js → chunk-U7JXQSEM.js} +3 -3
  33. package/dist/{chunk-SZ7VPIRA.js → chunk-W2AIGD35.js} +2 -2
  34. package/dist/{chunk-73K7575Z.js → chunk-WUUEKFKG.js} +2 -2
  35. package/dist/{chunk-PKBKWWPK.js → chunk-X3JR3GMT.js} +3 -3
  36. package/dist/{chunk-S77SLJ2J.js → chunk-XGUDCUMB.js} +2 -2
  37. package/dist/{cli-circuit-breaker-O5RV47BO.js → cli-circuit-breaker-BIJUQRQI.js} +4 -4
  38. package/dist/cli.js +148 -70
  39. package/dist/cli.js.map +1 -1
  40. package/dist/{composite-router-SKHVZ4UF.js → composite-router-FB7P22L5.js} +2 -2
  41. package/dist/{consensus-vote-VBXLXVFF.js → consensus-vote-KKAIFULI.js} +11 -11
  42. package/dist/{context-retriever-KLJ5X4TL.js → context-retriever-4JCGMWH7.js} +5 -5
  43. package/dist/{doctor-deep-IH4FG5YZ.js → doctor-deep-7YK4BZIJ.js} +3 -3
  44. package/dist/expert-bridge-DJM5GAWZ.js +11 -0
  45. package/dist/{factory-FTE7TDCT.js → factory-DOWBGVAL.js} +5 -5
  46. package/dist/{factory-CQUDIMIG.js → factory-PK4EZL7K.js} +4 -4
  47. package/dist/index.d.ts +13 -1
  48. package/dist/index.js +24 -24
  49. package/dist/index.js.map +1 -1
  50. package/dist/{init-opencode-MXZJKG32.js → init-opencode-QP5CAMWN.js} +5 -5
  51. package/dist/{issue-triage-H5VLNGWU.js → issue-triage-T3SKNBH5.js} +4 -4
  52. package/dist/{registry-command-ALVYOGQY.js → registry-command-TH7U6UMC.js} +2 -2
  53. package/dist/{repo-security-plan-VJCWWPWO.js → repo-security-plan-V257RYTW.js} +3 -3
  54. package/dist/{research-helpers-synthesize-XUTBDVI7.js → research-helpers-synthesize-Y3O76PY4.js} +3 -3
  55. package/dist/{routing-memory-QKQ3OGWW.js → routing-memory-AAH7NIHD.js} +2 -2
  56. package/dist/{session-memory-N76TNRSK.js → session-memory-MY6YS2VX.js} +3 -3
  57. package/dist/{setup-command-3VQHU7BZ.js → setup-command-B6EC3OJA.js} +10 -10
  58. package/dist/{setup-config-Y7KZSFX3.js → setup-config-HVO6ZSLW.js} +3 -3
  59. package/dist/{setup-custom-api-QEKHNYQJ.js → setup-custom-api-UOIKUQL4.js} +4 -4
  60. package/dist/{tool-memory-MFDLIJOB.js → tool-memory-T7ZYIUJ2.js} +4 -4
  61. package/dist/{weather-report-IXPYIYE4.js → weather-report-O3Z3BBAX.js} +2 -2
  62. package/package.json +1 -1
  63. package/dist/chunk-4OPS2AUD.js.map +0 -1
  64. package/dist/chunk-EKLY4LBJ.js.map +0 -1
  65. package/dist/chunk-P4W7PV6L.js.map +0 -1
  66. package/dist/chunk-SVKH6ASN.js.map +0 -1
  67. package/dist/chunk-V2KWEIV5.js.map +0 -1
  68. package/dist/chunk-WLAQXITV.js.map +0 -1
  69. package/dist/expert-bridge-EKPDZKMD.js +0 -11
  70. /package/dist/{child-mcp-config-LLLRMOTQ.js.map → child-mcp-config-BMSYR7VV.js.map} +0 -0
  71. /package/dist/{chunk-ERWTZSAR.js.map → chunk-2R5UUBGA.js.map} +0 -0
  72. /package/dist/{chunk-BMNWUPJO.js.map → chunk-2SQXJQTA.js.map} +0 -0
  73. /package/dist/{chunk-PUSFT342.js.map → chunk-BL5IBHEY.js.map} +0 -0
  74. /package/dist/{chunk-Q27M6KHP.js.map → chunk-C7P2HLJX.js.map} +0 -0
  75. /package/dist/{chunk-UZCDHAY3.js.map → chunk-G2DZBEMU.js.map} +0 -0
  76. /package/dist/{chunk-WZGCVCRQ.js.map → chunk-GNG7URCR.js.map} +0 -0
  77. /package/dist/{chunk-RLQZOEMX.js.map → chunk-HJUHDPXJ.js.map} +0 -0
  78. /package/dist/{chunk-PV3OEDLO.js.map → chunk-HVZ52LOL.js.map} +0 -0
  79. /package/dist/{chunk-M66MYHBT.js.map → chunk-NTLJ3INA.js.map} +0 -0
  80. /package/dist/{chunk-T7RGD5JW.js.map → chunk-OYDJ3C4N.js.map} +0 -0
  81. /package/dist/{chunk-UTL2SFIN.js.map → chunk-PZESEBD3.js.map} +0 -0
  82. /package/dist/{chunk-LIEFKEAO.js.map → chunk-QHL4KGNB.js.map} +0 -0
  83. /package/dist/{chunk-YLYT7GSG.js.map → chunk-SBZVRH4S.js.map} +0 -0
  84. /package/dist/{chunk-6YQCLEHL.js.map → chunk-SXL744NF.js.map} +0 -0
  85. /package/dist/{chunk-PZEE6T5Y.js.map → chunk-U7JXQSEM.js.map} +0 -0
  86. /package/dist/{chunk-SZ7VPIRA.js.map → chunk-W2AIGD35.js.map} +0 -0
  87. /package/dist/{chunk-73K7575Z.js.map → chunk-WUUEKFKG.js.map} +0 -0
  88. /package/dist/{chunk-PKBKWWPK.js.map → chunk-X3JR3GMT.js.map} +0 -0
  89. /package/dist/{chunk-S77SLJ2J.js.map → chunk-XGUDCUMB.js.map} +0 -0
  90. /package/dist/{cli-circuit-breaker-O5RV47BO.js.map → cli-circuit-breaker-BIJUQRQI.js.map} +0 -0
  91. /package/dist/{composite-router-SKHVZ4UF.js.map → composite-router-FB7P22L5.js.map} +0 -0
  92. /package/dist/{consensus-vote-VBXLXVFF.js.map → consensus-vote-KKAIFULI.js.map} +0 -0
  93. /package/dist/{context-retriever-KLJ5X4TL.js.map → context-retriever-4JCGMWH7.js.map} +0 -0
  94. /package/dist/{doctor-deep-IH4FG5YZ.js.map → doctor-deep-7YK4BZIJ.js.map} +0 -0
  95. /package/dist/{expert-bridge-EKPDZKMD.js.map → expert-bridge-DJM5GAWZ.js.map} +0 -0
  96. /package/dist/{factory-CQUDIMIG.js.map → factory-DOWBGVAL.js.map} +0 -0
  97. /package/dist/{factory-FTE7TDCT.js.map → factory-PK4EZL7K.js.map} +0 -0
  98. /package/dist/{init-opencode-MXZJKG32.js.map → init-opencode-QP5CAMWN.js.map} +0 -0
  99. /package/dist/{issue-triage-H5VLNGWU.js.map → issue-triage-T3SKNBH5.js.map} +0 -0
  100. /package/dist/{registry-command-ALVYOGQY.js.map → registry-command-TH7U6UMC.js.map} +0 -0
  101. /package/dist/{repo-security-plan-VJCWWPWO.js.map → repo-security-plan-V257RYTW.js.map} +0 -0
  102. /package/dist/{research-helpers-synthesize-XUTBDVI7.js.map → research-helpers-synthesize-Y3O76PY4.js.map} +0 -0
  103. /package/dist/{routing-memory-QKQ3OGWW.js.map → routing-memory-AAH7NIHD.js.map} +0 -0
  104. /package/dist/{session-memory-N76TNRSK.js.map → session-memory-MY6YS2VX.js.map} +0 -0
  105. /package/dist/{setup-command-3VQHU7BZ.js.map → setup-command-B6EC3OJA.js.map} +0 -0
  106. /package/dist/{setup-config-Y7KZSFX3.js.map → setup-config-HVO6ZSLW.js.map} +0 -0
  107. /package/dist/{setup-custom-api-QEKHNYQJ.js.map → setup-custom-api-UOIKUQL4.js.map} +0 -0
  108. /package/dist/{tool-memory-MFDLIJOB.js.map → tool-memory-T7ZYIUJ2.js.map} +0 -0
  109. /package/dist/{weather-report-IXPYIYE4.js.map → weather-report-O3Z3BBAX.js.map} +0 -0
@@ -2,7 +2,7 @@ import {
2
2
  createLogger,
3
3
  err,
4
4
  ok
5
- } from "./chunk-LJIB6TNE.js";
5
+ } from "./chunk-7VNVDFD5.js";
6
6
 
7
7
  // src/scm/token-resolver.ts
8
8
  import { execFile } from "child_process";
@@ -87,4 +87,4 @@ export {
87
87
  hasToken,
88
88
  getTokenEnvVars
89
89
  };
90
- //# sourceMappingURL=chunk-UZCDHAY3.js.map
90
+ //# sourceMappingURL=chunk-G2DZBEMU.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  DEFAULT_MODEL_PER_CLI,
3
3
  getTimeProvider
4
- } from "./chunk-LJIB6TNE.js";
4
+ } from "./chunk-7VNVDFD5.js";
5
5
 
6
6
  // src/config/model-availability.ts
7
7
  var DEFAULT_TTL_MS = 6e4;
@@ -133,4 +133,4 @@ export {
133
133
  resetAvailabilityCache,
134
134
  filterAvailableModels
135
135
  };
136
- //# sourceMappingURL=chunk-WZGCVCRQ.js.map
136
+ //# sourceMappingURL=chunk-GNG7URCR.js.map
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  GitHubProvider,
3
3
  ScmError
4
- } from "./chunk-UTL2SFIN.js";
4
+ } from "./chunk-PZESEBD3.js";
5
5
  import {
6
6
  CACHE_TIMEOUTS,
7
7
  createLogger,
8
8
  err,
9
9
  getTimeProvider,
10
10
  ok
11
- } from "./chunk-LJIB6TNE.js";
11
+ } from "./chunk-7VNVDFD5.js";
12
12
 
13
13
  // src/security/trust-types.ts
14
14
  import { z } from "zod";
@@ -1656,4 +1656,4 @@ export {
1656
1656
  IssueTriage,
1657
1657
  createIssueTriage
1658
1658
  };
1659
- //# sourceMappingURL=chunk-RLQZOEMX.js.map
1659
+ //# sourceMappingURL=chunk-HJUHDPXJ.js.map
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  getCliForModelId
3
- } from "./chunk-WZGCVCRQ.js";
3
+ } from "./chunk-GNG7URCR.js";
4
4
  import {
5
5
  MODEL_IDS,
6
6
  createLogger,
7
7
  getTimeProvider,
8
8
  isRateLimitText
9
- } from "./chunk-LJIB6TNE.js";
9
+ } from "./chunk-7VNVDFD5.js";
10
10
 
11
11
  // src/pipeline/expert-bridge.ts
12
12
  function resolveCliFromModelString(model) {
@@ -18,16 +18,21 @@ var logger = createLogger({ component: "expert-bridge" });
18
18
  var RATE_LIMIT_BASE_DELAY_MS = 3e3;
19
19
  var cachedRouter = null;
20
20
  var cachedMcpConfigPath = null;
21
+ var mcpConfigInitPromise = null;
21
22
  async function getMcpConfigPath() {
22
23
  if (cachedMcpConfigPath !== null) return cachedMcpConfigPath;
23
- try {
24
- const { generateMcpConfig } = await import("./child-mcp-config-LLLRMOTQ.js");
25
- const config = await generateMcpConfig();
26
- cachedMcpConfigPath = config.configPath;
27
- return cachedMcpConfigPath;
28
- } catch {
29
- return null;
30
- }
24
+ mcpConfigInitPromise ??= (async () => {
25
+ try {
26
+ const { generateMcpConfig } = await import("./child-mcp-config-BMSYR7VV.js");
27
+ const config = await generateMcpConfig();
28
+ cachedMcpConfigPath = config.configPath;
29
+ return cachedMcpConfigPath;
30
+ } catch {
31
+ mcpConfigInitPromise = null;
32
+ return null;
33
+ }
34
+ })();
35
+ return mcpConfigInitPromise;
31
36
  }
32
37
  var cachedCircuitBreaker = null;
33
38
  function adaptCompositeRouter(compositeRouter) {
@@ -50,21 +55,28 @@ function adaptCompositeRouter(compositeRouter) {
50
55
  }
51
56
  };
52
57
  }
58
+ var routerInitPromise = null;
53
59
  async function getRouter() {
54
60
  if (cachedRouter !== null) return cachedRouter;
55
- const { createAllAdapters } = await import("./factory-CQUDIMIG.js");
56
- const { createCompositeRouter } = await import("./composite-router-SKHVZ4UF.js");
57
- const adapters = createAllAdapters();
58
- if (adapters.size === 0) return null;
59
- cachedRouter = adaptCompositeRouter(createCompositeRouter(adapters));
60
- try {
61
- const { createCliCircuitBreakerIntegration } = await import("./cli-circuit-breaker-O5RV47BO.js");
62
- cachedCircuitBreaker = createCliCircuitBreakerIntegration([...adapters.values()]);
63
- } catch (error) {
64
- const msg = error instanceof Error ? error.message : String(error);
65
- logger.debug("Circuit breaker init failed; continuing without it", { error: msg });
66
- }
67
- return cachedRouter;
61
+ routerInitPromise ??= (async () => {
62
+ const { createAllAdapters } = await import("./factory-PK4EZL7K.js");
63
+ const { createCompositeRouter } = await import("./composite-router-FB7P22L5.js");
64
+ const adapters = createAllAdapters();
65
+ if (adapters.size === 0) {
66
+ routerInitPromise = null;
67
+ return null;
68
+ }
69
+ cachedRouter = adaptCompositeRouter(createCompositeRouter(adapters));
70
+ try {
71
+ const { createCliCircuitBreakerIntegration } = await import("./cli-circuit-breaker-BIJUQRQI.js");
72
+ cachedCircuitBreaker = createCliCircuitBreakerIntegration([...adapters.values()]);
73
+ } catch (error) {
74
+ const msg = error instanceof Error ? error.message : String(error);
75
+ logger.debug("Circuit breaker init failed; continuing without it", { error: msg });
76
+ }
77
+ return cachedRouter;
78
+ })();
79
+ return routerInitPromise;
68
80
  }
69
81
  function checkCircuitHealth() {
70
82
  if (cachedCircuitBreaker === null) return { healthy: true, message: "" };
@@ -160,4 +172,4 @@ ${prompt}`;
160
172
  export {
161
173
  executeExpert
162
174
  };
163
- //# sourceMappingURL=chunk-SVKH6ASN.js.map
175
+ //# sourceMappingURL=chunk-HMXQKDUV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/pipeline/expert-bridge.ts"],"sourcesContent":["/**\n * Expert Bridge — Programmatic access to the execute_expert pipeline (#1693)\n *\n * Provides a clean wrapper for calling experts with the full pipeline:\n * timeout, fallback cascade, degradation detection, heartbeat, outcome recording.\n *\n * DRY: reuses createBuiltInExpert + CompositeRouter instead of reimplementing.\n *\n * @module pipeline/expert-bridge\n */\n\nimport { createLogger, getTimeProvider } from '../core/index.js';\nimport type { BuiltInExpertType } from '../agents/experts/expert-config.js';\nimport { isRateLimitText } from '../adapters/rate-limit-detector.js';\nimport { getCliForModelId } from '../config/model-availability.js';\nimport { MODEL_IDS } from '../config/model-capabilities-types.js';\nimport type { CliNameLiteral, ModelId } from '../config/model-capabilities-types.js';\n\n/**\n * Resolves a CLI from a possibly-unknown model string returned by a CLI\n * response. Returns undefined if the model string isn't in the registry —\n * caller treats undefined as \"don't know which CLI ran\" rather than\n * fabricating a default (#2823).\n */\nfunction resolveCliFromModelString(model: string | undefined): CliNameLiteral | undefined {\n if (model === undefined) return undefined;\n if (!(MODEL_IDS as readonly string[]).includes(model)) return undefined;\n return getCliForModelId(model as ModelId);\n}\n\nconst logger = createLogger({ component: 'expert-bridge' });\n\n/** Base delay for rate limit retry backoff (ms). Scales linearly: 3s, 6s, 9s. */\nconst RATE_LIMIT_BASE_DELAY_MS = 3000;\n\n/** Result of an expert execution. */\nexport interface ExpertBridgeResult {\n readonly success: boolean;\n readonly text: string;\n readonly expertType: BuiltInExpertType;\n readonly durationMs: number;\n readonly error?: string;\n /**\n * CLI that actually executed the task, resolved from the underlying\n * `CliResponse.model` via `getCliForModelId`. Undefined when the bridge\n * failed before dispatch (no adapters / circuit-open / rate-limit cap).\n * Callers writing to OutcomeStore should use this rather than hardcoding\n * a cli — see #2823 (#1154 regression).\n */\n readonly cli?: CliNameLiteral;\n}\n\n/**\n * Execute an expert task with the full nexus-agents expert pipeline.\n *\n * Creates a built-in expert, executes via CompositeRouter (for intelligent\n * CLI routing), and records outcomes. Falls back gracefully on failure.\n *\n * @param expertType - Built-in expert type (code, architecture, security, qa, etc.)\n * @param prompt - Task prompt for the expert\n * @returns Expert result with text output\n */\n/** Minimal router interface for the bridge. */\ninterface RouterLike {\n executeTask(task: { content: string; options?: Record<string, unknown> | undefined }): Promise<{\n ok: boolean;\n value: { text: string; cli?: CliNameLiteral };\n error: { message: string };\n }>;\n}\n\n// Cached router — lazily initialized, reused across calls within a session\nlet cachedRouter: RouterLike | null = null;\n\n// Cached MCP config — generated once, reused across expert calls (#1708)\nlet cachedMcpConfigPath: string | null = null;\n// Coalesces concurrent init under voter fan-out (closes #2969). consensus_vote\n// fans out N=7 callers on cold start; without this each one ran the full init\n// including a mkdtemp() that the loser N-1 instances never cleaned up.\nlet mcpConfigInitPromise: Promise<string | null> | null = null;\n\n/** Get or create cached MCP config path for expert CLI sessions (#1708). */\nasync function getMcpConfigPath(): Promise<string | null> {\n if (cachedMcpConfigPath !== null) return cachedMcpConfigPath;\n mcpConfigInitPromise ??= (async (): Promise<string | null> => {\n try {\n const { generateMcpConfig } = await import('../cli-adapters/child-mcp-config.js');\n const config = await generateMcpConfig();\n cachedMcpConfigPath = config.configPath;\n return cachedMcpConfigPath;\n } catch {\n mcpConfigInitPromise = null; // allow retry on next call\n return null; // MCP config not available — experts run without tools\n }\n })();\n return mcpConfigInitPromise;\n}\n\n/** Cached circuit breaker for health monitoring (#1766). */\nlet cachedCircuitBreaker: {\n getHealthStatus(): {\n systemHealthy: boolean;\n healthyCount: number;\n clis: ReadonlyArray<{ name: string; healthy: boolean }>;\n };\n} | null = null;\n\n/**\n * Adapt a CompositeRouter to the narrower RouterLike interface used by this\n * bridge. Previously did `as unknown as RouterLike` which hid any structural\n * mismatch between CompositeRouter's `Result<CliResponse, CliError>` and\n * RouterLike's flat `{ ok, value: { text }, error: { message } }` shape.\n * If CliResponse renames `.text` → `.output` (or similar), this adapter\n * breaks at compile time instead of silently returning wrong data (#1921).\n */\nfunction adaptCompositeRouter(\n compositeRouter: import('../cli-adapters/composite-router.js').ICompositeRouter\n): RouterLike {\n return {\n async executeTask(task): Promise<{\n ok: boolean;\n value: { text: string; cli?: CliNameLiteral };\n error: { message: string };\n }> {\n const cliTask: import('../cli-adapters/types.js').CliTask = {\n content: task.content,\n ...(task.options !== undefined ? { options: task.options } : {}),\n };\n const result = await compositeRouter.executeTask(cliTask);\n if (result.ok) {\n // #2823: surface which CLI actually executed so callers writing to\n // OutcomeStore don't have to hardcode 'claude' (the bug #1154 fixed\n // and that regressed into the pipeline/ tree). Derive via the\n // canonical model→cli mapping in the registry — if the underlying\n // adapter didn't set `model` or the model isn't in the registry,\n // cli stays undefined and downstream code can skip the record\n // rather than lie.\n const cli = resolveCliFromModelString(result.value.model);\n return {\n ok: true,\n value: { text: result.value.text, ...(cli !== undefined && { cli }) },\n error: { message: '' },\n };\n }\n return { ok: false, value: { text: '' }, error: { message: result.error.message } };\n },\n };\n}\n\n// Coalesces concurrent router init the same way mcpConfigInitPromise does\n// (closes #2969). N=7 voter fan-out previously ran createAllAdapters() N times\n// — N sets of CLI probe subprocesses, all but one discarded.\nlet routerInitPromise: Promise<RouterLike | null> | null = null;\n\n/** Get or create a cached CompositeRouter with circuit breaker monitoring. */\nasync function getRouter(): Promise<RouterLike | null> {\n if (cachedRouter !== null) return cachedRouter;\n routerInitPromise ??= (async (): Promise<RouterLike | null> => {\n const { createAllAdapters } = await import('../cli-adapters/factory.js');\n const { createCompositeRouter } = await import('../cli-adapters/composite-router.js');\n const adapters = createAllAdapters();\n if (adapters.size === 0) {\n routerInitPromise = null; // allow retry once adapters become available\n return null;\n }\n cachedRouter = adaptCompositeRouter(createCompositeRouter(adapters));\n\n // Initialize circuit breaker monitoring (#1766)\n try {\n const { createCliCircuitBreakerIntegration } =\n await import('../cli-adapters/cli-circuit-breaker.js');\n cachedCircuitBreaker = createCliCircuitBreakerIntegration([...adapters.values()]);\n } catch (error: unknown) {\n // Circuit breaker not available — continue without it. Log so we can\n // notice if initialization silently stops working (#1913 Class B).\n const msg = error instanceof Error ? error.message : String(error);\n logger.debug('Circuit breaker init failed; continuing without it', { error: msg });\n }\n\n return cachedRouter;\n })();\n return routerInitPromise;\n}\n\n/** Check CLI health before dispatch (#1766). */\nfunction checkCircuitHealth(): { healthy: boolean; message: string } {\n if (cachedCircuitBreaker === null) return { healthy: true, message: '' };\n const status = cachedCircuitBreaker.getHealthStatus();\n if (!status.systemHealthy) {\n return {\n healthy: false,\n message: `All CLI circuits open (${String(status.healthyCount)}/${String(status.clis.length)} healthy)`,\n };\n }\n return { healthy: true, message: '' };\n}\n\n/** Dispatch task to router with rate limit retry (#1802). */\nasync function dispatchWithRateLimitRetry(\n router: RouterLike,\n task: { content: string; options?: Record<string, unknown> | undefined },\n expertType: BuiltInExpertType,\n start: number\n): Promise<ExpertBridgeResult> {\n const maxAttempts = 3;\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n const result = await router.executeTask(task);\n const durationMs = getTimeProvider().now() - start;\n\n if (result.ok) {\n logger.info('Expert executed successfully', {\n expertType,\n durationMs,\n cli: result.value.cli,\n });\n return {\n success: true,\n text: result.value.text,\n expertType,\n durationMs,\n ...(result.value.cli !== undefined && { cli: result.value.cli }),\n };\n }\n\n const isRateLimit = isRateLimitText(result.error.message);\n if (isRateLimit && attempt < maxAttempts - 1) {\n const backoffMs = RATE_LIMIT_BASE_DELAY_MS * (attempt + 1);\n logger.warn('Expert rate limited, retrying', { expertType, attempt: attempt + 1, backoffMs });\n await new Promise((resolve) => setTimeout(resolve, backoffMs));\n continue;\n }\n\n logger.warn('Expert execution failed', { expertType, error: result.error.message });\n return { success: false, text: '', expertType, durationMs, error: result.error.message };\n }\n\n return {\n success: false,\n text: '',\n expertType,\n durationMs: getTimeProvider().now() - start,\n error: 'Max retry attempts exceeded',\n };\n}\n\nexport async function executeExpert(\n expertType: BuiltInExpertType,\n prompt: string\n): Promise<ExpertBridgeResult> {\n const start = getTimeProvider().now();\n try {\n const { BUILT_IN_EXPERTS } = await import('../agents/experts/expert-config.js');\n const config = BUILT_IN_EXPERTS[expertType];\n const fullPrompt = `${config.systemPrompt}\\n\\n${prompt}`;\n\n const router = await getRouter();\n if (router === null) {\n return {\n success: false,\n text: `[No adapters] ${prompt}`,\n expertType,\n durationMs: getTimeProvider().now() - start,\n error: 'No CLI adapters available',\n };\n }\n\n // Check circuit breaker health before dispatch (#1766)\n const health = checkCircuitHealth();\n if (!health.healthy) {\n logger.warn('Circuit breaker: all CLIs unavailable', { expertType, reason: health.message });\n return {\n success: false,\n text: '',\n expertType,\n durationMs: getTimeProvider().now() - start,\n error: health.message,\n };\n }\n\n // Pass MCP config so CLI experts can call nexus-agents tools (#1708)\n const mcpConfigPath = await getMcpConfigPath();\n const task: { content: string; options?: Record<string, unknown> | undefined } = {\n content: fullPrompt,\n };\n if (mcpConfigPath !== null) task.options = { mcpConfigPath };\n\n return await dispatchWithRateLimitRetry(router, task, expertType, start);\n } catch (error) {\n const durationMs = getTimeProvider().now() - start;\n const msg = error instanceof Error ? error.message : String(error);\n logger.warn('Expert bridge error', { expertType, error: msg });\n return { success: false, text: '', expertType, durationMs, error: msg };\n }\n}\n"],"mappings":"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","names":[]}
@@ -4,7 +4,7 @@ import {
4
4
  getErrorMessage,
5
5
  getTimeProvider,
6
6
  ok
7
- } from "./chunk-LJIB6TNE.js";
7
+ } from "./chunk-7VNVDFD5.js";
8
8
 
9
9
  // src/context/session-memory.ts
10
10
  import * as fs from "fs";
@@ -351,4 +351,4 @@ export {
351
351
  SessionMemory,
352
352
  createSessionMemory
353
353
  };
354
- //# sourceMappingURL=chunk-PV3OEDLO.js.map
354
+ //# sourceMappingURL=chunk-HVZ52LOL.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runConfigInitSync
3
- } from "./chunk-6YQCLEHL.js";
3
+ } from "./chunk-SXL744NF.js";
4
4
  import {
5
5
  VERSION,
6
6
  checkApiKeys,
@@ -8,10 +8,10 @@ import {
8
8
  checkSqlite,
9
9
  defaultConfig,
10
10
  initDataDirectories
11
- } from "./chunk-WLAQXITV.js";
11
+ } from "./chunk-S36LIUV2.js";
12
12
  import {
13
13
  probeAllClis
14
- } from "./chunk-BMNWUPJO.js";
14
+ } from "./chunk-2SQXJQTA.js";
15
15
  import {
16
16
  BUILT_IN_EXPERTS
17
17
  } from "./chunk-ZM4O442V.js";
@@ -25,7 +25,7 @@ import {
25
25
  getErrorMessage,
26
26
  getTimeProvider,
27
27
  symbols
28
- } from "./chunk-LJIB6TNE.js";
28
+ } from "./chunk-7VNVDFD5.js";
29
29
  import {
30
30
  ensureGitignored,
31
31
  findRepoRoot
@@ -340,19 +340,24 @@ function areHooksConfigured() {
340
340
  return false;
341
341
  }
342
342
  }
343
- function getExistingHooks() {
343
+ function readExistingHooks() {
344
+ let raw;
344
345
  try {
345
- const result = execSync2("claude config get hooks", {
346
+ raw = execSync2("claude config get hooks", {
346
347
  encoding: "utf-8",
347
348
  stdio: ["pipe", "pipe", "pipe"]
348
349
  });
349
- const trimmed = result.trim();
350
- if (!trimmed || trimmed === "null" || trimmed === "undefined") {
351
- return void 0;
352
- }
353
- return JSON.parse(trimmed);
354
- } catch {
355
- return void 0;
350
+ } catch (error) {
351
+ return { kind: "unreadable", reason: getErrorMessage(error) };
352
+ }
353
+ const trimmed = raw.trim();
354
+ if (!trimmed || trimmed === "null" || trimmed === "undefined") {
355
+ return { kind: "absent" };
356
+ }
357
+ try {
358
+ return { kind: "present", hooks: JSON.parse(trimmed) };
359
+ } catch (error) {
360
+ return { kind: "parse_failed", reason: getErrorMessage(error), raw: trimmed };
356
361
  }
357
362
  }
358
363
  function mergeHookArrays(existing, newHooks) {
@@ -391,8 +396,16 @@ function configureHooks(force = false) {
391
396
  };
392
397
  }
393
398
  const nexusHookConfig = generateHookConfig();
399
+ const existing = readExistingHooks();
400
+ if (existing.kind === "parse_failed") {
401
+ return {
402
+ success: false,
403
+ alreadyConfigured: false,
404
+ message: `Refusing to configure hooks: existing hooks could not be parsed. Overwriting would wipe your current settings. Inspect with \`claude config get hooks\` and resolve manually. (parse error: ${existing.reason})`
405
+ };
406
+ }
407
+ const existingHooks = existing.kind === "present" ? existing.hooks : void 0;
394
408
  try {
395
- const existingHooks = getExistingHooks();
396
409
  const mergedHooks = mergeHookConfigs(existingHooks, nexusHookConfig.hooks);
397
410
  const configJson = JSON.stringify(mergedHooks);
398
411
  execFileSync("claude", ["config", "set", "hooks", configJson], {
@@ -1974,4 +1987,4 @@ export {
1974
1987
  setupCommand,
1975
1988
  setupCommandAsync
1976
1989
  };
1977
- //# sourceMappingURL=chunk-EKLY4LBJ.js.map
1990
+ //# sourceMappingURL=chunk-JM3R267Z.js.map