nexus-agents 2.95.0 → 2.96.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 (118) hide show
  1. package/README.md +4 -4
  2. package/dist/{child-mcp-config-NW7JMSDK.js → child-mcp-config-HZUEFKXB.js} +2 -2
  3. package/dist/{chunk-GC5FH2IA.js → chunk-23NNSR45.js} +7 -7
  4. package/dist/{chunk-ECZW5FXN.js → chunk-2472O6HR.js} +2 -2
  5. package/dist/{chunk-ECBH5INZ.js → chunk-2KHD2ANY.js} +4 -3
  6. package/dist/{chunk-ECBH5INZ.js.map → chunk-2KHD2ANY.js.map} +1 -1
  7. package/dist/chunk-3ZROPKLV.js +2133 -0
  8. package/dist/chunk-3ZROPKLV.js.map +1 -0
  9. package/dist/{chunk-FYGZ4MEQ.js → chunk-7P3UIYJH.js} +415 -1410
  10. package/dist/chunk-7P3UIYJH.js.map +1 -0
  11. package/dist/{chunk-WGA4VGIR.js → chunk-AJMHTC4J.js} +3 -3
  12. package/dist/{chunk-KHZGMF2W.js → chunk-ANH2A44T.js} +4 -4
  13. package/dist/{chunk-G42N55ZR.js → chunk-AREIPUCD.js} +2 -2
  14. package/dist/{chunk-D3JSXVX3.js → chunk-AW3HJHJT.js} +2 -2
  15. package/dist/{chunk-FXVJLJUF.js → chunk-DTFM37IG.js} +2 -2
  16. package/dist/{chunk-47Z3YPOK.js → chunk-EUUWRNDZ.js} +2 -2
  17. package/dist/{chunk-3HXWI34V.js → chunk-FHZUOIVC.js} +3 -3
  18. package/dist/{chunk-ZICVVBDW.js → chunk-FPAUF3YB.js} +2 -2
  19. package/dist/{chunk-55G7KQ7F.js → chunk-ICOHLRHT.js} +5 -5
  20. package/dist/{chunk-FTDVA33Z.js → chunk-INFJH4JX.js} +4 -4
  21. package/dist/{chunk-BSHDI4BH.js → chunk-JEK5CHK2.js} +2 -2
  22. package/dist/{chunk-7GUP6KQQ.js → chunk-MMW4KIBH.js} +2 -2
  23. package/dist/{chunk-LZOTH2GI.js → chunk-MVCJEIUU.js} +2 -2
  24. package/dist/{chunk-2X24T4ZD.js → chunk-NJN5SGU2.js} +7 -7
  25. package/dist/{chunk-5HBDXW44.js → chunk-OHGKVMT3.js} +2 -2
  26. package/dist/{chunk-4NVYN2MB.js → chunk-ONIHS7K7.js} +4 -4
  27. package/dist/{chunk-TEKWQNQ2.js → chunk-P7Y3KLKG.js} +3 -3
  28. package/dist/{chunk-O4LVC4MQ.js → chunk-R2KJ22LX.js} +2 -2
  29. package/dist/chunk-SRSAMAPP.js +1095 -0
  30. package/dist/chunk-SRSAMAPP.js.map +1 -0
  31. package/dist/{chunk-LXROEQAO.js → chunk-SSHL5TAX.js} +2 -2
  32. package/dist/{chunk-YYXJ6RTO.js → chunk-THVTU2UG.js} +3 -3
  33. package/dist/{chunk-3H6Q3RZM.js → chunk-XMYJWMWN.js} +4 -4
  34. package/dist/{chunk-PFOY5ML6.js → chunk-YSYBVLYS.js} +3 -3
  35. package/dist/{chunk-QUPPV6UO.js → chunk-YWIZ3UQ6.js} +2 -2
  36. package/dist/{chunk-6IWPN5UB.js → chunk-Z3XF5LRT.js} +2 -2
  37. package/dist/{chunk-VTMQND6B.js → chunk-Z7PILY4E.js} +361 -2468
  38. package/dist/chunk-Z7PILY4E.js.map +1 -0
  39. package/dist/{chunk-Y3OOHHKQ.js → chunk-ZBQXPP7M.js} +2 -2
  40. package/dist/{cli-circuit-breaker-LNU5DQSB.js → cli-circuit-breaker-L6SWUVOP.js} +4 -4
  41. package/dist/cli.js +104 -52
  42. package/dist/cli.js.map +1 -1
  43. package/dist/{composite-router-DJ54ND5X.js → composite-router-HFBOUCXD.js} +2 -2
  44. package/dist/{consensus-vote-XLEQFVE7.js → consensus-vote-YEZIP2JQ.js} +13 -12
  45. package/dist/{context-retriever-6O6TREXH.js → context-retriever-PTRDEBBH.js} +6 -6
  46. package/dist/{doctor-deep-PSNJPELP.js → doctor-deep-WHCDAV3Z.js} +3 -3
  47. package/dist/{expert-bridge-Q3OWPD4L.js → expert-bridge-N4L47MHU.js} +4 -4
  48. package/dist/{factory-43RVPRT5.js → factory-EFLOKY32.js} +5 -5
  49. package/dist/{factory-PSMTMC7V.js → factory-ZKGYCGDT.js} +5 -5
  50. package/dist/improvement-review-4MTIYCOZ.js +27 -0
  51. package/dist/index.js +52 -49
  52. package/dist/index.js.map +1 -1
  53. package/dist/{init-opencode-25AUARJH.js → init-opencode-42GKRQDA.js} +5 -5
  54. package/dist/{issue-triage-KZTENUDH.js → issue-triage-TEPE6VMA.js} +5 -5
  55. package/dist/{pr-reviewer-helpers-XENJ4E2T.js → pr-reviewer-helpers-G4O22XF6.js} +4 -4
  56. package/dist/{registry-command-X3O34FAK.js → registry-command-32PUZNNG.js} +2 -2
  57. package/dist/{repo-security-plan-XCX7EFJR.js → repo-security-plan-XWUDQB34.js} +3 -3
  58. package/dist/{research-helpers-synthesize-CGVR6M4S.js → research-helpers-synthesize-YI6S7SN6.js} +3 -3
  59. package/dist/{routing-memory-YZRYGXQC.js → routing-memory-Z3ZCTPFM.js} +2 -2
  60. package/dist/{session-memory-SXQAA2EN.js → session-memory-5ZZ2SXDE.js} +3 -3
  61. package/dist/{setup-command-VG7JZI6O.js → setup-command-U3ILRY5H.js} +11 -11
  62. package/dist/{setup-config-VJAK6AA2.js → setup-config-WZYLXPDO.js} +3 -3
  63. package/dist/{setup-custom-api-KSF2JMTS.js → setup-custom-api-K4EN47CP.js} +4 -4
  64. package/dist/{tool-memory-L7SDFSF5.js → tool-memory-53Y2TUR3.js} +5 -5
  65. package/dist/{weather-report-D6HFOK7S.js → weather-report-JOBWXWQ3.js} +2 -2
  66. package/dist/weather-report-JOBWXWQ3.js.map +1 -0
  67. package/package.json +12 -2
  68. package/dist/chunk-FYGZ4MEQ.js.map +0 -1
  69. package/dist/chunk-VTMQND6B.js.map +0 -1
  70. /package/dist/{child-mcp-config-NW7JMSDK.js.map → child-mcp-config-HZUEFKXB.js.map} +0 -0
  71. /package/dist/{chunk-GC5FH2IA.js.map → chunk-23NNSR45.js.map} +0 -0
  72. /package/dist/{chunk-ECZW5FXN.js.map → chunk-2472O6HR.js.map} +0 -0
  73. /package/dist/{chunk-WGA4VGIR.js.map → chunk-AJMHTC4J.js.map} +0 -0
  74. /package/dist/{chunk-KHZGMF2W.js.map → chunk-ANH2A44T.js.map} +0 -0
  75. /package/dist/{chunk-G42N55ZR.js.map → chunk-AREIPUCD.js.map} +0 -0
  76. /package/dist/{chunk-D3JSXVX3.js.map → chunk-AW3HJHJT.js.map} +0 -0
  77. /package/dist/{chunk-FXVJLJUF.js.map → chunk-DTFM37IG.js.map} +0 -0
  78. /package/dist/{chunk-47Z3YPOK.js.map → chunk-EUUWRNDZ.js.map} +0 -0
  79. /package/dist/{chunk-3HXWI34V.js.map → chunk-FHZUOIVC.js.map} +0 -0
  80. /package/dist/{chunk-ZICVVBDW.js.map → chunk-FPAUF3YB.js.map} +0 -0
  81. /package/dist/{chunk-55G7KQ7F.js.map → chunk-ICOHLRHT.js.map} +0 -0
  82. /package/dist/{chunk-FTDVA33Z.js.map → chunk-INFJH4JX.js.map} +0 -0
  83. /package/dist/{chunk-BSHDI4BH.js.map → chunk-JEK5CHK2.js.map} +0 -0
  84. /package/dist/{chunk-7GUP6KQQ.js.map → chunk-MMW4KIBH.js.map} +0 -0
  85. /package/dist/{chunk-LZOTH2GI.js.map → chunk-MVCJEIUU.js.map} +0 -0
  86. /package/dist/{chunk-2X24T4ZD.js.map → chunk-NJN5SGU2.js.map} +0 -0
  87. /package/dist/{chunk-5HBDXW44.js.map → chunk-OHGKVMT3.js.map} +0 -0
  88. /package/dist/{chunk-4NVYN2MB.js.map → chunk-ONIHS7K7.js.map} +0 -0
  89. /package/dist/{chunk-TEKWQNQ2.js.map → chunk-P7Y3KLKG.js.map} +0 -0
  90. /package/dist/{chunk-O4LVC4MQ.js.map → chunk-R2KJ22LX.js.map} +0 -0
  91. /package/dist/{chunk-LXROEQAO.js.map → chunk-SSHL5TAX.js.map} +0 -0
  92. /package/dist/{chunk-YYXJ6RTO.js.map → chunk-THVTU2UG.js.map} +0 -0
  93. /package/dist/{chunk-3H6Q3RZM.js.map → chunk-XMYJWMWN.js.map} +0 -0
  94. /package/dist/{chunk-PFOY5ML6.js.map → chunk-YSYBVLYS.js.map} +0 -0
  95. /package/dist/{chunk-QUPPV6UO.js.map → chunk-YWIZ3UQ6.js.map} +0 -0
  96. /package/dist/{chunk-6IWPN5UB.js.map → chunk-Z3XF5LRT.js.map} +0 -0
  97. /package/dist/{chunk-Y3OOHHKQ.js.map → chunk-ZBQXPP7M.js.map} +0 -0
  98. /package/dist/{cli-circuit-breaker-LNU5DQSB.js.map → cli-circuit-breaker-L6SWUVOP.js.map} +0 -0
  99. /package/dist/{composite-router-DJ54ND5X.js.map → composite-router-HFBOUCXD.js.map} +0 -0
  100. /package/dist/{consensus-vote-XLEQFVE7.js.map → consensus-vote-YEZIP2JQ.js.map} +0 -0
  101. /package/dist/{context-retriever-6O6TREXH.js.map → context-retriever-PTRDEBBH.js.map} +0 -0
  102. /package/dist/{doctor-deep-PSNJPELP.js.map → doctor-deep-WHCDAV3Z.js.map} +0 -0
  103. /package/dist/{expert-bridge-Q3OWPD4L.js.map → expert-bridge-N4L47MHU.js.map} +0 -0
  104. /package/dist/{factory-43RVPRT5.js.map → factory-EFLOKY32.js.map} +0 -0
  105. /package/dist/{factory-PSMTMC7V.js.map → factory-ZKGYCGDT.js.map} +0 -0
  106. /package/dist/{issue-triage-KZTENUDH.js.map → improvement-review-4MTIYCOZ.js.map} +0 -0
  107. /package/dist/{init-opencode-25AUARJH.js.map → init-opencode-42GKRQDA.js.map} +0 -0
  108. /package/dist/{pr-reviewer-helpers-XENJ4E2T.js.map → issue-triage-TEPE6VMA.js.map} +0 -0
  109. /package/dist/{repo-security-plan-XCX7EFJR.js.map → pr-reviewer-helpers-G4O22XF6.js.map} +0 -0
  110. /package/dist/{registry-command-X3O34FAK.js.map → registry-command-32PUZNNG.js.map} +0 -0
  111. /package/dist/{research-helpers-synthesize-CGVR6M4S.js.map → repo-security-plan-XWUDQB34.js.map} +0 -0
  112. /package/dist/{routing-memory-YZRYGXQC.js.map → research-helpers-synthesize-YI6S7SN6.js.map} +0 -0
  113. /package/dist/{session-memory-SXQAA2EN.js.map → routing-memory-Z3ZCTPFM.js.map} +0 -0
  114. /package/dist/{setup-command-VG7JZI6O.js.map → session-memory-5ZZ2SXDE.js.map} +0 -0
  115. /package/dist/{setup-config-VJAK6AA2.js.map → setup-command-U3ILRY5H.js.map} +0 -0
  116. /package/dist/{tool-memory-L7SDFSF5.js.map → setup-config-WZYLXPDO.js.map} +0 -0
  117. /package/dist/{setup-custom-api-KSF2JMTS.js.map → setup-custom-api-K4EN47CP.js.map} +0 -0
  118. /package/dist/{weather-report-D6HFOK7S.js.map → tool-memory-53Y2TUR3.js.map} +0 -0
