nexus-agents 2.83.1 → 2.85.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 (124) hide show
  1. package/dist/{child-mcp-config-3ZW2UPKZ.js → child-mcp-config-FARMFCA3.js} +3 -3
  2. package/dist/{chunk-DWOSFYI2.js → chunk-25AQZKMN.js} +2 -2
  3. package/dist/{chunk-I2HMWH4R.js → chunk-2WCYG75B.js} +13 -2
  4. package/dist/chunk-2WCYG75B.js.map +1 -0
  5. package/dist/{chunk-A6WC5I7V.js → chunk-4MYJNFYL.js} +4 -4
  6. package/dist/{chunk-W6MLS2UL.js → chunk-4S5GY2MF.js} +2 -2
  7. package/dist/{chunk-7V367KT4.js → chunk-4SU4Q37U.js} +7 -23
  8. package/dist/chunk-4SU4Q37U.js.map +1 -0
  9. package/dist/{chunk-J4ZBKE4B.js → chunk-6KZL5DMU.js} +910 -308
  10. package/dist/chunk-6KZL5DMU.js.map +1 -0
  11. package/dist/{chunk-JA6ON2RP.js → chunk-6QKMUPDP.js} +2 -2
  12. package/dist/{chunk-MATFDJRW.js → chunk-7J7D3LAL.js} +4 -4
  13. package/dist/{chunk-LM2S2QWO.js → chunk-CIW2BVSN.js} +3 -2
  14. package/dist/{chunk-LM2S2QWO.js.map → chunk-CIW2BVSN.js.map} +1 -1
  15. package/dist/{chunk-ZLGU7T6J.js → chunk-EL2KV773.js} +78 -63
  16. package/dist/chunk-EL2KV773.js.map +1 -0
  17. package/dist/{chunk-IM2B3FK2.js → chunk-ELVQORLX.js} +4 -4
  18. package/dist/chunk-ELVQORLX.js.map +1 -0
  19. package/dist/{chunk-VXIHHHLQ.js → chunk-FOG7PMGM.js} +2 -2
  20. package/dist/{chunk-HGPIHDC4.js → chunk-FR3P47J2.js} +4 -4
  21. package/dist/{chunk-ODKIRXN7.js → chunk-IF6TXCSE.js} +683 -227
  22. package/dist/chunk-IF6TXCSE.js.map +1 -0
  23. package/dist/{chunk-TKGVRHEI.js → chunk-J5S27RQ4.js} +2 -2
  24. package/dist/{chunk-UFUR6RBP.js → chunk-LY2KLNXM.js} +2 -2
  25. package/dist/{chunk-5QJPM5CB.js → chunk-NSOB2WRI.js} +3 -3
  26. package/dist/{chunk-4XSCU4B3.js → chunk-OXVOUVKH.js} +8 -8
  27. package/dist/{chunk-6XRNFLPI.js → chunk-POTGGTJD.js} +2 -2
  28. package/dist/{chunk-ZA6AZ7LK.js → chunk-QR4VYHMI.js} +6 -6
  29. package/dist/{chunk-FHY7I736.js → chunk-QR5KHIZG.js} +2 -2
  30. package/dist/{chunk-ELRNVADA.js → chunk-RTAIMK6P.js} +155 -47
  31. package/dist/chunk-RTAIMK6P.js.map +1 -0
  32. package/dist/{chunk-O3XJLOEX.js → chunk-SOKQOPTM.js} +2 -2
  33. package/dist/chunk-TRX7CAD5.js +27 -0
  34. package/dist/chunk-TRX7CAD5.js.map +1 -0
  35. package/dist/{chunk-BICIQYET.js → chunk-XZAWH36N.js} +3 -3
  36. package/dist/{chunk-6UI4NKT4.js → chunk-YLMB5MFQ.js} +27 -4
  37. package/dist/{chunk-6UI4NKT4.js.map → chunk-YLMB5MFQ.js.map} +1 -1
  38. package/dist/{chunk-BUXXAN6V.js → chunk-Z5BAZS6F.js} +2 -2
  39. package/dist/{chunk-SZZS57X7.js → chunk-ZF3MSYLG.js} +7 -7
  40. package/dist/{chunk-XODXYOFN.js → chunk-ZMERLMEP.js} +2 -2
  41. package/dist/{cli-circuit-breaker-LC4NZUGD.js → cli-circuit-breaker-LF22Z3QL.js} +5 -5
  42. package/dist/cli.d.ts +1 -1
  43. package/dist/cli.js +39 -34
  44. package/dist/cli.js.map +1 -1
  45. package/dist/{composite-router-GXQ25DO4.js → composite-router-TEXZI7WJ.js} +3 -3
  46. package/dist/{consensus-vote-MTLP6E72.js → consensus-vote-LPYEXUVC.js} +13 -12
  47. package/dist/{consensus-vote-types-CoGbAEjf.d.ts → consensus-vote-types-COAhHVIp.d.ts} +5 -0
  48. package/dist/{context-retriever-GQRC2MVM.js → context-retriever-3TKV4EEC.js} +7 -6
  49. package/dist/{dist-APHOQ26Z.js → dist-75MXB4R3.js} +917 -822
  50. package/dist/dist-75MXB4R3.js.map +1 -0
  51. package/dist/{doctor-deep-T3UUJX2E.js → doctor-deep-OUAKPLJX.js} +4 -4
  52. package/dist/expert-bridge-22UVN5TB.js +13 -0
  53. package/dist/{factory-OKNCTJO6.js → factory-IGHUOUBS.js} +6 -5
  54. package/dist/factory-JNXETBS4.js +14 -0
  55. package/dist/index.d.ts +137 -10
  56. package/dist/index.js +59 -26
  57. package/dist/index.js.map +1 -1
  58. package/dist/{init-opencode-KDTBKLXS.js → init-opencode-52TLZ2TO.js} +6 -6
  59. package/dist/issue-triage-WUK7L25X.js +15 -0
  60. package/dist/{learning-persistence-NX2KHL5T.js → learning-persistence-5ALG6XRC.js} +2 -2
  61. package/dist/{registry-command-D56ROMFJ.js → registry-command-ZIAJB2J3.js} +3 -3
  62. package/dist/{repo-security-plan-N3CDMW6L.js → repo-security-plan-THHLNGEQ.js} +4 -4
  63. package/dist/{research-helpers-synthesize-36QBOKII.js → research-helpers-synthesize-KNRCAIXK.js} +4 -4
  64. package/dist/{routing-memory-6IEPJ3EP.js → routing-memory-UY6KTGT2.js} +3 -3
  65. package/dist/{session-memory-X6SCDFER.js → session-memory-PUJMR6FE.js} +4 -4
  66. package/dist/{setup-command-5AEO5A4Z.js → setup-command-ZXDAR3GQ.js} +12 -11
  67. package/dist/setup-config-EYY5AYZ3.js +10 -0
  68. package/dist/{setup-custom-api-RBOJT3SS.js → setup-custom-api-5XRNYFOP.js} +5 -5
  69. package/dist/{tool-memory-EEHITQRJ.js → tool-memory-PNAHRFZM.js} +6 -5
  70. package/dist/{weather-report-6BC3JK5H.js → weather-report-RQMZOL7C.js} +3 -3
  71. package/package.json +4 -4
  72. package/dist/chunk-7V367KT4.js.map +0 -1
  73. package/dist/chunk-ELRNVADA.js.map +0 -1
  74. package/dist/chunk-I2HMWH4R.js.map +0 -1
  75. package/dist/chunk-IM2B3FK2.js.map +0 -1
  76. package/dist/chunk-J4ZBKE4B.js.map +0 -1
  77. package/dist/chunk-ODKIRXN7.js.map +0 -1
  78. package/dist/chunk-ZLGU7T6J.js.map +0 -1
  79. package/dist/dist-APHOQ26Z.js.map +0 -1
  80. package/dist/expert-bridge-7LPGCPPR.js +0 -13
  81. package/dist/factory-3XB5CAAA.js +0 -14
  82. package/dist/issue-triage-MURMDN2G.js +0 -15
  83. package/dist/setup-config-RPSVIQJO.js +0 -10
  84. /package/dist/{child-mcp-config-3ZW2UPKZ.js.map → child-mcp-config-FARMFCA3.js.map} +0 -0
  85. /package/dist/{chunk-DWOSFYI2.js.map → chunk-25AQZKMN.js.map} +0 -0
  86. /package/dist/{chunk-A6WC5I7V.js.map → chunk-4MYJNFYL.js.map} +0 -0
  87. /package/dist/{chunk-W6MLS2UL.js.map → chunk-4S5GY2MF.js.map} +0 -0
  88. /package/dist/{chunk-JA6ON2RP.js.map → chunk-6QKMUPDP.js.map} +0 -0
  89. /package/dist/{chunk-MATFDJRW.js.map → chunk-7J7D3LAL.js.map} +0 -0
  90. /package/dist/{chunk-VXIHHHLQ.js.map → chunk-FOG7PMGM.js.map} +0 -0
  91. /package/dist/{chunk-HGPIHDC4.js.map → chunk-FR3P47J2.js.map} +0 -0
  92. /package/dist/{chunk-TKGVRHEI.js.map → chunk-J5S27RQ4.js.map} +0 -0
  93. /package/dist/{chunk-UFUR6RBP.js.map → chunk-LY2KLNXM.js.map} +0 -0
  94. /package/dist/{chunk-5QJPM5CB.js.map → chunk-NSOB2WRI.js.map} +0 -0
  95. /package/dist/{chunk-4XSCU4B3.js.map → chunk-OXVOUVKH.js.map} +0 -0
  96. /package/dist/{chunk-6XRNFLPI.js.map → chunk-POTGGTJD.js.map} +0 -0
  97. /package/dist/{chunk-ZA6AZ7LK.js.map → chunk-QR4VYHMI.js.map} +0 -0
  98. /package/dist/{chunk-FHY7I736.js.map → chunk-QR5KHIZG.js.map} +0 -0
  99. /package/dist/{chunk-O3XJLOEX.js.map → chunk-SOKQOPTM.js.map} +0 -0
  100. /package/dist/{chunk-BICIQYET.js.map → chunk-XZAWH36N.js.map} +0 -0
  101. /package/dist/{chunk-BUXXAN6V.js.map → chunk-Z5BAZS6F.js.map} +0 -0
  102. /package/dist/{chunk-SZZS57X7.js.map → chunk-ZF3MSYLG.js.map} +0 -0
  103. /package/dist/{chunk-XODXYOFN.js.map → chunk-ZMERLMEP.js.map} +0 -0
  104. /package/dist/{cli-circuit-breaker-LC4NZUGD.js.map → cli-circuit-breaker-LF22Z3QL.js.map} +0 -0
  105. /package/dist/{composite-router-GXQ25DO4.js.map → composite-router-TEXZI7WJ.js.map} +0 -0
  106. /package/dist/{consensus-vote-MTLP6E72.js.map → consensus-vote-LPYEXUVC.js.map} +0 -0
  107. /package/dist/{context-retriever-GQRC2MVM.js.map → context-retriever-3TKV4EEC.js.map} +0 -0
  108. /package/dist/{doctor-deep-T3UUJX2E.js.map → doctor-deep-OUAKPLJX.js.map} +0 -0
  109. /package/dist/{expert-bridge-7LPGCPPR.js.map → expert-bridge-22UVN5TB.js.map} +0 -0
  110. /package/dist/{factory-3XB5CAAA.js.map → factory-IGHUOUBS.js.map} +0 -0
  111. /package/dist/{factory-OKNCTJO6.js.map → factory-JNXETBS4.js.map} +0 -0
  112. /package/dist/{init-opencode-KDTBKLXS.js.map → init-opencode-52TLZ2TO.js.map} +0 -0
  113. /package/dist/{issue-triage-MURMDN2G.js.map → issue-triage-WUK7L25X.js.map} +0 -0
  114. /package/dist/{learning-persistence-NX2KHL5T.js.map → learning-persistence-5ALG6XRC.js.map} +0 -0
  115. /package/dist/{registry-command-D56ROMFJ.js.map → registry-command-ZIAJB2J3.js.map} +0 -0
  116. /package/dist/{repo-security-plan-N3CDMW6L.js.map → repo-security-plan-THHLNGEQ.js.map} +0 -0
  117. /package/dist/{research-helpers-synthesize-36QBOKII.js.map → research-helpers-synthesize-KNRCAIXK.js.map} +0 -0
  118. /package/dist/{routing-memory-6IEPJ3EP.js.map → routing-memory-UY6KTGT2.js.map} +0 -0
  119. /package/dist/{session-memory-X6SCDFER.js.map → session-memory-PUJMR6FE.js.map} +0 -0
  120. /package/dist/{setup-command-5AEO5A4Z.js.map → setup-command-ZXDAR3GQ.js.map} +0 -0
  121. /package/dist/{setup-config-RPSVIQJO.js.map → setup-config-EYY5AYZ3.js.map} +0 -0
  122. /package/dist/{setup-custom-api-RBOJT3SS.js.map → setup-custom-api-5XRNYFOP.js.map} +0 -0
  123. /package/dist/{tool-memory-EEHITQRJ.js.map → tool-memory-PNAHRFZM.js.map} +0 -0
  124. /package/dist/{weather-report-6BC3JK5H.js.map → weather-report-RQMZOL7C.js.map} +0 -0
@@ -1,12 +1,13 @@
1
1
  import {
2
2
  getTokenEnvVars,
3
3
  resolveToken
4
- } from "./chunk-XODXYOFN.js";
4
+ } from "./chunk-ZMERLMEP.js";
5
5
  import {
6
6
  executeExpert
7
- } from "./chunk-SZZS57X7.js";
7
+ } from "./chunk-ZF3MSYLG.js";
8
8
  import {
9
9
  EventTopics,
10
+ JobStatusSchema,
10
11
  NOOP_NOTIFIER,
11
12
  RateLimiter,
12
13
  abortSignalStorage,
@@ -20,17 +21,27 @@ import {
20
21
  getToolAnnotations,
21
22
  getToolTimeout,
22
23
  isRateLimitError,
24
+ listJobs,
25
+ readJobResult,
26
+ registerIdempotentJob,
27
+ release,
28
+ shortCircuitOrFreshJobId,
29
+ suggestRetryAfterMs,
23
30
  toSdkCallback,
24
31
  toSdkCallbackWithBudgetCheck,
25
32
  toolError,
26
33
  toolStructuredError,
27
34
  toolSuccess,
28
35
  toolSuccessStructured,
36
+ tryAcquire,
29
37
  warnIfSimulatedOutsideTests,
30
38
  withAccessPolicy,
31
39
  withProgressHeartbeat,
32
- wrapToolWithTimeout
33
- } from "./chunk-ODKIRXN7.js";
40
+ wrapToolWithTimeout,
41
+ writeJobComplete,
42
+ writeJobFailed,
43
+ writeJobPending
44
+ } from "./chunk-IF6TXCSE.js";
34
45
  import {
35
46
  REGISTRY_PATH,
36
47
  getProjectRoot,
@@ -39,14 +50,14 @@ import {
39
50
  normalizeTopicToCanonical,
40
51
  savePapersRegistry,
41
52
  synthesizeResearch
42
- } from "./chunk-FHY7I736.js";
53
+ } from "./chunk-QR5KHIZG.js";
43
54
  import {
44
55
  IssueTriage,
45
56
  sanitizeInput
46
- } from "./chunk-5QJPM5CB.js";
57
+ } from "./chunk-NSOB2WRI.js";
47
58
  import {
48
59
  generateSecurityPlan
49
- } from "./chunk-TKGVRHEI.js";
60
+ } from "./chunk-J5S27RQ4.js";
50
61
  import {
51
62
  analyzeGitHubRepo
52
63
  } from "./chunk-HFOQKCD2.js";
