nexus-agents 8.89.0 → 8.89.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ast-rule-runner-HYMHJPAG.js → ast-rule-runner-AMZCLKRV.js} +5 -5
- package/dist/{child-mcp-config-V2KDXRWX.js → child-mcp-config-7DSYI325.js} +5 -5
- package/dist/{chunk-V2DMA45O.js → chunk-3IBALX36.js} +2 -2
- package/dist/{chunk-KTYUDC5Q.js → chunk-3PQIIMHN.js} +2 -2
- package/dist/{chunk-DQ3XMBOE.js → chunk-4IV25ZUM.js} +2 -2
- package/dist/{chunk-2KSAG3VC.js → chunk-5GZ4UN5F.js} +2 -2
- package/dist/{chunk-EEVZ7GLC.js → chunk-5UCGVAEZ.js} +4 -4
- package/dist/{chunk-4LRBHXR2.js → chunk-5XZCL7QT.js} +13 -13
- package/dist/{chunk-NOJ6LVFH.js → chunk-6FFBX665.js} +2 -2
- package/dist/{chunk-V6D32OOI.js → chunk-AXBEG6VW.js} +3 -3
- package/dist/{chunk-AQE77PSX.js → chunk-BJXSG5YL.js} +4 -4
- package/dist/{chunk-KZPXD7U6.js → chunk-CG7OSI5P.js} +3 -3
- package/dist/{chunk-W4VUK2R4.js → chunk-E6AJH4F4.js} +42 -41
- package/dist/{chunk-W4VUK2R4.js.map → chunk-E6AJH4F4.js.map} +1 -1
- package/dist/{chunk-VD5K6GS2.js → chunk-EKZ6V7SE.js} +9 -7
- package/dist/chunk-EKZ6V7SE.js.map +1 -0
- package/dist/{chunk-Z5UEPOL6.js → chunk-GXBXZCY7.js} +193 -34
- package/dist/chunk-GXBXZCY7.js.map +1 -0
- package/dist/{chunk-7EOV55QT.js → chunk-GYQIIAVM.js} +4 -4
- package/dist/{chunk-ZRHH7LN6.js → chunk-HLXXP3CS.js} +4 -4
- package/dist/{chunk-EPAGKDF6.js → chunk-ILA4UGXI.js} +2 -2
- package/dist/{chunk-BHU67ATO.js → chunk-JRZEB4OQ.js} +2 -2
- package/dist/{chunk-RGS3FYTS.js → chunk-JYKRCQSU.js} +5 -5
- package/dist/{chunk-WV23K2TM.js → chunk-JYZNPK62.js} +10 -10
- package/dist/{chunk-NQFMVMAK.js → chunk-KQE7EFBF.js} +7 -7
- package/dist/{chunk-HRZGFSSS.js → chunk-LFFXUHX3.js} +2 -2
- package/dist/{chunk-RNDHNRSX.js → chunk-LWOX65CP.js} +102 -21
- package/dist/chunk-LWOX65CP.js.map +1 -0
- package/dist/{chunk-BYQNCZSZ.js → chunk-LZNYQYDU.js} +2 -2
- package/dist/{chunk-4DSPBZY3.js → chunk-NZN3SWSZ.js} +17 -9
- package/dist/chunk-NZN3SWSZ.js.map +1 -0
- package/dist/{chunk-HERI7LXN.js → chunk-OITVVSWO.js} +2 -2
- package/dist/{chunk-O5L3O6ZP.js → chunk-PENEGF75.js} +2 -2
- package/dist/{chunk-X5JKKMNU.js → chunk-SCXCJSTT.js} +2 -2
- package/dist/{chunk-RE4CUPIU.js → chunk-TLFZPJOY.js} +4 -4
- package/dist/{chunk-6NHMBRTQ.js → chunk-TRCYUQ4M.js} +2 -2
- package/dist/{chunk-Z2JDWZNH.js → chunk-UDWZJY3V.js} +2 -2
- package/dist/{chunk-RQLIPUQK.js → chunk-UE7A2XHM.js} +2 -2
- package/dist/{chunk-HNWZNCST.js → chunk-VM4HZT3B.js} +6 -6
- package/dist/{chunk-BYVS6N3C.js → chunk-XJAGCUMD.js} +3 -3
- package/dist/{chunk-RKLT2TOT.js → chunk-XJWIBTUM.js} +2 -2
- package/dist/{chunk-ICPAPQKC.js → chunk-XU2SJKFK.js} +2 -2
- package/dist/{chunk-7D6D6SG2.js → chunk-Z5VUMKF5.js} +3 -3
- package/dist/{chunk-NLN7YJDT.js → chunk-ZTTBGME2.js} +2 -2
- package/dist/{cli-circuit-breaker-V3JIKQNR.js → cli-circuit-breaker-MCQG3PQK.js} +5 -5
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +62 -58
- package/dist/cli.js.map +1 -1
- package/dist/{composite-router-GY36ICWT.js → composite-router-QAYCHEFG.js} +4 -4
- package/dist/{consensus-vote-6ZU7GKSG.js → consensus-vote-UHNEKOO7.js} +20 -20
- package/dist/{consensus-vote-types-ptxFNv55.d.ts → consensus-vote-types-DhmacUE7.d.ts} +12 -0
- package/dist/{context-retriever-MIEU5JEN.js → context-retriever-UXQCDDRY.js} +11 -11
- package/dist/doctor-deep-QRLRDFM4.js +13 -0
- package/dist/{doctor-live-LTNJVKXN.js → doctor-live-CUKBQSSH.js} +13 -13
- package/dist/{expert-bridge-RU2W64EM.js → expert-bridge-ZG2IA3RJ.js} +6 -6
- package/dist/factory-FPNYFKXU.js +15 -0
- package/dist/factory-RQEHJ4AW.js +27 -0
- package/dist/{improvement-review-THY3BKTW.js → improvement-review-N36SVUDG.js} +7 -7
- package/dist/index.d.ts +12 -5
- package/dist/index.js +34 -34
- package/dist/{init-opencode-EZKEBCXO.js → init-opencode-4QECASK4.js} +7 -7
- package/dist/issue-triage-BIEZBWV2.js +16 -0
- package/dist/{learning-persistence-ER7E5Q6T.js → learning-persistence-FB4U5AX2.js} +3 -3
- package/dist/{pr-reviewer-helpers-NSXZZZPF.js → pr-reviewer-helpers-RK5IT4US.js} +6 -6
- package/dist/{registry-command-WZYYQVRI.js → registry-command-MBZFFDWS.js} +4 -4
- package/dist/{repo-security-plan-6BINWUKE.js → repo-security-plan-W76YLC2M.js} +5 -5
- package/dist/research-helpers-synthesize-GI5JFAQM.js +14 -0
- package/dist/{routing-memory-DLFZLG4R.js → routing-memory-WLCUOPDE.js} +4 -4
- package/dist/{session-memory-DHPZAKZW.js → session-memory-HU3XMQEH.js} +5 -5
- package/dist/setup-config-XA756R2O.js +11 -0
- package/dist/{setup-custom-api-5YAYMVXH.js → setup-custom-api-ETBGOE7O.js} +6 -6
- package/dist/setup-data-dir-UNM34FGW.js +32 -0
- package/dist/{tool-memory-TQCQJUC2.js → tool-memory-7XMQAQQM.js} +8 -8
- package/dist/{tool-memory-registry-adapters-2WWNV55A.js → tool-memory-registry-adapters-7CNLBBZU.js} +3 -3
- package/dist/{unified-registry-AGIN3Q3S.js → unified-registry-LR4OCUFI.js} +13 -13
- package/dist/{weather-report-5FMZQP5L.js → weather-report-UYKQUSBB.js} +4 -4
- package/package.json +1 -1
- package/dist/chunk-4DSPBZY3.js.map +0 -1
- package/dist/chunk-RNDHNRSX.js.map +0 -1
- package/dist/chunk-VD5K6GS2.js.map +0 -1
- package/dist/chunk-Z5UEPOL6.js.map +0 -1
- package/dist/doctor-deep-4J6BX5BV.js +0 -13
- package/dist/factory-2H6BJGI5.js +0 -27
- package/dist/factory-OJHA452T.js +0 -15
- package/dist/issue-triage-KSW7SNU6.js +0 -16
- package/dist/research-helpers-synthesize-F6PQD2SG.js +0 -14
- package/dist/setup-config-SLS5DTFQ.js +0 -11
- package/dist/setup-data-dir-J2AJOTLA.js +0 -32
- /package/dist/{ast-rule-runner-HYMHJPAG.js.map → ast-rule-runner-AMZCLKRV.js.map} +0 -0
- /package/dist/{child-mcp-config-V2KDXRWX.js.map → child-mcp-config-7DSYI325.js.map} +0 -0
- /package/dist/{chunk-V2DMA45O.js.map → chunk-3IBALX36.js.map} +0 -0
- /package/dist/{chunk-KTYUDC5Q.js.map → chunk-3PQIIMHN.js.map} +0 -0
- /package/dist/{chunk-DQ3XMBOE.js.map → chunk-4IV25ZUM.js.map} +0 -0
- /package/dist/{chunk-2KSAG3VC.js.map → chunk-5GZ4UN5F.js.map} +0 -0
- /package/dist/{chunk-EEVZ7GLC.js.map → chunk-5UCGVAEZ.js.map} +0 -0
- /package/dist/{chunk-4LRBHXR2.js.map → chunk-5XZCL7QT.js.map} +0 -0
- /package/dist/{chunk-NOJ6LVFH.js.map → chunk-6FFBX665.js.map} +0 -0
- /package/dist/{chunk-V6D32OOI.js.map → chunk-AXBEG6VW.js.map} +0 -0
- /package/dist/{chunk-AQE77PSX.js.map → chunk-BJXSG5YL.js.map} +0 -0
- /package/dist/{chunk-KZPXD7U6.js.map → chunk-CG7OSI5P.js.map} +0 -0
- /package/dist/{chunk-7EOV55QT.js.map → chunk-GYQIIAVM.js.map} +0 -0
- /package/dist/{chunk-ZRHH7LN6.js.map → chunk-HLXXP3CS.js.map} +0 -0
- /package/dist/{chunk-EPAGKDF6.js.map → chunk-ILA4UGXI.js.map} +0 -0
- /package/dist/{chunk-BHU67ATO.js.map → chunk-JRZEB4OQ.js.map} +0 -0
- /package/dist/{chunk-RGS3FYTS.js.map → chunk-JYKRCQSU.js.map} +0 -0
- /package/dist/{chunk-WV23K2TM.js.map → chunk-JYZNPK62.js.map} +0 -0
- /package/dist/{chunk-NQFMVMAK.js.map → chunk-KQE7EFBF.js.map} +0 -0
- /package/dist/{chunk-HRZGFSSS.js.map → chunk-LFFXUHX3.js.map} +0 -0
- /package/dist/{chunk-BYQNCZSZ.js.map → chunk-LZNYQYDU.js.map} +0 -0
- /package/dist/{chunk-HERI7LXN.js.map → chunk-OITVVSWO.js.map} +0 -0
- /package/dist/{chunk-O5L3O6ZP.js.map → chunk-PENEGF75.js.map} +0 -0
- /package/dist/{chunk-X5JKKMNU.js.map → chunk-SCXCJSTT.js.map} +0 -0
- /package/dist/{chunk-RE4CUPIU.js.map → chunk-TLFZPJOY.js.map} +0 -0
- /package/dist/{chunk-6NHMBRTQ.js.map → chunk-TRCYUQ4M.js.map} +0 -0
- /package/dist/{chunk-Z2JDWZNH.js.map → chunk-UDWZJY3V.js.map} +0 -0
- /package/dist/{chunk-RQLIPUQK.js.map → chunk-UE7A2XHM.js.map} +0 -0
- /package/dist/{chunk-HNWZNCST.js.map → chunk-VM4HZT3B.js.map} +0 -0
- /package/dist/{chunk-BYVS6N3C.js.map → chunk-XJAGCUMD.js.map} +0 -0
- /package/dist/{chunk-RKLT2TOT.js.map → chunk-XJWIBTUM.js.map} +0 -0
- /package/dist/{chunk-ICPAPQKC.js.map → chunk-XU2SJKFK.js.map} +0 -0
- /package/dist/{chunk-7D6D6SG2.js.map → chunk-Z5VUMKF5.js.map} +0 -0
- /package/dist/{chunk-NLN7YJDT.js.map → chunk-ZTTBGME2.js.map} +0 -0
- /package/dist/{cli-circuit-breaker-V3JIKQNR.js.map → cli-circuit-breaker-MCQG3PQK.js.map} +0 -0
- /package/dist/{composite-router-GY36ICWT.js.map → composite-router-QAYCHEFG.js.map} +0 -0
- /package/dist/{consensus-vote-6ZU7GKSG.js.map → consensus-vote-UHNEKOO7.js.map} +0 -0
- /package/dist/{context-retriever-MIEU5JEN.js.map → context-retriever-UXQCDDRY.js.map} +0 -0
- /package/dist/{doctor-deep-4J6BX5BV.js.map → doctor-deep-QRLRDFM4.js.map} +0 -0
- /package/dist/{doctor-live-LTNJVKXN.js.map → doctor-live-CUKBQSSH.js.map} +0 -0
- /package/dist/{expert-bridge-RU2W64EM.js.map → expert-bridge-ZG2IA3RJ.js.map} +0 -0
- /package/dist/{factory-2H6BJGI5.js.map → factory-FPNYFKXU.js.map} +0 -0
- /package/dist/{factory-OJHA452T.js.map → factory-RQEHJ4AW.js.map} +0 -0
- /package/dist/{improvement-review-THY3BKTW.js.map → improvement-review-N36SVUDG.js.map} +0 -0
- /package/dist/{init-opencode-EZKEBCXO.js.map → init-opencode-4QECASK4.js.map} +0 -0
- /package/dist/{issue-triage-KSW7SNU6.js.map → issue-triage-BIEZBWV2.js.map} +0 -0
- /package/dist/{learning-persistence-ER7E5Q6T.js.map → learning-persistence-FB4U5AX2.js.map} +0 -0
- /package/dist/{pr-reviewer-helpers-NSXZZZPF.js.map → pr-reviewer-helpers-RK5IT4US.js.map} +0 -0
- /package/dist/{registry-command-WZYYQVRI.js.map → registry-command-MBZFFDWS.js.map} +0 -0
- /package/dist/{repo-security-plan-6BINWUKE.js.map → repo-security-plan-W76YLC2M.js.map} +0 -0
- /package/dist/{research-helpers-synthesize-F6PQD2SG.js.map → research-helpers-synthesize-GI5JFAQM.js.map} +0 -0
- /package/dist/{routing-memory-DLFZLG4R.js.map → routing-memory-WLCUOPDE.js.map} +0 -0
- /package/dist/{session-memory-DHPZAKZW.js.map → session-memory-HU3XMQEH.js.map} +0 -0
- /package/dist/{setup-config-SLS5DTFQ.js.map → setup-config-XA756R2O.js.map} +0 -0
- /package/dist/{setup-custom-api-5YAYMVXH.js.map → setup-custom-api-ETBGOE7O.js.map} +0 -0
- /package/dist/{setup-data-dir-J2AJOTLA.js.map → setup-data-dir-UNM34FGW.js.map} +0 -0
- /package/dist/{tool-memory-TQCQJUC2.js.map → tool-memory-7XMQAQQM.js.map} +0 -0
- /package/dist/{tool-memory-registry-adapters-2WWNV55A.js.map → tool-memory-registry-adapters-7CNLBBZU.js.map} +0 -0
- /package/dist/{unified-registry-AGIN3Q3S.js.map → unified-registry-LR4OCUFI.js.map} +0 -0
- /package/dist/{weather-report-5FMZQP5L.js.map → weather-report-UYKQUSBB.js.map} +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveCliSlot
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-6FFBX665.js";
|
|
4
4
|
import {
|
|
5
5
|
createLogger,
|
|
6
6
|
getTimeProvider,
|
|
7
7
|
isRateLimitText
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-NZN3SWSZ.js";
|
|
9
9
|
|
|
10
10
|
// src/pipeline/expert-bridge.ts
|
|
11
11
|
function resolveCliFromModelString(model) {
|
|
@@ -17,6 +17,7 @@ function routedAttribution(routed, model) {
|
|
|
17
17
|
const cli = routed.routedCli ?? resolveCliFromModelString(model);
|
|
18
18
|
return {
|
|
19
19
|
...cli !== void 0 && { cli },
|
|
20
|
+
...routed.routedArm !== void 0 && { routedArm: routed.routedArm },
|
|
20
21
|
...routed.routedCli !== void 0 && { routedBy: "composite-router" },
|
|
21
22
|
...routed.routedDurationMs !== void 0 && { routedDurationMs: routed.routedDurationMs }
|
|
22
23
|
};
|
|
@@ -29,7 +30,7 @@ async function getMcpConfigPath() {
|
|
|
29
30
|
if (cachedMcpConfigPath !== null) return cachedMcpConfigPath;
|
|
30
31
|
mcpConfigInitPromise ??= (async () => {
|
|
31
32
|
try {
|
|
32
|
-
const { generateMcpConfig } = await import("./child-mcp-config-
|
|
33
|
+
const { generateMcpConfig } = await import("./child-mcp-config-7DSYI325.js");
|
|
33
34
|
const config = await generateMcpConfig();
|
|
34
35
|
cachedMcpConfigPath = config.configPath;
|
|
35
36
|
cachedMcpConfigCleanup = config.cleanup;
|
|
@@ -106,8 +107,8 @@ var routerInitPromise = null;
|
|
|
106
107
|
async function getRouter() {
|
|
107
108
|
if (cachedRouter !== null) return cachedRouter;
|
|
108
109
|
routerInitPromise ??= (async () => {
|
|
109
|
-
const { createAllAdapters } = await import("./factory-
|
|
110
|
-
const { createCompositeRouter } = await import("./composite-router-
|
|
110
|
+
const { createAllAdapters } = await import("./factory-RQEHJ4AW.js");
|
|
111
|
+
const { createCompositeRouter } = await import("./composite-router-QAYCHEFG.js");
|
|
111
112
|
const adapters = createAllAdapters();
|
|
112
113
|
if (adapters.size === 0) {
|
|
113
114
|
routerInitPromise = null;
|
|
@@ -115,7 +116,7 @@ async function getRouter() {
|
|
|
115
116
|
}
|
|
116
117
|
cachedRouter = adaptCompositeRouter(createCompositeRouter(adapters));
|
|
117
118
|
try {
|
|
118
|
-
const { createCliCircuitBreakerIntegration } = await import("./cli-circuit-breaker-
|
|
119
|
+
const { createCliCircuitBreakerIntegration } = await import("./cli-circuit-breaker-MCQG3PQK.js");
|
|
119
120
|
cachedCircuitBreaker = createCliCircuitBreakerIntegration([...adapters.values()]);
|
|
120
121
|
} catch (error) {
|
|
121
122
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -139,6 +140,7 @@ function checkCircuitHealth() {
|
|
|
139
140
|
function attributionOf(source) {
|
|
140
141
|
return {
|
|
141
142
|
...source.cli !== void 0 && { cli: source.cli },
|
|
143
|
+
...source.routedArm !== void 0 && { routedArm: source.routedArm },
|
|
142
144
|
...source.routedBy !== void 0 && { routedBy: source.routedBy },
|
|
143
145
|
...source.routedDurationMs !== void 0 && { routedDurationMs: source.routedDurationMs }
|
|
144
146
|
};
|
|
@@ -246,4 +248,4 @@ export {
|
|
|
246
248
|
tokenSplitFromUsage,
|
|
247
249
|
executeExpert
|
|
248
250
|
};
|
|
249
|
-
//# sourceMappingURL=chunk-
|
|
251
|
+
//# sourceMappingURL=chunk-EKZ6V7SE.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 { resolveCliSlot } from '../config/model-availability.js';\nimport type { CliNameLiteral } from '../config/model-capabilities-types.js';\nimport type { OutcomeRoutedBy } from '../orchestration/outcomes/outcome-types.js';\nimport type { RoutingArmId } from '../cli-adapters/types-core.js';\n\n/**\n * Resolves a CLI slot from the model string a (CLI or API) adapter returned.\n * Known models resolve to their exact slot; **unknown** models — new releases\n * or API/openrouter models not in the curated registry — fall back to the\n * vendor-derived slot (#3317 / #3293) so the outcome is recorded against a real\n * slot instead of being dropped with an undefined cli (the api-mode gap).\n * Returns undefined only when no model is present (the bridge failed before\n * dispatch — no execution to attribute).\n */\nfunction resolveCliFromModelString(model: string | undefined): CliNameLiteral | undefined {\n return resolveCliSlot(model);\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 * Routing arm id the router ran (#6552), when it names one: `api:anthropic`\n * for the Anthropic API arm, where {@link cli} reads the `claude` slot. An\n * outcome row records this, so warm start credits the arm that ran.\n * Undefined when no arm ran, or when the router named only a slot.\n */\n readonly routedArm?: RoutingArmId;\n /**\n * `'composite-router'` when `CompositeRouter.executeTask` selected the CLI\n * that produced this result, success or failure (#6521). Set where the\n * router's decision and the execution meet (`adaptCompositeRouter`), so an\n * outcome recorder copies it rather than asserting routing on its own.\n * Undefined when no arm ran: routing failed, no adapters, circuit open.\n */\n readonly routedBy?: OutcomeRoutedBy;\n /**\n * Wall time of the routed arm's call alone (#6521), from the router. Unlike\n * {@link durationMs} it excludes expert import, MCP-config setup and\n * rate-limit backoff. Undefined when no arm ran.\n */\n readonly routedDurationMs?: number;\n /**\n * Total tokens (input + output) the underlying CLI/adapter reported for this\n * call, when available (#3396). Best-effort: `CliResponse.usage` is optional\n * — CLI-subprocess paths whose `extractUsage` returns null leave this\n * undefined. Consumers (budget enforcement #3395, model.called attribution\n * #3387, routing-experience metrics) must tolerate `undefined`.\n */\n readonly tokensUsed?: number;\n /**\n * Concrete model id the underlying adapter reported (`CliResponse.model`),\n * when present (#3387). Distinct from {@link cli} (the slot): one CLI can run\n * several models. Undefined when the adapter didn't report a model or the\n * bridge failed before dispatch. Required to emit a `model.called` event.\n */\n readonly model?: string;\n /**\n * Input/output token split from the adapter's `CliResponse.usage` (#3387),\n * when reported. Best-effort like {@link tokensUsed}; both undefined together\n * when no usage was available. `tokensIn + tokensOut` reconciles with\n * `tokensUsed` (single source of truth — both derive from the same record).\n */\n readonly tokensIn?: number;\n readonly tokensOut?: number;\n}\n\n/** Attribution of a routed arm's run, on success and on failure (#6521). */\ninterface RoutedAttribution {\n cli?: CliNameLiteral;\n routedArm?: RoutingArmId;\n routedBy?: OutcomeRoutedBy;\n routedDurationMs?: number;\n}\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: RoutedAttribution & {\n text: string;\n tokensUsed?: number;\n model?: string;\n tokensIn?: number;\n tokensOut?: number;\n };\n error: RoutedAttribution & { message: string };\n }>;\n}\n\n/**\n * The bridge's attribution for a router result (#6521). The router's own\n * `routedCli` is authoritative: the model string can name another vendor's\n * slot (an `api:custom-openai` arm shows as opencode while serving a GPT\n * model). The model-derived CLI is the fallback only when no arm is named.\n * No `routedCli` on a failure means routing failed before an arm ran, and\n * then there is nothing to attribute.\n */\nfunction routedAttribution(\n routed: { routedCli?: CliNameLiteral; routedArm?: RoutingArmId; routedDurationMs?: number },\n model: string | undefined\n): RoutedAttribution {\n const cli = routed.routedCli ?? resolveCliFromModelString(model);\n return {\n ...(cli !== undefined && { cli }),\n ...(routed.routedArm !== undefined && { routedArm: routed.routedArm }),\n ...(routed.routedCli !== undefined && { routedBy: 'composite-router' as const }),\n ...(routed.routedDurationMs !== undefined && { routedDurationMs: routed.routedDurationMs }),\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// Cached cleanup for the cached config's tempdir (closes #2946). Previously\n// the cleanup returned by `generateMcpConfig` was thrown away, so\n// `/tmp/nexus-mcp-XXXXXX/` accumulated one entry per MCP server lifetime.\n// Stored here + invoked by `shutdownExpertBridge()` from the server's\n// graceful-shutdown path.\nlet cachedMcpConfigCleanup: (() => Promise<void>) | 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 cachedMcpConfigCleanup = config.cleanup;\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/**\n * Removes the cached MCP-config tempdir (closes #2946). Invoke from the\n * server's graceful-shutdown path so stale nexus-mcp-* tempdirs (under\n * the OS tmpdir, see child-mcp-config.ts) don't accumulate across daemon\n * restarts. Idempotent; safe to call multiple times. Never throws —\n * cleanup failures are logged and swallowed.\n */\nexport async function shutdownExpertBridge(): Promise<void> {\n const cleanup = cachedMcpConfigCleanup;\n if (cleanup === null) return;\n cachedMcpConfigCleanup = null;\n cachedMcpConfigPath = null;\n mcpConfigInitPromise = null;\n try {\n await cleanup();\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : String(error);\n logger.debug('Expert-bridge MCP-config cleanup failed', { error: msg });\n }\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 */\n/**\n * Total tokens from a best-effort `CliResponse.usage` record (#3396). Prefers\n * the reported `totalTokens`; falls back to input+output; returns undefined\n * when no usage was reported (so callers can distinguish \"0 tokens\" — which\n * never happens for a real call — from \"unknown\").\n */\nexport function totalTokensFromUsage(\n usage: { totalTokens?: number; inputTokens?: number; outputTokens?: number } | undefined\n): number | undefined {\n if (usage === undefined) return undefined;\n if (typeof usage.totalTokens === 'number') return usage.totalTokens;\n const total = (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);\n return total > 0 ? total : undefined;\n}\n\n/**\n * Per-direction token split from a best-effort `CliResponse.usage` record\n * (#3387). Unlike {@link totalTokensFromUsage} this keeps `tokensIn`/`tokensOut`\n * separate — the granularity `ModelCalledEvent` requires for attribution.\n * Returns undefined when no usage was reported or both directions are zero (no\n * real call), so callers skip emitting a noise event instead of recording\n * zeros. Reconciles with the total: `tokensIn + tokensOut === totalTokensFromUsage`.\n */\nexport function tokenSplitFromUsage(\n usage: { inputTokens?: number; outputTokens?: number; totalTokens?: number } | undefined\n): { tokensIn: number; tokensOut: number } | undefined {\n if (usage === undefined) return undefined;\n const tokensIn = usage.inputTokens ?? 0;\n const tokensOut = usage.outputTokens ?? 0;\n if (tokensIn + tokensOut === 0) return undefined;\n return { tokensIn, tokensOut };\n}\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: RoutedAttribution & {\n text: string;\n tokensUsed?: number;\n model?: string;\n tokensIn?: number;\n tokensOut?: number;\n };\n error: RoutedAttribution & { 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 // #6521: the arm the router ran is the attribution; see routedAttribution.\n const attribution = routedAttribution(result.value, result.value.model);\n // #3396: surface token usage (best-effort) so budget enforcement,\n // attribution, and routing-experience metrics get real numbers instead\n // of zeros. `usage` is optional and `totalTokens` may be absent — fall\n // back to input+output, and leave undefined when no usage was reported.\n const tokensUsed = totalTokensFromUsage(result.value.usage);\n // #3387: also surface the concrete model + per-direction token split so\n // a meaningful `model.called` event can be emitted. Both derive from the\n // same CliResponse, so tokensIn+tokensOut reconciles with tokensUsed.\n const model = result.value.model;\n const split = tokenSplitFromUsage(result.value.usage);\n return {\n ok: true,\n value: {\n text: result.value.text,\n ...attribution,\n ...(tokensUsed !== undefined && { tokensUsed }),\n ...(model !== undefined && { model }),\n ...(split !== undefined && { tokensIn: split.tokensIn, tokensOut: split.tokensOut }),\n },\n error: { message: '' },\n };\n }\n // #6521 I1: a routed failure keeps its arm, so it is recorded and the\n // loop does not see only the arm's successes.\n const routed = 'routedCli' in result.error ? result.error : {};\n return {\n ok: false,\n value: { text: '' },\n error: { message: result.error.message, ...routedAttribution(routed, undefined) },\n };\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 // ROUTER CONSTRUCTION, a distinct operation from adapter acquisition\n // (#5191, ratified 5/6). `createCompositeRouter` needs\n // `Map<RoutingArmId, ICliAdapter>`; `getGlobalRegistry()` returns\n // `IResilientAdapter` (extends `IModelAdapter`) one CLI at a time, so the\n // canonical path cannot type-check here.\n //\n // It also should not be used: the router IS the selection/failover layer,\n // so resilient-wrapped arms would nest two failover mechanisms, and the\n // shared circuit breaker would make an arm report unavailable without the\n // router ever testing it. That is the doctor-probe defect (#5209) applied\n // to routing — and this map is the LinUCB arm space, so a coupled arm\n // availability would distort exploration signals.\n //\n // Pinned by `router-operation.test.ts`.\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/** The attribution fields present on `source`; absent ones stay absent. */\nfunction attributionOf(source: RoutedAttribution): RoutedAttribution {\n return {\n ...(source.cli !== undefined && { cli: source.cli }),\n ...(source.routedArm !== undefined && { routedArm: source.routedArm }),\n ...(source.routedBy !== undefined && { routedBy: source.routedBy }),\n ...(source.routedDurationMs !== undefined && { routedDurationMs: source.routedDurationMs }),\n };\n}\n\n/** A successful router result as an {@link ExpertBridgeResult}; absent fields stay absent. */\nfunction toSuccessResult(\n value: Awaited<ReturnType<RouterLike['executeTask']>>['value'],\n expertType: BuiltInExpertType,\n durationMs: number\n): ExpertBridgeResult {\n return {\n success: true,\n text: value.text,\n expertType,\n durationMs,\n ...attributionOf(value),\n ...(value.tokensUsed !== undefined && { tokensUsed: value.tokensUsed }),\n ...(value.model !== undefined && { model: value.model }),\n ...(value.tokensIn !== undefined && { tokensIn: value.tokensIn }),\n ...(value.tokensOut !== undefined && { tokensOut: value.tokensOut }),\n };\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 toSuccessResult(result.value, expertType, durationMs);\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 // Only the final attempt is attributed: a rate-limited attempt that is\n // retried is not recorded as a routed outcome of its own.\n logger.warn('Expert execution failed', { expertType, error: result.error.message });\n return {\n success: false,\n text: '',\n expertType,\n durationMs,\n error: result.error.message,\n ...attributionOf(result.error),\n };\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\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 */\nexport function executeExpert(\n expertType: BuiltInExpertType,\n prompt: string\n): Promise<ExpertBridgeResult>;\nexport function executeExpert(\n expertType: BuiltInExpertType,\n prompt: string,\n // eslint-disable-next-line @typescript-eslint/unified-signatures -- Preserve the published two-argument API signature.\n options: { workDir?: string | undefined }\n): Promise<ExpertBridgeResult>;\n/** Execute with an optional working directory for the expert's CLI subprocess. */\nexport async function executeExpert(\n expertType: BuiltInExpertType,\n prompt: string,\n options?: { workDir?: string | undefined }\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 if (options?.workDir !== undefined) {\n task.options = { ...task.options, workDir: options.workDir };\n }\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":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isGatewayModelAdapter
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-BJXSG5YL.js";
|
|
4
4
|
import {
|
|
5
5
|
allOf
|
|
6
6
|
} from "./chunk-OQB3XC5O.js";
|
|
@@ -25,20 +25,20 @@ import {
|
|
|
25
25
|
toolSuccessStructured,
|
|
26
26
|
withProgressHeartbeat,
|
|
27
27
|
wrapToolWithTimeout
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-GYQIIAVM.js";
|
|
29
29
|
import {
|
|
30
30
|
VERSION
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-JRZEB4OQ.js";
|
|
32
32
|
import {
|
|
33
33
|
UNRESOLVED_MODEL_ID,
|
|
34
34
|
assessPanelIndependence,
|
|
35
35
|
countDistinctModels,
|
|
36
36
|
createEvent,
|
|
37
37
|
getGlobalRegistry
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-TLFZPJOY.js";
|
|
39
39
|
import {
|
|
40
40
|
getToolMemory
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-VM4HZT3B.js";
|
|
42
42
|
import {
|
|
43
43
|
authRemediation,
|
|
44
44
|
classifyExtractedError,
|
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
isTimeoutText,
|
|
49
49
|
sleep,
|
|
50
50
|
withTimeout
|
|
51
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-JYZNPK62.js";
|
|
52
52
|
import {
|
|
53
53
|
sanitizeErrorDetails,
|
|
54
54
|
sanitizeOutput
|
|
@@ -88,18 +88,18 @@ import {
|
|
|
88
88
|
resolveClassGuardMs,
|
|
89
89
|
resolveVoteTimeout,
|
|
90
90
|
stepBus
|
|
91
|
-
} from "./chunk-
|
|
91
|
+
} from "./chunk-NZN3SWSZ.js";
|
|
92
92
|
import {
|
|
93
93
|
ensureLearningDir,
|
|
94
94
|
getOutcomesFile
|
|
95
|
-
} from "./chunk-
|
|
95
|
+
} from "./chunk-UE7A2XHM.js";
|
|
96
96
|
import {
|
|
97
97
|
findRepoRoot,
|
|
98
98
|
getNexusDataDir,
|
|
99
99
|
nexusDataPath,
|
|
100
100
|
nexusDataPathEnsure,
|
|
101
101
|
nexusSharedPath
|
|
102
|
-
} from "./chunk-
|
|
102
|
+
} from "./chunk-LWOX65CP.js";
|
|
103
103
|
|
|
104
104
|
// src/mcp/tools/consensus-vote.ts
|
|
105
105
|
import { z as z16 } from "zod";
|
|
@@ -6435,7 +6435,7 @@ function logPartialProposal(bounded, log) {
|
|
|
6435
6435
|
}
|
|
6436
6436
|
async function runContrarianCheck(proposal, log, opts) {
|
|
6437
6437
|
try {
|
|
6438
|
-
const { executeExpert } = await import("./expert-bridge-
|
|
6438
|
+
const { executeExpert } = await import("./expert-bridge-ZG2IA3RJ.js");
|
|
6439
6439
|
const bounded = boundArtifactForReview(proposal, CONTRARIAN_PROPOSAL_BUDGET, "proposal");
|
|
6440
6440
|
logPartialProposal(bounded, log);
|
|
6441
6441
|
const result = await executeExpert("architecture", buildContrarianPrompt(bounded, opts), {
|
|
@@ -6809,8 +6809,125 @@ function parseVoteRecordsText(text) {
|
|
|
6809
6809
|
return { records, redactions, invalidLines };
|
|
6810
6810
|
}
|
|
6811
6811
|
|
|
6812
|
+
// src/mcp/tools/consensus-vote-recording.ts
|
|
6813
|
+
import { mkdirSync as mkdirSync3 } from "node:fs";
|
|
6814
|
+
import { dirname as dirname3 } from "node:path";
|
|
6815
|
+
|
|
6816
|
+
// src/utils/file-lock.ts
|
|
6817
|
+
import { closeSync, openSync, readFileSync as readFileSync4, statSync as statSync2, unlinkSync, writeSync } from "node:fs";
|
|
6818
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
6819
|
+
import { hostname } from "node:os";
|
|
6820
|
+
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
6821
|
+
var DEFAULT_STALE_MS = 3e4;
|
|
6822
|
+
var DEFAULT_RETRY_MS = 15;
|
|
6823
|
+
var FileLockTimeoutError = class extends Error {
|
|
6824
|
+
constructor(lockPath, timeoutMs) {
|
|
6825
|
+
super(`Timed out after ${String(timeoutMs)}ms waiting for lock ${lockPath}`);
|
|
6826
|
+
this.lockPath = lockPath;
|
|
6827
|
+
this.timeoutMs = timeoutMs;
|
|
6828
|
+
this.name = "FileLockTimeoutError";
|
|
6829
|
+
}
|
|
6830
|
+
lockPath;
|
|
6831
|
+
timeoutMs;
|
|
6832
|
+
};
|
|
6833
|
+
function errnoCode(error) {
|
|
6834
|
+
if (typeof error !== "object" || error === null) return void 0;
|
|
6835
|
+
const code = error.code;
|
|
6836
|
+
return typeof code === "string" ? code : void 0;
|
|
6837
|
+
}
|
|
6838
|
+
function newToken() {
|
|
6839
|
+
return `${hostname()}:${String(process.pid)}:${randomBytes2(8).toString("hex")}`;
|
|
6840
|
+
}
|
|
6841
|
+
function tryCreate(lockPath, token) {
|
|
6842
|
+
let fd;
|
|
6843
|
+
try {
|
|
6844
|
+
fd = openSync(lockPath, "wx", 384);
|
|
6845
|
+
} catch (error) {
|
|
6846
|
+
if (errnoCode(error) === "EEXIST") return false;
|
|
6847
|
+
throw error;
|
|
6848
|
+
}
|
|
6849
|
+
try {
|
|
6850
|
+
writeSync(fd, token);
|
|
6851
|
+
} finally {
|
|
6852
|
+
closeSync(fd);
|
|
6853
|
+
}
|
|
6854
|
+
return true;
|
|
6855
|
+
}
|
|
6856
|
+
function readLock(lockPath) {
|
|
6857
|
+
try {
|
|
6858
|
+
const { mtimeMs } = statSync2(lockPath);
|
|
6859
|
+
return { token: readFileSync4(lockPath, "utf-8"), mtimeMs };
|
|
6860
|
+
} catch (error) {
|
|
6861
|
+
if (errnoCode(error) === "ENOENT") return void 0;
|
|
6862
|
+
throw error;
|
|
6863
|
+
}
|
|
6864
|
+
}
|
|
6865
|
+
function isRunning(pid) {
|
|
6866
|
+
try {
|
|
6867
|
+
process.kill(pid, 0);
|
|
6868
|
+
return true;
|
|
6869
|
+
} catch (error) {
|
|
6870
|
+
return errnoCode(error) === "EPERM";
|
|
6871
|
+
}
|
|
6872
|
+
}
|
|
6873
|
+
function isStale(lock, staleMs) {
|
|
6874
|
+
const match = /^(.+):(\d+):[0-9a-z]+$/.exec(lock.token);
|
|
6875
|
+
if (match?.[1] === hostname()) return !isRunning(Number(match[2]));
|
|
6876
|
+
return Date.now() - lock.mtimeMs > staleMs;
|
|
6877
|
+
}
|
|
6878
|
+
function removeIfOwned(path2, token) {
|
|
6879
|
+
if (readLock(path2)?.token === token) unlinkSync(path2);
|
|
6880
|
+
}
|
|
6881
|
+
function unlinkIfPresent(path2) {
|
|
6882
|
+
try {
|
|
6883
|
+
unlinkSync(path2);
|
|
6884
|
+
} catch (error) {
|
|
6885
|
+
if (errnoCode(error) !== "ENOENT") throw error;
|
|
6886
|
+
}
|
|
6887
|
+
}
|
|
6888
|
+
async function breakIfStale(lockPath, staleMs, onStaleObserved) {
|
|
6889
|
+
const seen = readLock(lockPath);
|
|
6890
|
+
if (seen === void 0 || !isStale(seen, staleMs)) return;
|
|
6891
|
+
await onStaleObserved?.();
|
|
6892
|
+
const breakPath = `${lockPath}.break`;
|
|
6893
|
+
const breakToken = newToken();
|
|
6894
|
+
if (!tryCreate(breakPath, breakToken)) {
|
|
6895
|
+
const breaker = readLock(breakPath);
|
|
6896
|
+
if (breaker !== void 0 && isStale(breaker, staleMs)) unlinkIfPresent(breakPath);
|
|
6897
|
+
return;
|
|
6898
|
+
}
|
|
6899
|
+
try {
|
|
6900
|
+
const now = readLock(lockPath);
|
|
6901
|
+
if (now !== void 0 && isStale(now, staleMs)) {
|
|
6902
|
+
unlinkSync(lockPath);
|
|
6903
|
+
}
|
|
6904
|
+
} finally {
|
|
6905
|
+
removeIfOwned(breakPath, breakToken);
|
|
6906
|
+
}
|
|
6907
|
+
}
|
|
6908
|
+
function delay2(ms) {
|
|
6909
|
+
return new Promise((resolveDelay) => setTimeout(resolveDelay, ms));
|
|
6910
|
+
}
|
|
6911
|
+
async function withFileLock(lockPath, body, options = {}) {
|
|
6912
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
6913
|
+
const staleMs = options.staleMs ?? DEFAULT_STALE_MS;
|
|
6914
|
+
const retryMs = options.retryMs ?? DEFAULT_RETRY_MS;
|
|
6915
|
+
const token = newToken();
|
|
6916
|
+
const deadline = Date.now() + timeoutMs;
|
|
6917
|
+
while (!tryCreate(lockPath, token)) {
|
|
6918
|
+
await breakIfStale(lockPath, staleMs, options.onStaleObserved);
|
|
6919
|
+
if (Date.now() >= deadline) throw new FileLockTimeoutError(lockPath, timeoutMs);
|
|
6920
|
+
await delay2(retryMs + Math.floor(Math.random() * retryMs));
|
|
6921
|
+
}
|
|
6922
|
+
try {
|
|
6923
|
+
return await body();
|
|
6924
|
+
} finally {
|
|
6925
|
+
removeIfOwned(lockPath, token);
|
|
6926
|
+
}
|
|
6927
|
+
}
|
|
6928
|
+
|
|
6812
6929
|
// src/orchestration/outcomes/outcome-store-persistence.ts
|
|
6813
|
-
import { appendFileSync as appendFileSync3, readFileSync as
|
|
6930
|
+
import { appendFileSync as appendFileSync3, readFileSync as readFileSync5, writeFileSync, existsSync as existsSync3 } from "node:fs";
|
|
6814
6931
|
var PersistedOutcomeSchema = TaskOutcomeSchema.loose();
|
|
6815
6932
|
var PersistentOutcomeStore = class extends OutcomeStore {
|
|
6816
6933
|
filePath;
|
|
@@ -6869,7 +6986,7 @@ var PersistentOutcomeStore = class extends OutcomeStore {
|
|
|
6869
6986
|
return;
|
|
6870
6987
|
}
|
|
6871
6988
|
try {
|
|
6872
|
-
const content =
|
|
6989
|
+
const content = readFileSync5(this.filePath, "utf-8");
|
|
6873
6990
|
const lines = content.split("\n").filter((line) => line.trim().length > 0);
|
|
6874
6991
|
let loaded = 0;
|
|
6875
6992
|
let skipped = 0;
|
|
@@ -6983,7 +7100,7 @@ var VOTE_RECORD_STRATEGIES = /* @__PURE__ */ new Set([
|
|
|
6983
7100
|
function toRecordStrategy(strategy) {
|
|
6984
7101
|
return VOTE_RECORD_STRATEGIES.has(strategy) ? strategy : "simple_majority";
|
|
6985
7102
|
}
|
|
6986
|
-
function recordAuthenticVote(args) {
|
|
7103
|
+
async function recordAuthenticVote(args) {
|
|
6987
7104
|
const allSimulated = args.votes.length > 0 && args.votes.every((v) => v.source === "simulation");
|
|
6988
7105
|
if (allSimulated) {
|
|
6989
7106
|
logger6.debug("Skipping authentic vote record \u2014 all votes simulated");
|
|
@@ -7000,7 +7117,26 @@ function recordAuthenticVote(args) {
|
|
|
7000
7117
|
return { persisted: false, reason: "write-failed", detail };
|
|
7001
7118
|
}
|
|
7002
7119
|
const id = `vote-${String(getTimeProvider().now())}-${getRandomProvider().random().toString(36).slice(2, 9)}`;
|
|
7003
|
-
|
|
7120
|
+
let record;
|
|
7121
|
+
try {
|
|
7122
|
+
record = await underLedgerLock(
|
|
7123
|
+
resolvedPath,
|
|
7124
|
+
() => persistVoteRecord(storeInput(args, id, resolvedPath))
|
|
7125
|
+
);
|
|
7126
|
+
} catch (error) {
|
|
7127
|
+
return lockFailure(resolvedPath, error);
|
|
7128
|
+
}
|
|
7129
|
+
if (record === void 0) {
|
|
7130
|
+
return {
|
|
7131
|
+
persisted: false,
|
|
7132
|
+
reason: "write-failed",
|
|
7133
|
+
detail: voteRecordWriteFailedMessage(resolvedPath)
|
|
7134
|
+
};
|
|
7135
|
+
}
|
|
7136
|
+
return confirmPersisted(record, resolvedPath);
|
|
7137
|
+
}
|
|
7138
|
+
function storeInput(args, id, filePath) {
|
|
7139
|
+
return {
|
|
7004
7140
|
id,
|
|
7005
7141
|
proposal: args.proposal,
|
|
7006
7142
|
strategy: toRecordStrategy(args.strategy),
|
|
@@ -7013,16 +7149,39 @@ function recordAuthenticVote(args) {
|
|
|
7013
7149
|
...args.ratifies !== void 0 ? { ratifies: args.ratifies } : {},
|
|
7014
7150
|
...args.ratifiesPr !== void 0 ? { ratifiesPr: args.ratifiesPr } : {},
|
|
7015
7151
|
...args.errorPolicy !== void 0 ? { errorPolicy: args.errorPolicy } : {},
|
|
7152
|
+
// #6531: write to the path resolved by the caller, so the read-back and the
|
|
7153
|
+
// path the caller prints are the file the store wrote.
|
|
7154
|
+
filePath,
|
|
7016
7155
|
logger: logger6
|
|
7156
|
+
};
|
|
7157
|
+
}
|
|
7158
|
+
async function underLedgerLock(path2, write) {
|
|
7159
|
+
mkdirSync3(dirname3(path2), { recursive: true });
|
|
7160
|
+
return withFileLock(`${path2}.lock`, write);
|
|
7161
|
+
}
|
|
7162
|
+
function lockFailure(path2, error) {
|
|
7163
|
+
logger6.warn("Failed to take the vote-record ledger lock", {
|
|
7164
|
+
error: getErrorMessage(error),
|
|
7165
|
+
path: path2
|
|
7017
7166
|
});
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7167
|
+
const detail = error instanceof FileLockTimeoutError ? `Authentic vote record NOT persisted (${path2}): timed out after ${String(error.timeoutMs)}ms waiting for the ledger lock ${error.lockPath}, held by another live process.` : voteRecordWriteFailedMessage(path2);
|
|
7168
|
+
return { persisted: false, reason: "write-failed", detail };
|
|
7169
|
+
}
|
|
7170
|
+
function confirmPersisted(record, path2) {
|
|
7171
|
+
if (ledgerHolds(path2, record)) return { persisted: true, record, path: path2 };
|
|
7172
|
+
const detail = `record ${record.id} (sequence ${String(record.sequence)}) is not in ${path2} after the append; it was NOT persisted`;
|
|
7173
|
+
logger6.error(detail);
|
|
7174
|
+
return { persisted: false, reason: "read-back-missed", detail };
|
|
7175
|
+
}
|
|
7176
|
+
function ledgerHolds(path2, record) {
|
|
7177
|
+
try {
|
|
7178
|
+
return readVoteRecords(path2).records.some(
|
|
7179
|
+
(onDisk) => onDisk.id === record.id && onDisk.hash === record.hash
|
|
7180
|
+
);
|
|
7181
|
+
} catch (error) {
|
|
7182
|
+
logger6.warn("Vote-record read-back failed", { error: getErrorMessage(error), path: path2 });
|
|
7183
|
+
return false;
|
|
7024
7184
|
}
|
|
7025
|
-
return { persisted: true, record };
|
|
7026
7185
|
}
|
|
7027
7186
|
function recordVoteError(proposal, errorMessage) {
|
|
7028
7187
|
try {
|
|
@@ -7217,13 +7376,13 @@ function warnOnce(toolName, logger11) {
|
|
|
7217
7376
|
}
|
|
7218
7377
|
|
|
7219
7378
|
// src/mcp/jobs/job-result-store.ts
|
|
7220
|
-
import { existsSync as existsSync6, readdirSync, unlinkSync, writeFileSync as writeFileSync3, chmodSync, mkdirSync as
|
|
7221
|
-
import { dirname as
|
|
7379
|
+
import { existsSync as existsSync6, readdirSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3, chmodSync, mkdirSync as mkdirSync4 } from "node:fs";
|
|
7380
|
+
import { dirname as dirname4 } from "node:path";
|
|
7222
7381
|
import { z as z14 } from "zod";
|
|
7223
7382
|
|
|
7224
7383
|
// src/mcp/jobs/job-idempotency.ts
|
|
7225
7384
|
import { createHash as createHash3, randomUUID } from "node:crypto";
|
|
7226
|
-
import { existsSync as existsSync4, readFileSync as
|
|
7385
|
+
import { existsSync as existsSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "node:fs";
|
|
7227
7386
|
import { z as z12 } from "zod";
|
|
7228
7387
|
var logger7 = createLogger({ component: "job-idempotency" });
|
|
7229
7388
|
var IdempotencyIndexEntrySchema = z12.object({
|
|
@@ -7320,7 +7479,7 @@ function shortCircuitOrFreshJobId(params) {
|
|
|
7320
7479
|
}
|
|
7321
7480
|
function readIndexEntry(path2) {
|
|
7322
7481
|
try {
|
|
7323
|
-
const raw = JSON.parse(
|
|
7482
|
+
const raw = JSON.parse(readFileSync6(path2, "utf-8"));
|
|
7324
7483
|
const parsed = IdempotencyIndexEntrySchema.safeParse(raw);
|
|
7325
7484
|
if (!parsed.success) {
|
|
7326
7485
|
logger7.warn("Idempotency index file failed schema check", { path: path2 });
|
|
@@ -7337,7 +7496,7 @@ function readIndexEntry(path2) {
|
|
|
7337
7496
|
}
|
|
7338
7497
|
|
|
7339
7498
|
// src/mcp/jobs/job-result-candidates.ts
|
|
7340
|
-
import { existsSync as existsSync5, readFileSync as
|
|
7499
|
+
import { existsSync as existsSync5, readFileSync as readFileSync7 } from "node:fs";
|
|
7341
7500
|
import { join as join3 } from "node:path";
|
|
7342
7501
|
var candidatePathsResolverForTests;
|
|
7343
7502
|
function getExplicitDataDir() {
|
|
@@ -7409,7 +7568,7 @@ function selectAuthoritativeJobRecord(records) {
|
|
|
7409
7568
|
}
|
|
7410
7569
|
function readJobResultFile(path2, jobId, logger11) {
|
|
7411
7570
|
try {
|
|
7412
|
-
const raw = JSON.parse(
|
|
7571
|
+
const raw = JSON.parse(readFileSync7(path2, "utf-8"));
|
|
7413
7572
|
const parsed = JobResultSchema.safeParse(raw);
|
|
7414
7573
|
if (!parsed.success) {
|
|
7415
7574
|
logger11.warn("Job result file failed schema check", { jobId, path: path2 });
|
|
@@ -7648,7 +7807,7 @@ function isAbandonedAt(record, nowMs, abandonedAfter) {
|
|
|
7648
7807
|
}
|
|
7649
7808
|
function jobResultPath(jobId) {
|
|
7650
7809
|
const primary = candidateJobResultPaths(jobId)[0] ?? nexusDataPathEnsure("jobs", `result-${jobId}.json`);
|
|
7651
|
-
|
|
7810
|
+
mkdirSync4(dirname4(primary), { recursive: true });
|
|
7652
7811
|
return primary;
|
|
7653
7812
|
}
|
|
7654
7813
|
function persistJobRecord(path2, record) {
|
|
@@ -7864,7 +8023,7 @@ function sweepRecord(jobId, entry, sweep) {
|
|
|
7864
8023
|
}
|
|
7865
8024
|
const settledAt = record.completedAt ?? record.createdAt;
|
|
7866
8025
|
if (!isOlderThan(settledAt, sweep.nowMs, sweep.retentionMs)) return "kept";
|
|
7867
|
-
if (!sweep.dryRun)
|
|
8026
|
+
if (!sweep.dryRun) unlinkSync2(path2);
|
|
7868
8027
|
return "deleted";
|
|
7869
8028
|
}
|
|
7870
8029
|
function sweepKeyEntry(entry, removedJobIds, sweep) {
|
|
@@ -7874,7 +8033,7 @@ function sweepKeyEntry(entry, removedJobIds, sweep) {
|
|
|
7874
8033
|
if (!isOlderThan(indexEntry.createdAt, sweep.nowMs, sweep.retentionMs)) return null;
|
|
7875
8034
|
const recordGone = removedJobIds.has(indexEntry.jobId) || !candidateJobResultPaths(indexEntry.jobId).some((p) => existsSync6(p));
|
|
7876
8035
|
if (!recordGone) return null;
|
|
7877
|
-
if (!sweep.dryRun)
|
|
8036
|
+
if (!sweep.dryRun) unlinkSync2(path2);
|
|
7878
8037
|
return "deletedKeys";
|
|
7879
8038
|
}
|
|
7880
8039
|
function isOlderThan(isoTimestamp, nowMs, windowMs) {
|
|
@@ -9059,9 +9218,9 @@ function finalizeVotingResult(args) {
|
|
|
9059
9218
|
if (args.higherOrderResult !== void 0) result.higherOrderResult = args.higherOrderResult;
|
|
9060
9219
|
return result;
|
|
9061
9220
|
}
|
|
9062
|
-
function recordVoteSideEffects(proposal, strategy, result, logger11, declared) {
|
|
9221
|
+
async function recordVoteSideEffects(proposal, strategy, result, logger11, declared) {
|
|
9063
9222
|
const decisionId = `consensus-${String(getTimeProvider().now())}-${randomUUID2().slice(0, 8)}`;
|
|
9064
|
-
const voteRecord = recordAuthenticVote({
|
|
9223
|
+
const voteRecord = await recordAuthenticVote({
|
|
9065
9224
|
proposal,
|
|
9066
9225
|
strategy,
|
|
9067
9226
|
result: result.result,
|
|
@@ -9146,7 +9305,7 @@ async function handleConsensusVote(deps, args, signal, onVoteCollected) {
|
|
|
9146
9305
|
approvalPercentage: result.result.approvalPercentage,
|
|
9147
9306
|
votes: result.votes
|
|
9148
9307
|
});
|
|
9149
|
-
const { costSummary, voteRecord } = recordVoteSideEffects(
|
|
9308
|
+
const { costSummary, voteRecord } = await recordVoteSideEffects(
|
|
9150
9309
|
args.proposal,
|
|
9151
9310
|
result.strategy,
|
|
9152
9311
|
result,
|
|
@@ -9544,4 +9703,4 @@ export {
|
|
|
9544
9703
|
CONSENSUS_VOTE_TOOL_SCHEMA,
|
|
9545
9704
|
registerConsensusVoteTool
|
|
9546
9705
|
};
|
|
9547
|
-
//# sourceMappingURL=chunk-
|
|
9706
|
+
//# sourceMappingURL=chunk-GXBXZCY7.js.map
|