@@ -4,1820 +4,90 @@ import {
4
4
  createStream,
5
5
  requireApiKey,
6
6
  validateApiKeyPresence
7
- } from "./chunk-D3JSXVX3.js";
7
+ } from "./chunk-AW3HJHJT.js";
8
8
  import {
9
9
  CUSTOM_API_BASE_URL_ENV,
10
10
  PROVIDER_ENV_KEYS,
11
11
  validateCustomApiBaseUrl
12
- } from "./chunk-LXROEQAO.js";
12
+ } from "./chunk-SSHL5TAX.js";
13
13
  import {
14
- getToolMemory
15
- } from "./chunk-KHZGMF2W.js";
16
- import {
17
- getDefaultAvailableModelsCache
18
- } from "./chunk-Y3OOHHKQ.js";
19
- import {
20
- CUSTOM_API_DEFAULT_MODEL
21
- } from "./chunk-7GUP6KQQ.js";
22
- import {
23
- createCliAdapter,
24
- createCliDetectionCache,
25
- delay,
26
- getAvailableClis,
27
- isCliAvailable,
28
- sanitizeOutput,
29
- withTimeout
30
- } from "./chunk-3H6Q3RZM.js";
31
- import {
32
- AgentError,
33
- CACHE_TIMEOUTS,
34
- CLI_NAMES,
35
- CircularBuffer,
36
- DEFAULT_CLI,
37
- ErrorCode,
38
- MCP_TIMEOUTS,
39
- ModelCapability,
40
- ModelError,
41
- OutcomeStore,
42
- SecurityError,
43
- TASK_SPECIALIZATION_MATRIX,
44
- TIMEOUT_GUARD,
45
- TaskOutcomeSchema,
46
- VOTE_TIMEOUTS,
47
- ValidationError,
48
- categorizeOutcomeErrorMessage,
49
- clamp01,
50
- createLogger,
51
- createMetricsMiddleware,
52
- detectTaskCategory,
53
- err,
54
- estimateTokens,
55
- formatPercentage,
56
- formatZodError,
57
- getCliModelName,
58
- getDefaultModelForCli,
59
- getDefaultRegistry,
60
- getErrorMessage,
61
- getInTreeCapabilitiesMatrix,
62
- getMcpSafeDeadlineMs,
63
- getOutcomeStore,
64
- getPipelineEventBus,
65
- getRandomProvider,
66
- getTimeProvider,
67
- getTokenEstimator,
68
- isRateLimitLikeError,
69
- ok,
70
- recordRateLimitEvent,
71
- registerPersistentOutcomeStoreFactory,
72
- resolveCliAlias,
73
- resolveVoteTimeout,
74
- toRateLimitError
75
- } from "./chunk-ECBH5INZ.js";
76
- import {
77
- ensureLearningDir,
78
- getNexusDataDir,
79
- getOutcomesFile,
80
- nexusDataPath,
81
- nexusDataPathEnsure
82
- } from "./chunk-CH7QIDHQ.js";
83
-
84
- // src/mcp/tools/consensus-vote.ts
85
- import { z as z12 } from "zod";
86
-
87
- // src/mcp/mcp-notifier.ts
88
- import { AsyncLocalStorage } from "async_hooks";
89
- var internalLogger = createLogger({ component: "mcp-notifier" });
90
- function createMcpNotifier(server) {
91
- function send(level, logger11, data) {
92
- try {
93
- server.sendLoggingMessage({ level, logger: logger11, data }).catch((error) => {
94
- internalLogger.debug("Failed to send MCP notification", {
95
- level,
96
- logger: logger11,
97
- error: getErrorMessage(error)
98
- });
99
- });
100
- } catch (error) {
101
- internalLogger.debug("Failed to send MCP notification", {
102
- level,
103
- logger: logger11,
104
- error: getErrorMessage(error)
105
- });
106
- }
107
- }
108
- return {
109
- info: (logger11, data) => {
110
- send("info", logger11, data);
111
- },
112
- debug: (logger11, data) => {
113
- send("debug", logger11, data);
114
- },
115
- warn: (logger11, data) => {
116
- send("warning", logger11, data);
117
- }
118
- };
119
- }
120
- var NOOP_NOTIFIER = {
121
- info: () => void 0,
122
- debug: () => void 0,
123
- warn: () => void 0
124
- };
125
- var progressContextStorage = new AsyncLocalStorage();
126
- var abortSignalStorage = new AsyncLocalStorage();
127
- async function withProgressHeartbeat(toolName, notifier, operation, intervalMs = 15e3) {
128
- const startTime = Date.now();
129
- let beatCount = 0;
130
- const progressCtx = progressContextStorage.getStore();
131
- const timer = setInterval(() => {
132
- beatCount++;
133
- const elapsed = Math.round((Date.now() - startTime) / 1e3);
134
- if (progressCtx !== void 0) {
135
- progressCtx.sendNotification(beatCount);
136
- }
137
- notifier.debug(toolName, {
138
- event: "heartbeat",
139
- elapsedSeconds: elapsed,
140
- beatCount,
141
- hasProgressToken: progressCtx !== void 0
142
- });
143
- }, intervalMs);
144
- try {
145
- return await operation();
146
- } finally {
147
- clearInterval(timer);
148
- }
149
- }
150
-
151
- // src/mcp/middleware/tool-wrapper.ts
152
- import { randomUUID } from "crypto";
153
- import { appendFileSync, existsSync, mkdirSync } from "fs";
154
- import { dirname, join } from "path";
155
-
156
- // src/mcp/middleware/rate-limiter.ts
157
- var DEFAULT_REFILL_INTERVAL_MS = CACHE_TIMEOUTS.rateLimitRefillMs;
158
- var RateLimiter = class {
159
- tokens;
160
- capacity;
161
- refillRate;
162
- refillIntervalMs;
163
- lastRefillTime;
164
- logger;
165
- name;
166
- constructor(config) {
167
- this.capacity = config.capacity;
168
- this.refillRate = config.refillRate;
169
- this.refillIntervalMs = config.refillIntervalMs ?? DEFAULT_REFILL_INTERVAL_MS;
170
- this.tokens = this.capacity;
171
- this.lastRefillTime = getTimeProvider().now();
172
- this.name = config.name ?? "rate-limiter";
173
- this.logger = config.logger ?? createLogger({ component: this.name });
174
- this.logger.debug("Rate limiter initialized", {
175
- capacity: this.capacity,
176
- refillRate: this.refillRate,
177
- refillIntervalMs: this.refillIntervalMs
178
- });
179
- }
180
- /**
181
- * Refills tokens based on elapsed time.
182
- * Called automatically before each acquire attempt.
183
- */
184
- refill() {
185
- const now = getTimeProvider().now();
186
- const elapsed = now - this.lastRefillTime;
187
- const intervals = Math.floor(elapsed / this.refillIntervalMs);
188
- if (intervals > 0) {
189
- const tokensToAdd = intervals * this.refillRate;
190
- this.tokens = Math.min(this.capacity, this.tokens + tokensToAdd);
191
- this.lastRefillTime = now - elapsed % this.refillIntervalMs;
192
- if (tokensToAdd > 0) {
193
- this.logger.debug("Tokens refilled", {
194
- added: tokensToAdd,
195
- current: this.tokens
196
- });
197
- }
198
- }
199
- }
200
- /**
201
- * Attempts to acquire a token.
202
- *
203
- * @param count - Number of tokens to acquire (default: 1)
204
- * @returns True if tokens were acquired, false if rate limited
205
- */
206
- tryAcquire(count = 1) {
207
- this.refill();
208
- if (this.tokens >= count) {
209
- this.tokens -= count;
210
- this.logger.debug("Token acquired", {
211
- requested: count,
212
- remaining: this.tokens
213
- });
214
- return true;
215
- }
216
- this.logger.warn("Rate limit exceeded", {
217
- requested: count,
218
- available: this.tokens
219
- });
220
- return false;
221
- }
222
- /**
223
- * Gets the current state of the rate limiter.
224
- *
225
- * @returns The current rate limiter state
226
- */
227
- getState() {
228
- this.refill();
229
- const nextTokenMs = this.tokens > 0 ? 0 : this.refillIntervalMs - (getTimeProvider().now() - this.lastRefillTime);
230
- return {
231
- tokens: this.tokens,
232
- capacity: this.capacity,
233
- nextTokenMs: Math.max(0, nextTokenMs)
234
- };
235
- }
236
- /**
237
- * Resets the rate limiter to full capacity.
238
- * Useful for testing or after configuration changes.
239
- */
240
- reset() {
241
- this.tokens = this.capacity;
242
- this.lastRefillTime = getTimeProvider().now();
243
- this.logger.debug("Rate limiter reset", { tokens: this.tokens });
244
- }
245
- };
246
- function createDefaultRateLimiter(name, logger11) {
247
- const config = {
248
- capacity: 100,
249
- refillRate: 10,
250
- refillIntervalMs: 1e3
251
- };
252
- if (name !== void 0) {
253
- config.name = name;
254
- }
255
- if (logger11 !== void 0) {
256
- config.logger = logger11;
257
- }
258
- return new RateLimiter(config);
259
- }
260
-
261
- // src/mcp/middleware/validation.ts
262
- function validateToolInput(schema, args) {
263
- const parsed = schema.safeParse(args);
264
- if (parsed.success) {
265
- return ok(parsed.data);
266
- }
267
- const message = formatZodError(parsed.error);
268
- const validationError = new ValidationError(`Invalid tool input: ${message}`, {
269
- context: {
270
- issues: parsed.error.issues,
271
- receivedType: typeof args
272
- }
273
- });
274
- return err(validationError);
275
- }
276
- function createValidator(schema) {
277
- return (args) => validateToolInput(schema, args);
278
- }
279
-
280
- // src/mcp/middleware/policy-types.ts
281
- import { z } from "zod";
282
- var PolicyError = class extends SecurityError {
283
- decision;
284
- constructor(message, decision) {
285
- super(message, {
286
- context: {
287
- allowed: decision.allowed,
288
- reason: decision.reason,
289
- ruleName: decision.ruleName,
290
- requiredArtifact: decision.requiredArtifact
291
- }
292
- });
293
- this.name = "PolicyError";
294
- this.decision = decision;
295
- }
296
- };
297
- var PolicyConfigSchema = z.object({
298
- defaultMode: z.enum(["read-only", "read-write"]).default("read-only"),
299
- policyMode: z.enum(["enforce", "warn"]).default("enforce"),
300
- allowedPaths: z.array(z.string()).default(["./"])
301
- });
302
-
303
- // src/mcp/middleware/policy-helpers.ts
304
- function isPathSafe(targetPath, allowedPaths) {
305
- const normalizedTarget = normalizePath(targetPath);
306
- for (const allowed of allowedPaths) {
307
- const normalizedAllowed = normalizePath(allowed);
308
- if (normalizedTarget.startsWith(normalizedAllowed)) {
309
- return true;
310
- }
311
- }
312
- return false;
313
- }
314
- function normalizePath(p) {
315
- let normalized = p.replace(/\/{1,100}$/, "");
316
- if (normalized === ".") {
317
- normalized = "";
318
- } else if (normalized.startsWith("./")) {
319
- normalized = normalized.slice(2);
320
- }
321
- if (!normalized.startsWith("/")) {
322
- normalized = "/" + normalized;
323
- }
324
- return normalized;
325
- }
326
- function extractPathFromArgs(args) {
327
- if (args === null || typeof args !== "object") {
328
- return void 0;
329
- }
330
- const argsObj = args;
331
- const pathFields = ["path", "filePath", "file_path", "directory", "dir", "target"];
332
- for (const field of pathFields) {
333
- const value = argsObj[field];
334
- if (typeof value === "string") {
335
- return value;
336
- }
337
- }
338
- return void 0;
339
- }
340
-
341
- // src/mcp/middleware/policy-rules.ts
342
- var MUTATION_TOOLS = /* @__PURE__ */ new Set([
343
- "write_file",
344
- "edit_file",
345
- "delete_file",
346
- "create_directory",
347
- "remove_directory",
348
- "execute_command",
349
- "run_shell",
350
- "bash",
351
- "create_expert",
352
- "run_workflow"
353
- ]);
354
- var READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
355
- "read_file",
356
- "list_directory",
357
- "search_files",
358
- "get_status",
359
- "orchestrate",
360
- "delegate_to_model"
361
- ]);
362
- function isMutationTool(toolName) {
363
- if (MUTATION_TOOLS.has(toolName)) {
364
- return true;
365
- }
366
- if (READ_ONLY_TOOLS.has(toolName)) {
367
- return false;
368
- }
369
- return true;
370
- }
371
- var denyMutationsWithoutModeRule = {
372
- name: "deny-mutations-without-mode",
373
- description: "Blocks write operations unless mode is read-write",
374
- check(ctx) {
375
- if (ctx.mode === "read-write") {
376
- return { allowed: true, reason: "Read-write mode enabled" };
377
- }
378
- if (isMutationTool(ctx.toolName)) {
379
- return {
380
- allowed: false,
381
- reason: `Tool '${ctx.toolName}' is a mutation operation but mode is '${ctx.mode}'. Set mode to 'read-write' to enable.`
382
- };
383
- }
384
- return { allowed: true, reason: "Read-only operation allowed" };
385
- }
386
- };
387
- var safePathsRule = {
388
- name: "safe-paths",
389
- description: "Validates paths against allowed root directories",
390
- check(ctx) {
391
- const targetPath = extractPathFromArgs(ctx.args);
392
- if (targetPath === void 0) {
393
- return { allowed: true, reason: "No path argument found" };
394
- }
395
- if (targetPath.includes("..")) {
396
- return {
397
- allowed: false,
398
- reason: `Path contains '..' which may indicate path traversal: ${targetPath}`
399
- };
400
- }
401
- const allowedPaths = ctx.allowedPaths ?? ["./"];
402
- if (!isPathSafe(targetPath, allowedPaths)) {
403
- return {
404
- allowed: false,
405
- reason: `Path '${targetPath}' is outside allowed directories: ${allowedPaths.join(", ")}`
406
- };
407
- }
408
- return { allowed: true, reason: "Path is within allowed directories" };
409
- }
410
- };
411
-
412
- // src/mcp/middleware/policy.ts
413
- var PolicyFirewall = class {
414
- rules = [];
415
- mode;
416
- logger;
417
- constructor(config) {
418
- this.mode = config?.mode ?? "enforce";
419
- this.logger = config?.logger ?? createLogger({ component: "policy-firewall" });
420
- if (config?.rules) {
421
- for (const rule of config.rules) {
422
- this.rules.push(rule);
423
- }
424
- }
425
- this.logger.debug("Policy firewall initialized", {
426
- mode: this.mode,
427
- ruleCount: this.rules.length
428
- });
429
- }
430
- /**
431
- * Evaluates all policy rules against the given context.
432
- *
433
- * Rules are evaluated in order. The first rule that denies stops
434
- * evaluation and returns the denial decision.
435
- *
436
- * @param ctx - The policy context to evaluate
437
- * @returns The policy decision
438
- */
439
- evaluate(ctx) {
440
- this.logger.debug("Evaluating policy", {
441
- toolName: ctx.toolName,
442
- mode: ctx.mode,
443
- ruleCount: this.rules.length
444
- });
445
- if (this.rules.length === 0) {
446
- return this.allowWithReason(ctx, "No policy rules configured");
447
- }
448
- for (const rule of this.rules) {
449
- const decision = rule.check(ctx);
450
- if (!decision.allowed) {
451
- return this.handleDenial(ctx, rule, decision);
452
- }
453
- }
454
- return this.allowWithReason(ctx, "All policy rules passed");
455
- }
456
- /**
457
- * Creates an allow decision with the given reason and logs it.
458
- */
459
- allowWithReason(ctx, reason) {
460
- const decision = { allowed: true, reason };
461
- this.logDecision(ctx, decision);
462
- return decision;
463
- }
464
- /**
465
- * Handles a rule denial, respecting warn mode if configured.
466
- */
467
- handleDenial(ctx, rule, decision) {
468
- const denialDecision = {
469
- ...decision,
470
- ruleName: rule.name
471
- };
472
- this.logDecision(ctx, denialDecision);
473
- if (this.mode === "warn") {
474
- this.logger.warn("Policy denial overridden by warn mode", {
475
- toolName: ctx.toolName,
476
- ruleName: rule.name,
477
- reason: decision.reason
478
- });
479
- return {
480
- allowed: true,
481
- reason: `[WARN MODE] Would be denied: ${decision.reason}`,
482
- ruleName: rule.name
483
- };
484
- }
485
- return denialDecision;
486
- }
487
- /**
488
- * Adds a policy rule to the firewall.
489
- *
490
- * @param rule - The rule to add
491
- */
492
- addRule(rule) {
493
- const existingIndex = this.rules.findIndex((r) => r.name === rule.name);
494
- if (existingIndex >= 0) {
495
- this.logger.warn("Replacing existing policy rule", { ruleName: rule.name });
496
- this.rules[existingIndex] = rule;
497
- } else {
498
- this.rules.push(rule);
499
- this.logger.debug("Policy rule added", { ruleName: rule.name });
500
- }
501
- }
502
- /**
503
- * Removes a policy rule by name.
504
- *
505
- * @param name - The name of the rule to remove
506
- * @returns True if the rule was found and removed
507
- */
508
- removeRule(name) {
509
- const index = this.rules.findIndex((r) => r.name === name);
510
- if (index >= 0) {
511
- this.rules.splice(index, 1);
512
- this.logger.debug("Policy rule removed", { ruleName: name });
513
- return true;
514
- }
515
- return false;
516
- }
517
- /**
518
- * Gets all registered policy rules.
519
- *
520
- * @returns A readonly array of policy rules
521
- */
522
- getRules() {
523
- return [...this.rules];
524
- }
525
- /**
526
- * Sets the policy enforcement mode.
527
- *
528
- * @param mode - The new enforcement mode
529
- */
530
- setMode(mode) {
531
- const previousMode = this.mode;
532
- this.mode = mode;
533
- this.logger.info("Policy mode changed", { from: previousMode, to: mode });
534
- }
535
- /**
536
- * Gets the current policy enforcement mode.
537
- *
538
- * @returns The current mode
539
- */
540
- getMode() {
541
- return this.mode;
542
- }
543
- /**
544
- * Logs a policy decision for audit purposes.
545
- */
546
- logDecision(ctx, decision) {
547
- const logData = {
548
- toolName: ctx.toolName,
549
- mode: ctx.mode,
550
- workflowId: ctx.workflowId,
551
- allowed: decision.allowed,
552
- reason: decision.reason,
553
- ruleName: decision.ruleName
554
- };
555
- if (decision.allowed) {
556
- this.logger.debug("Policy decision: ALLOWED", logData);
557
- } else {
558
- this.logger.warn("Policy decision: DENIED", logData);
559
- }
560
- }
561
- };
562
- function createDefaultPolicyFirewall(config) {
563
- const firewall = new PolicyFirewall(config);
564
- firewall.addRule(denyMutationsWithoutModeRule);
565
- firewall.addRule(safePathsRule);
566
- return firewall;
567
- }
568
- function evaluatePolicy(firewall, ctx) {
569
- const decision = firewall.evaluate(ctx);
570
- if (decision.allowed) {
571
- return ok(void 0);
572
- }
573
- return err(new PolicyError(`Policy denied: ${decision.reason}`, decision));
574
- }
575
- function createPolicyContext(toolName, args, options) {
576
- const base = {
577
- toolName,
578
- args,
579
- mode: options?.mode ?? "read-only"
580
- };
581
- const result = { ...base };
582
- if (options?.artifacts !== void 0) {
583
- result["artifacts"] = options.artifacts;
584
- }
585
- if (options?.workflowId !== void 0) {
586
- result["workflowId"] = options.workflowId;
587
- }
588
- if (options?.allowedPaths !== void 0) {
589
- result["allowedPaths"] = options.allowedPaths;
590
- }
591
- return result;
592
- }
593
-
594
- // src/mcp/middleware/timeout-guard.ts
595
- var DEFAULT_TIMEOUT_MS = TIMEOUT_GUARD.defaultMs;
596
- var MAX_TIMEOUT_MS = TIMEOUT_GUARD.maxMs;
597
- var NEAR_TIMEOUT_THRESHOLD = TIMEOUT_GUARD.nearTimeoutThreshold;
598
- function createTimeoutError(operationName, timeoutMs) {
599
- return {
600
- code: "OPERATION_TIMEOUT",
601
- message: `Operation '${operationName}' timed out after ${String(timeoutMs)}ms`,
602
- operation: operationName,
603
- timeoutMs
604
- };
605
- }
606
- function createGuardError(error, operationName) {
607
- const guardError = {
608
- code: "GUARD_ERROR",
609
- message: getErrorMessage(error),
610
- operation: operationName
611
- };
612
- if (error instanceof Error) {
613
- return { ...guardError, cause: error };
614
- }
615
- return guardError;
616
- }
617
- var TimeoutGuard = class {
618
- defaultTimeoutMs;
619
- maxTimeoutMs;
620
- enableLogging;
621
- logger;
622
- constructor(config) {
623
- this.defaultTimeoutMs = config?.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS;
624
- this.maxTimeoutMs = config?.maxTimeoutMs ?? MAX_TIMEOUT_MS;
625
- this.enableLogging = config?.enableLogging ?? true;
626
- this.logger = config?.logger ?? createLogger({ component: "timeout-guard" });
627
- }
628
- /** Resolves effective timeout and operation name from options. */
629
- resolveOptions(options) {
630
- return {
631
- timeoutMs: Math.min(options?.timeoutMs ?? this.defaultTimeoutMs, this.maxTimeoutMs),
632
- operationName: options?.operationName ?? "unknown"
633
- };
634
- }
635
- /**
636
- * Executes an async operation with timeout protection.
637
- */
638
- async execute(operation, options) {
639
- const { timeoutMs, operationName } = this.resolveOptions(options);
640
- const validationError = this.validateTimeout(timeoutMs, operationName);
641
- if (validationError !== null) {
642
- return err(validationError);
643
- }
644
- return this.runGuarded(operation, timeoutMs, operationName, options);
645
- }
646
- /** Runs the operation with timeout and optional abort signal. */
647
- async runGuarded(operation, timeoutMs, operationName, options) {
648
- this.logStart(operationName, timeoutMs);
649
- const startTime = getTimeProvider().now();
650
- const state = { timeoutId: void 0, timedOut: false };
651
- try {
652
- const result = await this.runWithTimeout(
653
- operation,
654
- timeoutMs,
655
- state,
656
- options?.onTimeout,
657
- options?.signal
658
- );
659
- return this.handleSuccess(result, startTime, timeoutMs, operationName);
660
- } catch {
661
- const cancelled = options?.signal?.aborted === true && !state.timedOut;
662
- return err(
663
- this.handleFailure(state.timedOut, operationName, timeoutMs, startTime, cancelled)
664
- );
665
- } finally {
666
- if (state.timeoutId !== void 0) {
667
- clearTimeout(state.timeoutId);
668
- }
669
- }
670
- }
671
- validateTimeout(timeoutMs, operationName) {
672
- if (timeoutMs <= 0) {
673
- return {
674
- code: "INVALID_TIMEOUT",
675
- message: `Invalid timeout: ${String(timeoutMs)}ms`,
676
- operation: operationName
677
- };
678
- }
679
- return null;
680
- }
681
- logStart(operationName, timeoutMs) {
682
- if (this.enableLogging) {
683
- this.logger.debug("Starting guarded operation", { operation: operationName, timeoutMs });
684
- }
685
- }
686
- async runWithTimeout(operation, timeoutMs, state, onTimeout, signal) {
687
- const timeoutPromise = new Promise((_resolve, reject) => {
688
- state.timeoutId = setTimeout(() => {
689
- state.timedOut = true;
690
- onTimeout?.();
691
- reject(new Error(`Operation timed out after ${String(timeoutMs)}ms`));
692
- }, timeoutMs);
693
- });
694
- const promises = [operation(), timeoutPromise];
695
- if (signal !== void 0 && !signal.aborted) {
696
- const abortPromise = new Promise((_resolve, reject) => {
697
- signal.addEventListener(
698
- "abort",
699
- () => {
700
- reject(new Error("Operation cancelled by client"));
701
- },
702
- { once: true }
703
- );
704
- });
705
- promises.push(abortPromise);
706
- }
707
- return Promise.race(promises);
708
- }
709
- handleSuccess(result, startTime, timeoutMs, operationName) {
710
- const durationMs = getTimeProvider().now() - startTime;
711
- const nearTimeout = durationMs > timeoutMs * NEAR_TIMEOUT_THRESHOLD;
712
- if (nearTimeout && this.enableLogging) {
713
- this.logger.warn("Operation completed near timeout threshold", {
714
- operation: operationName,
715
- durationMs,
716
- timeoutMs,
717
- thresholdPercent: Math.round(durationMs / timeoutMs * 100)
718
- });
719
- }
720
- if (this.enableLogging) {
721
- this.logger.debug("Guarded operation completed", { operation: operationName, durationMs });
722
- }
723
- return ok({ value: result, durationMs, nearTimeout });
724
- }
725
- handleFailure(timedOut, operationName, timeoutMs, startTime, cancelled = false) {
726
- const durationMs = getTimeProvider().now() - startTime;
727
- if (cancelled) {
728
- this.logger.info("Operation cancelled by client", {
729
- operation: operationName,
730
- durationMs
731
- });
732
- return {
733
- code: "OPERATION_CANCELLED",
734
- message: `Operation '${operationName}' cancelled by client`,
735
- operation: operationName
736
- };
737
- }
738
- if (timedOut) {
739
- this.logger.error("Operation timed out", void 0, {
740
- operation: operationName,
741
- timeoutMs,
742
- durationMs
743
- });
744
- return createTimeoutError(operationName, timeoutMs);
745
- }
746
- return createGuardError(new Error("Unknown error"), operationName);
747
- }
748
- /**
749
- * Creates a guarded version of an async function.
750
- */
751
- guard(fn, options) {
752
- return async (...args) => {
753
- return this.execute(() => fn(...args), options);
754
- };
755
- }
756
- };
757
-
758
- // src/mcp/middleware/request-context.ts
759
- import { randomBytes } from "crypto";
760
- function generateRequestId() {
761
- const bytes = randomBytes(8);
762
- return `req_${bytes.toString("hex")}`;
763
- }
764
- function formatTimestamp() {
765
- const now = new Date(getTimeProvider().now());
766
- const formatter = new Intl.DateTimeFormat("en-US", {
767
- timeZone: "America/New_York",
768
- timeZoneName: "shortOffset"
769
- });
770
- const parts = formatter.formatToParts(now);
771
- const offset = parts.find((p) => p.type === "timeZoneName")?.value ?? "-05:00";
772
- const base = now.toLocaleString("sv-SE", {
773
- timeZone: "America/New_York",
774
- hour12: false
775
- });
776
- return base.replace(" ", "T") + offset.replace("GMT", "");
777
- }
778
- function deriveTrustTier(caller) {
779
- const knownClients = ["claude-cli", "gemini-cli", "codex-cli"];
780
- if (caller.transport === "stdio") return "1";
781
- if (caller.authenticated === true) {
782
- if (caller.clientId !== void 0 && knownClients.includes(caller.clientId)) {
783
- return "1";
784
- }
785
- return "2";
786
- }
787
- return "3";
788
- }
789
- function createRequestContext(options) {
790
- const caller = options.caller ?? {};
791
- const context = {
792
- requestId: generateRequestId(),
793
- timestamp: formatTimestamp(),
794
- toolName: options.toolName,
795
- caller,
796
- trustTier: options.trustTier ?? deriveTrustTier(caller),
797
- ...options.traceId !== void 0 && { traceId: options.traceId },
798
- ...options.parentSpanId !== void 0 && { parentSpanId: options.parentSpanId }
799
- };
800
- return Object.freeze(context);
801
- }
802
- function contextForLogging(ctx) {
803
- return {
804
- requestId: ctx.requestId,
805
- toolName: ctx.toolName,
806
- trustTier: ctx.trustTier,
807
- ...ctx.caller.clientId !== void 0 && { clientId: ctx.caller.clientId },
808
- ...ctx.traceId !== void 0 && { traceId: ctx.traceId }
809
- };
810
- }
811
-
812
- // src/security/access-constraint-deriver/denylist.ts
813
- var UNBYPASSABLE_PATH_PATTERNS = [
814
- // Environment files
815
- ".env",
816
- ".env.*",
817
- "**/.env",
818
- "**/.env.*",
819
- // SSH credentials
820
- "~/.ssh/**",
821
- "**/ssh/id_*",
822
- "**/*_rsa",
823
- "**/*_ed25519",
824
- "**/*.pem",
825
- // Cloud credentials
826
- "~/.aws/**",
827
- "~/.azure/**",
828
- "~/.gcp/**",
829
- "~/.config/gcloud/**",
830
- "~/.kube/config",
831
- // Unix secret files
832
- "/etc/shadow",
833
- "/etc/sudoers",
834
- "/etc/sudoers.d/**",
835
- // Common secret file patterns
836
- "**/secrets.*",
837
- "**/credentials.*",
838
- "**/private_key.*",
839
- "**/id_rsa*"
840
- ];
841
- var UNBYPASSABLE_TOOL_NAMES = [
842
- // Destructive git operations
843
- "git_push_force",
844
- "git_reset_hard",
845
- "git_branch_delete_force",
846
- "git_clean_force",
847
- // Destructive filesystem
848
- "rm_recursive_force",
849
- "chmod_recursive",
850
- // Identity / auth mutations
851
- "ssh_add_key",
852
- "gpg_add_key",
853
- "npm_publish_force",
854
- // Remote destruction
855
- "github_repo_delete",
856
- "github_org_transfer",
857
- "aws_account_close"
858
- ];
859
- function compileGlobToRegex(pattern) {
860
- const pat = pattern.toLowerCase();
861
- const escaped = pat.replace(/[\\.+^$()|[\]{}]/g, "\\$&").replace(/\*\*/g, "__DOUBLESTAR__").replace(/\*/g, "[^/]*").replace(/__DOUBLESTAR__/g, ".*");
862
- const anchored = escaped.startsWith("~/") ? `(^|/)${escaped.slice(2)}$` : escaped.startsWith("/") ? `^${escaped}$` : `(^|/)${escaped}$`;
863
- return new RegExp(anchored);
864
- }
865
- var COMPILED_PATH_PATTERNS = UNBYPASSABLE_PATH_PATTERNS.map((pattern) => ({
866
- pattern,
867
- regex: compileGlobToRegex(pattern)
868
- }));
869
- function isPathDenied(path) {
870
- const normalized = path.toLowerCase();
871
- return COMPILED_PATH_PATTERNS.some((c) => c.regex.test(normalized));
872
- }
873
- function isToolDenied(toolName) {
874
- return UNBYPASSABLE_TOOL_NAMES.includes(toolName);
875
- }
876
-
877
- // src/security/access-constraint-deriver/tool-risk.ts
878
- var READ_ONLY_TOOLS2 = /* @__PURE__ */ new Set([
879
- // Discovery / listing
880
- "list_experts",
881
- "list_workflows",
882
- // Research reads
883
- "research_query",
884
- "research_analyze",
885
- "research_catalog_review",
886
- "research_synthesize",
887
- // Memory reads
888
- "memory_query",
889
- "memory_stats",
890
- // Observability
891
- "weather_report",
892
- "query_trace",
893
- "query_task_state",
894
- // Async-mode result polling (#3042 / epic #2631)
895
- "get_job_result",
896
- // Async-mode job discovery (#3046 / epic #2631 Stage 5)
897
- "list_jobs",
898
- // Codebase intelligence (read-only over local files)
899
- "search_codebase",
900
- "extract_symbols",
901
- // Repo analysis (read-only)
902
- "repo_analyze",
903
- "repo_security_plan",
904
- // Routing recommendation (no side effects — returns recommendation)
905
- "delegate_to_model",
906
- // Registry import (returns a draft template — does not write)
907
- "registry_import"
908
- ]);
909
- function isRiskyTool(toolName) {
910
- return !READ_ONLY_TOOLS2.has(toolName);
911
- }
912
-
913
- // src/security/access-constraint-deriver/enforcer.ts
914
- function checkAccess(toolName, policy, args) {
915
- if (isToolDenied(toolName)) {
916
- return {
917
- decision: "deny",
918
- reason: `tool "${toolName}" is on the unbypassable deny-tool list`,
919
- matchedRule: "unbypassable:tool"
920
- };
921
- }
922
- if (typeof args?.path === "string" && args.path.length > 0 && isPathDenied(args.path)) {
923
- return {
924
- decision: "deny",
925
- reason: `path "${args.path}" is on the unbypassable deny-path list`,
926
- matchedRule: "unbypassable:path"
927
- };
928
- }
929
- if (policy.allowedTools === "*") return { decision: "allow" };
930
- if (policy.allowedTools.includes(toolName)) return { decision: "allow" };
931
- return decideOnViolation(toolName, policy.mode);
932
- }
933
- function decideOnViolation(toolName, mode) {
934
- if (mode === "audit") {
935
- return {
936
- decision: "log-and-allow",
937
- warning: `tool "${toolName}" not in derived policy (audit mode)`
938
- };
939
- }
940
- if (mode === "confirm_risky") {
941
- if (!isRiskyTool(toolName)) {
942
- return {
943
- decision: "log-and-allow",
944
- warning: `tool "${toolName}" not in derived policy (confirm_risky mode, read-only \u2014 would have required human approval, allowed because read-only)`
945
- };
946
- }
947
- return {
948
- decision: "deny",
949
- reason: `tool "${toolName}" not in derived policy (confirm_risky mode, risky \u2014 would have required human approval; denied for now, add to allowedTools or run in audit mode to allow)`,
950
- matchedRule: "allowedTools:confirm_risky"
951
- };
952
- }
953
- return {
954
- decision: "deny",
955
- reason: `tool "${toolName}" not in derived policy`,
956
- matchedRule: "allowedTools"
957
- };
958
- }
959
-
960
- // src/security/access-constraint-deriver/mcp-guard.ts
961
- import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
962
- var accessPolicyStorage = new AsyncLocalStorage2();
963
- function withAccessPolicy(policy, fn) {
964
- return accessPolicyStorage.run(policy, fn);
965
- }
966
- function getActivePolicy() {
967
- return accessPolicyStorage.getStore();
968
- }
969
- function denyToToolResult(decision, requestId) {
970
- return {
971
- isError: true,
972
- content: [
973
- {
974
- type: "text",
975
- text: `access denied: ${decision.reason} (rule: ${decision.matchedRule}, request: ${requestId})`
976
- }
977
- ]
978
- };
979
- }
980
-
981
- // src/security/access-constraint-deriver/chain-adapter.ts
982
- function toGuardArgs(args) {
983
- if (typeof args !== "object" || args === null) return void 0;
984
- const path = args["path"];
985
- return typeof path === "string" && path.length > 0 ? { path } : void 0;
986
- }
987
- function createAccessPolicyChainMiddleware(toolName) {
988
- return async (args, ctx, next) => {
989
- const policy = getActivePolicy();
990
- if (policy === void 0 || policy.mode === "off") {
991
- return next(args, ctx);
992
- }
993
- const decision = checkAccess(toolName, policy, toGuardArgs(args));
994
- if (decision.decision === "allow") {
995
- return next(args, ctx);
996
- }
997
- if (decision.decision === "log-and-allow") {
998
- ctx.logger.warn("access-policy: audit violation", {
999
- tool: toolName,
1000
- warning: decision.warning,
1001
- policySource: policy.source,
1002
- requestId: ctx.requestContext.requestId
1003
- });
1004
- return next(args, ctx);
1005
- }
1006
- ctx.logger.info("access-policy: tool call denied", {
1007
- tool: toolName,
1008
- reason: decision.reason,
1009
- matchedRule: decision.matchedRule,
1010
- policySource: policy.source,
1011
- mode: policy.mode,
1012
- requestId: ctx.requestContext.requestId
1013
- });
1014
- return denyToToolResult(decision, ctx.requestContext.requestId);
1015
- };
1016
- }
1017
-
1018
- // src/mcp/error-envelope.ts
1019
- import { z as z2 } from "zod";
1020
- var ErrorCategorySchema = z2.enum([
1021
- "transient",
1022
- "validation",
1023
- "permission",
1024
- "business",
1025
- "internal"
1026
- ]);
1027
- var ToolErrorEnvelopeSchema = z2.object({
1028
- errorCategory: ErrorCategorySchema,
1029
- /** Whether retrying the same call could succeed without caller changes. */
1030
- isRetryable: z2.boolean(),
1031
- /** Human-readable summary. Bounded to keep stack traces out of results. */
1032
- message: z2.string().min(1).max(2e3),
1033
- /**
1034
- * Optional structured context. MUST NOT carry secrets, credentials,
1035
- * absolute filesystem paths, or raw Error/response objects — those are
1036
- * an information-disclosure risk (this field is not output-sanitized).
1037
- */
1038
- detail: z2.record(z2.string(), z2.unknown()).optional()
1039
- });
1040
- var ERROR_ENVELOPE_META_KEY = "nexus-agents/error";
1041
- function defaultRetryable(category) {
1042
- return category === "transient";
1043
- }
1044
-
1045
- // src/mcp/tools/tool-result.ts
1046
- function toolSuccess(text) {
1047
- return {
1048
- content: [{ type: "text", text }]
1049
- };
1050
- }
1051
- function toolSuccessStructured(data) {
1052
- return {
1053
- content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
1054
- structuredContent: data
1055
- };
1056
- }
1057
- function toolStructuredError(input) {
1058
- const envelope = {
1059
- errorCategory: input.errorCategory,
1060
- isRetryable: input.isRetryable ?? defaultRetryable(input.errorCategory),
1061
- message: input.message,
1062
- ...input.detail !== void 0 ? { detail: input.detail } : {}
1063
- };
1064
- return {
1065
- isError: true,
1066
- content: [{ type: "text", text: envelope.message }],
1067
- _meta: { [ERROR_ENVELOPE_META_KEY]: envelope }
1068
- };
1069
- }
1070
- function toolError(message) {
1071
- return toolStructuredError({ errorCategory: "internal", message });
1072
- }
1073
-
1074
- // src/mcp/middleware/middleware-chain.ts
1075
- function errorResult(category, message, requestId) {
1076
- return toolStructuredError({
1077
- errorCategory: category,
1078
- message: `${message} (request: ${requestId})`
1079
- });
1080
- }
1081
- function createValidationMiddleware(schema) {
1082
- return async (args, ctx, next) => {
1083
- const result = validateToolInput(schema, args);
1084
- if (!result.ok) {
1085
- ctx.logger.warn("Validation failed", {
1086
- error: result.error.message
1087
- });
1088
- return errorResult(
1089
- "validation",
1090
- `Validation error: ${result.error.message}`,
1091
- ctx.requestContext.requestId
1092
- );
1093
- }
1094
- ctx.validatedArgs = result.value;
1095
- return next(result.value, ctx);
1096
- };
1097
- }
1098
- function createPolicyMiddleware(firewall, toolName, mode, allowedPaths) {
1099
- return async (args, ctx, next) => {
1100
- const policyCtx = createPolicyContext(toolName, args, {
1101
- mode,
1102
- ...allowedPaths !== void 0 && { allowedPaths }
1103
- });
1104
- const decision = firewall.evaluate(policyCtx);
1105
- if (!decision.allowed) {
1106
- ctx.logger.warn("Policy denied", {
1107
- reason: decision.reason,
1108
- ruleName: decision.ruleName
1109
- });
1110
- return errorResult(
1111
- "permission",
1112
- `Policy denied: ${decision.reason}`,
1113
- ctx.requestContext.requestId
1114
- );
1115
- }
1116
- ctx.logger.debug("Policy check passed", { reason: decision.reason });
1117
- return next(args, ctx);
1118
- };
1119
- }
1120
- function createRateLimitMiddleware(limiter) {
1121
- return async (args, ctx, next) => {
1122
- const acquired = limiter.tryAcquire();
1123
- if (!acquired) {
1124
- const state = limiter.getState();
1125
- ctx.logger.warn("Rate limit exceeded", {
1126
- nextTokenMs: state.nextTokenMs
1127
- });
1128
- return errorResult(
1129
- "transient",
1130
- `Rate limit exceeded. Try again in ${String(state.nextTokenMs)}ms`,
1131
- ctx.requestContext.requestId
1132
- );
1133
- }
1134
- return next(args, ctx);
1135
- };
1136
- }
1137
- function createTimeoutMiddleware(guard, toolName) {
1138
- return async (args, ctx, next) => {
1139
- const signal = abortSignalStorage.getStore();
1140
- const result = await guard.execute(() => next(args, ctx), {
1141
- operationName: toolName,
1142
- ...signal !== void 0 ? { signal } : {}
1143
- });
1144
- if (!result.ok) {
1145
- ctx.logger.error("Operation timed out", void 0, {
1146
- code: result.error.code,
1147
- timeoutMs: result.error.timeoutMs
1148
- });
1149
- return errorResult("transient", result.error.message, ctx.requestContext.requestId);
1150
- }
1151
- if (result.value.nearTimeout) {
1152
- ctx.logger.warn("Operation completed near timeout threshold", {
1153
- durationMs: result.value.durationMs
1154
- });
1155
- }
1156
- return result.value.value;
1157
- };
1158
- }
1159
- function createAuditMiddleware() {
1160
- return async (args, ctx, next) => {
1161
- const startTime = getTimeProvider().now();
1162
- ctx.logger.info("Tool invocation started");
1163
- try {
1164
- const result = await next(args, ctx);
1165
- const durationMs = getTimeProvider().now() - startTime;
1166
- if (result.isError === true) {
1167
- ctx.logger.warn("Tool execution completed with error", { durationMs });
1168
- } else {
1169
- ctx.logger.info("Tool execution completed", { durationMs });
1170
- }
1171
- return result;
1172
- } catch (error) {
1173
- const durationMs = getTimeProvider().now() - startTime;
1174
- const message = error instanceof Error ? error.message : "Unknown error";
1175
- ctx.logger.error("Tool execution failed", error instanceof Error ? error : void 0, {
1176
- durationMs
1177
- });
1178
- return errorResult("internal", `Internal error: ${message}`, ctx.requestContext.requestId);
1179
- }
1180
- };
1181
- }
1182
- function composeMiddleware(middlewares) {
1183
- return (args, ctx, finalHandler) => {
1184
- const dispatch = (index, currentArgs) => {
1185
- if (index >= middlewares.length) {
1186
- return finalHandler(currentArgs, ctx);
1187
- }
1188
- const middleware = middlewares[index];
1189
- if (middleware === void 0) {
1190
- return finalHandler(currentArgs, ctx);
1191
- }
1192
- return middleware(currentArgs, ctx, (nextArgs) => dispatch(index + 1, nextArgs));
1193
- };
1194
- return dispatch(0, args);
1195
- };
1196
- }
1197
- function addAuditMiddleware(middlewares, skip) {
1198
- if (skip.audit !== true) {
1199
- middlewares.push(createAuditMiddleware());
1200
- }
1201
- }
1202
- function addRateLimitMiddleware(middlewares, config, skip) {
1203
- if (skip.rateLimit !== true && config.rateLimiter !== void 0) {
1204
- const limiter = config.rateLimiter instanceof RateLimiter ? config.rateLimiter : new RateLimiter(config.rateLimiter);
1205
- middlewares.push(createRateLimitMiddleware(limiter));
1206
- }
1207
- }
1208
- function addValidationMiddleware(middlewares, config, skip) {
1209
- if (skip.validation !== true && config.schema !== void 0) {
1210
- middlewares.push(createValidationMiddleware(config.schema));
1211
- }
1212
- }
1213
- function addPolicyMiddleware(middlewares, config, skip) {
1214
- if (skip.policy !== true && config.policyFirewall !== void 0) {
1215
- const mode = config.executionMode ?? "read-only";
1216
- middlewares.push(
1217
- createPolicyMiddleware(config.policyFirewall, config.toolName, mode, config.allowedPaths)
1218
- );
1219
- }
1220
- }
1221
- function addTimeoutMiddleware(middlewares, config, skip) {
1222
- if (skip.timeout !== true && config.timeout !== void 0) {
1223
- const guard = new TimeoutGuard(config.timeout);
1224
- middlewares.push(createTimeoutMiddleware(guard, config.toolName));
1225
- }
1226
- }
1227
- function addAccessPolicyMiddleware(middlewares, config, skip) {
1228
- if (skip.accessPolicy !== true) {
1229
- middlewares.push(createAccessPolicyChainMiddleware(config.toolName));
1230
- }
1231
- }
1232
- function buildMiddlewareStack(config) {
1233
- const skip = config.skip ?? {};
1234
- const middlewares = [];
1235
- middlewares.push(createMetricsMiddleware());
1236
- addAuditMiddleware(middlewares, skip);
1237
- addRateLimitMiddleware(middlewares, config, skip);
1238
- addValidationMiddleware(middlewares, config, skip);
1239
- addPolicyMiddleware(middlewares, config, skip);
1240
- addAccessPolicyMiddleware(middlewares, config, skip);
1241
- addTimeoutMiddleware(middlewares, config, skip);
1242
- return middlewares;
1243
- }
1244
- function createMiddlewareChain(config) {
1245
- const logger11 = config.logger ?? createLogger({ tool: config.toolName });
1246
- const middlewares = buildMiddlewareStack(config);
1247
- const composed = composeMiddleware(middlewares);
1248
- return (handler) => {
1249
- return async (args) => {
1250
- const requestContext = createRequestContext({ toolName: config.toolName });
1251
- const requestLogger = logger11.child(contextForLogging(requestContext));
1252
- const ctx = { requestContext, logger: requestLogger };
1253
- return composed(args, ctx, (finalArgs, finalCtx) => handler(finalArgs, finalCtx));
1254
- };
1255
- };
1256
- }
1257
- function withMiddleware(toolName, handler, options) {
1258
- const config = {
1259
- toolName,
1260
- ...options
1261
- };
1262
- const chain = createMiddlewareChain(config);
1263
- const wrappedHandler = (args, ctx) => {
1264
- if (handler.length >= 2) {
1265
- return handler(args, ctx);
1266
- }
1267
- return handler(args);
1268
- };
1269
- return chain(wrappedHandler);
1270
- }
1271
-
1272
- // src/mcp/middleware/tool-wrapper.ts
1273
- var DEFAULT_TIMEOUT_CONFIG = {
1274
- defaultTimeoutMs: MCP_TIMEOUTS.defaultMs,
1275
- maxTimeoutMs: MCP_TIMEOUTS.maxMs,
1276
- enableLogging: true,
1277
- uriValidation: true
1278
- };
1279
- var DEFAULT_TOOL_TIMEOUTS = {
1280
- ...MCP_TIMEOUTS.perTool
1281
- };
1282
- function getToolTimeout(toolName, security, explicitMs) {
1283
- if (explicitMs !== void 0) {
1284
- return explicitMs;
1285
- }
1286
- const perToolConfig = security?.timeout?.perToolTimeout;
1287
- const perToolMs = perToolConfig?.[toolName];
1288
- if (perToolMs !== void 0) {
1289
- return perToolMs;
1290
- }
1291
- const builtInDefault = DEFAULT_TOOL_TIMEOUTS[toolName];
1292
- if (builtInDefault !== void 0) {
1293
- return builtInDefault;
1294
- }
1295
- return security?.timeout?.defaultTimeoutMs ?? DEFAULT_TIMEOUT_CONFIG.defaultTimeoutMs;
1296
- }
1297
- function getTimeoutConfig(security, overrideMs) {
1298
- const timeoutConfig = security?.timeout ?? DEFAULT_TIMEOUT_CONFIG;
1299
- return {
1300
- defaultTimeoutMs: overrideMs ?? timeoutConfig.defaultTimeoutMs,
1301
- maxTimeoutMs: timeoutConfig.maxTimeoutMs,
1302
- enableLogging: timeoutConfig.enableLogging
1303
- };
1304
- }
1305
- function wrapToolWithTimeout(toolName, handler, options) {
1306
- return withMiddleware(toolName, handler, {
1307
- timeout: getTimeoutConfig(void 0, options?.timeoutMs),
1308
- logger: options?.logger
1309
- });
1310
- }
1311
- var wrapperLogger = createLogger({ component: "tool-wrapper" });
1312
- function extractProgressContext(extra) {
1313
- const sdk = extra;
1314
- const token = sdk?._meta?.progressToken;
1315
- const sendFn = sdk?.sendNotification;
1316
- if (token === void 0 || sendFn === void 0) return void 0;
1317
- return {
1318
- progressToken: token,
1319
- sendNotification: (progress, total) => {
1320
- const params = {
1321
- progressToken: token,
1322
- progress
1323
- };
1324
- if (total !== void 0) params["total"] = total;
1325
- sendFn({ method: "notifications/progress", params }).catch((err2) => {
1326
- wrapperLogger.debug("Failed to send progress notification", {
1327
- error: getErrorMessage(err2)
1328
- });
1329
- });
1330
- }
1331
- };
1332
- }
1333
- function runWithContexts(handler, args, progressCtx, signal) {
1334
- const run = () => handler(args);
1335
- if (signal !== void 0 && progressCtx !== void 0) {
1336
- return abortSignalStorage.run(signal, () => progressContextStorage.run(progressCtx, run));
1337
- }
1338
- if (signal !== void 0) {
1339
- return abortSignalStorage.run(signal, run);
1340
- }
1341
- if (progressCtx !== void 0) {
1342
- return progressContextStorage.run(progressCtx, run);
1343
- }
1344
- return run();
1345
- }
1346
- function toSdkCallback(handler) {
1347
- return (args, extra) => {
1348
- const progressCtx = extractProgressContext(extra);
1349
- const signal = extra?.signal;
1350
- return runWithContexts(handler, args, progressCtx, signal);
1351
- };
1352
- }
1353
- var MCP_SDK_DEFAULT_REQUEST_TIMEOUT_MS = 6e4;
1354
- var TIMEOUT_MISMATCH_TELEMETRY_REL_PATH = "mcp-telemetry/timeout-mismatch-events.jsonl";
1355
- var ensuredDirs = /* @__PURE__ */ new Set();
1356
- function appendTimeoutMismatchEvent(event) {
1357
- try {
1358
- const path = join(getNexusDataDir(), TIMEOUT_MISMATCH_TELEMETRY_REL_PATH);
1359
- const dir = dirname(path);
1360
- if (!ensuredDirs.has(dir)) {
1361
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
1362
- ensuredDirs.add(dir);
1363
- }
1364
- appendFileSync(path, JSON.stringify(event) + "\n", "utf-8");
1365
- } catch (err2) {
1366
- wrapperLogger.debug("Best-effort timeout-mismatch event recording failed", {
1367
- error: getErrorMessage(err2)
1368
- });
1369
- }
1370
- }
1371
- function extractErrorCategoryFromResult(result) {
1372
- const envelope = result._meta?.["nexus-agents/error"];
1373
- if (envelope !== null && typeof envelope === "object" && "errorCategory" in envelope) {
1374
- const cat = envelope.errorCategory;
1375
- if (typeof cat === "string") return cat;
1376
- }
1377
- return void 0;
1378
- }
1379
- function extractErrorMessageFromResult(result) {
1380
- const first = result.content[0];
1381
- if (first?.type === "text" && typeof first.text === "string") {
1382
- return first.text.slice(0, 500);
1383
- }
1384
- return void 0;
1385
- }
1386
- function buildMismatchEvent(ctx, eventId, t0, outcome) {
1387
- const t1 = Date.now();
1388
- return {
1389
- eventId,
1390
- toolName: ctx.toolName,
1391
- configuredTimeoutMs: ctx.configuredTimeoutMs,
1392
- mcpSdkDefaultMs: MCP_SDK_DEFAULT_REQUEST_TIMEOUT_MS,
1393
- startedAt: new Date(t0).toISOString(),
1394
- endedAt: new Date(t1).toISOString(),
1395
- durationMs: t1 - t0,
1396
- outcome: outcome.outcome,
1397
- ...outcome.errorCategory !== void 0 ? { errorCategory: outcome.errorCategory } : {},
1398
- ...outcome.errorMessage !== void 0 ? { errorMessage: outcome.errorMessage } : {}
1399
- };
1400
- }
1401
- function classifyResult(result) {
1402
- if (result.isError !== true) return { outcome: "success" };
1403
- const errorCategory = extractErrorCategoryFromResult(result);
1404
- const errorMessage = extractErrorMessageFromResult(result);
1405
- return {
1406
- outcome: "error",
1407
- ...errorCategory !== void 0 ? { errorCategory } : {},
1408
- ...errorMessage !== void 0 ? { errorMessage } : {}
1409
- };
1410
- }
1411
- async function runMismatchedCall(ctx) {
1412
- const eventId = randomUUID();
1413
- const t0 = Date.now();
1414
- ctx.log.warn(
1415
- "MCP tool budget exceeds client default and no progressToken received \u2014 request likely to be killed by client before server-side deadline",
1416
- {
1417
- tool: ctx.toolName,
1418
- eventId,
1419
- configuredTimeoutMs: ctx.configuredTimeoutMs,
1420
- mcpSdkDefaultMs: MCP_SDK_DEFAULT_REQUEST_TIMEOUT_MS,
1421
- remediation: "Client should pass `onprogress` and `resetTimeoutOnProgress: true` when calling, or extend `options.timeout`. See docs/architecture/MCP_PROTOCOL.md."
1422
- }
1423
- );
1424
- try {
1425
- const result = await runWithContexts(ctx.handler, ctx.args, ctx.progressCtx, ctx.signal);
1426
- appendTimeoutMismatchEvent(buildMismatchEvent(ctx, eventId, t0, classifyResult(result)));
1427
- return result;
1428
- } catch (err2) {
1429
- appendTimeoutMismatchEvent(
1430
- buildMismatchEvent(ctx, eventId, t0, {
1431
- outcome: "error",
1432
- errorMessage: getErrorMessage(err2).slice(0, 500)
1433
- })
1434
- );
1435
- throw err2;
1436
- }
1437
- }
1438
- function toSdkCallbackWithBudgetCheck(handler, toolName, configuredTimeoutMs, logger11) {
1439
- const log = logger11 ?? wrapperLogger;
1440
- return (args, extra) => {
1441
- const progressCtx = extractProgressContext(extra);
1442
- const signal = extra?.signal;
1443
- const isMismatch = configuredTimeoutMs > MCP_SDK_DEFAULT_REQUEST_TIMEOUT_MS && progressCtx === void 0;
1444
- if (!isMismatch) return runWithContexts(handler, args, progressCtx, signal);
1445
- return runMismatchedCall({
1446
- log,
1447
- handler,
1448
- args,
1449
- progressCtx,
1450
- signal,
1451
- toolName,
1452
- configuredTimeoutMs
1453
- });
1454
- };
1455
- }
1456
-
1457
- // src/audit/secure-handler-audit.ts
1458
- function actorFromContext(ctx, fallback) {
1459
- const caller = ctx.caller;
1460
- const clientId = caller.clientId;
1461
- if (clientId !== void 0 && clientId.length > 0) {
1462
- return {
1463
- type: clientId.includes("api") ? "external" : clientId.includes("cli") ? "agent" : "user",
1464
- id: clientId,
1465
- name: caller.userAgent
1466
- };
1467
- }
1468
- return fallback ?? { type: "system", id: "unknown", name: "Unknown Caller" };
1469
- }
1470
- function resultToOutcome(isError, isPolicyDenied) {
1471
- if (isPolicyDenied) return "denied";
1472
- if (isError === true) return "failure";
1473
- return "success";
1474
- }
1475
- function logToolInvocationAudit(opts) {
1476
- opts.auditLogger.logToolInvocation({
1477
- toolName: opts.toolName,
1478
- outcome: opts.outcome,
1479
- actor: opts.actor,
1480
- requestId: opts.requestId,
1481
- durationMs: opts.durationMs,
1482
- errorMessage: opts.errorMessage
1483
- });
1484
- }
1485
- function logPolicyAudit(opts) {
1486
- opts.auditLogger.logPolicyDecision({
1487
- policyName: opts.policyName,
1488
- decision: opts.decision,
1489
- reason: opts.reason,
1490
- toolName: opts.toolName,
1491
- actor: opts.actor,
1492
- requestId: opts.requestId
1493
- });
1494
- }
1495
- function logRateLimitAudit(opts) {
1496
- opts.auditLogger.logRateLimitViolation({
1497
- toolName: opts.toolName,
1498
- actor: opts.actor,
1499
- currentRate: opts.currentRate,
1500
- limitRate: opts.limitRate,
1501
- requestId: opts.requestId
1502
- });
1503
- }
1504
-
1505
- // src/mcp/middleware/tool-input-sanitizer.ts
1506
- var XML_INJECTION_PATTERN = /<\/?(system|human|assistant|instructions|user|prompt|context|tool_use|tool_result)\b[^>]*>/gi;
1507
- var INJECTION_DETECTORS = [
1508
- { name: "system_prompt_override", pattern: /ignore (?:all )?previous (?:instructions|rules)/i },
1509
- { name: "role_impersonation", pattern: /i(?:'m| am) the (?:repo |project )?(?:owner|admin)/i },
1510
- { name: "hidden_instruction", pattern: /<!--[\s\S]*?(?:execute|delete|merge|apply)[\s\S]*?-->/i }
1511
- ];
1512
- function sanitizeString(value) {
1513
- XML_INJECTION_PATTERN.lastIndex = 0;
1514
- const cleaned = value.replace(XML_INJECTION_PATTERN, "");
1515
- return { cleaned, modified: cleaned !== value };
1516
- }
1517
- function detectPatterns(value) {
1518
- const detected = [];
1519
- for (const { name, pattern } of INJECTION_DETECTORS) {
1520
- pattern.lastIndex = 0;
1521
- if (pattern.test(value)) {
1522
- detected.push(name);
1523
- }
1524
- }
1525
- return detected;
1526
- }
1527
- function sanitizeValue(value, stats) {
1528
- if (typeof value === "string") {
1529
- const patterns = detectPatterns(value);
1530
- if (patterns.length > 0) {
1531
- stats.patterns.push(...patterns);
1532
- }
1533
- const { cleaned, modified } = sanitizeString(value);
1534
- if (modified) stats.count++;
1535
- return cleaned;
1536
- }
1537
- if (Array.isArray(value)) {
1538
- return value.map((item) => sanitizeValue(item, stats));
1539
- }
1540
- if (value !== null && typeof value === "object") {
1541
- const result = {};
1542
- for (const [key, val] of Object.entries(value)) {
1543
- result[key] = sanitizeValue(val, stats);
1544
- }
1545
- return result;
1546
- }
1547
- return value;
1548
- }
1549
- function sanitizeToolInput(args) {
1550
- if (args === void 0 || args === null) {
1551
- return { sanitized: args, wasModified: false, modifiedCount: 0, detectedPatterns: [] };
1552
- }
1553
- const stats = { count: 0, patterns: [] };
1554
- const sanitized = sanitizeValue(args, stats);
1555
- const uniquePatterns = [...new Set(stats.patterns)];
1556
- return {
1557
- sanitized,
1558
- wasModified: stats.count > 0,
1559
- modifiedCount: stats.count,
1560
- detectedPatterns: uniquePatterns
1561
- };
1562
- }
1563
- function logSanitizationResult(result, logger11, toolName) {
1564
- if (result.wasModified) {
1565
- logger11.warn("Tool input sanitized \u2014 XML injection tags stripped", {
1566
- tool: toolName,
1567
- modifiedFields: result.modifiedCount
1568
- });
1569
- }
1570
- if (result.detectedPatterns.length > 0) {
1571
- logger11.warn("Injection patterns detected in tool input", {
1572
- tool: toolName,
1573
- patterns: result.detectedPatterns
1574
- });
1575
- }
1576
- }
14
+ NOOP_NOTIFIER,
15
+ createMcpNotifier,
16
+ createSecureHandler,
17
+ getToolAnnotations,
18
+ getToolTimeout,
19
+ toSdkCallbackWithBudgetCheck,
20
+ toolStructuredError,
21
+ toolSuccess,
22
+ withProgressHeartbeat,
23
+ wrapToolWithTimeout
24
+ } from "./chunk-3ZROPKLV.js";
25
+ import {
26
+ getToolMemory
27
+ } from "./chunk-ANH2A44T.js";
28
+ import {
29
+ getDefaultAvailableModelsCache
30
+ } from "./chunk-ZBQXPP7M.js";
31
+ import {
32
+ CUSTOM_API_DEFAULT_MODEL
33
+ } from "./chunk-MMW4KIBH.js";
34
+ import {
35
+ createCliAdapter,
36
+ createCliDetectionCache,
37
+ delay,
38
+ getAvailableClis,
39
+ isCliAvailable,
40
+ sanitizeOutput,
41
+ withTimeout
42
+ } from "./chunk-XMYJWMWN.js";
43
+ import {
44
+ AgentError,
45
+ CLI_NAMES,
46
+ CircularBuffer,
47
+ DEFAULT_CLI,
48
+ ErrorCode,
49
+ ModelCapability,
50
+ ModelError,
51
+ OutcomeStore,
52
+ TASK_SPECIALIZATION_MATRIX,
53
+ TaskOutcomeSchema,
54
+ VOTE_TIMEOUTS,
55
+ categorizeOutcomeErrorMessage,
56
+ clamp01,
57
+ createLogger,
58
+ detectTaskCategory,
59
+ err,
60
+ estimateTokens,
61
+ formatPercentage,
62
+ formatZodError,
63
+ getCliModelName,
64
+ getDefaultModelForCli,
65
+ getDefaultRegistry,
66
+ getErrorMessage,
67
+ getInTreeCapabilitiesMatrix,
68
+ getMcpSafeDeadlineMs,
69
+ getOutcomeStore,
70
+ getPipelineEventBus,
71
+ getRandomProvider,
72
+ getTimeProvider,
73
+ getTokenEstimator,
74
+ isRateLimitLikeError,
75
+ ok,
76
+ recordRateLimitEvent,
77
+ registerPersistentOutcomeStoreFactory,
78
+ resolveCliAlias,
79
+ resolveVoteTimeout,
80
+ toRateLimitError
81
+ } from "./chunk-2KHD2ANY.js";
82
+ import {
83
+ ensureLearningDir,
84
+ getOutcomesFile,
85
+ nexusDataPath,
86
+ nexusDataPathEnsure
87
+ } from "./chunk-CH7QIDHQ.js";
1577
88
 
1578
- // src/mcp/middleware/secure-handler.ts
1579
- function rateLimitError(nextTokenMs) {
1580
- return toolStructuredError({
1581
- errorCategory: "transient",
1582
- message: `Rate limit exceeded. Try again in ${String(nextTokenMs)}ms.`
1583
- });
1584
- }
1585
- function policyDeniedError(reason, requestId) {
1586
- return toolStructuredError({
1587
- errorCategory: "permission",
1588
- message: `Policy denied: ${reason} (request: ${requestId})`
1589
- });
1590
- }
1591
- function internalError(message, requestId) {
1592
- return toolStructuredError({
1593
- errorCategory: "internal",
1594
- message: `Internal error: ${message} (request: ${requestId})`
1595
- });
1596
- }
1597
- var MAX_INPUT_SIZE_BYTES = 10 * 1024 * 1024;
1598
- var SECRET_PATTERNS = [
1599
- // API keys with common prefixes
1600
- /\b(sk-[a-zA-Z0-9]{20,})\b/g,
1601
- /\b(pk-[a-zA-Z0-9]{20,})\b/g,
1602
- // AWS-style keys
1603
- /\b(AKIA[A-Z0-9]{16})\b/g,
1604
- // Bearer tokens in output
1605
- /Bearer\s+[a-zA-Z0-9_\-.~+/]+=*/g,
1606
- // Generic long hex secrets (40+ chars)
1607
- /\b[0-9a-f]{40,}\b/gi,
1608
- // password= or token= in output
1609
- /(?:password|token|secret|apikey|api_key)\s*[=:]\s*\S{8,}/gi
1610
- ];
1611
- function sanitizeOutput2(text, logger11) {
1612
- let sanitized = text;
1613
- for (const pattern of SECRET_PATTERNS) {
1614
- const before = sanitized;
1615
- sanitized = sanitized.replace(pattern, "[REDACTED]");
1616
- if (sanitized !== before) {
1617
- logger11.warn("Potential secret detected in tool output, redacting", {
1618
- pattern: pattern.source.slice(0, 30)
1619
- });
1620
- }
1621
- }
1622
- return sanitized;
1623
- }
1624
- function sanitizeToolResult(result, logger11) {
1625
- for (const item of result.content) {
1626
- item.text = sanitizeOutput2(item.text, logger11);
1627
- }
1628
- }
1629
- function checkInputSize(args, logger11, requestId) {
1630
- if (args === void 0) return null;
1631
- const inputSize = JSON.stringify(args).length;
1632
- if (inputSize > MAX_INPUT_SIZE_BYTES) {
1633
- logger11.warn("Input size exceeds limit", { inputSize, limit: MAX_INPUT_SIZE_BYTES });
1634
- return internalError("Input too large", requestId);
1635
- }
1636
- return null;
1637
- }
1638
- function checkRateLimit(rateLimiter, logger11) {
1639
- const acquired = rateLimiter.tryAcquire();
1640
- if (!acquired) {
1641
- const state = rateLimiter.getState();
1642
- logger11.warn("Rate limit exceeded");
1643
- return rateLimitError(state.nextTokenMs);
1644
- }
1645
- return null;
1646
- }
1647
- function checkPolicy(opts) {
1648
- const ctxOpts = {
1649
- mode: opts.mode,
1650
- ...opts.allowedPaths && { allowedPaths: opts.allowedPaths }
1651
- };
1652
- const decision = opts.firewall.evaluate(createPolicyContext(opts.toolName, opts.args, ctxOpts));
1653
- if (!decision.allowed) {
1654
- opts.logger.warn("Policy denied tool execution", {
1655
- reason: decision.reason,
1656
- ruleName: decision.ruleName
1657
- });
1658
- return policyDeniedError(decision.reason, opts.requestId);
1659
- }
1660
- opts.logger.debug("Policy check passed", { reason: decision.reason });
1661
- return null;
1662
- }
1663
- async function executeHandler(handler, args, ctx, logger11) {
1664
- const startTime = getTimeProvider().now();
1665
- const result = handler.length >= 2 ? await handler(args, ctx) : await handler(args);
1666
- const durationMs = getTimeProvider().now() - startTime;
1667
- if (result.isError === true) {
1668
- logger11.warn("Tool execution completed with error", { durationMs });
1669
- } else {
1670
- logger11.info("Tool execution completed", { durationMs });
1671
- }
1672
- return result;
1673
- }
1674
- function emitToolAudit(auditLogger, toolName, ctx, result, durationMs) {
1675
- const actor = actorFromContext(ctx);
1676
- const outcome = resultToOutcome(result.isError, false);
1677
- auditLogger.logToolInvocation({
1678
- toolName,
1679
- outcome,
1680
- actor,
1681
- requestId: ctx.requestId,
1682
- durationMs
1683
- });
1684
- }
1685
- function emitToolAuditException(auditLogger, toolName, ctx, durationMs) {
1686
- const actor = actorFromContext(ctx);
1687
- auditLogger.logToolInvocation({
1688
- toolName,
1689
- outcome: "error",
1690
- actor,
1691
- requestId: ctx.requestId,
1692
- durationMs
1693
- });
1694
- }
1695
- function emitPolicyAudit(auditLogger, toolName, ctx, reason) {
1696
- const actor = actorFromContext(ctx);
1697
- auditLogger.logPolicyDecision({
1698
- policyName: "default",
1699
- decision: "deny",
1700
- reason,
1701
- toolName,
1702
- actor,
1703
- requestId: ctx.requestId
1704
- });
1705
- }
1706
- function emitRateLimitAudit(auditLogger, toolName, ctx) {
1707
- const actor = actorFromContext(ctx);
1708
- auditLogger.logRateLimitViolation({
1709
- toolName,
1710
- actor,
1711
- currentRate: 0,
1712
- limitRate: 0,
1713
- requestId: ctx.requestId
1714
- });
1715
- }
1716
- function checkSecurityTier(config, sanitizeResult, logger11) {
1717
- const tier = config.securityTier ?? "standard";
1718
- if (tier === "standard" || sanitizeResult.detectedPatterns.length === 0) {
1719
- return null;
1720
- }
1721
- logger11.warn("Input rejected by security tier validation", {
1722
- tier,
1723
- patterns: sanitizeResult.detectedPatterns
1724
- });
1725
- return toolStructuredError({
1726
- errorCategory: "permission",
1727
- message: `Input validation failed: detected patterns [${sanitizeResult.detectedPatterns.join(", ")}]. Remove prompt injection patterns and retry.`
1728
- });
1729
- }
1730
- function runPreChecks(config, args, mode, requestContext, logger11) {
1731
- const sizeResult = checkInputSize(args, logger11, requestContext.requestId);
1732
- if (sizeResult) return { error: sizeResult, sanitizedArgs: args };
1733
- const sanitizeResult = sanitizeToolInput(args);
1734
- logSanitizationResult(sanitizeResult, logger11, config.toolName);
1735
- const sanitizedArgs = sanitizeResult.wasModified ? sanitizeResult.sanitized : args;
1736
- const tierError = checkSecurityTier(config, sanitizeResult, logger11);
1737
- if (tierError !== null) return { error: tierError, sanitizedArgs };
1738
- if (config.rateLimiter) {
1739
- const rlResult = checkRateLimit(config.rateLimiter, logger11);
1740
- if (rlResult) {
1741
- if (config.auditLogger)
1742
- emitRateLimitAudit(config.auditLogger, config.toolName, requestContext);
1743
- return { error: rlResult, sanitizedArgs };
1744
- }
1745
- }
1746
- if (config.policyFirewall) {
1747
- const pResult = checkPolicy({
1748
- firewall: config.policyFirewall,
1749
- toolName: config.toolName,
1750
- args: sanitizedArgs,
1751
- mode,
1752
- allowedPaths: config.allowedPaths,
1753
- logger: logger11,
1754
- requestId: requestContext.requestId
1755
- });
1756
- if (pResult) {
1757
- if (config.auditLogger)
1758
- emitPolicyAudit(config.auditLogger, config.toolName, requestContext, "policy denied");
1759
- return { error: pResult, sanitizedArgs };
1760
- }
1761
- }
1762
- return { error: null, sanitizedArgs };
1763
- }
1764
- function createSecureHandler(handler, config) {
1765
- const logger11 = config.logger ?? createLogger({ tool: config.toolName });
1766
- const mode = config.executionMode ?? "read-only";
1767
- return async (args) => {
1768
- const ctxOpts = {
1769
- toolName: config.toolName,
1770
- ...config.callerInfo && { caller: config.callerInfo }
1771
- };
1772
- const requestContext = createRequestContext(ctxOpts);
1773
- const requestLogger = logger11.child(contextForLogging(requestContext));
1774
- requestLogger.info("Tool invocation started");
1775
- const { error: preCheckError, sanitizedArgs } = runPreChecks(
1776
- config,
1777
- args,
1778
- mode,
1779
- requestContext,
1780
- requestLogger
1781
- );
1782
- if (preCheckError) return preCheckError;
1783
- return executeAndAudit(handler, sanitizedArgs, requestContext, requestLogger, config);
1784
- };
1785
- }
1786
- async function executeAndAudit(handler, sanitizedArgs, requestContext, requestLogger, config) {
1787
- const execStartTime = getTimeProvider().now();
1788
- try {
1789
- const result = await executeHandler(
1790
- handler,
1791
- sanitizedArgs,
1792
- { requestContext, logger: requestLogger },
1793
- requestLogger
1794
- );
1795
- sanitizeToolResult(result, requestLogger);
1796
- if (config.auditLogger) {
1797
- emitToolAudit(
1798
- config.auditLogger,
1799
- config.toolName,
1800
- requestContext,
1801
- result,
1802
- getTimeProvider().now() - execStartTime
1803
- );
1804
- }
1805
- return result;
1806
- } catch (error) {
1807
- const rawMessage = error instanceof Error ? error.message : "Unknown error";
1808
- requestLogger.error("Tool execution failed", error instanceof Error ? error : void 0);
1809
- if (config.auditLogger) {
1810
- emitToolAuditException(
1811
- config.auditLogger,
1812
- config.toolName,
1813
- requestContext,
1814
- getTimeProvider().now() - execStartTime
1815
- );
1816
- }
1817
- const sanitized = sanitizeOutput2(rawMessage, requestLogger);
1818
- return internalError(sanitized, requestContext.requestId);
1819
- }
1820
- }
89
+ // src/mcp/tools/consensus-vote.ts
90
+ import { z as z10 } from "zod";
1821
91
 
1822
92
  // src/cli/vote-types.ts
1823
93
  var VOTER_ROLES = {
@@ -2824,7 +1094,7 @@ async function createAutoAdapter(config = {}) {
2824
1094
  }
2825
1095
 
2826
1096
  // src/agents/collaboration/event-bus-helpers.ts
2827
- import { randomUUID as randomUUID2 } from "crypto";
1097
+ import { randomUUID } from "crypto";
2828
1098
  var DEFAULT_MAX_HISTORY_SIZE = 1e3;
2829
1099
  var MAX_SUBSCRIPTIONS = 500;
2830
1100
  var MAX_TOPIC_PATTERN_LENGTH = 200;
@@ -2845,10 +1115,10 @@ function topicMatchesPattern(topic, regex) {
2845
1115
  return regex.test(topic);
2846
1116
  }
2847
1117
  function generateEventId() {
2848
- return `evt-${String(getTimeProvider().now())}-${randomUUID2().slice(0, 8)}`;
1118
+ return `evt-${String(getTimeProvider().now())}-${randomUUID().slice(0, 8)}`;
2849
1119
  }
2850
1120
  function generateSubscriptionId() {
2851
- return `sub-${String(getTimeProvider().now())}-${randomUUID2().slice(0, 8)}`;
1121
+ return `sub-${String(getTimeProvider().now())}-${randomUUID().slice(0, 8)}`;
2852
1122
  }
2853
1123
  function applyHistoryFilters(history, filter) {
2854
1124
  let result = history;
@@ -4000,7 +2270,7 @@ var SIMULATED_VOTE_REASONING = {
4000
2270
  };
4001
2271
 
4002
2272
  // src/cli/voter-response.ts
4003
- import { z as z3 } from "zod";
2273
+ import { z } from "zod";
4004
2274
  var SyntheticVoteError = class extends Error {
4005
2275
  constructor(reason, rawOutput) {
4006
2276
  super(
@@ -4010,26 +2280,26 @@ var SyntheticVoteError = class extends Error {
4010
2280
  this.name = "SyntheticVoteError";
4011
2281
  }
4012
2282
  };
4013
- var RawFindingSchema = z3.object({
4014
- summary: z3.string().min(1).max(500).describe("One-line summary of the issue"),
4015
- location: z3.string().min(1).max(200).describe("path/file.ext:line"),
4016
- severity: z3.enum(["critical", "high", "medium", "low"]).default("medium"),
4017
- gate: z3.object({
4018
- reread_cited_line: z3.enum(["passed", "failed", "skipped"]).default("skipped"),
4019
- traced_call_path: z3.enum(["passed", "failed", "skipped"]).default("skipped"),
4020
- named_assertion: z3.string().default("").describe("Concrete failing assertion \u2014 substantive, not a rubber-stamp word"),
4021
- ruled_out_language_non_issue: z3.enum(["passed", "failed", "skipped"]).default("skipped")
2283
+ var RawFindingSchema = z.object({
2284
+ summary: z.string().min(1).max(500).describe("One-line summary of the issue"),
2285
+ location: z.string().min(1).max(200).describe("path/file.ext:line"),
2286
+ severity: z.enum(["critical", "high", "medium", "low"]).default("medium"),
2287
+ gate: z.object({
2288
+ reread_cited_line: z.enum(["passed", "failed", "skipped"]).default("skipped"),
2289
+ traced_call_path: z.enum(["passed", "failed", "skipped"]).default("skipped"),
2290
+ named_assertion: z.string().default("").describe("Concrete failing assertion \u2014 substantive, not a rubber-stamp word"),
2291
+ ruled_out_language_non_issue: z.enum(["passed", "failed", "skipped"]).default("skipped")
4022
2292
  }),
4023
- claim: z3.string().min(1).max(2e3).describe("What is wrong and why it justifies blocking")
2293
+ claim: z.string().min(1).max(2e3).describe("What is wrong and why it justifies blocking")
4024
2294
  });
4025
- var VoteResponseSchema = z3.object({
4026
- decision: z3.enum(["approve", "reject", "abstain"]).describe("Your vote decision"),
4027
- reasoning: z3.string().min(10).max(4e3).describe("Explanation for your vote (10-4000 chars)"),
4028
- confidence: z3.number().min(0).max(1).describe("Confidence level 0-1"),
4029
- conditions: z3.array(z3.string()).optional().describe("Optional conditions for approval"),
2295
+ var VoteResponseSchema = z.object({
2296
+ decision: z.enum(["approve", "reject", "abstain"]).describe("Your vote decision"),
2297
+ reasoning: z.string().min(10).max(4e3).describe("Explanation for your vote (10-4000 chars)"),
2298
+ confidence: z.number().min(0).max(1).describe("Confidence level 0-1"),
2299
+ conditions: z.array(z.string()).optional().describe("Optional conditions for approval"),
4030
2300
  /** Structured rejection categories for reject→refine→re-vote loops (Issue #1213). */
4031
- rejectionCategories: z3.array(
4032
- z3.enum([
2301
+ rejectionCategories: z.array(
2302
+ z.enum([
4033
2303
  "YAGNI",
4034
2304
  "DRY_VIOLATION",
4035
2305
  "OVER_ENGINEERING",
@@ -4041,7 +2311,7 @@ var VoteResponseSchema = z3.object({
4041
2311
  ).optional().describe("Rejection reason categories when decision is reject"),
4042
2312
  /** Top-level structured findings for PR-review mode (#2245 v4 follow-up).
4043
2313
  * Replaces the YAML-in-reasoning encoding that proved lossy. */
4044
- findings: z3.array(RawFindingSchema).optional().describe("Structured findings (PR review only)")
2314
+ findings: z.array(RawFindingSchema).optional().describe("Structured findings (PR review only)")
4045
2315
  });
4046
2316
  var VOTE_PROMPT_EXAMPLES = `Example approve response:
4047
2317
  {
@@ -4572,8 +2842,8 @@ async function collectRealVotes(options) {
4572
2842
  }
4573
2843
 
4574
2844
  // src/consensus/types-core.ts
4575
- import { z as z4 } from "zod";
4576
- var ConsensusAlgorithmSchema = z4.enum([
2845
+ import { z as z2 } from "zod";
2846
+ var ConsensusAlgorithmSchema = z2.enum([
4577
2847
  "simple_majority",
4578
2848
  "supermajority",
4579
2849
  "unanimous",
@@ -4581,8 +2851,8 @@ var ConsensusAlgorithmSchema = z4.enum([
4581
2851
  "opinion_wise",
4582
2852
  "higher_order"
4583
2853
  ]);
4584
- var VoteDecisionSchema = z4.enum(["approve", "reject", "abstain"]);
4585
- var ProposalStatusSchema = z4.enum([
2854
+ var VoteDecisionSchema = z2.enum(["approve", "reject", "abstain"]);
2855
+ var ProposalStatusSchema = z2.enum([
4586
2856
  "pending",
4587
2857
  "voting",
4588
2858
  "approved",
@@ -4590,7 +2860,7 @@ var ProposalStatusSchema = z4.enum([
4590
2860
  "timeout",
4591
2861
  "closed"
4592
2862
  ]);
4593
- var RejectionCategorySchema = z4.enum([
2863
+ var RejectionCategorySchema = z2.enum([
4594
2864
  "YAGNI",
4595
2865
  "DRY_VIOLATION",
4596
2866
  "OVER_ENGINEERING",
@@ -4600,69 +2870,69 @@ var RejectionCategorySchema = z4.enum([
4600
2870
  "INSUFFICIENT_EVIDENCE"
4601
2871
  ]);
4602
2872
  var REJECTION_CATEGORIES = RejectionCategorySchema.options;
4603
- var FindingShapeSchema = z4.object({
4604
- summary: z4.string().min(1).max(500),
4605
- location: z4.string().min(1).max(200),
4606
- severity: z4.enum(["critical", "high", "medium", "low"]).default("medium"),
4607
- gate: z4.object({
4608
- reread_cited_line: z4.enum(["passed", "failed", "skipped"]).default("skipped"),
4609
- traced_call_path: z4.enum(["passed", "failed", "skipped"]).default("skipped"),
4610
- named_assertion: z4.string().default(""),
4611
- ruled_out_language_non_issue: z4.enum(["passed", "failed", "skipped"]).default("skipped")
2873
+ var FindingShapeSchema = z2.object({
2874
+ summary: z2.string().min(1).max(500),
2875
+ location: z2.string().min(1).max(200),
2876
+ severity: z2.enum(["critical", "high", "medium", "low"]).default("medium"),
2877
+ gate: z2.object({
2878
+ reread_cited_line: z2.enum(["passed", "failed", "skipped"]).default("skipped"),
2879
+ traced_call_path: z2.enum(["passed", "failed", "skipped"]).default("skipped"),
2880
+ named_assertion: z2.string().default(""),
2881
+ ruled_out_language_non_issue: z2.enum(["passed", "failed", "skipped"]).default("skipped")
4612
2882
  }),
4613
- claim: z4.string().min(1).max(2e3)
2883
+ claim: z2.string().min(1).max(2e3)
4614
2884
  });
4615
- var VoteSchema = z4.object({
2885
+ var VoteSchema = z2.object({
4616
2886
  decision: VoteDecisionSchema,
4617
- reasoning: z4.string().min(1).describe("Explanation for the vote"),
4618
- confidence: z4.number().min(0).max(1).describe("Confidence level 0-1"),
4619
- conditions: z4.array(z4.string()).optional().describe("Conditions for approval"),
2887
+ reasoning: z2.string().min(1).describe("Explanation for the vote"),
2888
+ confidence: z2.number().min(0).max(1).describe("Confidence level 0-1"),
2889
+ conditions: z2.array(z2.string()).optional().describe("Conditions for approval"),
4620
2890
  /** Structured rejection categories for reject→refine→re-vote loops (Issue #1213). */
4621
- rejectionCategories: z4.array(RejectionCategorySchema).optional().describe("Rejection reason categories when decision is reject"),
2891
+ rejectionCategories: z2.array(RejectionCategorySchema).optional().describe("Rejection reason categories when decision is reject"),
4622
2892
  /** Pre-verified PR-review findings (#2245 v4 follow-up). Optional;
4623
2893
  * populated only when the voter emits the structured top-level array. */
4624
- findings: z4.array(FindingShapeSchema).optional().describe("PR-review findings (pre-verified)"),
4625
- timestamp: z4.iso.datetime().optional()
2894
+ findings: z2.array(FindingShapeSchema).optional().describe("PR-review findings (pre-verified)"),
2895
+ timestamp: z2.iso.datetime().optional()
4626
2896
  });
4627
- var ProposalSchema = z4.object({
4628
- id: z4.string().optional().describe("Auto-generated if not provided"),
4629
- title: z4.string().min(1).max(200).describe("Short proposal title"),
4630
- description: z4.string().min(1).describe("Detailed proposal description"),
2897
+ var ProposalSchema = z2.object({
2898
+ id: z2.string().optional().describe("Auto-generated if not provided"),
2899
+ title: z2.string().min(1).max(200).describe("Short proposal title"),
2900
+ description: z2.string().min(1).describe("Detailed proposal description"),
4631
2901
  algorithm: ConsensusAlgorithmSchema,
4632
- timeout: z4.number().int().positive().optional().describe("Timeout in milliseconds"),
4633
- requiredVoters: z4.array(z4.string()).optional().describe("Agent IDs that must vote"),
4634
- metadata: z4.record(z4.string(), z4.unknown()).optional().describe("Additional context"),
4635
- createdAt: z4.iso.datetime().optional()
2902
+ timeout: z2.number().int().positive().optional().describe("Timeout in milliseconds"),
2903
+ requiredVoters: z2.array(z2.string()).optional().describe("Agent IDs that must vote"),
2904
+ metadata: z2.record(z2.string(), z2.unknown()).optional().describe("Additional context"),
2905
+ createdAt: z2.iso.datetime().optional()
4636
2906
  });
4637
- var ConsensusResultSchema = z4.object({
4638
- proposalId: z4.string(),
2907
+ var ConsensusResultSchema = z2.object({
2908
+ proposalId: z2.string(),
4639
2909
  proposal: ProposalSchema,
4640
2910
  outcome: ProposalStatusSchema,
4641
- votes: z4.map(z4.string(), VoteSchema),
4642
- voteCounts: z4.object({
4643
- approve: z4.number().int().nonnegative(),
4644
- reject: z4.number().int().nonnegative(),
4645
- abstain: z4.number().int().nonnegative(),
4646
- total: z4.number().int().nonnegative()
2911
+ votes: z2.map(z2.string(), VoteSchema),
2912
+ voteCounts: z2.object({
2913
+ approve: z2.number().int().nonnegative(),
2914
+ reject: z2.number().int().nonnegative(),
2915
+ abstain: z2.number().int().nonnegative(),
2916
+ total: z2.number().int().nonnegative()
4647
2917
  }),
4648
- weightedCounts: z4.object({
4649
- approve: z4.number().nonnegative(),
4650
- reject: z4.number().nonnegative(),
4651
- abstain: z4.number().nonnegative(),
4652
- totalWeight: z4.number().nonnegative()
2918
+ weightedCounts: z2.object({
2919
+ approve: z2.number().nonnegative(),
2920
+ reject: z2.number().nonnegative(),
2921
+ abstain: z2.number().nonnegative(),
2922
+ totalWeight: z2.number().nonnegative()
4653
2923
  }).optional(),
4654
- approvalPercentage: z4.number().min(0).max(100),
4655
- quorumReached: z4.boolean(),
4656
- startedAt: z4.iso.datetime(),
4657
- closedAt: z4.iso.datetime(),
4658
- durationMs: z4.number().int().nonnegative()
2924
+ approvalPercentage: z2.number().min(0).max(100),
2925
+ quorumReached: z2.boolean(),
2926
+ startedAt: z2.iso.datetime(),
2927
+ closedAt: z2.iso.datetime(),
2928
+ durationMs: z2.number().int().nonnegative()
4659
2929
  });
4660
- var AgentPerformanceSchema = z4.object({
4661
- agentId: z4.string(),
4662
- totalVotes: z4.number().int().nonnegative(),
4663
- correctVotes: z4.number().int().nonnegative(),
4664
- successRate: z4.number().min(0).max(1),
4665
- lastUpdated: z4.iso.datetime()
2930
+ var AgentPerformanceSchema = z2.object({
2931
+ agentId: z2.string(),
2932
+ totalVotes: z2.number().int().nonnegative(),
2933
+ correctVotes: z2.number().int().nonnegative(),
2934
+ successRate: z2.number().min(0).max(1),
2935
+ lastUpdated: z2.iso.datetime()
4666
2936
  });
4667
2937
  var DEFAULT_INCREMENTAL_QUORUM_CONFIG = {
4668
2938
  enabled: false,
@@ -4671,19 +2941,19 @@ var DEFAULT_INCREMENTAL_QUORUM_CONFIG = {
4671
2941
  confidenceThreshold: 0.6,
4672
2942
  ambiguityBand: 0.15
4673
2943
  };
4674
- var ProposalCacheConfigSchema = z4.object({
4675
- enabled: z4.boolean().default(false),
4676
- ttlMs: z4.number().int().positive().default(36e5),
2944
+ var ProposalCacheConfigSchema = z2.object({
2945
+ enabled: z2.boolean().default(false),
2946
+ ttlMs: z2.number().int().positive().default(36e5),
4677
2947
  // 1 hour
4678
- maxEntries: z4.number().int().positive().default(500)
2948
+ maxEntries: z2.number().int().positive().default(500)
4679
2949
  });
4680
- var ConsensusEngineConfigSchema = z4.object({
4681
- defaultTimeout: z4.number().int().positive().default(3e5),
2950
+ var ConsensusEngineConfigSchema = z2.object({
2951
+ defaultTimeout: z2.number().int().positive().default(3e5),
4682
2952
  // 5 minutes
4683
- minVotersForQuorum: z4.number().int().positive().default(2),
4684
- maxActiveProposals: z4.number().int().positive().default(100),
4685
- enablePerformanceTracking: z4.boolean().default(true),
4686
- maxClosedProposals: z4.number().int().positive().default(1e3),
2953
+ minVotersForQuorum: z2.number().int().positive().default(2),
2954
+ maxActiveProposals: z2.number().int().positive().default(100),
2955
+ enablePerformanceTracking: z2.boolean().default(true),
2956
+ maxClosedProposals: z2.number().int().positive().default(1e3),
4687
2957
  // Issue #549
4688
2958
  proposalCache: ProposalCacheConfigSchema.optional()
4689
2959
  // Issue #589
@@ -4708,50 +2978,50 @@ var VOTING_THRESHOLDS = {
4708
2978
  higher_order: 0.5
4709
2979
  // Alias for opinion_wise (Issue #514)
4710
2980
  };
4711
- var ConsensusMetricsSchema = z4.object({
4712
- totalProposals: z4.number().int().nonnegative(),
4713
- approvedProposals: z4.number().int().nonnegative(),
4714
- rejectedProposals: z4.number().int().nonnegative(),
4715
- timedOutProposals: z4.number().int().nonnegative(),
4716
- averageDurationMs: z4.number().nonnegative(),
4717
- averageVotesPerProposal: z4.number().nonnegative(),
4718
- algorithmUsage: z4.record(ConsensusAlgorithmSchema, z4.number().int().nonnegative())
2981
+ var ConsensusMetricsSchema = z2.object({
2982
+ totalProposals: z2.number().int().nonnegative(),
2983
+ approvedProposals: z2.number().int().nonnegative(),
2984
+ rejectedProposals: z2.number().int().nonnegative(),
2985
+ timedOutProposals: z2.number().int().nonnegative(),
2986
+ averageDurationMs: z2.number().nonnegative(),
2987
+ averageVotesPerProposal: z2.number().nonnegative(),
2988
+ algorithmUsage: z2.record(ConsensusAlgorithmSchema, z2.number().int().nonnegative())
4719
2989
  });
4720
2990
 
4721
2991
  // src/consensus/types-voting-protocol.ts
4722
- import { z as z5 } from "zod";
4723
- var VotingRoundPhaseSchema = z5.enum(["analysis", "deliberation", "consensus"]);
4724
- var VotingRoundStatusSchema = z5.enum([
2992
+ import { z as z3 } from "zod";
2993
+ var VotingRoundPhaseSchema = z3.enum(["analysis", "deliberation", "consensus"]);
2994
+ var VotingRoundStatusSchema = z3.enum([
4725
2995
  "pending",
4726
2996
  "in_progress",
4727
2997
  "awaiting_votes",
4728
2998
  "completed",
4729
2999
  "aborted"
4730
3000
  ]);
4731
- var AgentFindingSchema = z5.object({
4732
- agentId: z5.string(),
4733
- category: z5.enum(["bug", "security", "performance", "style", "design", "documentation", "other"]),
4734
- severity: z5.enum(["critical", "major", "minor", "suggestion"]),
4735
- description: z5.string().min(1),
4736
- location: z5.string().optional().describe("File path and line range if applicable"),
4737
- suggestion: z5.string().optional().describe("Recommended fix"),
4738
- confidence: z5.number().min(0).max(1),
4739
- timestamp: z5.iso.datetime().optional()
3001
+ var AgentFindingSchema = z3.object({
3002
+ agentId: z3.string(),
3003
+ category: z3.enum(["bug", "security", "performance", "style", "design", "documentation", "other"]),
3004
+ severity: z3.enum(["critical", "major", "minor", "suggestion"]),
3005
+ description: z3.string().min(1),
3006
+ location: z3.string().optional().describe("File path and line range if applicable"),
3007
+ suggestion: z3.string().optional().describe("Recommended fix"),
3008
+ confidence: z3.number().min(0).max(1),
3009
+ timestamp: z3.iso.datetime().optional()
4740
3010
  });
4741
- var FindingVoteSchema = z5.object({
4742
- agentId: z5.string(),
4743
- findingId: z5.string(),
4744
- agree: z5.boolean(),
4745
- reasoning: z5.string().optional(),
4746
- amendedSeverity: z5.enum(["critical", "major", "minor", "suggestion"]).optional()
3011
+ var FindingVoteSchema = z3.object({
3012
+ agentId: z3.string(),
3013
+ findingId: z3.string(),
3014
+ agree: z3.boolean(),
3015
+ reasoning: z3.string().optional(),
3016
+ amendedSeverity: z3.enum(["critical", "major", "minor", "suggestion"]).optional()
4747
3017
  });
4748
- var VotingProtocolConfigSchema = z5.object({
4749
- committeeSize: z5.number().int().min(2).max(7).default(3),
4750
- maxRounds: z5.number().int().min(1).max(5).default(3),
4751
- roundTimeoutMs: z5.number().int().positive().default(6e4),
4752
- agreementThreshold: z5.number().min(0.5).max(1).default(0.67),
4753
- enableAntiSycophancy: z5.boolean().default(true),
4754
- sycophancyThreshold: z5.number().min(0).max(1).default(0.8)
3018
+ var VotingProtocolConfigSchema = z3.object({
3019
+ committeeSize: z3.number().int().min(2).max(7).default(3),
3020
+ maxRounds: z3.number().int().min(1).max(5).default(3),
3021
+ roundTimeoutMs: z3.number().int().positive().default(6e4),
3022
+ agreementThreshold: z3.number().min(0.5).max(1).default(0.67),
3023
+ enableAntiSycophancy: z3.boolean().default(true),
3024
+ sycophancyThreshold: z3.number().min(0).max(1).default(0.8)
4755
3025
  });
4756
3026
  var DEFAULT_VOTING_PROTOCOL_CONFIG = {
4757
3027
  committeeSize: 3,
@@ -4763,30 +3033,30 @@ var DEFAULT_VOTING_PROTOCOL_CONFIG = {
4763
3033
  };
4764
3034
 
4765
3035
  // src/consensus/types-weighted-voting.ts
4766
- import { z as z6 } from "zod";
4767
- var TaskOutcomeSchema2 = z6.enum(["success", "failure", "partial", "unknown"]);
4768
- var WeightedAgentRecordSchema = z6.object({
4769
- agentId: z6.string().min(1),
4770
- totalTasks: z6.number().int().nonnegative(),
4771
- successfulTasks: z6.number().int().nonnegative(),
4772
- failedTasks: z6.number().int().nonnegative(),
4773
- partialTasks: z6.number().int().nonnegative(),
4774
- successRate: z6.number().min(0).max(1),
4775
- weight: z6.number().min(0).max(1),
4776
- trustScore: z6.number().min(0).max(1),
4777
- byzantineFlags: z6.number().int().nonnegative(),
4778
- lastActive: z6.date(),
4779
- createdAt: z6.date()
3036
+ import { z as z4 } from "zod";
3037
+ var TaskOutcomeSchema2 = z4.enum(["success", "failure", "partial", "unknown"]);
3038
+ var WeightedAgentRecordSchema = z4.object({
3039
+ agentId: z4.string().min(1),
3040
+ totalTasks: z4.number().int().nonnegative(),
3041
+ successfulTasks: z4.number().int().nonnegative(),
3042
+ failedTasks: z4.number().int().nonnegative(),
3043
+ partialTasks: z4.number().int().nonnegative(),
3044
+ successRate: z4.number().min(0).max(1),
3045
+ weight: z4.number().min(0).max(1),
3046
+ trustScore: z4.number().min(0).max(1),
3047
+ byzantineFlags: z4.number().int().nonnegative(),
3048
+ lastActive: z4.date(),
3049
+ createdAt: z4.date()
4780
3050
  });
4781
- var WeightedVotingConfigSchema = z6.object({
4782
- minWeight: z6.number().min(0).max(1).default(0.1),
4783
- maxByzantineFraction: z6.number().min(0).max(0.5).default(0.33),
4784
- weightDecayFactor: z6.number().min(0.5).max(1).default(0.9),
4785
- weightRecoveryFactor: z6.number().min(1).max(2).default(1.05),
4786
- minTrustScore: z6.number().min(0).max(1).default(0.3),
4787
- byzantineFlagThreshold: z6.number().int().positive().default(3),
4788
- initialWeight: z6.number().min(0).max(1).default(0.5),
4789
- quorumThreshold: z6.number().min(0.5).max(1).default(0.67)
3051
+ var WeightedVotingConfigSchema = z4.object({
3052
+ minWeight: z4.number().min(0).max(1).default(0.1),
3053
+ maxByzantineFraction: z4.number().min(0).max(0.5).default(0.33),
3054
+ weightDecayFactor: z4.number().min(0.5).max(1).default(0.9),
3055
+ weightRecoveryFactor: z4.number().min(1).max(2).default(1.05),
3056
+ minTrustScore: z4.number().min(0).max(1).default(0.3),
3057
+ byzantineFlagThreshold: z4.number().int().positive().default(3),
3058
+ initialWeight: z4.number().min(0).max(1).default(0.5),
3059
+ quorumThreshold: z4.number().min(0.5).max(1).default(0.67)
4790
3060
  });
4791
3061
  var DEFAULT_WEIGHTED_VOTING_CONFIG = {
4792
3062
  minWeight: 0.1,
@@ -4800,7 +3070,7 @@ var DEFAULT_WEIGHTED_VOTING_CONFIG = {
4800
3070
  };
4801
3071
 
4802
3072
  // src/consensus/higher-order-types.ts
4803
- import { z as z7 } from "zod";
3073
+ import { z as z5 } from "zod";
4804
3074
  function createAgentPairKey(agentA, agentB) {
4805
3075
  return agentA < agentB ? `${agentA}:${agentB}` : `${agentB}:${agentA}`;
4806
3076
  }
@@ -4811,40 +3081,40 @@ function parseAgentPairKey(key) {
4811
3081
  }
4812
3082
  return [parts[0], parts[1]];
4813
3083
  }
4814
- var CorrelationCoefficientSchema = z7.number().min(-1).max(1);
4815
- var IndependentSubsetSchema = z7.object({
4816
- id: z7.string(),
4817
- agentIds: z7.array(z7.string()),
4818
- independenceScore: z7.number().min(0).max(1),
4819
- observationCount: z7.number().int().nonnegative()
3084
+ var CorrelationCoefficientSchema = z5.number().min(-1).max(1);
3085
+ var IndependentSubsetSchema = z5.object({
3086
+ id: z5.string(),
3087
+ agentIds: z5.array(z5.string()),
3088
+ independenceScore: z5.number().min(0).max(1),
3089
+ observationCount: z5.number().int().nonnegative()
4820
3090
  });
4821
- var VotingObservationSchema = z7.object({
4822
- proposalId: z7.string(),
4823
- agentId: z7.string(),
4824
- decision: z7.enum(["approve", "reject", "abstain"]),
4825
- confidence: z7.number().min(0).max(1),
4826
- alignedWithOutcome: z7.boolean(),
4827
- timestamp: z7.date()
3091
+ var VotingObservationSchema = z5.object({
3092
+ proposalId: z5.string(),
3093
+ agentId: z5.string(),
3094
+ decision: z5.enum(["approve", "reject", "abstain"]),
3095
+ confidence: z5.number().min(0).max(1),
3096
+ alignedWithOutcome: z5.boolean(),
3097
+ timestamp: z5.date()
4828
3098
  });
4829
- var PairwiseVotingHistorySchema = z7.object({
4830
- pairKey: z7.string(),
4831
- jointObservations: z7.number().int().nonnegative(),
4832
- agreements: z7.number().int().nonnegative(),
4833
- disagreements: z7.number().int().nonnegative(),
3099
+ var PairwiseVotingHistorySchema = z5.object({
3100
+ pairKey: z5.string(),
3101
+ jointObservations: z5.number().int().nonnegative(),
3102
+ agreements: z5.number().int().nonnegative(),
3103
+ disagreements: z5.number().int().nonnegative(),
4834
3104
  correlation: CorrelationCoefficientSchema,
4835
- lastUpdated: z7.date()
3105
+ lastUpdated: z5.date()
4836
3106
  });
4837
- var HigherOrderVotingConfigSchema = z7.object({
4838
- minObservationsForCorrelation: z7.number().int().positive().default(10),
4839
- correlationThreshold: z7.number().min(0).max(1).default(0.3),
4840
- correlationMaxAgeMs: z7.number().int().positive().default(864e5),
3107
+ var HigherOrderVotingConfigSchema = z5.object({
3108
+ minObservationsForCorrelation: z5.number().int().positive().default(10),
3109
+ correlationThreshold: z5.number().min(0).max(1).default(0.3),
3110
+ correlationMaxAgeMs: z5.number().int().positive().default(864e5),
4841
3111
  // 24 hours
4842
- independenceThreshold: z7.number().min(0).max(1).default(0.2),
4843
- fallbackToSimpleVoting: z7.boolean().default(true),
4844
- observationDecayFactor: z7.number().min(0).max(1).default(0.95),
4845
- maxObservationsPerAgent: z7.number().int().positive().default(1e3),
4846
- maxProposals: z7.number().int().positive().default(5e3),
4847
- maxTrackedPairs: z7.number().int().positive().default(100)
3112
+ independenceThreshold: z5.number().min(0).max(1).default(0.2),
3113
+ fallbackToSimpleVoting: z5.boolean().default(true),
3114
+ observationDecayFactor: z5.number().min(0).max(1).default(0.95),
3115
+ maxObservationsPerAgent: z5.number().int().positive().default(1e3),
3116
+ maxProposals: z5.number().int().positive().default(5e3),
3117
+ maxTrackedPairs: z5.number().int().positive().default(100)
4848
3118
  });
4849
3119
  var DEFAULT_HIGHER_ORDER_CONFIG = {
4850
3120
  minObservationsForCorrelation: 10,
@@ -4858,25 +3128,25 @@ var DEFAULT_HIGHER_ORDER_CONFIG = {
4858
3128
  maxProposals: 5e3,
4859
3129
  maxTrackedPairs: 100
4860
3130
  };
4861
- var HigherOrderVotingResultSchema = z7.object({
4862
- decision: z7.enum(["approve", "reject", "no_consensus"]),
4863
- posteriorApproval: z7.number().min(0).max(1),
4864
- posteriorRejection: z7.number().min(0).max(1),
4865
- effectiveVoteCount: z7.number().nonnegative(),
4866
- usedCorrelationData: z7.boolean(),
4867
- method: z7.enum(["ow", "isp", "simple"]),
4868
- improvementOverBaseline: z7.number(),
4869
- independentSubsets: z7.array(IndependentSubsetSchema).optional(),
4870
- downweightedAgents: z7.array(z7.string()),
4871
- reasoning: z7.string()
3131
+ var HigherOrderVotingResultSchema = z5.object({
3132
+ decision: z5.enum(["approve", "reject", "no_consensus"]),
3133
+ posteriorApproval: z5.number().min(0).max(1),
3134
+ posteriorRejection: z5.number().min(0).max(1),
3135
+ effectiveVoteCount: z5.number().nonnegative(),
3136
+ usedCorrelationData: z5.boolean(),
3137
+ method: z5.enum(["ow", "isp", "simple"]),
3138
+ improvementOverBaseline: z5.number(),
3139
+ independentSubsets: z5.array(IndependentSubsetSchema).optional(),
3140
+ downweightedAgents: z5.array(z5.string()),
3141
+ reasoning: z5.string()
4872
3142
  });
4873
- var CorrelationTrackerStatsSchema = z7.object({
4874
- totalAgents: z7.number().int().nonnegative(),
4875
- trackedPairs: z7.number().int().nonnegative(),
4876
- totalObservations: z7.number().int().nonnegative(),
4877
- averageCorrelation: z7.number(),
4878
- independentSubsetCount: z7.number().int().nonnegative(),
4879
- pairsWithSufficientData: z7.number().int().nonnegative()
3143
+ var CorrelationTrackerStatsSchema = z5.object({
3144
+ totalAgents: z5.number().int().nonnegative(),
3145
+ trackedPairs: z5.number().int().nonnegative(),
3146
+ totalObservations: z5.number().int().nonnegative(),
3147
+ averageCorrelation: z5.number(),
3148
+ independentSubsetCount: z5.number().int().nonnegative(),
3149
+ pairsWithSufficientData: z5.number().int().nonnegative()
4880
3150
  });
4881
3151
 
4882
3152
  // src/consensus/higher-order-helpers.ts
@@ -7564,7 +5834,7 @@ function createCorrelationTracker(config) {
7564
5834
 
7565
5835
  // src/consensus/correlation-persistence.ts
7566
5836
  import * as fs from "fs";
7567
- import { z as z8 } from "zod";
5837
+ import { z as z6 } from "zod";
7568
5838
  var logger6 = createLogger({ component: "correlation-persistence" });
7569
5839
  var VOTING_SUBDIR = "voting";
7570
5840
  var CORRELATIONS_FILE = "correlations.json";
@@ -7572,21 +5842,21 @@ var CORRELATIONS_JSONL_FILE = "correlations.jsonl";
7572
5842
  var FILE_MODE = 384;
7573
5843
  var DIR_MODE = 448;
7574
5844
  var SCHEMA_VERSION = 2;
7575
- var PersistedVoteSchema = z8.object({
7576
- agentId: z8.string(),
7577
- decision: z8.enum(["approve", "reject", "abstain"]),
7578
- confidence: z8.number().min(0).max(1)
5845
+ var PersistedVoteSchema = z6.object({
5846
+ agentId: z6.string(),
5847
+ decision: z6.enum(["approve", "reject", "abstain"]),
5848
+ confidence: z6.number().min(0).max(1)
7579
5849
  });
7580
- var PersistedProposalSchema = z8.object({
7581
- proposalId: z8.string(),
7582
- votes: z8.array(PersistedVoteSchema),
7583
- outcome: z8.enum(["approved", "rejected"]),
7584
- timestamp: z8.iso.datetime()
5850
+ var PersistedProposalSchema = z6.object({
5851
+ proposalId: z6.string(),
5852
+ votes: z6.array(PersistedVoteSchema),
5853
+ outcome: z6.enum(["approved", "rejected"]),
5854
+ timestamp: z6.iso.datetime()
7585
5855
  });
7586
- var PersistedCorrelationDataSchema = z8.object({
7587
- version: z8.number().int().positive(),
7588
- proposals: z8.array(PersistedProposalSchema),
7589
- savedAt: z8.iso.datetime()
5856
+ var PersistedCorrelationDataSchema = z6.object({
5857
+ version: z6.number().int().positive(),
5858
+ proposals: z6.array(PersistedProposalSchema),
5859
+ savedAt: z6.iso.datetime()
7590
5860
  });
7591
5861
  function getCorrelationDataPath() {
7592
5862
  return nexusDataPath(VOTING_SUBDIR, CORRELATIONS_FILE);
@@ -7787,9 +6057,9 @@ function createPersistedProposal(proposalId, votes, outcome) {
7787
6057
  }
7788
6058
 
7789
6059
  // src/mcp/tools/consensus-vote-types.ts
7790
- import { z as z9 } from "zod";
6060
+ import { z as z7 } from "zod";
7791
6061
  var MAX_PROPOSAL_LENGTH = 4e3;
7792
- var VotingStrategySchema = z9.enum([
6062
+ var VotingStrategySchema = z7.enum([
7793
6063
  "simple_majority",
7794
6064
  "supermajority",
7795
6065
  "unanimous",
@@ -7797,8 +6067,8 @@ var VotingStrategySchema = z9.enum([
7797
6067
  "higher_order",
7798
6068
  "opinion_wise"
7799
6069
  ]);
7800
- var ErrorPolicySchema = z9.enum(["reduce_denominator", "count_as_abstain", "fail_closed"]);
7801
- var VoteThresholdSchema = z9.enum(["majority", "supermajority", "unanimous"]);
6070
+ var ErrorPolicySchema = z7.enum(["reduce_denominator", "count_as_abstain", "fail_closed"]);
6071
+ var VoteThresholdSchema = z7.enum(["majority", "supermajority", "unanimous"]);
7802
6072
  var ERROR_FLOOR_FRACTION = 0.5;
7803
6073
  function getDefaultErrorPolicy(strategy) {
7804
6074
  if (strategy === "unanimous") {
@@ -7806,8 +6076,8 @@ function getDefaultErrorPolicy(strategy) {
7806
6076
  }
7807
6077
  return "reduce_denominator";
7808
6078
  }
7809
- var ConsensusVoteInputSchema = z9.object({
7810
- proposal: z9.string().min(1).max(MAX_PROPOSAL_LENGTH).describe("Proposal text to vote on"),
6079
+ var ConsensusVoteInputSchema = z7.object({
6080
+ proposal: z7.string().min(1).max(MAX_PROPOSAL_LENGTH).describe("Proposal text to vote on"),
7811
6081
  threshold: VoteThresholdSchema.optional().describe(
7812
6082
  "Voting threshold (legacy): majority, supermajority, unanimous. Use strategy instead."
7813
6083
  ),
@@ -7817,8 +6087,8 @@ var ConsensusVoteInputSchema = z9.object({
7817
6087
  errorPolicy: ErrorPolicySchema.optional().describe(
7818
6088
  "How to treat voters that errored or timed out (#2630). Default: fail_closed for unanimous only; reduce_denominator for all other strategies incl. higher_order/opinion_wise (#3138 \u2014 a single infra timeout should not void an otherwise-unanimous vote). Regardless of policy, errors > 50% always fails."
7819
6089
  ),
7820
- quickMode: z9.boolean().optional().default(false).describe("Use 3 agents instead of 5 for faster execution"),
7821
- simulateVotes: z9.boolean().optional().default(false).describe(
6090
+ quickMode: z7.boolean().optional().default(false).describe("Use 3 agents instead of the full 7-role panel for faster execution"),
6091
+ simulateVotes: z7.boolean().optional().default(false).describe(
7822
6092
  "TESTS ONLY \u2014 when true, voters return random decisions. Output must not be used for real decisions. (#2319)"
7823
6093
  ),
7824
6094
  /**
@@ -7838,7 +6108,7 @@ var ConsensusVoteInputSchema = z9.object({
7838
6108
  * Kept optional (no `.default()`) so the inferred type doesn't force
7839
6109
  * `mode: 'sync'` on every existing call site / test fixture.
7840
6110
  */
7841
- mode: z9.enum(["sync", "async"]).optional().describe(
6111
+ mode: z7.enum(["sync", "async"]).optional().describe(
7842
6112
  'Dispatch mode (default: sync). Use "async" for higher-order strategies with 7 voters.'
7843
6113
  ),
7844
6114
  /**
@@ -7847,7 +6117,7 @@ var ConsensusVoteInputSchema = z9.object({
7847
6117
  * same key with different inputs fails closed with
7848
6118
  * `idempotency_key_collision`. Sync mode ignores this.
7849
6119
  */
7850
- idempotencyKey: z9.string().min(1).max(256).optional().describe(
6120
+ idempotencyKey: z7.string().min(1).max(256).optional().describe(
7851
6121
  "Replay-safe key for async-mode dispatch (#3042 Stage 1c). Same (key, inputs) returns existing jobId."
7852
6122
  )
7853
6123
  });
@@ -7954,7 +6224,7 @@ function applyErrorPolicy(votes, policy) {
7954
6224
  }
7955
6225
 
7956
6226
  // src/orchestration/outcomes/outcome-store-persistence.ts
7957
- import { appendFileSync as appendFileSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync3 } from "fs";
6227
+ import { appendFileSync as appendFileSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2 } from "fs";
7958
6228
  var PersistentOutcomeStore = class extends OutcomeStore {
7959
6229
  filePath;
7960
6230
  logger;
@@ -8005,7 +6275,7 @@ var PersistentOutcomeStore = class extends OutcomeStore {
8005
6275
  }
8006
6276
  }
8007
6277
  hydrate() {
8008
- if (!existsSync3(this.filePath)) {
6278
+ if (!existsSync2(this.filePath)) {
8009
6279
  this.logger.debug("No outcomes file found, starting fresh", {
8010
6280
  path: this.filePath
8011
6281
  });
@@ -8064,7 +6334,7 @@ var PersistentOutcomeStore = class extends OutcomeStore {
8064
6334
  }
8065
6335
  persistLine(outcome) {
8066
6336
  try {
8067
- appendFileSync3(this.filePath, JSON.stringify(outcome) + "\n", "utf-8");
6337
+ appendFileSync2(this.filePath, JSON.stringify(outcome) + "\n", "utf-8");
8068
6338
  } catch (error) {
8069
6339
  const msg = getErrorMessage(error);
8070
6340
  this.logger.warn("Failed to persist outcome to disk", {
@@ -8190,384 +6460,39 @@ function warnIfSimulatedOutsideTests(toolName, logger11) {
8190
6460
  );
8191
6461
  }
8192
6462
 
8193
- // src/mcp/tool-annotations.ts
8194
- var TOOL_ANNOTATIONS = {
8195
- // ============================================================================
8196
- // Orchestration & expert lifecycle
8197
- // ============================================================================
8198
- /** Orchestrator coordinates expert agents; spawns workers that may mutate state. */
8199
- orchestrate: {
8200
- readOnlyHint: false,
8201
- destructiveHint: false,
8202
- idempotentHint: false,
8203
- openWorldHint: true
8204
- },
8205
- /** Creates an expert and adds it to the in-memory expert registry. */
8206
- create_expert: {
8207
- readOnlyHint: false,
8208
- destructiveHint: false,
8209
- idempotentHint: false,
8210
- openWorldHint: false
8211
- },
8212
- /** Executes a previously created expert; invokes external CLIs. */
8213
- execute_expert: {
8214
- readOnlyHint: false,
8215
- destructiveHint: false,
8216
- idempotentHint: false,
8217
- openWorldHint: true
8218
- },
8219
- // ============================================================================
8220
- // Workflow / pipeline execution
8221
- // ============================================================================
8222
- /** Runs a workflow template; steps may write to the registry or filesystem. */
8223
- run_workflow: {
8224
- readOnlyHint: false,
8225
- destructiveHint: false,
8226
- idempotentHint: false,
8227
- openWorldHint: true
8228
- },
8229
- /** Runs a graph-based workflow with checkpointing. */
8230
- run_graph_workflow: {
8231
- readOnlyHint: false,
8232
- destructiveHint: false,
8233
- idempotentHint: false,
8234
- openWorldHint: true
8235
- },
8236
- /** Runs a pipeline plugin by name. */
8237
- run_pipeline: {
8238
- readOnlyHint: false,
8239
- destructiveHint: false,
8240
- idempotentHint: false,
8241
- openWorldHint: true
8242
- },
8243
- /** Full dev pipeline: research → plan → vote → implement → QA. */
8244
- run_dev_pipeline: {
8245
- readOnlyHint: false,
8246
- destructiveHint: false,
8247
- idempotentHint: false,
8248
- openWorldHint: true
8249
- },
8250
- /** Executes an AI-software-factory spec pipeline. */
8251
- execute_spec: {
8252
- readOnlyHint: false,
8253
- destructiveHint: false,
8254
- idempotentHint: false,
8255
- openWorldHint: true
8256
- },
8257
- // ============================================================================
8258
- // Voting / decision
8259
- // ============================================================================
8260
- /** Records vote outcomes to the audit log; doesn't write to repo state. */
8261
- consensus_vote: {
8262
- readOnlyHint: false,
8263
- destructiveHint: false,
8264
- idempotentHint: false,
8265
- openWorldHint: true
8266
- },
8267
- /** Per-axis tradeoff vote; records outcome to the store. */
8268
- supply_chain_tradeoff_panel: {
8269
- readOnlyHint: false,
8270
- destructiveHint: false,
8271
- idempotentHint: false,
8272
- openWorldHint: true
8273
- },
8274
- /** Multi-voter PR review; may write review comments. */
8275
- pr_review: {
8276
- readOnlyHint: false,
8277
- destructiveHint: false,
8278
- idempotentHint: false,
8279
- openWorldHint: true
8280
- },
8281
- // ============================================================================
8282
- // Routing & introspection (read-only)
8283
- // ============================================================================
8284
- /** Returns a routing recommendation; doesn't execute. */
8285
- delegate_to_model: {
8286
- readOnlyHint: true,
8287
- destructiveHint: false,
8288
- idempotentHint: true,
8289
- openWorldHint: false
8290
- },
8291
- /** Lists registered expert types. */
8292
- list_experts: {
8293
- readOnlyHint: true,
8294
- destructiveHint: false,
8295
- idempotentHint: true,
8296
- openWorldHint: false
8297
- },
8298
- /** Lists registered workflow templates. */
8299
- list_workflows: {
8300
- readOnlyHint: true,
8301
- destructiveHint: false,
8302
- idempotentHint: true,
8303
- openWorldHint: false
8304
- },
8305
- // ============================================================================
8306
- // Research registry — reads
8307
- // ============================================================================
8308
- /** Queries the research registry. */
8309
- research_query: {
8310
- readOnlyHint: true,
8311
- destructiveHint: false,
8312
- idempotentHint: true,
8313
- openWorldHint: false
8314
- },
8315
- /** Analyzes registry for gaps, trends, coverage. */
8316
- research_analyze: {
8317
- readOnlyHint: true,
8318
- destructiveHint: false,
8319
- idempotentHint: true,
8320
- openWorldHint: false
8321
- },
8322
- /** Synthesizes registry into topic clusters. */
8323
- research_synthesize: {
8324
- readOnlyHint: true,
8325
- destructiveHint: false,
8326
- idempotentHint: true,
8327
- openWorldHint: false
8328
- },
8329
- /** Discovers research items via external APIs; doesn't mutate registry. */
8330
- research_discover: {
8331
- readOnlyHint: true,
8332
- destructiveHint: false,
8333
- idempotentHint: true,
8334
- openWorldHint: true
8335
- },
8336
- // ============================================================================
8337
- // Research registry — mutations
8338
- // ============================================================================
8339
- /** Adds an arXiv paper to the registry. Dedup-checked but first call has effects. */
8340
- research_add: {
8341
- readOnlyHint: false,
8342
- destructiveHint: false,
8343
- idempotentHint: false,
8344
- openWorldHint: true
8345
- },
8346
- /** Adds a non-paper source to the registry. */
8347
- research_add_source: {
8348
- readOnlyHint: false,
8349
- destructiveHint: false,
8350
- idempotentHint: false,
8351
- openWorldHint: true
8352
- },
8353
- /** Reviews auto-cataloged research references; may approve/dismiss. */
8354
- research_catalog_review: {
8355
- readOnlyHint: false,
8356
- destructiveHint: false,
8357
- idempotentHint: false,
8358
- openWorldHint: false
8359
- },
8360
- // ============================================================================
8361
- // Transient lookups (no registry persistence)
8362
- // ============================================================================
8363
- /** Transient OSS search via GitHub API; no persistence. */
8364
- survey_oss_landscape: {
8365
- readOnlyHint: true,
8366
- destructiveHint: false,
8367
- idempotentHint: true,
8368
- openWorldHint: true
8369
- },
8370
- /** Static lookup against curated vendor seed data. */
8371
- vendor_publishing_audit: {
8372
- readOnlyHint: true,
8373
- destructiveHint: false,
8374
- idempotentHint: true,
8375
- openWorldHint: false
8376
- },
8377
- /** Diffs two YAML/JSON files; local-only. */
8378
- compare_data_feeds: {
8379
- readOnlyHint: true,
8380
- destructiveHint: false,
8381
- idempotentHint: true,
8382
- openWorldHint: false
8383
- },
8384
- // ============================================================================
8385
- // Memory
8386
- // ============================================================================
8387
- /** Reads from memory backends. */
8388
- memory_query: {
8389
- readOnlyHint: true,
8390
- destructiveHint: false,
8391
- idempotentHint: true,
8392
- openWorldHint: false
8393
- },
8394
- /** Returns memory statistics. */
8395
- memory_stats: {
8396
- readOnlyHint: true,
8397
- destructiveHint: false,
8398
- idempotentHint: true,
8399
- openWorldHint: false
8400
- },
8401
- /** Writes to a memory backend. */
8402
- memory_write: {
8403
- readOnlyHint: false,
8404
- destructiveHint: false,
8405
- idempotentHint: false,
8406
- openWorldHint: false
8407
- },
8408
- // ============================================================================
8409
- // Observability
8410
- // ============================================================================
8411
- /** Multi-CLI performance weather report; reads outcome store. */
8412
- weather_report: {
8413
- readOnlyHint: true,
8414
- destructiveHint: false,
8415
- idempotentHint: true,
8416
- openWorldHint: false
8417
- },
8418
- /** Queries execution traces from disk. */
8419
- query_trace: {
8420
- readOnlyHint: true,
8421
- destructiveHint: false,
8422
- idempotentHint: true,
8423
- openWorldHint: false
8424
- },
8425
- /** Queries structured task-state log. */
8426
- query_task_state: {
8427
- readOnlyHint: true,
8428
- destructiveHint: false,
8429
- idempotentHint: true,
8430
- openWorldHint: false
8431
- },
8432
- /** Reads job-result sidecar file for an async-mode dispatch (#3042 / #2631). */
8433
- get_job_result: {
8434
- readOnlyHint: true,
8435
- destructiveHint: false,
8436
- idempotentHint: true,
8437
- openWorldHint: false
8438
- },
8439
- /** Lists async-mode job summaries from the sidecar dir (#3046 / #2631 Stage 5). */
8440
- list_jobs: {
8441
- readOnlyHint: true,
8442
- destructiveHint: false,
8443
- idempotentHint: true,
8444
- openWorldHint: false
8445
- },
8446
- /** Cancels an in-flight async-mode job (#3042 Stage 1b / #2631). */
8447
- cancel_job: {
8448
- // Mutates the sidecar record — NOT read-only.
8449
- readOnlyHint: false,
8450
- // Reversibility: cancel writes a new state, but doesn't delete data —
8451
- // not destructive in the OWASP sense (no irreversible data loss).
8452
- destructiveHint: false,
8453
- // Idempotent: repeat cancels are no-ops with explicit outcome envelope.
8454
- idempotentHint: true,
8455
- openWorldHint: false
8456
- },
8457
- /** Verifies hash chain of audit log files. */
8458
- verify_audit_chain: {
8459
- readOnlyHint: true,
8460
- destructiveHint: false,
8461
- idempotentHint: true,
8462
- openWorldHint: false
8463
- },
8464
- /** CI infrastructure health check — composes status-page + recent-runs signals (#3076). */
8465
- ci_health_check: {
8466
- readOnlyHint: true,
8467
- destructiveHint: false,
8468
- idempotentHint: true,
8469
- // Hits external services (githubstatus.com + GitHub API) — `openWorldHint`.
8470
- openWorldHint: true
8471
- },
8472
- /** Threshold-gated observability loop; may file GitHub issues when fileIssues=true. */
8473
- improvement_review: {
8474
- readOnlyHint: false,
8475
- destructiveHint: false,
8476
- idempotentHint: false,
8477
- openWorldHint: true
8478
- },
8479
- // ============================================================================
8480
- // Repository analysis
8481
- // ============================================================================
8482
- /** Analyzes a GitHub repository structure; doesn't write. */
8483
- repo_analyze: {
8484
- readOnlyHint: true,
8485
- destructiveHint: false,
8486
- idempotentHint: true,
8487
- openWorldHint: true
8488
- },
8489
- /** Generates a security-scanning pipeline plan; returns plan, doesn't write it. */
8490
- repo_security_plan: {
8491
- readOnlyHint: true,
8492
- destructiveHint: false,
8493
- idempotentHint: true,
8494
- openWorldHint: true
8495
- },
8496
- /** Extracts code symbols from source files. */
8497
- extract_symbols: {
8498
- readOnlyHint: true,
8499
- destructiveHint: false,
8500
- idempotentHint: true,
8501
- openWorldHint: false
8502
- },
8503
- /** Searches codebase for patterns or symbols. */
8504
- search_codebase: {
8505
- readOnlyHint: true,
8506
- destructiveHint: false,
8507
- idempotentHint: true,
8508
- openWorldHint: false
8509
- },
8510
- // ============================================================================
8511
- // Issue triage & registry imports
8512
- // ============================================================================
8513
- /** Triages a GitHub issue; may write labels/comments when authorized. */
8514
- issue_triage: {
8515
- readOnlyHint: false,
8516
- destructiveHint: false,
8517
- idempotentHint: false,
8518
- openWorldHint: true
8519
- },
8520
- /** Generates a draft model-registry entry; doesn't write. */
8521
- registry_import: {
8522
- readOnlyHint: true,
8523
- destructiveHint: false,
8524
- idempotentHint: true,
8525
- openWorldHint: true
8526
- }
8527
- };
8528
- function getToolAnnotations(name) {
8529
- const a = TOOL_ANNOTATIONS[name];
8530
- if (a === void 0) {
8531
- throw new Error(
8532
- `getToolAnnotations: no entry for tool "${name}". Add it to TOOL_ANNOTATIONS in src/mcp/tool-annotations.ts (#2648).`
8533
- );
8534
- }
8535
- return a;
8536
- }
8537
-
8538
6463
  // src/mcp/jobs/job-result-store.ts
8539
- import { existsSync as existsSync4, readFileSync as readFileSync3, readdirSync, writeFileSync as writeFileSync3 } from "fs";
8540
- import { z as z10 } from "zod";
6464
+ import { existsSync as existsSync3, readFileSync as readFileSync3, readdirSync, writeFileSync as writeFileSync3 } from "fs";
6465
+ import { z as z8 } from "zod";
8541
6466
  var logger8 = createLogger({ component: "job-result-store" });
8542
- var JobStatusSchema = z10.enum(["pending", "complete", "failed", "cancelled"]);
8543
- var JobResultSchema = z10.object({
6467
+ var JobStatusSchema = z8.enum(["pending", "complete", "failed", "cancelled"]);
6468
+ var JobResultSchema = z8.object({
8544
6469
  /** Format version. Currently `1` — bump if the shape changes. */
8545
- v: z10.literal(1),
8546
- jobId: z10.string().min(1),
6470
+ v: z8.literal(1),
6471
+ jobId: z8.string().min(1),
8547
6472
  /** Tool that was invoked (e.g. `orchestrate`). */
8548
- toolName: z10.string().min(1),
6473
+ toolName: z8.string().min(1),
8549
6474
  status: JobStatusSchema,
8550
- createdAt: z10.iso.datetime(),
6475
+ createdAt: z8.iso.datetime(),
8551
6476
  /** Set when the job leaves `pending` — either via `complete` or `failed` or `cancelled`. */
8552
- completedAt: z10.iso.datetime().optional(),
6477
+ completedAt: z8.iso.datetime().optional(),
8553
6478
  /**
8554
6479
  * Structured payload the synchronous mode would have returned. Present
8555
6480
  * only when `status === 'complete'`. Shape is tool-specific — readers
8556
6481
  * cast to the tool's known output type after status check.
8557
6482
  */
8558
- result: z10.unknown().optional(),
6483
+ result: z8.unknown().optional(),
8559
6484
  /**
8560
6485
  * Failure message when `status === 'failed'`. Cannot be paired with
8561
6486
  * `result` — the discriminator is `status`.
8562
6487
  */
8563
- error: z10.string().optional()
6488
+ error: z8.string().optional()
8564
6489
  });
8565
6490
  function jobResultPath(jobId) {
8566
6491
  return nexusDataPathEnsure("jobs", `result-${jobId}.json`);
8567
6492
  }
8568
6493
  function writeJobPending(jobId, toolName) {
8569
6494
  const path = jobResultPath(jobId);
8570
- if (existsSync4(path)) {
6495
+ if (existsSync3(path)) {
8571
6496
  logger8.debug("Job result file already exists \u2014 leaving in place", { jobId });
8572
6497
  return;
8573
6498
  }
@@ -8622,7 +6547,7 @@ function writeJobCancelled(jobId, toolName, reason) {
8622
6547
  }
8623
6548
  function readJobResult(jobId) {
8624
6549
  const path = nexusDataPath("jobs", `result-${jobId}.json`);
8625
- if (!existsSync4(path)) return null;
6550
+ if (!existsSync3(path)) return null;
8626
6551
  try {
8627
6552
  const raw = JSON.parse(readFileSync3(path, "utf-8"));
8628
6553
  const parsed = JobResultSchema.safeParse(raw);
@@ -8642,7 +6567,7 @@ function readJobResult(jobId) {
8642
6567
  }
8643
6568
  function listJobs() {
8644
6569
  const dir = nexusDataPath("jobs");
8645
- if (!existsSync4(dir)) return [];
6570
+ if (!existsSync3(dir)) return [];
8646
6571
  let entries;
8647
6572
  try {
8648
6573
  entries = readdirSync(dir);
@@ -8675,22 +6600,22 @@ function listJobs() {
8675
6600
  }
8676
6601
 
8677
6602
  // src/mcp/jobs/job-idempotency.ts
8678
- import { createHash, randomUUID as randomUUID3 } from "crypto";
8679
- import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
8680
- import { z as z11 } from "zod";
6603
+ import { createHash, randomUUID as randomUUID2 } from "crypto";
6604
+ import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
6605
+ import { z as z9 } from "zod";
8681
6606
  var logger9 = createLogger({ component: "job-idempotency" });
8682
- var IdempotencyIndexEntrySchema = z11.object({
8683
- v: z11.literal(1),
6607
+ var IdempotencyIndexEntrySchema = z9.object({
6608
+ v: z9.literal(1),
8684
6609
  /** MCP tool name (e.g. `orchestrate`, `run_workflow`, `consensus_vote`). */
8685
- tool: z11.string().min(1),
6610
+ tool: z9.string().min(1),
8686
6611
  /** Caller-supplied idempotency key. */
8687
- key: z11.string().min(1),
6612
+ key: z9.string().min(1),
8688
6613
  /** sha256 of the canonical input JSON. */
8689
- inputsHash: z11.string().length(64),
6614
+ inputsHash: z9.string().length(64),
8690
6615
  /** Existing jobId for this (tool, key, inputs) tuple. */
8691
- jobId: z11.string().min(1),
6616
+ jobId: z9.string().min(1),
8692
6617
  /** ISO timestamp of first dispatch. */
8693
- createdAt: z11.iso.datetime()
6618
+ createdAt: z9.iso.datetime()
8694
6619
  });
8695
6620
  function sha256Hex(input) {
8696
6621
  return createHash("sha256").update(input).digest("hex");
@@ -8712,13 +6637,13 @@ function indexFilePathReadOnly(tool, key) {
8712
6637
  const filename = `key-${sha256Hex(`${tool}:${key}`)}.json`;
8713
6638
  return nexusDataPath("jobs", filename);
8714
6639
  }
8715
- function resolveIdempotency(tool, idempotencyKey, inputs, randomFallback = randomUUID3) {
6640
+ function resolveIdempotency(tool, idempotencyKey, inputs, randomFallback = randomUUID2) {
8716
6641
  if (idempotencyKey === void 0 || idempotencyKey === "") {
8717
6642
  return { kind: "fresh", jobId: randomFallback() };
8718
6643
  }
8719
6644
  const incomingInputsHash = computeInputsHash(inputs);
8720
6645
  const path = indexFilePathReadOnly(tool, idempotencyKey);
8721
- if (existsSync5(path)) {
6646
+ if (existsSync4(path)) {
8722
6647
  const entry = readIndexEntry(path);
8723
6648
  if (entry !== null) {
8724
6649
  if (entry.inputsHash === incomingInputsHash) {
@@ -8738,7 +6663,7 @@ function resolveIdempotency(tool, idempotencyKey, inputs, randomFallback = rando
8738
6663
  }
8739
6664
  function registerIdempotentJob(params) {
8740
6665
  const path = indexFilePath(params.tool, params.idempotencyKey);
8741
- if (existsSync5(path)) {
6666
+ if (existsSync4(path)) {
8742
6667
  logger9.debug("Idempotency index entry already present; skipping write", {
8743
6668
  tool: params.tool,
8744
6669
  jobId: params.jobId
@@ -8862,7 +6787,7 @@ function suggestRetryAfterMs(toolName) {
8862
6787
  }
8863
6788
 
8864
6789
  // src/mcp/tools/consensus-vote.ts
8865
- import { randomUUID as randomUUID4 } from "crypto";
6790
+ import { randomUUID as randomUUID3 } from "crypto";
8866
6791
  var persistentCorrelationTracker;
8867
6792
  function getOrCreateCorrelationTracker() {
8868
6793
  persistentCorrelationTracker ??= createPersistentCorrelationTracker();
@@ -9043,7 +6968,7 @@ async function processVotesWithCascade(engineVotes, opts) {
9043
6968
  var CONTRARIAN_ESCALATION_THRESHOLD = 0.8;
9044
6969
  async function runContrarianCheck(proposal, log) {
9045
6970
  try {
9046
- const { executeExpert } = await import("./expert-bridge-Q3OWPD4L.js");
6971
+ const { executeExpert } = await import("./expert-bridge-N4L47MHU.js");
9047
6972
  const prompt = [
9048
6973
  "You are a contrarian analyst. Your job is to find reasons this proposal should be REJECTED.",
9049
6974
  "Look for: YAGNI (not needed), MISALIGNED (wrong tech/architecture), SECURITY_RISK, SCOPE_CREEP.",
@@ -9237,7 +7162,7 @@ function dispatchAsyncConsensusVote(deps, args) {
9237
7162
  tool: "consensus_vote",
9238
7163
  idempotencyKey: args.idempotencyKey,
9239
7164
  inputs: args,
9240
- freshJobId: () => `job-vote-${randomUUID4()}`,
7165
+ freshJobId: () => `job-vote-${randomUUID3()}`,
9241
7166
  replayEnvelope: buildConsensusVoteReplayEnvelope,
9242
7167
  collisionEnvelope: buildConsensusVoteCollisionEnvelope
9243
7168
  });
@@ -9348,27 +7273,27 @@ function createConsensusVoteHandler(deps) {
9348
7273
  };
9349
7274
  }
9350
7275
  var CONSENSUS_VOTE_OUTPUT_SCHEMA = {
9351
- proposal: z12.string(),
7276
+ proposal: z10.string(),
9352
7277
  strategy: VotingStrategySchema,
9353
- decision: z12.enum(["approved", "rejected", "no_quorum"]),
9354
- approvalPercentage: z12.number(),
9355
- voteCounts: z12.object({
9356
- approve: z12.number(),
9357
- reject: z12.number(),
9358
- abstain: z12.number(),
9359
- error: z12.number()
7278
+ decision: z10.enum(["approved", "rejected", "no_quorum"]),
7279
+ approvalPercentage: z10.number(),
7280
+ voteCounts: z10.object({
7281
+ approve: z10.number(),
7282
+ reject: z10.number(),
7283
+ abstain: z10.number(),
7284
+ error: z10.number()
9360
7285
  }),
9361
- votes: z12.array(
9362
- z12.object({
9363
- role: z12.string().max(100),
9364
- decision: z12.enum(["approve", "reject", "abstain"]),
9365
- confidence: z12.number(),
9366
- reasoning: z12.string().max(4e3),
9367
- simulated: z12.boolean(),
9368
- error: z12.boolean(),
9369
- modelUsed: z12.string().max(100).optional(),
9370
- rejectionCategories: z12.array(
9371
- z12.enum([
7286
+ votes: z10.array(
7287
+ z10.object({
7288
+ role: z10.string().max(100),
7289
+ decision: z10.enum(["approve", "reject", "abstain"]),
7290
+ confidence: z10.number(),
7291
+ reasoning: z10.string().max(4e3),
7292
+ simulated: z10.boolean(),
7293
+ error: z10.boolean(),
7294
+ modelUsed: z10.string().max(100).optional(),
7295
+ rejectionCategories: z10.array(
7296
+ z10.enum([
9372
7297
  "YAGNI",
9373
7298
  "DRY_VIOLATION",
9374
7299
  "OVER_ENGINEERING",
@@ -9381,34 +7306,34 @@ var CONSENSUS_VOTE_OUTPUT_SCHEMA = {
9381
7306
  })
9382
7307
  ),
9383
7308
  threshold: VoteThresholdSchema.optional(),
9384
- durationMs: z12.number(),
9385
- simulateVotes: z12.boolean(),
9386
- higherOrderMetadata: z12.object({
9387
- posteriorApproval: z12.number(),
9388
- posteriorRejection: z12.number(),
9389
- effectiveVoteCount: z12.number(),
9390
- method: z12.enum(["ow", "isp", "simple"]),
9391
- usedCorrelationData: z12.boolean(),
9392
- improvementOverBaseline: z12.number(),
9393
- downweightedAgents: z12.array(z12.string().max(100)).max(10),
9394
- reasoning: z12.string().max(2e3)
7309
+ durationMs: z10.number(),
7310
+ simulateVotes: z10.boolean(),
7311
+ higherOrderMetadata: z10.object({
7312
+ posteriorApproval: z10.number(),
7313
+ posteriorRejection: z10.number(),
7314
+ effectiveVoteCount: z10.number(),
7315
+ method: z10.enum(["ow", "isp", "simple"]),
7316
+ usedCorrelationData: z10.boolean(),
7317
+ improvementOverBaseline: z10.number(),
7318
+ downweightedAgents: z10.array(z10.string().max(100)).max(10),
7319
+ reasoning: z10.string().max(2e3)
9395
7320
  }).optional(),
9396
7321
  // #3124: explains a `rejected` decision that coexists with a high
9397
7322
  // approvalPercentage (an error-policy short-circuit, e.g. fail_closed).
9398
- policyReason: z12.string().max(200).optional()
7323
+ policyReason: z10.string().max(200).optional()
9399
7324
  };
9400
7325
  function registerConsensusVoteTool(server, deps) {
9401
7326
  const logger11 = deps.logger ?? createLogger({ tool: "consensus_vote" });
9402
7327
  const notifier = deps.notifier ?? createMcpNotifier(server);
9403
7328
  const depsWithNotifier = { ...deps, notifier };
9404
7329
  const toolSchema = {
9405
- proposal: z12.string().min(1).max(MAX_PROPOSAL_LENGTH).describe("Proposal text to vote on"),
9406
- threshold: z12.enum(["majority", "supermajority", "unanimous"]).optional().describe("Voting threshold (legacy). Use strategy instead."),
7330
+ proposal: z10.string().min(1).max(MAX_PROPOSAL_LENGTH).describe("Proposal text to vote on"),
7331
+ threshold: z10.enum(["majority", "supermajority", "unanimous"]).optional().describe("Voting threshold (legacy). Use strategy instead."),
9407
7332
  strategy: VotingStrategySchema.optional().describe(
9408
7333
  "Voting strategy: simple_majority (default), supermajority, unanimous, proof_of_learning, or higher_order"
9409
7334
  ),
9410
- quickMode: z12.boolean().optional().default(false).describe("Use 3 agents instead of 7"),
9411
- simulateVotes: z12.boolean().optional().default(false).describe("TESTS ONLY \u2014 random output, must not be used for real decisions (#2319)")
7335
+ quickMode: z10.boolean().optional().default(false).describe("Use 3 agents instead of 7"),
7336
+ simulateVotes: z10.boolean().optional().default(false).describe("TESTS ONLY \u2014 random output, must not be used for real decisions (#2319)")
9412
7337
  };
9413
7338
  const description = "Execute multi-model consensus voting on a proposal. Uses 7 specialized agent roles (architect, security, devex, ai_ml, pm, catfish, scope_steward) to vote on proposals with configurable strategies. Supports higher_order strategy for Bayesian-optimal aggregation with correlation awareness (Issue #514).";
9414
7339
  const secureHandler = createSecureHandler(createConsensusVoteHandler(depsWithNotifier), {
@@ -9451,38 +7376,6 @@ export {
9451
7376
  wrapResilientWithFallback,
9452
7377
  createUnifiedRegistry,
9453
7378
  getGlobalRegistry,
9454
- validateToolInput,
9455
- createValidator,
9456
- RateLimiter,
9457
- createDefaultRateLimiter,
9458
- PolicyError,
9459
- PolicyConfigSchema,
9460
- denyMutationsWithoutModeRule,
9461
- safePathsRule,
9462
- PolicyFirewall,
9463
- createDefaultPolicyFirewall,
9464
- evaluatePolicy,
9465
- createPolicyContext,
9466
- actorFromContext,
9467
- resultToOutcome,
9468
- logToolInvocationAudit,
9469
- logPolicyAudit,
9470
- logRateLimitAudit,
9471
- toolSuccess,
9472
- toolSuccessStructured,
9473
- toolStructuredError,
9474
- toolError,
9475
- createSecureHandler,
9476
- createMcpNotifier,
9477
- NOOP_NOTIFIER,
9478
- abortSignalStorage,
9479
- withProgressHeartbeat,
9480
- withAccessPolicy,
9481
- getToolTimeout,
9482
- wrapToolWithTimeout,
9483
- toSdkCallback,
9484
- toSdkCallbackWithBudgetCheck,
9485
- getToolAnnotations,
9486
7379
  PersistentOutcomeStore,
9487
7380
  JobStatusSchema,
9488
7381
  writeJobPending,
@@ -9566,4 +7459,4 @@ export {
9566
7459
  CONSENSUS_VOTE_OUTPUT_SCHEMA,
9567
7460
  registerConsensusVoteTool
9568
7461
  };
9569
- //# sourceMappingURL=chunk-VTMQND6B.js.map
7462
+ //# sourceMappingURL=chunk-Z7PILY4E.js.map