@@ -59,27 +70,25 @@ import {
59
70
  getContextForTask,
60
71
  inferTaskCategory,
61
72
  summarizeContextForPrompt
62
- } from "./chunk-HGPIHDC4.js";
73
+ } from "./chunk-FR3P47J2.js";
63
74
  import {
64
75
  DEFAULT_RELEVANCE_CONFIG,
65
76
  MemoryImportance,
66
77
  calculateTextJaccardSimilarity,
67
- generateHyphenId,
68
- generateUUID,
69
78
  getToolMemory
70
- } from "./chunk-7V367KT4.js";
79
+ } from "./chunk-4SU4Q37U.js";
71
80
  import {
72
81
  DEFAULT_TASK_TTL_MS,
73
82
  DEFAULT_TOOL_RATE_LIMITS,
74
83
  clampTaskTtl
75
- } from "./chunk-4XSCU4B3.js";
84
+ } from "./chunk-OXVOUVKH.js";
76
85
  import {
77
86
  getAvailabilityCache,
78
87
  resolveFallback
79
- } from "./chunk-W6MLS2UL.js";
88
+ } from "./chunk-4S5GY2MF.js";
80
89
  import {
81
90
  DEFAULTS
82
- } from "./chunk-DWOSFYI2.js";
91
+ } from "./chunk-25AQZKMN.js";
83
92
  import {
84
93
  resolveInsideRoot
85
94
  } from "./chunk-NUBSJGQZ.js";
@@ -95,7 +104,11 @@ import {
95
104
  getAvailableClis,
96
105
  sleep,
97
106
  withTimeout
98
- } from "./chunk-ELRNVADA.js";
107
+ } from "./chunk-RTAIMK6P.js";
108
+ import {
109
+ generateHyphenId,
110
+ generateUUID
111
+ } from "./chunk-TRX7CAD5.js";
99
112
  import {
100
113
  BUILT_IN_EXPERTS,
101
114
  BuiltInExpertTypeSchema,
@@ -107,7 +120,7 @@ import {
107
120
  } from "./chunk-PQHVC4BD.js";
108
121
  import {
109
122
  createSessionMemory
110
- } from "./chunk-UFUR6RBP.js";
123
+ } from "./chunk-LY2KLNXM.js";
111
124
  import {
112
125
  AGENT_ROUTER_TIMEOUTS,
113
126
  API_TIMEOUTS,
@@ -178,11 +191,11 @@ import {
178
191
  resolveModelIdentitySync,
179
192
  toExpertTaskAnalysisResult,
180
193
  withStep
181
- } from "./chunk-6UI4NKT4.js";
194
+ } from "./chunk-YLMB5MFQ.js";
182
195
  import {
183
196
  getNexusDataDir,
184
197
  nexusDataPath
185
- } from "./chunk-I2HMWH4R.js";
198
+ } from "./chunk-2WCYG75B.js";
186
199
 
187
200
  // src/agents/state-machine-types.ts
188
201
  var VALID_TRANSITIONS = /* @__PURE__ */ new Map([
@@ -2611,11 +2624,25 @@ function setupExecute(ctx, task) {
2611
2624
  }
2612
2625
  return { valid: true, startTime: getTimeProvider().now() };
2613
2626
  }
2614
- async function runTaskWithTimeout(task, agentId, executeTask) {
2627
+ function wireExternalAbort(externalSignal, controller) {
2628
+ if (externalSignal === void 0) return void 0;
2629
+ if (externalSignal.aborted) {
2630
+ controller.abort();
2631
+ return void 0;
2632
+ }
2633
+ const listener = () => {
2634
+ controller.abort();
2635
+ };
2636
+ externalSignal.addEventListener("abort", listener, { once: true });
2637
+ return listener;
2638
+ }
2639
+ async function runTaskWithTimeout(task, agentId, executeTask, options) {
2615
2640
  const maxDuration = task.constraints?.maxDuration ?? HEARTBEAT_TIMEOUTS.absoluteMaxMs;
2616
2641
  const controller = new AbortController();
2617
2642
  const monitor = getHeartbeatMonitor();
2618
2643
  const sessionId = monitor.startSession(agentId);
2644
+ const externalSignal = options?.externalSignal;
2645
+ const externalAbortListener = wireExternalAbort(externalSignal, controller);
2619
2646
  const healthCheckTimer = setInterval(() => {
2620
2647
  const transition = monitor.getSessionHealth(sessionId);
2621
2648
  if (transition?.changed === true) {
@@ -2643,6 +2670,9 @@ async function runTaskWithTimeout(task, agentId, executeTask) {
2643
2670
  } finally {
2644
2671
  clearInterval(healthCheckTimer);
2645
2672
  monitor.endSession(sessionId);
2673
+ if (externalSignal !== void 0 && externalAbortListener !== void 0) {
2674
+ externalSignal.removeEventListener("abort", externalAbortListener);
2675
+ }
2646
2676
  }
2647
2677
  }
2648
2678
  function handleExecutionFailure(task, result, ctx) {
@@ -2992,6 +3022,14 @@ var BaseAgent = class {
2992
3022
  memoryConfig;
2993
3023
  memoryState = null;
2994
3024
  relevantMemories = [];
3025
+ /**
3026
+ * AbortSignal set by `execute()` when the caller passes one. `complete()`
3027
+ * forwards it onto `CompletionRequest.signal` so the in-flight model call
3028
+ * cancels when the caller's deadline wins a race (#3016/#3040). Set only
3029
+ * for the duration of one execute() and cleared in finally — the field is
3030
+ * single-task scoped and never crosses tasks.
3031
+ */
3032
+ currentExecutionSignal = void 0;
2995
3033
  constructor(options) {
2996
3034
  const validation = BaseAgentOptionsSchema.safeParse(options);
2997
3035
  if (!validation.success) {
@@ -3075,7 +3113,7 @@ var BaseAgent = class {
3075
3113
  this.initialized = true;
3076
3114
  return ok(void 0);
3077
3115
  }
3078
- async execute(task) {
3116
+ async execute(task, options) {
3079
3117
  const execCtx = buildExecuteFlowContext(this.contextState);
3080
3118
  const setup = setupExecute(execCtx, task);
3081
3119
  if (!setup.valid && setup.error !== void 0) return err(setup.error);
@@ -3084,8 +3122,11 @@ var BaseAgent = class {
3084
3122
  this.budgetTracker.startTask(task.id);
3085
3123
  this.logger.info("Executing task", { taskId: task.id, priority: task.priority });
3086
3124
  const taskMemCtx = buildTaskMemoryContext(this.contextState);
3125
+ this.currentExecutionSignal = options?.signal;
3087
3126
  try {
3088
- const result = await runTaskWithTimeout(task, this.id, (t) => this.executeTask(t));
3127
+ const result = await runTaskWithTimeout(task, this.id, (t) => this.executeTask(t), {
3128
+ externalSignal: options?.signal
3129
+ });
3089
3130
  if (!result.ok) return handleExecutionFailure(task, result, execCtx);
3090
3131
  this.memoryState = await finalizeSuccessfulExecution(
3091
3132
  task,
@@ -3104,6 +3145,8 @@ var BaseAgent = class {
3104
3145
  );
3105
3146
  this.memoryState = updatedMemoryState;
3106
3147
  return err(agentError);
3148
+ } finally {
3149
+ this.currentExecutionSignal = void 0;
3107
3150
  }
3108
3151
  }
3109
3152
  async handleMessage(msg) {
@@ -3152,7 +3195,8 @@ var BaseAgent = class {
3152
3195
  logger: this.logger,
3153
3196
  newState: "acting"
3154
3197
  });
3155
- const result = await runModelCompletion(ctx, adapterResult.value, request);
3198
+ const requestWithSignal = request.signal === void 0 && this.currentExecutionSignal !== void 0 ? { ...request, signal: this.currentExecutionSignal } : request;
3199
+ const result = await runModelCompletion(ctx, adapterResult.value, requestWithSignal);
3156
3200
  transitionToState({
3157
3201
  stateMachine: this.stateMachine,
3158
3202
  logger: this.logger,
@@ -20434,9 +20478,10 @@ var StepExecutor = class {
20434
20478
  }
20435
20479
  }
20436
20480
  async runExpertWithTimeout(expert, task, step, timeoutMs, startTime) {
20481
+ const controller = new AbortController();
20437
20482
  try {
20438
20483
  const taskResult = await Promise.race([
20439
- expert.execute(task),
20484
+ expert.execute(task, { signal: controller.signal }),
20440
20485
  createTimeout(timeoutMs, step.id)
20441
20486
  ]);
20442
20487
  if (!taskResult.ok) {
@@ -20455,6 +20500,8 @@ var StepExecutor = class {
20455
20500
  });
20456
20501
  } catch (error) {
20457
20502
  return this.handleExecutionError(error, step, timeoutMs);
20503
+ } finally {
20504
+ controller.abort();
20458
20505
  }
20459
20506
  }
20460
20507
  handleExecutionError(error, step, timeoutMs) {
@@ -21049,8 +21096,16 @@ var WorkflowEngine = class {
21049
21096
  async loadTemplate(path14) {
21050
21097
  return this.deps.loadWorkflowFile(path14);
21051
21098
  }
21052
- /** Execute a workflow with inputs. */
21053
- async execute(workflow, inputs) {
21099
+ /**
21100
+ * Execute a workflow with inputs.
21101
+ *
21102
+ * `options.phaseTimeoutMs` (added in #3017) overrides the per-phase
21103
+ * execution timeout for this run only — wins over both `workflow.timeout`
21104
+ * (set in the template YAML) and the engine's `defaultTimeoutMs`. Used
21105
+ * by the `run_workflow` MCP tool to expose a caller-supplied `timeoutMs`
21106
+ * for known-long templates (e.g. security-audit over a large repo).
21107
+ */
21108
+ async execute(workflow, inputs, options) {
21054
21109
  const inputValidation = this.validateInputs(workflow, inputs);
21055
21110
  if (!inputValidation.ok) {
21056
21111
  return inputValidation;
@@ -21068,19 +21123,21 @@ var WorkflowEngine = class {
21068
21123
  });
21069
21124
  this.executions.set(initResult.executionId, initResult.execution);
21070
21125
  try {
21071
- return await this.runExecution(
21126
+ return await this.runExecution({
21072
21127
  workflow,
21073
- planResult.value,
21074
- initResult.context,
21075
- initResult.executionId,
21076
- initResult.startTime
21077
- );
21128
+ plan: planResult.value,
21129
+ context: initResult.context,
21130
+ executionId: initResult.executionId,
21131
+ startTime: initResult.startTime,
21132
+ ...options?.phaseTimeoutMs !== void 0 ? { phaseTimeoutMs: options.phaseTimeoutMs } : {}
21133
+ });
21078
21134
  } catch (error) {
21079
21135
  return this.handleExecutionError(error, initResult.executionId, workflow.name);
21080
21136
  }
21081
21137
  }
21082
- async runExecution(workflow, plan, context, executionId, startTime) {
21083
- const stepResults = await this.executePhases(plan, context, workflow);
21138
+ async runExecution(args) {
21139
+ const { workflow, plan, context, executionId, startTime, phaseTimeoutMs } = args;
21140
+ const stepResults = await this.executePhases(plan, context, workflow, phaseTimeoutMs);
21084
21141
  if (!stepResults.ok) {
21085
21142
  this.updateExecutionStatus(executionId, {
21086
21143
  state: "failed",
@@ -21191,7 +21248,7 @@ var WorkflowEngine = class {
21191
21248
  }
21192
21249
  return ok(void 0);
21193
21250
  }
21194
- async executePhases(plan, context, workflow) {
21251
+ async executePhases(plan, context, workflow, phaseTimeoutMs) {
21195
21252
  const allResults = [];
21196
21253
  const totalSteps = plan.phases.reduce((sum, p) => sum + p.steps.length, 0);
21197
21254
  let completedSteps = 0;
@@ -21219,7 +21276,7 @@ var WorkflowEngine = class {
21219
21276
  const options = {
21220
21277
  maxConcurrency: this.config.maxConcurrency,
21221
21278
  failFast: true,
21222
- timeoutMs: workflow.timeout ?? this.config.defaultTimeoutMs
21279
+ timeoutMs: phaseTimeoutMs ?? workflow.timeout ?? this.config.defaultTimeoutMs
21223
21280
  };
21224
21281
  const phaseResult = await this.deps.executePhase(phase.steps, context, options);
21225
21282
  if (!phaseResult.ok) return phaseResult;
@@ -23489,10 +23546,10 @@ function calculateZStatistic(params) {
23489
23546
  function calculateDifferenceCI(p1, p2, total1, total2, confidence) {
23490
23547
  const difference = p1 - p2;
23491
23548
  const seDiff = Math.sqrt(p1 * (1 - p1) / (total1 || 1) + p2 * (1 - p2) / (total2 || 1));
23492
- const z107 = getZScore(confidence);
23549
+ const z109 = getZScore(confidence);
23493
23550
  return {
23494
- lower: difference - z107 * seDiff,
23495
- upper: difference + z107 * seDiff,
23551
+ lower: difference - z109 * seDiff,
23552
+ upper: difference + z109 * seDiff,
23496
23553
  estimate: difference,
23497
23554
  confidence,
23498
23555
  n: total1 + total2,
@@ -23515,11 +23572,11 @@ function proportionConfidenceInterval(successes, total, options = {}) {
23515
23572
  standardError: 0
23516
23573
  };
23517
23574
  }
23518
- const z107 = getZScore(opts.confidence);
23519
- const z210 = z107 * z107;
23575
+ const z109 = getZScore(opts.confidence);
23576
+ const z210 = z109 * z109;
23520
23577
  const denominator = 1 + z210 / n;
23521
23578
  const center = (p + z210 / (2 * n)) / denominator;
23522
- const margin = z107 / denominator * Math.sqrt(p * (1 - p) / n + z210 / (4 * n * n));
23579
+ const margin = z109 / denominator * Math.sqrt(p * (1 - p) / n + z210 / (4 * n * n));
23523
23580
  const lower = Math.max(0, center - margin);
23524
23581
  const upper = Math.min(1, center + margin);
23525
23582
  const standardError = Math.sqrt(p * (1 - p) / n);
@@ -23549,8 +23606,8 @@ function meanConfidenceInterval(values, options = {}) {
23549
23606
  const variance = values.reduce((sum, v) => sum + (v - mean) ** 2, 0) / (n - 1 || 1);
23550
23607
  const stdDev = Math.sqrt(variance);
23551
23608
  const standardError = stdDev / Math.sqrt(n);
23552
- const z107 = getZScore(opts.confidence);
23553
- const margin = z107 * standardError;
23609
+ const z109 = getZScore(opts.confidence);
23610
+ const margin = z109 * standardError;
23554
23611
  return {
23555
23612
  lower: mean - margin,
23556
23613
  upper: mean + margin,
@@ -25958,7 +26015,45 @@ import { z as z45 } from "zod";
25958
26015
  var RunWorkflowInputSchema = z45.object({
25959
26016
  template: z45.string().min(1).describe("Workflow template name (e.g., code-review) or file path"),
25960
26017
  inputs: z45.record(z45.string(), z45.unknown()).describe("Workflow inputs as key-value pairs"),
25961
- dryRun: z45.boolean().optional().default(false).describe("Validate workflow without executing")
26018
+ dryRun: z45.boolean().optional().default(false).describe("Validate workflow without executing"),
26019
+ /**
26020
+ * Per-phase execution timeout in milliseconds (closes #3017). Wins over
26021
+ * both `workflow.timeout` (set in the template YAML) and the engine's
26022
+ * `defaultTimeoutMs`. Use for known-long workflow templates (e.g.,
26023
+ * security-audit over a large repo) where the default phase budget
26024
+ * isn't enough. Bounded to [1s, 30min] to prevent both flapping
26025
+ * cancellations and unbounded hangs that would defeat the
26026
+ * timeout-mismatch telemetry.
26027
+ */
26028
+ timeoutMs: z45.number().int().min(1e3).max(18e5).optional().describe("Per-phase execution timeout in ms (overrides workflow.timeout)"),
26029
+ /**
26030
+ * Async-mode dispatch (#3044, Stage 3 of epic #2631). Default `sync` —
26031
+ * backward-compat invariant; existing callers see no behavior change.
26032
+ * `async` returns `{ status: 'pending', jobId }` immediately; caller
26033
+ * polls `get_job_result(jobId)` for the structured payload. Sidesteps
26034
+ * the MCP-SDK 60s client-request timeout that's the #2631 root cause
26035
+ * (per #2703 telemetry: run_workflow was the gate-firing tool at
26036
+ * 28.6% timeout-shaped errors).
26037
+ *
26038
+ * Per the #3041 vote's binding staging order this lands AFTER
26039
+ * Stage 1's protocol (#3048) was validated on orchestrate. Concurrency
26040
+ * cap is enforced in-process via NEXUS_JOB_MAX_CONCURRENT_RUN_WORKFLOW;
26041
+ * over-cap returns `{ status: 'busy', retryAfterMs }` synchronously.
26042
+ *
26043
+ * Kept optional (no `.default()`) so the inferred type doesn't force
26044
+ * `mode: 'sync'` on every existing call site / test fixture. The
26045
+ * handler treats `undefined` as `'sync'`.
26046
+ */
26047
+ mode: z45.enum(["sync", "async"]).optional().describe('Dispatch mode (default: sync). Use "async" for long-running workflows.'),
26048
+ /**
26049
+ * Idempotency key for async-mode replay-safety (#3042 Stage 1c / epic
26050
+ * #2631). When set: identical (key, inputs) returns the existing job;
26051
+ * same key with different inputs fails closed with
26052
+ * `idempotency_key_collision`. Sync mode ignores this.
26053
+ */
26054
+ idempotencyKey: z45.string().min(1).max(256).optional().describe(
26055
+ "Replay-safe key for async-mode dispatch (#3042 Stage 1c). Same (key, inputs) returns existing jobId."
26056
+ )
25962
26057
  });
25963
26058
 
25964
26059
  // src/mcp/tools/run-workflow.ts
@@ -26158,14 +26253,16 @@ function formatValidationErrors(validation) {
26158
26253
  }
26159
26254
 
26160
26255
  // src/mcp/tools/run-workflow.ts
26161
- async function executeWorkflow(deps, workflow, inputs) {
26256
+ import { randomUUID as randomUUID8 } from "crypto";
26257
+ async function executeWorkflow(deps, workflow, inputs, options) {
26162
26258
  const { workflowEngine, logger: logger53 } = deps;
26163
26259
  logger53?.info("Executing workflow", {
26164
26260
  workflowName: workflow.name,
26165
- inputCount: Object.keys(inputs).length
26261
+ inputCount: Object.keys(inputs).length,
26262
+ ...options?.phaseTimeoutMs !== void 0 ? { phaseTimeoutMs: options.phaseTimeoutMs } : {}
26166
26263
  });
26167
26264
  const startTime = getTimeProvider().now();
26168
- const result = await workflowEngine.execute(workflow, inputs);
26265
+ const result = options?.phaseTimeoutMs !== void 0 ? await workflowEngine.execute(workflow, inputs, { phaseTimeoutMs: options.phaseTimeoutMs }) : await workflowEngine.execute(workflow, inputs);
26169
26266
  if (!result.ok) {
26170
26267
  logger53?.error("Workflow execution failed", result.error, {
26171
26268
  workflowName: workflow.name
@@ -26241,8 +26338,13 @@ function buildFailureEnvelope(workflowName, error) {
26241
26338
  });
26242
26339
  }
26243
26340
  async function handleRunWorkflow(deps, args) {
26244
- const { template, inputs, dryRun } = args;
26245
- deps.logger?.debug("run_workflow called", { template, dryRun, inputKeys: Object.keys(inputs) });
26341
+ const { template, inputs, dryRun, timeoutMs } = args;
26342
+ deps.logger?.debug("run_workflow called", {
26343
+ template,
26344
+ dryRun,
26345
+ inputKeys: Object.keys(inputs),
26346
+ ...timeoutMs !== void 0 ? { timeoutMs } : {}
26347
+ });
26246
26348
  const loadResult = await loadWorkflow(deps, template);
26247
26349
  if (!loadResult.ok) {
26248
26350
  return errorResponse(loadResult.error.message);
@@ -26255,7 +26357,12 @@ async function handleRunWorkflow(deps, args) {
26255
26357
  if (!validation.valid) {
26256
26358
  return errorResponse(formatValidationErrors(validation));
26257
26359
  }
26258
- const executeResult = await executeWorkflow(deps, workflow, inputs);
26360
+ const executeResult = await executeWorkflow(
26361
+ deps,
26362
+ workflow,
26363
+ inputs,
26364
+ timeoutMs !== void 0 ? { phaseTimeoutMs: timeoutMs } : void 0
26365
+ );
26259
26366
  if (!executeResult.ok) {
26260
26367
  recordWorkflowError(template, executeResult.error.message);
26261
26368
  return buildFailureEnvelope(workflow.name, executeResult.error);
@@ -26270,8 +26377,73 @@ async function handleRunWorkflow(deps, args) {
26270
26377
  var toolInputSchema = {
26271
26378
  template: z46.string().min(1).describe("Workflow template name (e.g., code-review) or file path"),
26272
26379
  inputs: z46.record(z46.string().max(100), z46.unknown()).describe("Workflow inputs as key-value pairs"),
26273
- dryRun: z46.boolean().optional().default(false).describe("Validate workflow without executing")
26380
+ dryRun: z46.boolean().optional().default(false).describe("Validate workflow without executing"),
26381
+ // #3017
26382
+ timeoutMs: z46.number().int().min(1e3).max(18e5).optional().describe("Per-phase execution timeout in ms (overrides workflow.timeout, bound [1s, 30min])"),
26383
+ // #3044 / epic #2631 Stage 3
26384
+ mode: z46.enum(["sync", "async"]).optional().describe(
26385
+ 'Dispatch mode (default: sync). "async" returns { jobId } immediately; poll via get_job_result.'
26386
+ )
26274
26387
  };
26388
+ function buildRunWorkflowReplayEnvelope(jobId) {
26389
+ return successResponse({
26390
+ status: "replay",
26391
+ jobId,
26392
+ pollTool: "get_job_result",
26393
+ note: "Idempotency key matched a prior dispatch \u2014 poll get_job_result for current status."
26394
+ });
26395
+ }
26396
+ function buildRunWorkflowCollisionEnvelope(existingJobId) {
26397
+ return errorResponse(
26398
+ `Idempotency key already used with different inputs. Existing jobId: ${existingJobId}. Use a fresh key or omit it.`
26399
+ );
26400
+ }
26401
+ function dispatchAsyncRunWorkflow(deps, args) {
26402
+ const idempotency = shortCircuitOrFreshJobId({
26403
+ tool: "run_workflow",
26404
+ idempotencyKey: args.idempotencyKey,
26405
+ inputs: args,
26406
+ freshJobId: () => `job-rw-${randomUUID8()}`,
26407
+ replayEnvelope: buildRunWorkflowReplayEnvelope,
26408
+ collisionEnvelope: buildRunWorkflowCollisionEnvelope
26409
+ });
26410
+ if (idempotency.kind === "shortCircuit") return idempotency.value;
26411
+ if (!tryAcquire("run_workflow")) {
26412
+ return successResponse({
26413
+ status: "busy",
26414
+ retryAfterMs: suggestRetryAfterMs("run_workflow"),
26415
+ note: 'Async-mode concurrency cap reached for run_workflow. Retry later or use mode: "sync".'
26416
+ });
26417
+ }
26418
+ const jobId = idempotency.jobId;
26419
+ writeJobPending(jobId, "run_workflow");
26420
+ if (args.idempotencyKey !== void 0 && args.idempotencyKey !== "") {
26421
+ registerIdempotentJob({
26422
+ tool: "run_workflow",
26423
+ idempotencyKey: args.idempotencyKey,
26424
+ inputs: args,
26425
+ jobId
26426
+ });
26427
+ }
26428
+ void (async () => {
26429
+ try {
26430
+ const result = await handleRunWorkflow(deps, args);
26431
+ writeJobComplete(jobId, "run_workflow", result);
26432
+ } catch (err2) {
26433
+ const errObj = err2 instanceof Error ? err2 : new Error(String(err2));
26434
+ deps.logger?.error("Async run_workflow dispatch failed", errObj, { jobId });
26435
+ writeJobFailed(jobId, "run_workflow", errObj.message);
26436
+ } finally {
26437
+ release("run_workflow");
26438
+ }
26439
+ })();
26440
+ return successResponse({
26441
+ status: "pending",
26442
+ jobId,
26443
+ pollTool: "get_job_result",
26444
+ note: 'Poll via get_job_result({ jobId }) until status !== "pending".'
26445
+ });
26446
+ }
26275
26447
  function createRunWorkflowHandler(deps) {
26276
26448
  const notifier = deps.notifier ?? NOOP_NOTIFIER;
26277
26449
  return async (args, ctx) => {
@@ -26282,10 +26454,19 @@ function createRunWorkflowHandler(deps) {
26282
26454
  }
26283
26455
  ctx.logger.debug("Running workflow", {
26284
26456
  template: validated.data.template,
26285
- dryRun: validated.data.dryRun
26457
+ dryRun: validated.data.dryRun,
26458
+ ...validated.data.mode !== void 0 ? { mode: validated.data.mode } : {}
26286
26459
  });
26287
26460
  notifier.info("run_workflow", { event: "workflow_start", template: validated.data.template });
26288
26461
  const startMs = getTimeProvider().now();
26462
+ if (validated.data.mode === "async" && !validated.data.dryRun) {
26463
+ const asyncResult = dispatchAsyncRunWorkflow(deps, validated.data);
26464
+ notifier.info("run_workflow", {
26465
+ event: "workflow_dispatched_async",
26466
+ template: validated.data.template
26467
+ });
26468
+ return asyncResult;
26469
+ }
26289
26470
  const result = await handleRunWorkflow(deps, validated.data);
26290
26471
  if (result.isError !== true) {
26291
26472
  notifier.info("run_workflow", {
@@ -26703,7 +26884,7 @@ async function populateUnifiedContextOnState(state) {
26703
26884
  try {
26704
26885
  const taskCandidate = state["task"];
26705
26886
  if (typeof taskCandidate !== "string" || taskCandidate === "") return;
26706
- const { getContextForTask: getContextForTask2, inferTaskCategory: inferTaskCategory2 } = await import("./context-retriever-GQRC2MVM.js");
26887
+ const { getContextForTask: getContextForTask2, inferTaskCategory: inferTaskCategory2 } = await import("./context-retriever-3TKV4EEC.js");
26707
26888
  const ctx = await getContextForTask2({
26708
26889
  task: taskCandidate,
26709
26890
  category: inferTaskCategory2(taskCandidate),
@@ -28384,11 +28565,11 @@ function logViolations(context, violations, mode) {
28384
28565
  }
28385
28566
 
28386
28567
  // src/pipeline/task-contract-builders.ts
28387
- import { randomUUID as randomUUID8 } from "crypto";
28568
+ import { randomUUID as randomUUID9 } from "crypto";
28388
28569
  function buildBaseTaskContract(input) {
28389
28570
  const now = Date.now();
28390
28571
  return {
28391
- id: `${input.idPrefix}-${randomUUID8().slice(0, 8)}`,
28572
+ id: `${input.idPrefix}-${randomUUID9().slice(0, 8)}`,
28392
28573
  description: input.task,
28393
28574
  status: "approved",
28394
28575
  analysis: input.analysis,
@@ -28578,7 +28759,7 @@ async function executeOrchestratePipeline(task) {
28578
28759
  }
28579
28760
 
28580
28761
  // src/orchestration/orchestrator-factory.ts
28581
- import { randomUUID as randomUUID9 } from "crypto";
28762
+ import { randomUUID as randomUUID10 } from "crypto";
28582
28763
 
28583
28764
  // src/orchestration/orchestrator-adapters.ts
28584
28765
  function generateId2(prefix) {
@@ -28777,7 +28958,7 @@ var WorkflowOrchestratorAdapter = class {
28777
28958
  executions = /* @__PURE__ */ new Map();
28778
28959
  history = [];
28779
28960
  constructor(engine, logger53) {
28780
- this.id = `workflow-${randomUUID9().slice(0, 8)}`;
28961
+ this.id = `workflow-${randomUUID10().slice(0, 8)}`;
28781
28962
  this.engine = engine;
28782
28963
  this.logger = logger53 ?? createLogger({ component: "WorkflowOrchestratorAdapter" });
28783
28964
  }
@@ -28790,7 +28971,7 @@ var WorkflowOrchestratorAdapter = class {
28790
28971
  )
28791
28972
  );
28792
28973
  }
28793
- const executionId = randomUUID9();
28974
+ const executionId = randomUUID10();
28794
28975
  const startTime = getTimeProvider().now();
28795
28976
  this.setRunning(executionId);
28796
28977
  try {
@@ -29258,7 +29439,32 @@ var OrchestrateInputSchema = z50.object({
29258
29439
  task: z50.string().min(1).max(5e4).describe("Task description to orchestrate"),
29259
29440
  context: z50.record(z50.string(), z50.unknown()).optional().describe("Additional context for the task"),
29260
29441
  maxIterations: z50.number().min(1).max(50).optional().default(10).describe("Maximum iterations for orchestration"),
29261
- timeout: z50.number().min(1e3).max(6e5).optional().describe("Timeout in milliseconds for orchestration (default: 300000)")
29442
+ timeout: z50.number().min(1e3).max(6e5).optional().describe("Timeout in milliseconds for orchestration (default: 300000)"),
29443
+ /**
29444
+ * Async-mode dispatch (#3042, Stage 1 of epic #2631). Default `sync` —
29445
+ * backward-compat invariant; existing callers see no behavior change.
29446
+ * `async` returns `{ status: 'pending', jobId }` immediately; caller
29447
+ * polls `get_job_result(jobId)` for the structured payload. Sidesteps
29448
+ * the MCP-SDK 60s client-request timeout that was killing long
29449
+ * orchestrations (#2631 evidence: 28.6% timeout-shaped errors on
29450
+ * `run_workflow` at the gate-firing measurement).
29451
+ *
29452
+ * Kept optional (no `.default()`) so the inferred type doesn't force
29453
+ * `mode: 'sync'` on every existing call site / test fixture. The
29454
+ * handler treats `undefined` as `'sync'`.
29455
+ */
29456
+ mode: z50.enum(["sync", "async"]).optional().describe('Dispatch mode (default: sync). Use "async" for long-running orchestrations.'),
29457
+ /**
29458
+ * Idempotency key for async-mode replay-safety (#3042 Stage 1c / epic
29459
+ * #2631). When set: identical (key, inputs) returns the existing job;
29460
+ * same key with different inputs fails closed with
29461
+ * `idempotency_key_collision`. Without a key, every call gets a fresh
29462
+ * jobId (existing behavior). Sync mode ignores this — sync calls are
29463
+ * synchronous by definition and the caller can dedupe themselves.
29464
+ */
29465
+ idempotencyKey: z50.string().min(1).max(256).optional().describe(
29466
+ "Replay-safe key for async-mode dispatch (#3042 Stage 1c). Same (key, inputs) returns existing jobId; same key + different inputs fails closed."
29467
+ )
29262
29468
  });
29263
29469
  var OrchestrateOutputSchema = z50.object({
29264
29470
  taskId: z50.string().describe("Unique execution ID"),
@@ -29306,7 +29512,13 @@ var ORCHESTRATE_TOOL_SCHEMA = {
29306
29512
  task: z50.string().min(1).max(5e4).describe("Task description to orchestrate"),
29307
29513
  context: z50.record(z50.string(), z50.unknown()).optional().describe("Additional context for the task"),
29308
29514
  maxIterations: z50.number().min(1).max(50).optional().describe("Maximum iterations for orchestration (default: 10)"),
29309
- timeout: z50.number().min(1e3).max(6e5).optional().describe("Timeout in milliseconds for orchestration (default: 300000)")
29515
+ timeout: z50.number().min(1e3).max(6e5).optional().describe("Timeout in milliseconds for orchestration (default: 300000)"),
29516
+ mode: z50.enum(["sync", "async"]).optional().describe(
29517
+ 'Dispatch mode (default: sync). "async" returns { jobId } immediately; poll via get_job_result.'
29518
+ ),
29519
+ idempotencyKey: z50.string().min(1).max(256).optional().describe(
29520
+ "Replay-safe key for async-mode dispatch (#3042 Stage 1c). Same (key, inputs) returns existing jobId."
29521
+ )
29310
29522
  };
29311
29523
  function mapPatternToOrchestratorType(pattern) {
29312
29524
  if (pattern === "puppeteer") return "puppeteer";
@@ -30132,42 +30344,58 @@ async function withWatchdog(role, timeoutMs, task) {
30132
30344
  timeoutMs,
30133
30345
  state: "healthy"
30134
30346
  };
30135
- const taskPromise = task();
30136
- let timeoutHandle;
30137
- const timeoutPromise = new Promise((_, reject) => {
30138
- timeoutHandle = setTimeout(() => {
30347
+ const controller = new AbortController();
30348
+ const taskPromise = task(controller.signal);
30349
+ const { promise: timeoutPromise, cancel: cancelTimeout } = createTerminationTimer(
30350
+ entry,
30351
+ timeoutMs,
30352
+ controller
30353
+ );
30354
+ const watchdogTimer = startEscalationMonitor(entry, timeoutMs);
30355
+ try {
30356
+ return await Promise.race([taskPromise, timeoutPromise]);
30357
+ } finally {
30358
+ clearInterval(watchdogTimer);
30359
+ cancelTimeout();
30360
+ controller.abort();
30361
+ }
30362
+ }
30363
+ function createTerminationTimer(entry, timeoutMs, controller) {
30364
+ let handle;
30365
+ const promise = new Promise((_, reject) => {
30366
+ handle = setTimeout(() => {
30139
30367
  entry.state = "terminated";
30140
30368
  logger23.warn("Worker terminated by watchdog", {
30141
- role,
30369
+ role: entry.role,
30142
30370
  timeoutMs,
30143
30371
  elapsed: getTimeProvider().now() - entry.startMs,
30144
30372
  state: "terminated"
30145
30373
  });
30374
+ controller.abort();
30146
30375
  reject(new Error(`Worker timeout after ${String(timeoutMs)}ms`));
30147
30376
  }, timeoutMs);
30148
30377
  });
30149
- const watchdogTimer = setInterval(() => {
30378
+ const cancel = () => {
30379
+ if (handle !== void 0) clearTimeout(handle);
30380
+ };
30381
+ return { promise, cancel };
30382
+ }
30383
+ function startEscalationMonitor(entry, timeoutMs) {
30384
+ return setInterval(() => {
30150
30385
  const newState = evaluateState(entry, getTimeProvider().now());
30151
- if (newState !== entry.state) {
30152
- entry.state = newState;
30153
- if (newState === "warned") {
30154
- const elapsed = getTimeProvider().now() - entry.startMs;
30155
- logger23.warn("Worker approaching timeout", {
30156
- role,
30157
- elapsed,
30158
- timeoutMs,
30159
- percentUsed: Math.round(elapsed / timeoutMs * 100),
30160
- state: "warned"
30161
- });
30162
- }
30386
+ if (newState === entry.state) return;
30387
+ entry.state = newState;
30388
+ if (newState === "warned") {
30389
+ const elapsed = getTimeProvider().now() - entry.startMs;
30390
+ logger23.warn("Worker approaching timeout", {
30391
+ role: entry.role,
30392
+ elapsed,
30393
+ timeoutMs,
30394
+ percentUsed: Math.round(elapsed / timeoutMs * 100),
30395
+ state: "warned"
30396
+ });
30163
30397
  }
30164
30398
  }, WATCHDOG_CHECK_INTERVAL_MS);
30165
- try {
30166
- return await Promise.race([taskPromise, timeoutPromise]);
30167
- } finally {
30168
- clearInterval(watchdogTimer);
30169
- if (timeoutHandle !== void 0) clearTimeout(timeoutHandle);
30170
- }
30171
30399
  }
30172
30400
 
30173
30401
  // src/orchestration/aorchestra/quality-gate.ts
@@ -30557,7 +30785,8 @@ function createWorkerTask(entry, taskIndex, waveNumber, opts) {
30557
30785
  error: "Role auto-disabled after consecutive failures"
30558
30786
  };
30559
30787
  }
30560
- const staggerMs = taskIndex * opts.staggerDelayMs;
30788
+ const staggerSlot = taskIndex % opts.maxConcurrency;
30789
+ const staggerMs = staggerSlot * opts.staggerDelayMs;
30561
30790
  if (staggerMs > 0) {
30562
30791
  await new Promise((resolve19) => setTimeout(resolve19, staggerMs));
30563
30792
  }
@@ -30676,7 +30905,11 @@ async function executeSafe(opts) {
30676
30905
  async function attemptExecution(entry, executeWorker, priorWaveResults, timeoutMs) {
30677
30906
  const startMs = Date.now();
30678
30907
  try {
30679
- return await withWatchdog(entry.role, timeoutMs, () => executeWorker(entry, priorWaveResults));
30908
+ return await withWatchdog(
30909
+ entry.role,
30910
+ timeoutMs,
30911
+ (signal) => executeWorker(entry, priorWaveResults, signal)
30912
+ );
30680
30913
  } catch (error) {
30681
30914
  const durationMs = Date.now() - startMs;
30682
30915
  const message = getErrorMessage(error);
@@ -31593,7 +31826,16 @@ function resolveWorkerAdapter(entry, fallback, fallbackCli, perWorkerRouting, lo
31593
31826
  return { adapter: resolved, cliName };
31594
31827
  }
31595
31828
  async function executeOnAdapter(opts) {
31596
- const { entry, adapter, cliName, taskDescription, learnings, priorWaveResults, workerStartMs } = opts;
31829
+ const {
31830
+ entry,
31831
+ adapter,
31832
+ cliName,
31833
+ taskDescription,
31834
+ learnings,
31835
+ priorWaveResults,
31836
+ workerStartMs,
31837
+ signal
31838
+ } = opts;
31597
31839
  const prompt = composeWorkerPrompt({
31598
31840
  entry,
31599
31841
  taskDescription,
@@ -31603,7 +31845,8 @@ async function executeOnAdapter(opts) {
31603
31845
  try {
31604
31846
  const result = await adapter.complete({
31605
31847
  messages: [{ role: "user", content: prompt }],
31606
- maxTokens: WORKER_MAX_TOKENS
31848
+ maxTokens: WORKER_MAX_TOKENS,
31849
+ ...signal !== void 0 ? { signal } : {}
31607
31850
  });
31608
31851
  if (!result.ok) {
31609
31852
  return makeErrorResult(entry, workerStartMs, result.error.message, cliName);
@@ -31625,7 +31868,7 @@ async function executeOnAdapter(opts) {
31625
31868
  function createWorkerExecutor(config) {
31626
31869
  const { taskDescription, modelAdapter, logger: logger53, learnings, perWorkerRouting } = config;
31627
31870
  const effectiveFallbackCli = modelAdapter.providerId;
31628
- return async (entry, priorWaveResults) => {
31871
+ return async (entry, priorWaveResults, signal) => {
31629
31872
  const workerStartMs = getTimeProvider().now();
31630
31873
  const { adapter, cliName } = resolveWorkerAdapter(
31631
31874
  entry,
@@ -31641,7 +31884,8 @@ function createWorkerExecutor(config) {
31641
31884
  taskDescription,
31642
31885
  workerStartMs,
31643
31886
  ...learnings !== void 0 ? { learnings } : {},
31644
- ...priorWaveResults !== void 0 ? { priorWaveResults } : {}
31887
+ ...priorWaveResults !== void 0 ? { priorWaveResults } : {},
31888
+ ...signal !== void 0 ? { signal } : {}
31645
31889
  });
31646
31890
  };
31647
31891
  }
@@ -31661,7 +31905,7 @@ function resolveAltAdapter(entry, primaryCli, log) {
31661
31905
  function createAltWorkerExecutor(config) {
31662
31906
  const { taskDescription, modelAdapter, logger: log, learnings } = config;
31663
31907
  const primaryCli = modelAdapter.providerId;
31664
- return async (entry, priorWaveResults) => {
31908
+ return async (entry, priorWaveResults, signal) => {
31665
31909
  const workerStartMs = getTimeProvider().now();
31666
31910
  const alt = resolveAltAdapter(entry, primaryCli, log);
31667
31911
  if (alt === null) {
@@ -31675,7 +31919,8 @@ function createAltWorkerExecutor(config) {
31675
31919
  taskDescription,
31676
31920
  workerStartMs,
31677
31921
  ...learnings !== void 0 ? { learnings } : {},
31678
- ...priorWaveResults !== void 0 ? { priorWaveResults } : {}
31922
+ ...priorWaveResults !== void 0 ? { priorWaveResults } : {},
31923
+ ...signal !== void 0 ? { signal } : {}
31679
31924
  });
31680
31925
  };
31681
31926
  }
@@ -32744,6 +32989,11 @@ var ProgressLedgerEntrySchema = z55.object({
32744
32989
  /** Why this action was chosen — required so future readers can audit the call. */
32745
32990
  rationale: z55.string().min(1)
32746
32991
  });
32992
+ var TaskCancellationSchema = z55.object({
32993
+ requestedAt: z55.iso.datetime(),
32994
+ /** Optional human-readable note carried back to the caller. */
32995
+ reason: z55.string().max(1e3).optional()
32996
+ });
32747
32997
  var StructuredTaskStateSchema = z55.object({
32748
32998
  taskId: z55.string().min(1),
32749
32999
  stage: TaskStageSchema,
@@ -32762,6 +33012,40 @@ var StructuredTaskStateSchema = z55.object({
32762
33012
  * for the same backward-compat reason as `taskLedger`.
32763
33013
  */
32764
33014
  progressLedger: z55.array(ProgressLedgerEntrySchema).optional(),
33015
+ /**
33016
+ * Monotonic version counter (#3043 / epic #2631 Stage 2). Increments by
33017
+ * 1 on every write; polling clients use this to detect "I missed a
33018
+ * transition" and resync rather than silently observe a stale snapshot.
33019
+ *
33020
+ * Optional + defaulting-to-0 in the reducer for backward-compat — old
33021
+ * state logs (pre-Stage-2) don't carry it; the reducer treats their
33022
+ * baseline as v0 and starts counting from there.
33023
+ */
33024
+ version: z55.number().int().nonnegative().optional(),
33025
+ /**
33026
+ * Tool result payload (#3043 / epic #2631 Stage 2). Set atomically
33027
+ * via the `result` log event when `stage === 'complete'`. Carries the
33028
+ * same shape the synchronous mode would have returned inline.
33029
+ *
33030
+ * Capped at `TASK_RESULT_MAX_BYTES` at write time; over-cap payloads
33031
+ * are replaced with `{ truncated: true, originalBytes }` so the
33032
+ * cap is observable rather than silent.
33033
+ *
33034
+ * Once Stage 2 (this) ships, Stage 3+ (#3044 / #3045) migrate the
33035
+ * orchestrate / run_workflow / consensus_vote async-mode writers
33036
+ * from the Stage-1 sidecar (`mcp/jobs/job-result-store.ts`) to this
33037
+ * field, then the sidecar files become legacy that the next cleanup
33038
+ * sweep can remove.
33039
+ */
33040
+ result: z55.unknown().optional(),
33041
+ /**
33042
+ * Cancellation marker (#3043 / epic #2631 Stage 2). Set by `cancel_job`
33043
+ * — the running tool checks for this at safe-point boundaries (between
33044
+ * steps, between waves) and aborts via the AbortSignal plumbing from
33045
+ * #3035 / #3038. Append-only by construction (the reducer ignores a
33046
+ * second cancellation event).
33047
+ */
33048
+ cancellation: TaskCancellationSchema.optional(),
32765
33049
  updatedAt: z55.iso.datetime()
32766
33050
  });
32767
33051
  var StructuredTaskLogEntrySchema = z55.discriminatedUnion("event", [
@@ -32809,6 +33093,23 @@ var StructuredTaskLogEntrySchema = z55.discriminatedUnion("event", [
32809
33093
  event: z55.literal("progress_ledger"),
32810
33094
  ts: z55.iso.datetime(),
32811
33095
  entry: ProgressLedgerEntrySchema
33096
+ }),
33097
+ // #3043 / epic #2631 Stage 2 — tool result payload set when stage flips
33098
+ // to 'complete'. Written by appendResult; replayed into state.result.
33099
+ // The payload itself is `unknown` because each tool's result shape is
33100
+ // its own; readers cast after a status check.
33101
+ z55.object({
33102
+ event: z55.literal("result"),
33103
+ ts: z55.iso.datetime(),
33104
+ result: z55.unknown()
33105
+ }),
33106
+ // #3043 / epic #2631 Stage 2 — cancellation marker. Append-only: the
33107
+ // reducer ignores a second cancellation event so a malicious or buggy
33108
+ // double-cancel can't rewrite the requestedAt timestamp.
33109
+ z55.object({
33110
+ event: z55.literal("cancellation"),
33111
+ ts: z55.iso.datetime(),
33112
+ cancellation: TaskCancellationSchema
32812
33113
  })
32813
33114
  ]);
32814
33115
 
@@ -32916,7 +33217,8 @@ function reduceLogEntries(taskId, entries) {
32916
33217
  let state = {
32917
33218
  ...initState,
32918
33219
  decisions: [...initState.decisions],
32919
- blockers: initState.blockers.map((b) => ({ ...b }))
33220
+ blockers: initState.blockers.map((b) => ({ ...b })),
33221
+ version: initState.version ?? 0
32920
33222
  };
32921
33223
  for (const entry of entries) {
32922
33224
  if (entry === init) continue;
@@ -32924,47 +33226,98 @@ function reduceLogEntries(taskId, entries) {
32924
33226
  }
32925
33227
  return ok(state);
32926
33228
  }
32927
- function applyLogEntry(state, entry) {
33229
+ function applyBlockerEvent(state, entry, nextVersion) {
33230
+ if (entry.event === "blocker") {
33231
+ return {
33232
+ ...state,
33233
+ blockers: [...state.blockers, entry.blocker],
33234
+ updatedAt: entry.ts,
33235
+ version: nextVersion
33236
+ };
33237
+ }
33238
+ return {
33239
+ ...state,
33240
+ blockers: state.blockers.map(
33241
+ (b, i) => i === entry.blockerIndex ? { ...b, resolved: entry.resolvedAt } : b
33242
+ ),
33243
+ updatedAt: entry.ts,
33244
+ version: nextVersion
33245
+ };
33246
+ }
33247
+ function applyReplacementEvent(state, entry, nextVersion) {
32928
33248
  switch (entry.event) {
32929
- case "init":
32930
- return state;
32931
- // init is handled by reduceLogEntries
32932
33249
  case "decision":
32933
33250
  return {
32934
33251
  ...state,
32935
33252
  decisions: [...state.decisions, entry.decision],
32936
- updatedAt: entry.ts
32937
- };
32938
- case "blocker":
32939
- return {
32940
- ...state,
32941
- blockers: [...state.blockers, entry.blocker],
32942
- updatedAt: entry.ts
32943
- };
32944
- case "blocker_resolved":
32945
- return {
32946
- ...state,
32947
- blockers: state.blockers.map(
32948
- (b, i) => i === entry.blockerIndex ? { ...b, resolved: entry.resolvedAt } : b
32949
- ),
32950
- updatedAt: entry.ts
33253
+ updatedAt: entry.ts,
33254
+ version: nextVersion
32951
33255
  };
32952
33256
  case "stage":
32953
- return { ...state, stage: entry.stage, updatedAt: entry.ts };
33257
+ return { ...state, stage: entry.stage, updatedAt: entry.ts, version: nextVersion };
32954
33258
  case "position":
32955
- return { ...state, position: entry.position, updatedAt: entry.ts };
33259
+ return { ...state, position: entry.position, updatedAt: entry.ts, version: nextVersion };
32956
33260
  case "task_ledger":
32957
- return { ...state, taskLedger: entry.ledger, updatedAt: entry.ts };
33261
+ return { ...state, taskLedger: entry.ledger, updatedAt: entry.ts, version: nextVersion };
32958
33262
  case "progress_ledger":
32959
33263
  return {
32960
33264
  ...state,
32961
33265
  progressLedger: [...state.progressLedger ?? [], entry.entry],
32962
- updatedAt: entry.ts
33266
+ updatedAt: entry.ts,
33267
+ version: nextVersion
32963
33268
  };
32964
33269
  }
32965
33270
  }
33271
+ function applyTerminalEvent(state, entry, nextVersion) {
33272
+ if (entry.event === "result") {
33273
+ return { ...state, result: entry.result, updatedAt: entry.ts, version: nextVersion };
33274
+ }
33275
+ return {
33276
+ ...state,
33277
+ cancellation: state.cancellation ?? entry.cancellation,
33278
+ updatedAt: entry.ts,
33279
+ version: nextVersion
33280
+ };
33281
+ }
33282
+ var EVENT_CATEGORY = {
33283
+ init: "init",
33284
+ blocker: "blocker",
33285
+ blocker_resolved: "blocker",
33286
+ decision: "replace",
33287
+ stage: "replace",
33288
+ position: "replace",
33289
+ task_ledger: "replace",
33290
+ progress_ledger: "replace",
33291
+ result: "terminal",
33292
+ cancellation: "terminal"
33293
+ };
33294
+ function applyLogEntry(state, entry) {
33295
+ const category = EVENT_CATEGORY[entry.event];
33296
+ if (category === "init") return state;
33297
+ const nextVersion = (state.version ?? 0) + 1;
33298
+ if (category === "blocker") {
33299
+ return applyBlockerEvent(
33300
+ state,
33301
+ entry,
33302
+ nextVersion
33303
+ );
33304
+ }
33305
+ if (category === "terminal") {
33306
+ return applyTerminalEvent(
33307
+ state,
33308
+ entry,
33309
+ nextVersion
33310
+ );
33311
+ }
33312
+ return applyReplacementEvent(
33313
+ state,
33314
+ entry,
33315
+ nextVersion
33316
+ );
33317
+ }
32966
33318
 
32967
33319
  // src/mcp/tools/orchestrate.ts
33320
+ import { randomUUID as randomUUID11 } from "crypto";
32968
33321
  function generateTaskId() {
32969
33322
  const timestamp = getTimeProvider().now().toString(36);
32970
33323
  const random = getRandomProvider().random().toString(36).substring(2, 8);
@@ -33651,6 +34004,15 @@ function createOrchestrateHandler(deps) {
33651
34004
  message: `Validation error: ${formatZodError(validated.error)}`
33652
34005
  });
33653
34006
  }
34007
+ if (validated.data.mode === "async") {
34008
+ return dispatchAsyncOrchestrate({
34009
+ input: validated.data,
34010
+ deps,
34011
+ notifier,
34012
+ logger: ctx.logger,
34013
+ trustTier: ctx.requestContext.trustTier
34014
+ });
34015
+ }
33654
34016
  try {
33655
34017
  return await withDepthGuard(
33656
34018
  "orchestrate",
@@ -33670,6 +34032,80 @@ function createOrchestrateHandler(deps) {
33670
34032
  }
33671
34033
  };
33672
34034
  }
34035
+ function buildReplayEnvelope(jobId) {
34036
+ return toolSuccess(
34037
+ JSON.stringify({
34038
+ status: "replay",
34039
+ jobId,
34040
+ pollTool: "get_job_result",
34041
+ note: "Idempotency key matched a prior dispatch \u2014 poll get_job_result for current status."
34042
+ })
34043
+ );
34044
+ }
34045
+ function buildCollisionEnvelope(existingJobId) {
34046
+ return toolStructuredError({
34047
+ errorCategory: "validation",
34048
+ message: `Idempotency key already used with different inputs. Existing jobId: ${existingJobId}. Use a fresh key or omit it.`
34049
+ });
34050
+ }
34051
+ function dispatchAsyncOrchestrate(params) {
34052
+ const idempotency = shortCircuitOrFreshJobId({
34053
+ tool: "orchestrate",
34054
+ idempotencyKey: params.input.idempotencyKey,
34055
+ inputs: params.input,
34056
+ freshJobId: () => `job-orch-${randomUUID11()}`,
34057
+ replayEnvelope: buildReplayEnvelope,
34058
+ collisionEnvelope: buildCollisionEnvelope
34059
+ });
34060
+ if (idempotency.kind === "shortCircuit") return idempotency.value;
34061
+ if (!tryAcquire("orchestrate")) {
34062
+ return toolSuccess(
34063
+ JSON.stringify({
34064
+ status: "busy",
34065
+ retryAfterMs: suggestRetryAfterMs("orchestrate"),
34066
+ note: 'Async-mode concurrency cap reached for orchestrate. Retry later or use mode: "sync".'
34067
+ })
34068
+ );
34069
+ }
34070
+ const jobId = idempotency.jobId;
34071
+ recordPendingAndRegister(jobId, params.input.idempotencyKey, params.input);
34072
+ void runOrchestrateInBackground(jobId, params);
34073
+ return toolSuccess(
34074
+ JSON.stringify({
34075
+ status: "pending",
34076
+ jobId,
34077
+ pollTool: "get_job_result",
34078
+ note: 'Poll via get_job_result({ jobId }) until status !== "pending".'
34079
+ })
34080
+ );
34081
+ }
34082
+ function recordPendingAndRegister(jobId, key, inputs) {
34083
+ writeJobPending(jobId, "orchestrate");
34084
+ if (key !== void 0 && key !== "") {
34085
+ registerIdempotentJob({ tool: "orchestrate", idempotencyKey: key, inputs, jobId });
34086
+ }
34087
+ }
34088
+ async function runOrchestrateInBackground(jobId, params) {
34089
+ try {
34090
+ const result = await withDepthGuard(
34091
+ "orchestrate",
34092
+ () => runOrchestratePipeline({
34093
+ input: params.input,
34094
+ deps: params.deps,
34095
+ notifier: params.notifier,
34096
+ logger: params.logger,
34097
+ ...params.trustTier !== void 0 ? { trustTier: params.trustTier } : {}
34098
+ })
34099
+ );
34100
+ writeJobComplete(jobId, "orchestrate", result);
34101
+ } catch (err2) {
34102
+ const errObj = err2 instanceof Error ? err2 : new Error(String(err2));
34103
+ params.logger.error("Async orchestrate dispatch failed", errObj, { jobId });
34104
+ writeJobFailed(jobId, "orchestrate", errObj.message);
34105
+ } finally {
34106
+ release("orchestrate");
34107
+ }
34108
+ }
33673
34109
  function registerOrchestrateTool(server, deps) {
33674
34110
  const logger53 = deps.logger ?? createLogger({ tool: "orchestrate" });
33675
34111
  const notifier = deps.notifier ?? createMcpNotifier(server);
@@ -42014,7 +42450,7 @@ async function tryIssueTriage(task) {
42014
42450
  try {
42015
42451
  const issueMatch = task.match(/github\.com\/([^/]+\/[^/]+)\/issues\/(\d+)/);
42016
42452
  if (issueMatch === null) return null;
42017
- const { createIssueTriage } = await import("./issue-triage-MURMDN2G.js");
42453
+ const { createIssueTriage } = await import("./issue-triage-WUK7L25X.js");
42018
42454
  const triage = createIssueTriage();
42019
42455
  const owner = issueMatch[1] ?? "";
42020
42456
  const num = issueMatch[2] ?? "";
@@ -42042,7 +42478,7 @@ var VALID_TEMPLATES = /* @__PURE__ */ new Set([
42042
42478
  ]);
42043
42479
  async function classifyWithLLM(task) {
42044
42480
  try {
42045
- const { executeExpert: executeExpert2 } = await import("./expert-bridge-7LPGCPPR.js");
42481
+ const { executeExpert: executeExpert2 } = await import("./expert-bridge-22UVN5TB.js");
42046
42482
  const prompt = [
42047
42483
  "Classify this task into exactly one pipeline template.",
42048
42484
  "Templates: dev (implementation/bug fix/refactor), research (investigate/evaluate/compare),",
@@ -42824,8 +43260,8 @@ var memoryInitPromise = null;
42824
43260
  async function initPipelineMemory() {
42825
43261
  if (cachedMemory !== null) return cachedMemory;
42826
43262
  try {
42827
- const { createSessionMemory: createSessionMemory2 } = await import("./session-memory-X6SCDFER.js");
42828
- const { getLearningDir } = await import("./learning-persistence-NX2KHL5T.js");
43263
+ const { createSessionMemory: createSessionMemory2 } = await import("./session-memory-PUJMR6FE.js");
43264
+ const { getLearningDir } = await import("./learning-persistence-5ALG6XRC.js");
42829
43265
  const mem = createSessionMemory2(getLearningDir());
42830
43266
  mem.startSession(`pipeline-${String(getTimeProvider().now())}`);
42831
43267
  cachedMemory = {
@@ -42881,7 +43317,7 @@ function recordRoutingExperience(category, success, durationMs) {
42881
43317
  callRecord(routingMemoryCache);
42882
43318
  return;
42883
43319
  }
42884
- routingMemoryInitPromise ??= import("./routing-memory-6IEPJ3EP.js").then(({ createRoutingMemory }) => {
43320
+ routingMemoryInitPromise ??= import("./routing-memory-UY6KTGT2.js").then(({ createRoutingMemory }) => {
42885
43321
  routingMemoryCache ??= createRoutingMemory();
42886
43322
  return routingMemoryCache;
42887
43323
  }).catch((error) => {
@@ -42915,7 +43351,7 @@ ${text}` : "";
42915
43351
  }
42916
43352
  async function getWeatherContext() {
42917
43353
  try {
42918
- const { generateWeatherReport: generateWeatherReport2 } = await import("./weather-report-6BC3JK5H.js");
43354
+ const { generateWeatherReport: generateWeatherReport2 } = await import("./weather-report-RQMZOL7C.js");
42919
43355
  const report = generateWeatherReport2({ includeAdaptive: true });
42920
43356
  const mappings = "recommendedMappings" in report ? report.recommendedMappings : [];
42921
43357
  if (!Array.isArray(mappings) || mappings.length === 0) return "";
@@ -42933,8 +43369,8 @@ ${lines}
42933
43369
  }
42934
43370
  async function getMemoryContext(task) {
42935
43371
  try {
42936
- const { createSessionMemory: createSessionMemory2 } = await import("./session-memory-X6SCDFER.js");
42937
- const { getLearningDir } = await import("./learning-persistence-NX2KHL5T.js");
43372
+ const { createSessionMemory: createSessionMemory2 } = await import("./session-memory-PUJMR6FE.js");
43373
+ const { getLearningDir } = await import("./learning-persistence-5ALG6XRC.js");
42938
43374
  const memory = createSessionMemory2(getLearningDir(), { maxLearningsInContext: 10 });
42939
43375
  const learnings = memory.searchLearnings(task.slice(0, 200));
42940
43376
  if (learnings.length === 0) return "";
@@ -43039,7 +43475,7 @@ ${contextBlock}`;
43039
43475
  const strategy = config.votingStrategy ?? "higher_order";
43040
43476
  await postProgress(config, "Vote", `Running consensus with ${strategy} strategy...`);
43041
43477
  try {
43042
- const { executeVoting } = await import("./consensus-vote-MTLP6E72.js");
43478
+ const { executeVoting } = await import("./consensus-vote-LPYEXUVC.js");
43043
43479
  const votingResult = await executeVoting(
43044
43480
  {
43045
43481
  proposal: plan.slice(0, 4e3),
@@ -43966,7 +44402,7 @@ async function searchCodebaseForTask(task) {
43966
44402
  }
43967
44403
  async function queryResearchRegistry(task) {
43968
44404
  try {
43969
- const { synthesizeResearch: synthesizeResearch2 } = await import("./research-helpers-synthesize-36QBOKII.js");
44405
+ const { synthesizeResearch: synthesizeResearch2 } = await import("./research-helpers-synthesize-KNRCAIXK.js");
43970
44406
  const topic = task.split(/[.!?\n]/).filter((s) => s.trim().length > 10)[0]?.trim();
43971
44407
  if (topic === void 0) return null;
43972
44408
  const result = await synthesizeResearch2(topic.slice(0, 50));
@@ -44037,7 +44473,7 @@ function createScanStageWrapper() {
44037
44473
  try {
44038
44474
  const slug = ctx.task.match(/([a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+)/)?.[1];
44039
44475
  if (slug !== void 0) {
44040
- const { generateSecurityPlan: generateSecurityPlan2 } = await import("./repo-security-plan-N3CDMW6L.js");
44476
+ const { generateSecurityPlan: generateSecurityPlan2 } = await import("./repo-security-plan-THHLNGEQ.js");
44041
44477
  const plan = await generateSecurityPlan2({ repo: slug, maxScanners: 10 });
44042
44478
  const recs = plan.recommendations.slice(0, 5).map((r) => `${r.priority}: ${r.displayName} (${r.category})`).join("; ");
44043
44479
  return output(PIPELINE_STATE_KEYS.FINDINGS, recs, getTimeProvider().now() - start, true);
@@ -45854,12 +46290,144 @@ function registerQueryTaskStateTool(server, deps) {
45854
46290
  logger53.info("Registered query_task_state tool");
45855
46291
  }
45856
46292
 
46293
+ // src/mcp/tools/get-job-result-tool.ts
46294
+ import { z as z97 } from "zod";
46295
+ var GetJobResultInputSchema = z97.object({
46296
+ jobId: z97.string().min(1).max(128).describe('Job ID returned by orchestrate({ mode: "async" })')
46297
+ });
46298
+ function getJobResultHandler(args) {
46299
+ const parsed = GetJobResultInputSchema.safeParse(args);
46300
+ if (!parsed.success) {
46301
+ return Promise.resolve(
46302
+ toolStructuredError({
46303
+ errorCategory: "validation",
46304
+ message: `Validation error: ${formatZodError(parsed.error)}`
46305
+ })
46306
+ );
46307
+ }
46308
+ const record = readJobResult(parsed.data.jobId);
46309
+ if (record === null) {
46310
+ const response2 = {
46311
+ jobId: parsed.data.jobId,
46312
+ found: false,
46313
+ errorMessage: "Unknown jobId, or the sidecar file is unreadable (corrupt / future schema). Re-check the jobId returned by the async-mode dispatch."
46314
+ };
46315
+ return Promise.resolve(toolSuccess(JSON.stringify(response2, null, 2)));
46316
+ }
46317
+ const response = {
46318
+ jobId: parsed.data.jobId,
46319
+ found: true,
46320
+ record
46321
+ };
46322
+ return Promise.resolve(toolSuccess(JSON.stringify(response, null, 2)));
46323
+ }
46324
+ function registerGetJobResultTool(server, deps) {
46325
+ const logger53 = deps.logger ?? createLogger({ tool: "get_job_result" });
46326
+ const toolSchema = {
46327
+ jobId: z97.string().min(1).max(128).describe('Job ID returned by orchestrate({ mode: "async" })')
46328
+ };
46329
+ const description2 = 'Read the result of an async-mode tool invocation by jobId. Returns the structured record (status, result | error, timestamps). Poll until status !== "pending". Stage-1 of epic #2631 \u2014 Stage 2 will fold this into query_task_state once StructuredTaskState gains the result field.';
46330
+ const secureHandler = createSecureHandler(getJobResultHandler, {
46331
+ toolName: "get_job_result",
46332
+ rateLimiter: deps.rateLimiter,
46333
+ logger: logger53
46334
+ });
46335
+ const timeoutMs = getToolTimeout("get_job_result", deps.security);
46336
+ const wrappedHandler = wrapToolWithTimeout("get_job_result", secureHandler, {
46337
+ timeoutMs,
46338
+ logger: logger53
46339
+ });
46340
+ server.registerTool(
46341
+ "get_job_result",
46342
+ { description: description2, inputSchema: toolSchema, annotations: getToolAnnotations("get_job_result") },
46343
+ toSdkCallback(wrappedHandler)
46344
+ );
46345
+ logger53.info("Registered get_job_result tool");
46346
+ }
46347
+
46348
+ // src/mcp/tools/list-jobs-tool.ts
46349
+ import { z as z98 } from "zod";
46350
+ var MAX_LIST_JOBS_RESULTS = 200;
46351
+ var ListJobsInputSchema = z98.object({
46352
+ /**
46353
+ * Filter to jobs from a specific tool (exact match — e.g. `'orchestrate'`).
46354
+ * Omit to list every tool's jobs.
46355
+ */
46356
+ toolName: z98.string().min(1).max(128).optional().describe("Filter to one tool (exact match)."),
46357
+ /**
46358
+ * Filter to jobs in a specific lifecycle state.
46359
+ * Omit to list every state.
46360
+ */
46361
+ status: JobStatusSchema.optional().describe(
46362
+ "Filter to pending | complete | failed | cancelled. Omit for all."
46363
+ ),
46364
+ /**
46365
+ * Maximum summaries to return — capped at MAX_LIST_JOBS_RESULTS (200).
46366
+ * Newest jobs are returned first, so a smaller limit shows the most
46367
+ * recent activity.
46368
+ */
46369
+ limit: z98.number().int().min(1).max(MAX_LIST_JOBS_RESULTS).optional().describe(`Max summaries to return (1-${String(MAX_LIST_JOBS_RESULTS)}, newest first).`)
46370
+ });
46371
+ function listJobsHandler(args) {
46372
+ const parsed = ListJobsInputSchema.safeParse(args);
46373
+ if (!parsed.success) {
46374
+ return Promise.resolve(
46375
+ toolStructuredError({
46376
+ errorCategory: "validation",
46377
+ message: `Validation error: ${formatZodError(parsed.error)}`
46378
+ })
46379
+ );
46380
+ }
46381
+ const { toolName, status, limit } = parsed.data;
46382
+ const all = listJobs();
46383
+ const filtered = all.filter((j) => {
46384
+ if (toolName !== void 0 && j.toolName !== toolName) return false;
46385
+ if (status !== void 0 && j.status !== status) return false;
46386
+ return true;
46387
+ });
46388
+ const cap = limit ?? MAX_LIST_JOBS_RESULTS;
46389
+ const trimmed = filtered.slice(0, cap);
46390
+ const response = {
46391
+ count: trimmed.length,
46392
+ truncated: filtered.length > trimmed.length,
46393
+ jobs: trimmed
46394
+ };
46395
+ return Promise.resolve(toolSuccess(JSON.stringify(response, null, 2)));
46396
+ }
46397
+ function registerListJobsTool(server, deps) {
46398
+ const logger53 = deps.logger ?? createLogger({ tool: "list_jobs" });
46399
+ const toolSchema = {
46400
+ toolName: z98.string().min(1).max(128).optional().describe("Filter to one tool (exact match)."),
46401
+ status: JobStatusSchema.optional().describe(
46402
+ "Filter to pending | complete | failed | cancelled. Omit for all."
46403
+ ),
46404
+ limit: z98.number().int().min(1).max(MAX_LIST_JOBS_RESULTS).optional().describe(`Max summaries to return (1-${String(MAX_LIST_JOBS_RESULTS)}, newest first).`)
46405
+ };
46406
+ const description2 = "List async-mode jobs (cross-session discovery). Returns summaries \u2014 jobId, toolName, status, timestamps \u2014 newest first. Filter by toolName / status / limit. Result payloads excluded; fetch via get_job_result(jobId). Stage 5 of epic #2631.";
46407
+ const secureHandler = createSecureHandler(listJobsHandler, {
46408
+ toolName: "list_jobs",
46409
+ rateLimiter: deps.rateLimiter,
46410
+ logger: logger53
46411
+ });
46412
+ const timeoutMs = getToolTimeout("list_jobs", deps.security);
46413
+ const wrappedHandler = wrapToolWithTimeout("list_jobs", secureHandler, {
46414
+ timeoutMs,
46415
+ logger: logger53
46416
+ });
46417
+ server.registerTool(
46418
+ "list_jobs",
46419
+ { description: description2, inputSchema: toolSchema, annotations: getToolAnnotations("list_jobs") },
46420
+ toSdkCallback(wrappedHandler)
46421
+ );
46422
+ logger53.info("Registered list_jobs tool");
46423
+ }
46424
+
45857
46425
  // src/mcp/tools/verify-audit-chain-tool.ts
45858
46426
  import * as fs12 from "fs/promises";
45859
46427
  import * as path11 from "path";
45860
- import { z as z97 } from "zod";
45861
- var VerifyAuditChainInputSchema = z97.object({
45862
- logDir: z97.string().min(1).max(512).describe(
46428
+ import { z as z99 } from "zod";
46429
+ var VerifyAuditChainInputSchema = z99.object({
46430
+ logDir: z99.string().min(1).max(512).describe(
45863
46431
  "Filesystem path to the FileAuditStorage log directory. Tool reads all `audit-*.jsonl` files in lexicographic order and verifies the combined chain."
45864
46432
  )
45865
46433
  });
@@ -45936,7 +46504,7 @@ async function handler2(args, ctx) {
45936
46504
  function registerVerifyAuditChainTool(server, deps) {
45937
46505
  const logger53 = deps.logger ?? createLogger({ tool: "verify_audit_chain" });
45938
46506
  const toolSchema = {
45939
- logDir: z97.string().min(1).max(512).describe(
46507
+ logDir: z99.string().min(1).max(512).describe(
45940
46508
  "Filesystem path to the FileAuditStorage log directory. Tool reads all `audit-*.jsonl` files and verifies the combined hash chain."
45941
46509
  )
45942
46510
  };
@@ -45960,18 +46528,18 @@ function registerVerifyAuditChainTool(server, deps) {
45960
46528
  }
45961
46529
 
45962
46530
  // src/mcp/tools/pipeline-tool.ts
45963
- import { z as z98 } from "zod";
46531
+ import { z as z100 } from "zod";
45964
46532
  import * as fs13 from "fs";
45965
46533
  import * as path12 from "path";
45966
- var PipelineInputSchema = z98.object({
46534
+ var PipelineInputSchema = z100.object({
45967
46535
  /** The task to execute. */
45968
- task: z98.string().min(5).max(1e4).describe("Task description \u2014 pipeline template auto-selected based on content"),
46536
+ task: z100.string().min(5).max(1e4).describe("Task description \u2014 pipeline template auto-selected based on content"),
45969
46537
  /** Path to a spec file (.md, .yaml) to use as task input. */
45970
- specFile: z98.string().max(500).optional().describe("Path to a spec file \u2014 content prepended to task for greenfield projects"),
46538
+ specFile: z100.string().max(500).optional().describe("Path to a spec file \u2014 content prepended to task for greenfield projects"),
45971
46539
  /** Override template — see `listTemplateIds()` for the canonical list (#2728). Auto-detected if omitted. */
45972
- template: z98.string().max(50).optional().describe(`Pipeline template override. Available: ${listTemplateIds().join(", ")}`),
46540
+ template: z100.string().max(50).optional().describe(`Pipeline template override. Available: ${listTemplateIds().join(", ")}`),
45973
46541
  /** Voting strategy for consensus stages. */
45974
- votingStrategy: z98.enum([
46542
+ votingStrategy: z100.enum([
45975
46543
  "simple_majority",
45976
46544
  "supermajority",
45977
46545
  "unanimous",
@@ -45982,13 +46550,13 @@ var PipelineInputSchema = z98.object({
45982
46550
  "Voting strategy for plan approval. simple_majority (default), supermajority (67%), unanimous, higher_order (Bayesian), proof_of_learning, opinion_wise"
45983
46551
  ),
45984
46552
  /** Use 3 agents instead of 6 for faster voting. */
45985
- quickMode: z98.boolean().default(false).describe("Use 3 agents instead of 6 for faster consensus voting"),
46553
+ quickMode: z100.boolean().default(false).describe("Use 3 agents instead of 6 for faster consensus voting"),
45986
46554
  /** Maximum execution time per stage in milliseconds (min 30s, max 600s). */
45987
- timeoutMs: z98.number().int().min(3e4).max(6e5).optional().describe("Max time per stage in ms (30000-600000). Default: varies by stage complexity"),
46555
+ timeoutMs: z100.number().int().min(3e4).max(6e5).optional().describe("Max time per stage in ms (30000-600000). Default: varies by stage complexity"),
45988
46556
  /** Stop after planning/voting (no implementation). */
45989
- dryRun: z98.boolean().default(false).describe("Stop after vote stage (no implementation)"),
46557
+ dryRun: z100.boolean().default(false).describe("Stop after vote stage (no implementation)"),
45990
46558
  /** TESTS ONLY — random output, must not be used for real decisions. (#2319) */
45991
- simulateVotes: z98.boolean().default(false).describe("TESTS ONLY \u2014 random output, must not be used for real decisions (#2319)")
46559
+ simulateVotes: z100.boolean().default(false).describe("TESTS ONLY \u2014 random output, must not be used for real decisions (#2319)")
45992
46560
  });
45993
46561
  function buildOutput2(result) {
45994
46562
  return {
@@ -46090,7 +46658,7 @@ function registerPipelineTool(server, deps) {
46090
46658
  }
46091
46659
 
46092
46660
  // src/mcp/tools/supply-chain-tradeoff-panel.ts
46093
- import { z as z99 } from "zod";
46661
+ import { z as z101 } from "zod";
46094
46662
  var DEFAULT_AXES = [
46095
46663
  "build_time_determinism",
46096
46664
  "supply_chain_risk",
@@ -46110,16 +46678,16 @@ var FULL_PANEL = [
46110
46678
  "scope_steward"
46111
46679
  ];
46112
46680
  var QUICK_PANEL = ["architect", "security", "scope_steward"];
46113
- var SupplyChainTradeoffPanelInputSchema = z99.object({
46114
- proposal: z99.string().min(1).max(MAX_PROPOSAL_LENGTH).describe('The proposal under tradeoff review (e.g. "Should aegis-boot adopt cargo-nextest?")'),
46115
- axes: z99.array(z99.string().min(1).max(MAX_AXIS_NAME_LENGTH)).min(1).max(MAX_AXES).optional().describe(
46681
+ var SupplyChainTradeoffPanelInputSchema = z101.object({
46682
+ proposal: z101.string().min(1).max(MAX_PROPOSAL_LENGTH).describe('The proposal under tradeoff review (e.g. "Should aegis-boot adopt cargo-nextest?")'),
46683
+ axes: z101.array(z101.string().min(1).max(MAX_AXIS_NAME_LENGTH)).min(1).max(MAX_AXES).optional().describe(
46116
46684
  `Tradeoff axes to evaluate. Default: ${DEFAULT_AXES.join(", ")}. Custom axes accepted; max ${String(MAX_AXES)}.`
46117
46685
  ),
46118
- context: z99.string().max(MAX_CONTEXT_LENGTH).optional().describe(
46686
+ context: z101.string().max(MAX_CONTEXT_LENGTH).optional().describe(
46119
46687
  "Optional context: relevant repo state, dependency tree, vendor publishing patterns, etc."
46120
46688
  ),
46121
- quickMode: z99.boolean().optional().default(false).describe("Use 3 voters (architect, security, scope_steward) instead of 7"),
46122
- simulate: z99.boolean().optional().default(false).describe("Use simulated voters (testing only)")
46689
+ quickMode: z101.boolean().optional().default(false).describe("Use 3 voters (architect, security, scope_steward) instead of 7"),
46690
+ simulate: z101.boolean().optional().default(false).describe("Use simulated voters (testing only)")
46123
46691
  });
46124
46692
  function buildTradeoffProposal(input) {
46125
46693
  const axes = input.axes ?? DEFAULT_AXES;
@@ -46755,6 +47323,36 @@ var TOOL_ANNOTATIONS = {
46755
47323
  { category: "implicit", description: "Reads the structured task-state log (#2278)" }
46756
47324
  ]
46757
47325
  },
47326
+ get_job_result: {
47327
+ annotations: {
47328
+ title: "Get Job Result",
47329
+ readOnlyHint: true,
47330
+ destructiveHint: false,
47331
+ idempotentHint: true,
47332
+ openWorldHint: false
47333
+ },
47334
+ sideEffects: [
47335
+ {
47336
+ category: "implicit",
47337
+ description: "Reads the async-mode job-result sidecar (#3042 / epic #2631)"
47338
+ }
47339
+ ]
47340
+ },
47341
+ list_jobs: {
47342
+ annotations: {
47343
+ title: "List Jobs",
47344
+ readOnlyHint: true,
47345
+ destructiveHint: false,
47346
+ idempotentHint: true,
47347
+ openWorldHint: false
47348
+ },
47349
+ sideEffects: [
47350
+ {
47351
+ category: "implicit",
47352
+ description: "Lists async-mode job summaries from the sidecar dir (#3046 / epic #2631 Stage 5)"
47353
+ }
47354
+ ]
47355
+ },
46758
47356
  verify_audit_chain: {
46759
47357
  annotations: {
46760
47358
  title: "Verify Audit Chain",
@@ -46971,6 +47569,8 @@ var REGISTERED_TOOL_NAMES = [
46971
47569
  "registry_import",
46972
47570
  "query_trace",
46973
47571
  "query_task_state",
47572
+ "get_job_result",
47573
+ "list_jobs",
46974
47574
  "verify_audit_chain",
46975
47575
  "repo_analyze",
46976
47576
  "repo_security_plan",
@@ -47115,40 +47715,40 @@ var RiskLevel = /* @__PURE__ */ ((RiskLevel2) => {
47115
47715
  })(RiskLevel || {});
47116
47716
 
47117
47717
  // src/mcp/safety/stpa-schemas.ts
47118
- import { z as z100 } from "zod";
47119
- var HazardCategorySchema = z100.enum(HazardCategory);
47120
- var HazardSeveritySchema = z100.enum(HazardSeverity);
47121
- var ConstraintPrioritySchema = z100.enum(ConstraintPriority);
47122
- var RiskLevelSchema = z100.enum(RiskLevel);
47123
- var TriggerPatternSchema = z100.object({
47124
- parameter: z100.string().min(1),
47125
- matchType: z100.enum(["contains", "regex", "equals", "startsWith", "endsWith"]),
47126
- pattern: z100.string(),
47127
- reason: z100.string()
47718
+ import { z as z102 } from "zod";
47719
+ var HazardCategorySchema = z102.enum(HazardCategory);
47720
+ var HazardSeveritySchema = z102.enum(HazardSeverity);
47721
+ var ConstraintPrioritySchema = z102.enum(ConstraintPriority);
47722
+ var RiskLevelSchema = z102.enum(RiskLevel);
47723
+ var TriggerPatternSchema = z102.object({
47724
+ parameter: z102.string().min(1),
47725
+ matchType: z102.enum(["contains", "regex", "equals", "startsWith", "endsWith"]),
47726
+ pattern: z102.string(),
47727
+ reason: z102.string()
47128
47728
  });
47129
- var HazardSchema = z100.object({
47130
- id: z100.string().min(1),
47131
- description: z100.string(),
47729
+ var HazardSchema = z102.object({
47730
+ id: z102.string().min(1),
47731
+ description: z102.string(),
47132
47732
  category: HazardCategorySchema,
47133
47733
  severity: HazardSeveritySchema,
47134
- likelihood: z100.enum(["almost_certain", "likely", "possible", "unlikely", "rare"]),
47135
- triggerConditions: z100.array(z100.string()),
47136
- consequences: z100.array(z100.string())
47734
+ likelihood: z102.enum(["almost_certain", "likely", "possible", "unlikely", "rare"]),
47735
+ triggerConditions: z102.array(z102.string()),
47736
+ consequences: z102.array(z102.string())
47137
47737
  });
47138
- var UnsafeControlActionSchema = z100.object({
47139
- id: z100.string().min(1),
47140
- toolName: z100.string().min(1),
47141
- type: z100.enum(["not_provided", "provided_causes_hazard", "wrong_timing", "wrong_duration"]),
47142
- description: z100.string(),
47143
- unsafeContext: z100.string(),
47144
- relatedHazards: z100.array(z100.string()),
47145
- triggerPatterns: z100.array(TriggerPatternSchema).optional()
47738
+ var UnsafeControlActionSchema = z102.object({
47739
+ id: z102.string().min(1),
47740
+ toolName: z102.string().min(1),
47741
+ type: z102.enum(["not_provided", "provided_causes_hazard", "wrong_timing", "wrong_duration"]),
47742
+ description: z102.string(),
47743
+ unsafeContext: z102.string(),
47744
+ relatedHazards: z102.array(z102.string()),
47745
+ triggerPatterns: z102.array(TriggerPatternSchema).optional()
47146
47746
  });
47147
- var SafetyConstraintSchema = z100.object({
47148
- id: z100.string().min(1),
47149
- description: z100.string(),
47150
- mitigates: z100.array(z100.string()),
47151
- enforcement: z100.enum([
47747
+ var SafetyConstraintSchema = z102.object({
47748
+ id: z102.string().min(1),
47749
+ description: z102.string(),
47750
+ mitigates: z102.array(z102.string()),
47751
+ enforcement: z102.enum([
47152
47752
  "prevent",
47153
47753
  "require_confirmation",
47154
47754
  "alert",
@@ -47156,54 +47756,54 @@ var SafetyConstraintSchema = z100.object({
47156
47756
  "rate_limit",
47157
47757
  "require_privilege"
47158
47758
  ]),
47159
- validationFunction: z100.string().optional(),
47759
+ validationFunction: z102.string().optional(),
47160
47760
  priority: ConstraintPrioritySchema
47161
47761
  });
47162
- var PropertySchemaSchema = z100.object({
47163
- type: z100.string(),
47164
- description: z100.string().optional(),
47165
- enum: z100.array(z100.unknown()).optional(),
47166
- pattern: z100.string().optional(),
47167
- minimum: z100.number().optional(),
47168
- maximum: z100.number().optional()
47762
+ var PropertySchemaSchema = z102.object({
47763
+ type: z102.string(),
47764
+ description: z102.string().optional(),
47765
+ enum: z102.array(z102.unknown()).optional(),
47766
+ pattern: z102.string().optional(),
47767
+ minimum: z102.number().optional(),
47768
+ maximum: z102.number().optional()
47169
47769
  });
47170
- var ToolInputSchemaSchema = z100.object({
47171
- type: z100.string(),
47172
- properties: z100.record(z100.string(), PropertySchemaSchema).optional(),
47173
- required: z100.array(z100.string()).optional(),
47174
- additionalProperties: z100.boolean().optional()
47770
+ var ToolInputSchemaSchema = z102.object({
47771
+ type: z102.string(),
47772
+ properties: z102.record(z102.string(), PropertySchemaSchema).optional(),
47773
+ required: z102.array(z102.string()).optional(),
47774
+ additionalProperties: z102.boolean().optional()
47175
47775
  });
47176
- var ToolDefinitionSchema = z100.object({
47177
- name: z100.string().min(1),
47178
- description: z100.string(),
47776
+ var ToolDefinitionSchema = z102.object({
47777
+ name: z102.string().min(1),
47778
+ description: z102.string(),
47179
47779
  inputSchema: ToolInputSchemaSchema
47180
47780
  });
47181
- var AnalysisConfigurationSchema = z100.object({
47182
- includeLowSeverity: z100.boolean().default(true),
47183
- generateAllConstraints: z100.boolean().default(true),
47184
- checkInteractions: z100.boolean().default(true),
47185
- maxHazardsPerTool: z100.number().int().min(1).max(100).default(50),
47186
- categories: z100.array(HazardCategorySchema).default([])
47781
+ var AnalysisConfigurationSchema = z102.object({
47782
+ includeLowSeverity: z102.boolean().default(true),
47783
+ generateAllConstraints: z102.boolean().default(true),
47784
+ checkInteractions: z102.boolean().default(true),
47785
+ maxHazardsPerTool: z102.number().int().min(1).max(100).default(50),
47786
+ categories: z102.array(HazardCategorySchema).default([])
47187
47787
  });
47188
- var ConstraintViolationSchema = z100.object({
47189
- constraintId: z100.string().min(1),
47190
- constraintDescription: z100.string(),
47788
+ var ConstraintViolationSchema = z102.object({
47789
+ constraintId: z102.string().min(1),
47790
+ constraintDescription: z102.string(),
47191
47791
  severity: HazardSeveritySchema,
47192
- details: z100.string(),
47193
- remediation: z100.string()
47792
+ details: z102.string(),
47793
+ remediation: z102.string()
47194
47794
  });
47195
- var ValidationWarningSchema = z100.object({
47196
- code: z100.string().min(1),
47197
- message: z100.string(),
47198
- affected: z100.string()
47795
+ var ValidationWarningSchema = z102.object({
47796
+ code: z102.string().min(1),
47797
+ message: z102.string(),
47798
+ affected: z102.string()
47199
47799
  });
47200
- var ValidationResultSchema = z100.object({
47201
- valid: z100.boolean(),
47202
- toolName: z100.string().min(1),
47203
- violations: z100.array(ConstraintViolationSchema),
47204
- passed: z100.array(z100.string()),
47205
- warnings: z100.array(ValidationWarningSchema),
47206
- validatedAt: z100.date()
47800
+ var ValidationResultSchema = z102.object({
47801
+ valid: z102.boolean(),
47802
+ toolName: z102.string().min(1),
47803
+ violations: z102.array(ConstraintViolationSchema),
47804
+ passed: z102.array(z102.string()),
47805
+ warnings: z102.array(ValidationWarningSchema),
47806
+ validatedAt: z102.date()
47207
47807
  });
47208
47808
 
47209
47809
  // src/mcp/safety/stpa-types.ts
@@ -48288,43 +48888,43 @@ var GeminiResponseParser = class {
48288
48888
  };
48289
48889
 
48290
48890
  // src/cli-adapters/router-types.ts
48291
- import { z as z101 } from "zod";
48292
- var RouterConfigSchema = z101.object({
48293
- minCapacityThreshold: z101.number().min(0).max(1).default(0.1),
48294
- preferCostEfficient: z101.boolean().default(false),
48295
- maxDecisionTimeMs: z101.number().min(1).max(1e3).default(100)
48891
+ import { z as z103 } from "zod";
48892
+ var RouterConfigSchema = z103.object({
48893
+ minCapacityThreshold: z103.number().min(0).max(1).default(0.1),
48894
+ preferCostEfficient: z103.boolean().default(false),
48895
+ maxDecisionTimeMs: z103.number().min(1).max(1e3).default(100)
48296
48896
  });
48297
48897
 
48298
48898
  // src/cli-adapters/agreement-cascade-types.ts
48299
- import { z as z102 } from "zod";
48300
- var AgreementCascadeConfigSchema = z102.object({
48301
- agreementThreshold: z102.number().min(0.5).max(1).default(0.7),
48302
- maxStages: z102.number().int().min(1).max(5).default(3),
48303
- modelTimeoutMs: z102.number().int().min(1e3).max(3e5).default(6e4)
48899
+ import { z as z104 } from "zod";
48900
+ var AgreementCascadeConfigSchema = z104.object({
48901
+ agreementThreshold: z104.number().min(0.5).max(1).default(0.7),
48902
+ maxStages: z104.number().int().min(1).max(5).default(3),
48903
+ modelTimeoutMs: z104.number().int().min(1e3).max(3e5).default(6e4)
48304
48904
  });
48305
48905
 
48306
48906
  // src/cli-adapters/agreement-cascade-router.ts
48307
48907
  var logger43 = createLogger({ component: "agreement-cascade-router" });
48308
48908
 
48309
48909
  // src/cli-adapters/task-classifier.ts
48310
- import { z as z103 } from "zod";
48311
- var ClassificationPatternsSchema = z103.object({
48312
- code: z103.array(z103.string()).readonly(),
48313
- research: z103.array(z103.string()).readonly(),
48314
- documentation: z103.array(z103.string()).readonly(),
48315
- analysis: z103.array(z103.string()).readonly()
48910
+ import { z as z105 } from "zod";
48911
+ var ClassificationPatternsSchema = z105.object({
48912
+ code: z105.array(z105.string()).readonly(),
48913
+ research: z105.array(z105.string()).readonly(),
48914
+ documentation: z105.array(z105.string()).readonly(),
48915
+ analysis: z105.array(z105.string()).readonly()
48316
48916
  });
48317
48917
 
48318
48918
  // src/cli-adapters/response-cache-types.ts
48319
- import { z as z104 } from "zod";
48320
- var ResponseCacheConfigSchema = z104.object({
48321
- defaultTTL: z104.number().min(1e3).max(36e5).default(3e5),
48919
+ import { z as z106 } from "zod";
48920
+ var ResponseCacheConfigSchema = z106.object({
48921
+ defaultTTL: z106.number().min(1e3).max(36e5).default(3e5),
48322
48922
  // 5 minutes
48323
- maxEntries: z104.number().min(10).max(1e5).default(1e3),
48324
- maxMemoryMB: z104.number().min(1).max(1e3).default(50),
48325
- cleanupInterval: z104.number().min(1e3).max(6e5).default(6e4),
48923
+ maxEntries: z106.number().min(10).max(1e5).default(1e3),
48924
+ maxMemoryMB: z106.number().min(1).max(1e3).default(50),
48925
+ cleanupInterval: z106.number().min(1e3).max(6e5).default(6e4),
48326
48926
  // 1 minute
48327
- enableLogging: z104.boolean().default(false)
48927
+ enableLogging: z106.boolean().default(false)
48328
48928
  });
48329
48929
 
48330
48930
  // src/cli-adapters/response-cache-utils.ts
@@ -48332,12 +48932,12 @@ import { createHash as createHash4 } from "crypto";
48332
48932
  var logger44 = createLogger({ component: "ResponseCacheUtils" });
48333
48933
 
48334
48934
  // src/cli-adapters/unified-routing-types.ts
48335
- import { z as z105 } from "zod";
48336
- var UnifiedRoutingDecisionSchema = z105.object({
48337
- selectedCli: z105.string(),
48338
- confidence: z105.number().min(0).max(1),
48339
- reason: z105.string(),
48340
- strategy: z105.enum([
48935
+ import { z as z107 } from "zod";
48936
+ var UnifiedRoutingDecisionSchema = z107.object({
48937
+ selectedCli: z107.string(),
48938
+ confidence: z107.number().min(0).max(1),
48939
+ reason: z107.string(),
48940
+ strategy: z107.enum([
48341
48941
  "composite",
48342
48942
  "quality",
48343
48943
  "budget",
@@ -48349,57 +48949,57 @@ var UnifiedRoutingDecisionSchema = z105.object({
48349
48949
  "linucb",
48350
48950
  "direct"
48351
48951
  ]),
48352
- decisionTimeMs: z105.number().nonnegative(),
48353
- alternatives: z105.array(z105.string()).readonly(),
48354
- stagesExecuted: z105.array(z105.string()).readonly(),
48355
- withinBudget: z105.boolean().optional(),
48356
- estimatedComplexity: z105.enum(["simple", "moderate", "complex", "expert"]).optional(),
48357
- estimatedTokens: z105.number().int().positive().optional(),
48358
- topsisScore: z105.number().optional(),
48359
- ucbScore: z105.number().optional(),
48360
- resolvedAtStage: z105.number().int().nonnegative().optional(),
48361
- consensusReached: z105.boolean().optional(),
48362
- agreementScore: z105.number().min(0).max(1).optional(),
48363
- metadata: z105.record(z105.string(), z105.unknown()).optional()
48952
+ decisionTimeMs: z107.number().nonnegative(),
48953
+ alternatives: z107.array(z107.string()).readonly(),
48954
+ stagesExecuted: z107.array(z107.string()).readonly(),
48955
+ withinBudget: z107.boolean().optional(),
48956
+ estimatedComplexity: z107.enum(["simple", "moderate", "complex", "expert"]).optional(),
48957
+ estimatedTokens: z107.number().int().positive().optional(),
48958
+ topsisScore: z107.number().optional(),
48959
+ ucbScore: z107.number().optional(),
48960
+ resolvedAtStage: z107.number().int().nonnegative().optional(),
48961
+ consensusReached: z107.boolean().optional(),
48962
+ agreementScore: z107.number().min(0).max(1).optional(),
48963
+ metadata: z107.record(z107.string(), z107.unknown()).optional()
48364
48964
  });
48365
48965
 
48366
48966
  // src/learning/outcome-feedback-types.ts
48367
- import { z as z106 } from "zod";
48368
- var QualitySignalsSchema = z106.object({
48369
- testsPass: z106.boolean().optional(),
48370
- lintErrors: z106.number().int().min(0).optional(),
48371
- userApproved: z106.boolean().optional(),
48372
- retryCount: z106.number().int().min(0).default(0),
48373
- completionRatio: z106.number().min(0).max(1).default(1),
48374
- validStructure: z106.boolean().optional(),
48375
- coherenceScore: z106.number().min(0).max(1).optional()
48967
+ import { z as z108 } from "zod";
48968
+ var QualitySignalsSchema = z108.object({
48969
+ testsPass: z108.boolean().optional(),
48970
+ lintErrors: z108.number().int().min(0).optional(),
48971
+ userApproved: z108.boolean().optional(),
48972
+ retryCount: z108.number().int().min(0).default(0),
48973
+ completionRatio: z108.number().min(0).max(1).default(1),
48974
+ validStructure: z108.boolean().optional(),
48975
+ coherenceScore: z108.number().min(0).max(1).optional()
48376
48976
  });
48377
- var RoutingDecisionSchema = z106.object({
48378
- id: z106.uuid(),
48379
- timestamp: z106.iso.datetime(),
48380
- query: z106.string(),
48381
- routerType: z106.enum(["linucb", "preference", "quality", "cascade", "topsis"]),
48382
- selectedModel: z106.string(),
48383
- selectedTier: z106.enum(["strong", "weak"]).optional(),
48384
- armIndex: z106.number().int().min(0).optional(),
48385
- banditContext: z106.record(z106.string(), z106.unknown()).optional(),
48386
- queryFeatures: z106.record(z106.string(), z106.unknown()).optional(),
48387
- ucbScore: z106.number().optional(),
48388
- confidence: z106.number().min(0).max(1).optional(),
48389
- traceId: z106.string(),
48390
- domain: z106.string().optional()
48977
+ var RoutingDecisionSchema = z108.object({
48978
+ id: z108.uuid(),
48979
+ timestamp: z108.iso.datetime(),
48980
+ query: z108.string(),
48981
+ routerType: z108.enum(["linucb", "preference", "quality", "cascade", "topsis"]),
48982
+ selectedModel: z108.string(),
48983
+ selectedTier: z108.enum(["strong", "weak"]).optional(),
48984
+ armIndex: z108.number().int().min(0).optional(),
48985
+ banditContext: z108.record(z108.string(), z108.unknown()).optional(),
48986
+ queryFeatures: z108.record(z108.string(), z108.unknown()).optional(),
48987
+ ucbScore: z108.number().optional(),
48988
+ confidence: z108.number().min(0).max(1).optional(),
48989
+ traceId: z108.string(),
48990
+ domain: z108.string().optional()
48391
48991
  });
48392
- var TaskOutcomeSchema = z106.object({
48393
- routingDecisionId: z106.uuid(),
48394
- timestamp: z106.iso.datetime(),
48395
- outcomeClass: z106.enum(["success", "partial", "failure", "timeout", "error"]),
48396
- success: z106.boolean(),
48397
- qualityScore: z106.number().min(0).max(1),
48398
- durationMs: z106.number().min(0),
48399
- tokenUsage: z106.number().int().min(0),
48400
- errorMessage: z106.string().optional(),
48992
+ var TaskOutcomeSchema = z108.object({
48993
+ routingDecisionId: z108.uuid(),
48994
+ timestamp: z108.iso.datetime(),
48995
+ outcomeClass: z108.enum(["success", "partial", "failure", "timeout", "error"]),
48996
+ success: z108.boolean(),
48997
+ qualityScore: z108.number().min(0).max(1),
48998
+ durationMs: z108.number().min(0),
48999
+ tokenUsage: z108.number().int().min(0),
49000
+ errorMessage: z108.string().optional(),
48401
49001
  qualitySignals: QualitySignalsSchema,
48402
- traceId: z106.string()
49002
+ traceId: z108.string()
48403
49003
  });
48404
49004
  var DEFAULT_FEEDBACK_COLLECTOR_CONFIG = {
48405
49005
  maxPendingDecisions: 1e3,
@@ -48414,21 +49014,21 @@ var DEFAULT_FEEDBACK_COLLECTOR_CONFIG = {
48414
49014
  targetTokenUsage: 2e3,
48415
49015
  maxHistorySize: 1e4
48416
49016
  };
48417
- var FeedbackCollectorConfigSchema = z106.object({
48418
- maxPendingDecisions: z106.number().int().positive().default(1e3),
48419
- pendingTimeoutMs: z106.number().positive().default(3e5),
48420
- enableAutoReward: z106.boolean().default(true),
48421
- qualityWeight: z106.number().min(0).max(1).default(0.5),
48422
- speedWeight: z106.number().min(0).max(1).default(0.2),
48423
- efficiencyWeight: z106.number().min(0).max(1).default(0.2),
48424
- retryPenalty: z106.number().min(0).max(1).default(0.1),
48425
- targetDurationMs: z106.number().positive().default(5e3),
48426
- targetTokenUsage: z106.number().positive().default(2e3),
48427
- maxHistorySize: z106.number().int().positive().default(1e4)
49017
+ var FeedbackCollectorConfigSchema = z108.object({
49018
+ maxPendingDecisions: z108.number().int().positive().default(1e3),
49019
+ pendingTimeoutMs: z108.number().positive().default(3e5),
49020
+ enableAutoReward: z108.boolean().default(true),
49021
+ qualityWeight: z108.number().min(0).max(1).default(0.5),
49022
+ speedWeight: z108.number().min(0).max(1).default(0.2),
49023
+ efficiencyWeight: z108.number().min(0).max(1).default(0.2),
49024
+ retryPenalty: z108.number().min(0).max(1).default(0.1),
49025
+ targetDurationMs: z108.number().positive().default(5e3),
49026
+ targetTokenUsage: z108.number().positive().default(2e3),
49027
+ maxHistorySize: z108.number().int().positive().default(1e4)
48428
49028
  });
48429
49029
 
48430
49030
  // src/learning/outcome-feedback-helpers.ts
48431
- import { randomUUID as randomUUID10 } from "crypto";
49031
+ import { randomUUID as randomUUID12 } from "crypto";
48432
49032
  function countOutcomesByClass(outcomes) {
48433
49033
  const counts = {
48434
49034
  success: 0,
@@ -48481,7 +49081,7 @@ function generateRewardExplanation(outcome, reward) {
48481
49081
  }
48482
49082
  function createRoutingDecision(params) {
48483
49083
  return {
48484
- id: randomUUID10(),
49084
+ id: randomUUID12(),
48485
49085
  timestamp: getTimeProvider().nowIso(),
48486
49086
  ...params
48487
49087
  };
@@ -48737,7 +49337,7 @@ var DEFAULT_FEEDBACK_INTEGRATION_CONFIG = {
48737
49337
  };
48738
49338
 
48739
49339
  // src/learning/feedback-integration.ts
48740
- import { randomUUID as randomUUID11 } from "crypto";
49340
+ import { randomUUID as randomUUID13 } from "crypto";
48741
49341
  var STEP_QUALITY_SCORING = {
48742
49342
  /** Base score for successful steps. */
48743
49343
  successBase: 0.8,
@@ -48813,8 +49413,8 @@ var FeedbackIntegration = class {
48813
49413
  });
48814
49414
  }
48815
49415
  recordRoutingDecision(decision, traceId) {
48816
- const id = randomUUID11();
48817
- const trace = traceId ?? randomUUID11();
49416
+ const id = randomUUID13();
49417
+ const trace = traceId ?? randomUUID13();
48818
49418
  const now = getTimeProvider().now();
48819
49419
  this.evictStaleEntriesThrottled(now);
48820
49420
  if (this.decisionMap.size >= MAX_DECISION_MAP_SIZE) {
@@ -48887,7 +49487,7 @@ var FeedbackIntegration = class {
48887
49487
  } = params;
48888
49488
  const outcomeClass = this.determineOutcomeClass(success, qualityScore);
48889
49489
  const completionRatio = success ? 1 : qualityScore / this.config.successQualityThreshold;
48890
- const trace = traceId ?? randomUUID11();
49490
+ const trace = traceId ?? randomUUID13();
48891
49491
  const outcome = {
48892
49492
  routingDecisionId,
48893
49493
  timestamp: getTimeProvider().nowIso(),
@@ -50041,7 +50641,7 @@ var GitHubTaskTracker = class {
50041
50641
  cachedProvider = null;
50042
50642
  async getProvider() {
50043
50643
  if (this.cachedProvider !== null) return this.cachedProvider;
50044
- const { createScmProvider } = await import("./factory-3XB5CAAA.js");
50644
+ const { createScmProvider } = await import("./factory-JNXETBS4.js");
50045
50645
  const result = await createScmProvider({ repo: this.config.repo ?? "" });
50046
50646
  if (!result.ok) throw new Error(`SCM provider error: ${result.error.message}`);
50047
50647
  this.cachedProvider = result.value;
@@ -50668,6 +51268,8 @@ export {
50668
51268
  QueryTraceInputSchema,
50669
51269
  registerQueryTraceTool,
50670
51270
  registerQueryTaskStateTool,
51271
+ registerGetJobResultTool,
51272
+ registerListJobsTool,
50671
51273
  AuditError,
50672
51274
  AuditCategorySchema,
50673
51275
  AuditSeveritySchema,
@@ -50751,4 +51353,4 @@ export {
50751
51353
  detectBackend,
50752
51354
  createTaskTracker
50753
51355
  };
50754
- //# sourceMappingURL=chunk-J4ZBKE4B.js.map
51356
+ //# sourceMappingURL=chunk-6KZL5DMU.js.map