@mcoda/mswarm 0.1.56 → 0.1.60

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 (250) hide show
  1. package/README.md +20 -1
  2. package/dist/codali-executor.d.ts +266 -0
  3. package/dist/codali-executor.d.ts.map +1 -0
  4. package/dist/codali-executor.js +227 -0
  5. package/dist/codali-executor.js.map +1 -0
  6. package/dist/runtime.d.ts +47 -1
  7. package/dist/runtime.d.ts.map +1 -1
  8. package/dist/runtime.js +248 -30
  9. package/dist/runtime.js.map +1 -1
  10. package/dist/server.d.ts.map +1 -1
  11. package/dist/server.js +83 -3
  12. package/dist/server.js.map +1 -1
  13. package/dist/vendor/codali/agents/AgentProtocol.d.ts +287 -0
  14. package/dist/vendor/codali/agents/AgentProtocol.d.ts.map +1 -0
  15. package/dist/vendor/codali/agents/AgentProtocol.js +365 -0
  16. package/dist/vendor/codali/agents/AgentResolver.d.ts +23 -0
  17. package/dist/vendor/codali/agents/AgentResolver.d.ts.map +1 -0
  18. package/dist/vendor/codali/agents/AgentResolver.js +77 -0
  19. package/dist/vendor/codali/agents/PhaseAgentSelector.d.ts +23 -0
  20. package/dist/vendor/codali/agents/PhaseAgentSelector.d.ts.map +1 -0
  21. package/dist/vendor/codali/agents/PhaseAgentSelector.js +287 -0
  22. package/dist/vendor/codali/cli/EvalCommand.d.ts +37 -0
  23. package/dist/vendor/codali/cli/EvalCommand.d.ts.map +1 -0
  24. package/dist/vendor/codali/cli/EvalCommand.js +333 -0
  25. package/dist/vendor/codali/cli/FeedbackCommand.d.ts +22 -0
  26. package/dist/vendor/codali/cli/FeedbackCommand.d.ts.map +1 -0
  27. package/dist/vendor/codali/cli/FeedbackCommand.js +163 -0
  28. package/dist/vendor/codali/cli/RunCommand.d.ts +78 -0
  29. package/dist/vendor/codali/cli/RunCommand.d.ts.map +1 -0
  30. package/dist/vendor/codali/cli/RunCommand.js +2261 -0
  31. package/dist/vendor/codali/cli.d.ts +3 -0
  32. package/dist/vendor/codali/cli.d.ts.map +1 -0
  33. package/dist/vendor/codali/cli.js +109 -0
  34. package/dist/vendor/codali/cognitive/ArchitectPlanner.d.ts +107 -0
  35. package/dist/vendor/codali/cognitive/ArchitectPlanner.d.ts.map +1 -0
  36. package/dist/vendor/codali/cognitive/ArchitectPlanner.js +1726 -0
  37. package/dist/vendor/codali/cognitive/BuilderOutputParser.d.ts +25 -0
  38. package/dist/vendor/codali/cognitive/BuilderOutputParser.d.ts.map +1 -0
  39. package/dist/vendor/codali/cognitive/BuilderOutputParser.js +164 -0
  40. package/dist/vendor/codali/cognitive/BuilderRunner.d.ts +76 -0
  41. package/dist/vendor/codali/cognitive/BuilderRunner.d.ts.map +1 -0
  42. package/dist/vendor/codali/cognitive/BuilderRunner.js +1159 -0
  43. package/dist/vendor/codali/cognitive/ContextAssembler.d.ts +91 -0
  44. package/dist/vendor/codali/cognitive/ContextAssembler.d.ts.map +1 -0
  45. package/dist/vendor/codali/cognitive/ContextAssembler.js +4547 -0
  46. package/dist/vendor/codali/cognitive/ContextBudget.d.ts +19 -0
  47. package/dist/vendor/codali/cognitive/ContextBudget.d.ts.map +1 -0
  48. package/dist/vendor/codali/cognitive/ContextBudget.js +35 -0
  49. package/dist/vendor/codali/cognitive/ContextFileLoader.d.ts +30 -0
  50. package/dist/vendor/codali/cognitive/ContextFileLoader.d.ts.map +1 -0
  51. package/dist/vendor/codali/cognitive/ContextFileLoader.js +307 -0
  52. package/dist/vendor/codali/cognitive/ContextManager.d.ts +47 -0
  53. package/dist/vendor/codali/cognitive/ContextManager.d.ts.map +1 -0
  54. package/dist/vendor/codali/cognitive/ContextManager.js +272 -0
  55. package/dist/vendor/codali/cognitive/ContextRedactor.d.ts +18 -0
  56. package/dist/vendor/codali/cognitive/ContextRedactor.d.ts.map +1 -0
  57. package/dist/vendor/codali/cognitive/ContextRedactor.js +53 -0
  58. package/dist/vendor/codali/cognitive/ContextSelector.d.ts +22 -0
  59. package/dist/vendor/codali/cognitive/ContextSelector.d.ts.map +1 -0
  60. package/dist/vendor/codali/cognitive/ContextSelector.js +431 -0
  61. package/dist/vendor/codali/cognitive/ContextSerializer.d.ts +8 -0
  62. package/dist/vendor/codali/cognitive/ContextSerializer.d.ts.map +1 -0
  63. package/dist/vendor/codali/cognitive/ContextSerializer.js +882 -0
  64. package/dist/vendor/codali/cognitive/ContextStore.d.ts +27 -0
  65. package/dist/vendor/codali/cognitive/ContextStore.d.ts.map +1 -0
  66. package/dist/vendor/codali/cognitive/ContextStore.js +79 -0
  67. package/dist/vendor/codali/cognitive/ContextSummarizer.d.ts +16 -0
  68. package/dist/vendor/codali/cognitive/ContextSummarizer.d.ts.map +1 -0
  69. package/dist/vendor/codali/cognitive/ContextSummarizer.js +45 -0
  70. package/dist/vendor/codali/cognitive/CostEstimator.d.ts +31 -0
  71. package/dist/vendor/codali/cognitive/CostEstimator.d.ts.map +1 -0
  72. package/dist/vendor/codali/cognitive/CostEstimator.js +66 -0
  73. package/dist/vendor/codali/cognitive/CriticEvaluator.d.ts +32 -0
  74. package/dist/vendor/codali/cognitive/CriticEvaluator.d.ts.map +1 -0
  75. package/dist/vendor/codali/cognitive/CriticEvaluator.js +297 -0
  76. package/dist/vendor/codali/cognitive/EvidenceGate.d.ts +9 -0
  77. package/dist/vendor/codali/cognitive/EvidenceGate.d.ts.map +1 -0
  78. package/dist/vendor/codali/cognitive/EvidenceGate.js +75 -0
  79. package/dist/vendor/codali/cognitive/GoldenExampleIndexer.d.ts +12 -0
  80. package/dist/vendor/codali/cognitive/GoldenExampleIndexer.d.ts.map +1 -0
  81. package/dist/vendor/codali/cognitive/GoldenExampleIndexer.js +34 -0
  82. package/dist/vendor/codali/cognitive/GoldenSetStore.d.ts +33 -0
  83. package/dist/vendor/codali/cognitive/GoldenSetStore.d.ts.map +1 -0
  84. package/dist/vendor/codali/cognitive/GoldenSetStore.js +159 -0
  85. package/dist/vendor/codali/cognitive/IntentSignals.d.ts +7 -0
  86. package/dist/vendor/codali/cognitive/IntentSignals.d.ts.map +1 -0
  87. package/dist/vendor/codali/cognitive/IntentSignals.js +285 -0
  88. package/dist/vendor/codali/cognitive/LearningGovernance.d.ts +100 -0
  89. package/dist/vendor/codali/cognitive/LearningGovernance.d.ts.map +1 -0
  90. package/dist/vendor/codali/cognitive/LearningGovernance.js +276 -0
  91. package/dist/vendor/codali/cognitive/MemoryWriteback.d.ts +64 -0
  92. package/dist/vendor/codali/cognitive/MemoryWriteback.d.ts.map +1 -0
  93. package/dist/vendor/codali/cognitive/MemoryWriteback.js +287 -0
  94. package/dist/vendor/codali/cognitive/PatchApplier.d.ts +49 -0
  95. package/dist/vendor/codali/cognitive/PatchApplier.d.ts.map +1 -0
  96. package/dist/vendor/codali/cognitive/PatchApplier.js +199 -0
  97. package/dist/vendor/codali/cognitive/PatchInterpreter.d.ts +35 -0
  98. package/dist/vendor/codali/cognitive/PatchInterpreter.d.ts.map +1 -0
  99. package/dist/vendor/codali/cognitive/PatchInterpreter.js +100 -0
  100. package/dist/vendor/codali/cognitive/PatchOutputNormalizer.d.ts +7 -0
  101. package/dist/vendor/codali/cognitive/PatchOutputNormalizer.d.ts.map +1 -0
  102. package/dist/vendor/codali/cognitive/PatchOutputNormalizer.js +59 -0
  103. package/dist/vendor/codali/cognitive/PostMortemAnalyzer.d.ts +17 -0
  104. package/dist/vendor/codali/cognitive/PostMortemAnalyzer.d.ts.map +1 -0
  105. package/dist/vendor/codali/cognitive/PostMortemAnalyzer.js +131 -0
  106. package/dist/vendor/codali/cognitive/PreferenceExtraction.d.ts +3 -0
  107. package/dist/vendor/codali/cognitive/PreferenceExtraction.d.ts.map +1 -0
  108. package/dist/vendor/codali/cognitive/PreferenceExtraction.js +85 -0
  109. package/dist/vendor/codali/cognitive/Prompts.d.ts +15 -0
  110. package/dist/vendor/codali/cognitive/Prompts.d.ts.map +1 -0
  111. package/dist/vendor/codali/cognitive/Prompts.js +326 -0
  112. package/dist/vendor/codali/cognitive/ProviderRouting.d.ts +16 -0
  113. package/dist/vendor/codali/cognitive/ProviderRouting.d.ts.map +1 -0
  114. package/dist/vendor/codali/cognitive/ProviderRouting.js +24 -0
  115. package/dist/vendor/codali/cognitive/QueryExtraction.d.ts +12 -0
  116. package/dist/vendor/codali/cognitive/QueryExtraction.d.ts.map +1 -0
  117. package/dist/vendor/codali/cognitive/QueryExtraction.js +262 -0
  118. package/dist/vendor/codali/cognitive/RunHistoryIndexer.d.ts +13 -0
  119. package/dist/vendor/codali/cognitive/RunHistoryIndexer.d.ts.map +1 -0
  120. package/dist/vendor/codali/cognitive/RunHistoryIndexer.js +125 -0
  121. package/dist/vendor/codali/cognitive/SmartPipeline.d.ts +92 -0
  122. package/dist/vendor/codali/cognitive/SmartPipeline.d.ts.map +1 -0
  123. package/dist/vendor/codali/cognitive/SmartPipeline.js +4804 -0
  124. package/dist/vendor/codali/cognitive/Types.d.ts +474 -0
  125. package/dist/vendor/codali/cognitive/Types.d.ts.map +1 -0
  126. package/dist/vendor/codali/cognitive/Types.js +7 -0
  127. package/dist/vendor/codali/cognitive/ValidationRunner.d.ts +57 -0
  128. package/dist/vendor/codali/cognitive/ValidationRunner.d.ts.map +1 -0
  129. package/dist/vendor/codali/cognitive/ValidationRunner.js +515 -0
  130. package/dist/vendor/codali/config/Config.d.ts +249 -0
  131. package/dist/vendor/codali/config/Config.d.ts.map +1 -0
  132. package/dist/vendor/codali/config/Config.js +200 -0
  133. package/dist/vendor/codali/config/ConfigLoader.d.ts +56 -0
  134. package/dist/vendor/codali/config/ConfigLoader.d.ts.map +1 -0
  135. package/dist/vendor/codali/config/ConfigLoader.js +1246 -0
  136. package/dist/vendor/codali/docdex/DocdexClient.d.ts +113 -0
  137. package/dist/vendor/codali/docdex/DocdexClient.d.ts.map +1 -0
  138. package/dist/vendor/codali/docdex/DocdexClient.js +524 -0
  139. package/dist/vendor/codali/eval/EvalRunner.d.ts +35 -0
  140. package/dist/vendor/codali/eval/EvalRunner.d.ts.map +1 -0
  141. package/dist/vendor/codali/eval/EvalRunner.js +38 -0
  142. package/dist/vendor/codali/eval/EvalTaskExecutor.d.ts +81 -0
  143. package/dist/vendor/codali/eval/EvalTaskExecutor.d.ts.map +1 -0
  144. package/dist/vendor/codali/eval/EvalTaskExecutor.js +371 -0
  145. package/dist/vendor/codali/eval/GateEvaluator.d.ts +31 -0
  146. package/dist/vendor/codali/eval/GateEvaluator.d.ts.map +1 -0
  147. package/dist/vendor/codali/eval/GateEvaluator.js +134 -0
  148. package/dist/vendor/codali/eval/MetricTypes.d.ts +28 -0
  149. package/dist/vendor/codali/eval/MetricTypes.d.ts.map +1 -0
  150. package/dist/vendor/codali/eval/MetricTypes.js +1 -0
  151. package/dist/vendor/codali/eval/MetricsAggregator.d.ts +4 -0
  152. package/dist/vendor/codali/eval/MetricsAggregator.d.ts.map +1 -0
  153. package/dist/vendor/codali/eval/MetricsAggregator.js +97 -0
  154. package/dist/vendor/codali/eval/RegressionComparator.d.ts +29 -0
  155. package/dist/vendor/codali/eval/RegressionComparator.d.ts.map +1 -0
  156. package/dist/vendor/codali/eval/RegressionComparator.js +155 -0
  157. package/dist/vendor/codali/eval/ReportInputAdapter.d.ts +52 -0
  158. package/dist/vendor/codali/eval/ReportInputAdapter.d.ts.map +1 -0
  159. package/dist/vendor/codali/eval/ReportInputAdapter.js +229 -0
  160. package/dist/vendor/codali/eval/ReportSerializer.d.ts +32 -0
  161. package/dist/vendor/codali/eval/ReportSerializer.d.ts.map +1 -0
  162. package/dist/vendor/codali/eval/ReportSerializer.js +33 -0
  163. package/dist/vendor/codali/eval/ReportStore.d.ts +18 -0
  164. package/dist/vendor/codali/eval/ReportStore.d.ts.map +1 -0
  165. package/dist/vendor/codali/eval/ReportStore.js +96 -0
  166. package/dist/vendor/codali/eval/SuiteLoader.d.ts +12 -0
  167. package/dist/vendor/codali/eval/SuiteLoader.d.ts.map +1 -0
  168. package/dist/vendor/codali/eval/SuiteLoader.js +51 -0
  169. package/dist/vendor/codali/eval/SuiteSchema.d.ts +56 -0
  170. package/dist/vendor/codali/eval/SuiteSchema.d.ts.map +1 -0
  171. package/dist/vendor/codali/eval/SuiteSchema.js +357 -0
  172. package/dist/vendor/codali/index.d.ts +11 -0
  173. package/dist/vendor/codali/index.d.ts.map +1 -0
  174. package/dist/vendor/codali/index.js +5 -0
  175. package/dist/vendor/codali/providers/CodexCliProvider.d.ts +8 -0
  176. package/dist/vendor/codali/providers/CodexCliProvider.d.ts.map +1 -0
  177. package/dist/vendor/codali/providers/CodexCliProvider.js +282 -0
  178. package/dist/vendor/codali/providers/OllamaRemoteProvider.d.ts +8 -0
  179. package/dist/vendor/codali/providers/OllamaRemoteProvider.d.ts.map +1 -0
  180. package/dist/vendor/codali/providers/OllamaRemoteProvider.js +300 -0
  181. package/dist/vendor/codali/providers/OpenAiCompatibleProvider.d.ts +8 -0
  182. package/dist/vendor/codali/providers/OpenAiCompatibleProvider.d.ts.map +1 -0
  183. package/dist/vendor/codali/providers/OpenAiCompatibleProvider.js +192 -0
  184. package/dist/vendor/codali/providers/ProviderRegistry.d.ts +12 -0
  185. package/dist/vendor/codali/providers/ProviderRegistry.d.ts.map +1 -0
  186. package/dist/vendor/codali/providers/ProviderRegistry.js +28 -0
  187. package/dist/vendor/codali/providers/ProviderTypes.d.ts +81 -0
  188. package/dist/vendor/codali/providers/ProviderTypes.d.ts.map +1 -0
  189. package/dist/vendor/codali/providers/ProviderTypes.js +1 -0
  190. package/dist/vendor/codali/runtime/CodaliRuntime.d.ts +183 -0
  191. package/dist/vendor/codali/runtime/CodaliRuntime.d.ts.map +1 -0
  192. package/dist/vendor/codali/runtime/CodaliRuntime.js +1363 -0
  193. package/dist/vendor/codali/runtime/DeepInvestigationErrors.d.ts +39 -0
  194. package/dist/vendor/codali/runtime/DeepInvestigationErrors.d.ts.map +1 -0
  195. package/dist/vendor/codali/runtime/DeepInvestigationErrors.js +57 -0
  196. package/dist/vendor/codali/runtime/RunContext.d.ts +27 -0
  197. package/dist/vendor/codali/runtime/RunContext.d.ts.map +1 -0
  198. package/dist/vendor/codali/runtime/RunContext.js +51 -0
  199. package/dist/vendor/codali/runtime/RunLogQuery.d.ts +48 -0
  200. package/dist/vendor/codali/runtime/RunLogQuery.d.ts.map +1 -0
  201. package/dist/vendor/codali/runtime/RunLogQuery.js +36 -0
  202. package/dist/vendor/codali/runtime/RunLogReader.d.ts +19 -0
  203. package/dist/vendor/codali/runtime/RunLogReader.d.ts.map +1 -0
  204. package/dist/vendor/codali/runtime/RunLogReader.js +361 -0
  205. package/dist/vendor/codali/runtime/RunLogger.d.ts +71 -0
  206. package/dist/vendor/codali/runtime/RunLogger.d.ts.map +1 -0
  207. package/dist/vendor/codali/runtime/RunLogger.js +100 -0
  208. package/dist/vendor/codali/runtime/RunTelemetryTypes.d.ts +117 -0
  209. package/dist/vendor/codali/runtime/RunTelemetryTypes.d.ts.map +1 -0
  210. package/dist/vendor/codali/runtime/RunTelemetryTypes.js +299 -0
  211. package/dist/vendor/codali/runtime/Runner.d.ts +66 -0
  212. package/dist/vendor/codali/runtime/Runner.d.ts.map +1 -0
  213. package/dist/vendor/codali/runtime/Runner.js +215 -0
  214. package/dist/vendor/codali/runtime/StoragePaths.d.ts +3 -0
  215. package/dist/vendor/codali/runtime/StoragePaths.d.ts.map +1 -0
  216. package/dist/vendor/codali/runtime/StoragePaths.js +19 -0
  217. package/dist/vendor/codali/runtime/WorkspaceLock.d.ts +30 -0
  218. package/dist/vendor/codali/runtime/WorkspaceLock.d.ts.map +1 -0
  219. package/dist/vendor/codali/runtime/WorkspaceLock.js +141 -0
  220. package/dist/vendor/codali/session/InstructionLoader.d.ts +14 -0
  221. package/dist/vendor/codali/session/InstructionLoader.d.ts.map +1 -0
  222. package/dist/vendor/codali/session/InstructionLoader.js +107 -0
  223. package/dist/vendor/codali/session/SessionStore.d.ts +81 -0
  224. package/dist/vendor/codali/session/SessionStore.d.ts.map +1 -0
  225. package/dist/vendor/codali/session/SessionStore.js +244 -0
  226. package/dist/vendor/codali/subagents/SubagentOrchestrator.d.ts +68 -0
  227. package/dist/vendor/codali/subagents/SubagentOrchestrator.d.ts.map +1 -0
  228. package/dist/vendor/codali/subagents/SubagentOrchestrator.js +150 -0
  229. package/dist/vendor/codali/tools/ToolRegistry.d.ts +9 -0
  230. package/dist/vendor/codali/tools/ToolRegistry.d.ts.map +1 -0
  231. package/dist/vendor/codali/tools/ToolRegistry.js +263 -0
  232. package/dist/vendor/codali/tools/ToolTypes.d.ts +66 -0
  233. package/dist/vendor/codali/tools/ToolTypes.d.ts.map +1 -0
  234. package/dist/vendor/codali/tools/ToolTypes.js +32 -0
  235. package/dist/vendor/codali/tools/diff/DiffTool.d.ts +3 -0
  236. package/dist/vendor/codali/tools/diff/DiffTool.d.ts.map +1 -0
  237. package/dist/vendor/codali/tools/diff/DiffTool.js +34 -0
  238. package/dist/vendor/codali/tools/docdex/DocdexTools.d.ts +4 -0
  239. package/dist/vendor/codali/tools/docdex/DocdexTools.d.ts.map +1 -0
  240. package/dist/vendor/codali/tools/docdex/DocdexTools.js +453 -0
  241. package/dist/vendor/codali/tools/filesystem/FileTools.d.ts +3 -0
  242. package/dist/vendor/codali/tools/filesystem/FileTools.d.ts.map +1 -0
  243. package/dist/vendor/codali/tools/filesystem/FileTools.js +141 -0
  244. package/dist/vendor/codali/tools/search/SearchTool.d.ts +3 -0
  245. package/dist/vendor/codali/tools/search/SearchTool.d.ts.map +1 -0
  246. package/dist/vendor/codali/tools/search/SearchTool.js +46 -0
  247. package/dist/vendor/codali/tools/shell/ShellTool.d.ts +3 -0
  248. package/dist/vendor/codali/tools/shell/ShellTool.d.ts.map +1 -0
  249. package/dist/vendor/codali/tools/shell/ShellTool.js +104 -0
  250. package/package.json +5 -3
@@ -0,0 +1,2261 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { spawnSync } from "node:child_process";
3
+ import { createWriteStream, existsSync } from "node:fs";
4
+ import { readFile, mkdir } from "node:fs/promises";
5
+ import path from "node:path";
6
+ import { createInterface } from "node:readline/promises";
7
+ import process from "node:process";
8
+ import { loadConfig } from "../config/ConfigLoader.js";
9
+ import { createProvider } from "../providers/ProviderRegistry.js";
10
+ import { OpenAiCompatibleProvider } from "../providers/OpenAiCompatibleProvider.js";
11
+ import { OllamaRemoteProvider } from "../providers/OllamaRemoteProvider.js";
12
+ import { CodexCliProvider } from "../providers/CodexCliProvider.js";
13
+ import { ToolRegistry } from "../tools/ToolRegistry.js";
14
+ import { createFileTools } from "../tools/filesystem/FileTools.js";
15
+ import { createDiffTool } from "../tools/diff/DiffTool.js";
16
+ import { createSearchTool } from "../tools/search/SearchTool.js";
17
+ import { createShellTool } from "../tools/shell/ShellTool.js";
18
+ import { DocdexClient } from "../docdex/DocdexClient.js";
19
+ import { createDocdexTools } from "../tools/docdex/DocdexTools.js";
20
+ import { RunContext } from "../runtime/RunContext.js";
21
+ import { WorkspaceLock } from "../runtime/WorkspaceLock.js";
22
+ import { runCodaliTask } from "../runtime/CodaliRuntime.js";
23
+ import { RunLogger } from "../runtime/RunLogger.js";
24
+ import { RunLogReader } from "../runtime/RunLogReader.js";
25
+ import { registerProvider } from "../providers/ProviderRegistry.js";
26
+ import { ContextAssembler } from "../cognitive/ContextAssembler.js";
27
+ import { ArchitectPlanner } from "../cognitive/ArchitectPlanner.js";
28
+ import { BuilderRunner } from "../cognitive/BuilderRunner.js";
29
+ import { CriticEvaluator } from "../cognitive/CriticEvaluator.js";
30
+ import { ValidationRunner } from "../cognitive/ValidationRunner.js";
31
+ import { MemoryWriteback } from "../cognitive/MemoryWriteback.js";
32
+ import { PatchApplier } from "../cognitive/PatchApplier.js";
33
+ import { PatchInterpreter } from "../cognitive/PatchInterpreter.js";
34
+ import { SmartPipeline } from "../cognitive/SmartPipeline.js";
35
+ import { buildRoutedProvider } from "../cognitive/ProviderRouting.js";
36
+ import { ContextManager } from "../cognitive/ContextManager.js";
37
+ import { ContextStore } from "../cognitive/ContextStore.js";
38
+ import { ContextSummarizer } from "../cognitive/ContextSummarizer.js";
39
+ import { ContextRedactor } from "../cognitive/ContextRedactor.js";
40
+ import { estimateCostFromChars, estimateCostFromUsage, estimateUsageCostTelemetry, resolvePricing, } from "../cognitive/CostEstimator.js";
41
+ import { getGlobalWorkspaceDir } from "../runtime/StoragePaths.js";
42
+ import { resolveAgentConfig } from "../agents/AgentResolver.js";
43
+ import { selectPhaseAgents } from "../agents/PhaseAgentSelector.js";
44
+ export const parseArgs = (argv) => {
45
+ const parseNumberArg = (value) => {
46
+ if (!value)
47
+ return undefined;
48
+ const parsed = Number(value);
49
+ return Number.isFinite(parsed) ? parsed : undefined;
50
+ };
51
+ const parseBooleanArg = (value) => {
52
+ if (!value)
53
+ return undefined;
54
+ const normalized = value.trim().toLowerCase();
55
+ if (["1", "true", "yes", "on"].includes(normalized))
56
+ return true;
57
+ if (["0", "false", "no", "off"].includes(normalized))
58
+ return false;
59
+ return undefined;
60
+ };
61
+ const parseListArg = (value) => {
62
+ if (!value)
63
+ return undefined;
64
+ const items = value
65
+ .split(",")
66
+ .map((entry) => entry.trim())
67
+ .filter(Boolean);
68
+ return items.length ? items : undefined;
69
+ };
70
+ const parsed = {};
71
+ const positionals = [];
72
+ for (let i = 0; i < argv.length; i += 1) {
73
+ const arg = argv[i];
74
+ const next = argv[i + 1];
75
+ if (arg === "--workspace-root" && next) {
76
+ parsed.workspaceRoot = next;
77
+ i += 1;
78
+ continue;
79
+ }
80
+ if (arg === "--project" && next) {
81
+ parsed.project = next;
82
+ i += 1;
83
+ continue;
84
+ }
85
+ if (arg === "--command" && next) {
86
+ parsed.command = next;
87
+ i += 1;
88
+ continue;
89
+ }
90
+ if (arg === "--command-run-id" && next) {
91
+ parsed.commandRunId = next;
92
+ i += 1;
93
+ continue;
94
+ }
95
+ if (arg === "--job-id" && next) {
96
+ parsed.jobId = next;
97
+ i += 1;
98
+ continue;
99
+ }
100
+ if (arg === "--run-id" && next) {
101
+ parsed.runId = next;
102
+ i += 1;
103
+ continue;
104
+ }
105
+ if (arg === "--task-id" && next) {
106
+ parsed.taskId = next;
107
+ i += 1;
108
+ continue;
109
+ }
110
+ if (arg === "--task-key" && next) {
111
+ parsed.taskKey = next;
112
+ i += 1;
113
+ continue;
114
+ }
115
+ if (arg === "--agent" && next) {
116
+ parsed.agent = next;
117
+ i += 1;
118
+ continue;
119
+ }
120
+ if (arg === "--agent-id" && next) {
121
+ parsed.agentId = next;
122
+ i += 1;
123
+ continue;
124
+ }
125
+ if (arg === "--agent-slug" && next) {
126
+ parsed.agentSlug = next;
127
+ i += 1;
128
+ continue;
129
+ }
130
+ if (arg === "--agent-librarian" && next) {
131
+ parsed.agentLibrarian = next;
132
+ i += 1;
133
+ continue;
134
+ }
135
+ if (arg === "--agent-architect" && next) {
136
+ parsed.agentArchitect = next;
137
+ i += 1;
138
+ continue;
139
+ }
140
+ if (arg === "--agent-builder" && next) {
141
+ parsed.agentBuilder = next;
142
+ i += 1;
143
+ continue;
144
+ }
145
+ if (arg === "--agent-critic" && next) {
146
+ parsed.agentCritic = next;
147
+ i += 1;
148
+ continue;
149
+ }
150
+ if (arg === "--agent-interpreter" && next) {
151
+ parsed.agentInterpreter = next;
152
+ i += 1;
153
+ continue;
154
+ }
155
+ if (arg === "--plan-hint" && next) {
156
+ parsed.planHint = next;
157
+ i += 1;
158
+ continue;
159
+ }
160
+ if (arg === "--smart") {
161
+ parsed.smart = true;
162
+ continue;
163
+ }
164
+ if (arg === "--no-deep-investigation") {
165
+ parsed.deepInvestigationEnabled = false;
166
+ continue;
167
+ }
168
+ if (arg === "--provider" && next) {
169
+ parsed.provider = next;
170
+ i += 1;
171
+ continue;
172
+ }
173
+ if (arg === "--model" && next) {
174
+ parsed.model = next;
175
+ i += 1;
176
+ continue;
177
+ }
178
+ if (arg === "--api-key" && next) {
179
+ parsed.apiKey = next;
180
+ i += 1;
181
+ continue;
182
+ }
183
+ if (arg === "--base-url" && next) {
184
+ parsed.baseUrl = next;
185
+ i += 1;
186
+ continue;
187
+ }
188
+ if ((arg === "--workflow-profile" || arg === "--profile") && next) {
189
+ parsed.workflowProfile = next;
190
+ i += 1;
191
+ continue;
192
+ }
193
+ if ((arg === "--task" || arg === "--task-file") && next) {
194
+ parsed.taskFile = next;
195
+ i += 1;
196
+ continue;
197
+ }
198
+ if (arg === "--config" && next) {
199
+ parsed.configPath = next;
200
+ i += 1;
201
+ continue;
202
+ }
203
+ if (arg === "--docdex-base-url" && next) {
204
+ parsed.docdexBaseUrl = next;
205
+ i += 1;
206
+ continue;
207
+ }
208
+ if (arg === "--docdex-repo-id" && next) {
209
+ parsed.docdexRepoId = next;
210
+ i += 1;
211
+ continue;
212
+ }
213
+ if (arg === "--docdex-repo-root" && next) {
214
+ parsed.docdexRepoRoot = next;
215
+ i += 1;
216
+ continue;
217
+ }
218
+ if (arg === "--context-mode" && next) {
219
+ if (next === "bundle_text" || next === "json")
220
+ parsed.contextMode = next;
221
+ i += 1;
222
+ continue;
223
+ }
224
+ if (arg === "--context-max-files" && next) {
225
+ parsed.contextMaxFiles = parseNumberArg(next);
226
+ i += 1;
227
+ continue;
228
+ }
229
+ if (arg === "--context-max-total-bytes" && next) {
230
+ parsed.contextMaxTotalBytes = parseNumberArg(next);
231
+ i += 1;
232
+ continue;
233
+ }
234
+ if (arg === "--context-token-budget" && next) {
235
+ parsed.contextTokenBudget = parseNumberArg(next);
236
+ i += 1;
237
+ continue;
238
+ }
239
+ if (arg === "--context-focus-max-bytes" && next) {
240
+ parsed.contextFocusMaxBytes = parseNumberArg(next);
241
+ i += 1;
242
+ continue;
243
+ }
244
+ if (arg === "--context-periphery-max-bytes" && next) {
245
+ parsed.contextPeripheryMaxBytes = parseNumberArg(next);
246
+ i += 1;
247
+ continue;
248
+ }
249
+ if (arg === "--context-include-repo-map" && next) {
250
+ parsed.contextIncludeRepoMap = parseBooleanArg(next);
251
+ i += 1;
252
+ continue;
253
+ }
254
+ if (arg === "--context-include-impact" && next) {
255
+ parsed.contextIncludeImpact = parseBooleanArg(next);
256
+ i += 1;
257
+ continue;
258
+ }
259
+ if (arg === "--context-include-snippets" && next) {
260
+ parsed.contextIncludeSnippets = parseBooleanArg(next);
261
+ i += 1;
262
+ continue;
263
+ }
264
+ if (arg === "--context-read-strategy" && next) {
265
+ if (next === "docdex" || next === "fs")
266
+ parsed.contextReadStrategy = next;
267
+ i += 1;
268
+ continue;
269
+ }
270
+ if (arg === "--context-max-refreshes" && next) {
271
+ parsed.contextMaxRefreshes = parseNumberArg(next);
272
+ i += 1;
273
+ continue;
274
+ }
275
+ if (arg === "--context-skeletonize" && next) {
276
+ parsed.contextSkeletonize = parseBooleanArg(next);
277
+ i += 1;
278
+ continue;
279
+ }
280
+ if (arg === "--context-redact-secrets" && next) {
281
+ parsed.contextRedactSecrets = parseBooleanArg(next);
282
+ i += 1;
283
+ continue;
284
+ }
285
+ if (arg === "--context-ignore-files-from" && next) {
286
+ parsed.contextIgnoreFilesFrom = parseListArg(next);
287
+ i += 1;
288
+ continue;
289
+ }
290
+ if (arg === "--security-redact-patterns" && next) {
291
+ parsed.securityRedactPatterns = parseListArg(next);
292
+ i += 1;
293
+ continue;
294
+ }
295
+ if (arg === "--builder-mode" && next) {
296
+ if (next === "tool_calls" || next === "patch_json" || next === "freeform") {
297
+ parsed.builderMode = next;
298
+ }
299
+ i += 1;
300
+ continue;
301
+ }
302
+ if (arg === "--builder-patch-format" && next) {
303
+ if (next === "search_replace" || next === "file_writes")
304
+ parsed.builderPatchFormat = next;
305
+ i += 1;
306
+ continue;
307
+ }
308
+ if (arg === "--interpreter-provider" && next) {
309
+ parsed.interpreterProvider = next;
310
+ i += 1;
311
+ continue;
312
+ }
313
+ if (arg === "--interpreter-model" && next) {
314
+ parsed.interpreterModel = next;
315
+ i += 1;
316
+ continue;
317
+ }
318
+ if (arg === "--interpreter-format" && next) {
319
+ parsed.interpreterFormat = next;
320
+ i += 1;
321
+ continue;
322
+ }
323
+ if (arg === "--interpreter-grammar" && next) {
324
+ parsed.interpreterGrammar = next;
325
+ i += 1;
326
+ continue;
327
+ }
328
+ if (arg === "--interpreter-max-retries" && next) {
329
+ parsed.interpreterMaxRetries = parseNumberArg(next);
330
+ i += 1;
331
+ continue;
332
+ }
333
+ if (arg === "--interpreter-timeout-ms" && next) {
334
+ parsed.interpreterTimeoutMs = parseNumberArg(next);
335
+ i += 1;
336
+ continue;
337
+ }
338
+ if (arg === "--streaming-flush-ms" && next) {
339
+ parsed.streamingFlushMs = parseNumberArg(next);
340
+ i += 1;
341
+ continue;
342
+ }
343
+ if (arg === "--cost-max" && next) {
344
+ parsed.costMaxPerRun = parseNumberArg(next);
345
+ i += 1;
346
+ continue;
347
+ }
348
+ if (arg === "--cost-char-per-token" && next) {
349
+ parsed.costCharPerToken = parseNumberArg(next);
350
+ i += 1;
351
+ continue;
352
+ }
353
+ if (arg === "--cost-pricing-overrides" && next) {
354
+ parsed.costPricingOverrides = next;
355
+ i += 1;
356
+ continue;
357
+ }
358
+ if (!arg.startsWith("-")) {
359
+ positionals.push(arg);
360
+ }
361
+ }
362
+ if (positionals.length) {
363
+ parsed.inlineTask = positionals.join(" ");
364
+ }
365
+ return parsed;
366
+ };
367
+ const ROOT_MARKERS = [
368
+ ".git",
369
+ "package.json",
370
+ "pnpm-workspace.yaml",
371
+ "yarn.lock",
372
+ "bun.lockb",
373
+ "go.mod",
374
+ "Cargo.toml",
375
+ "pyproject.toml",
376
+ "requirements.txt",
377
+ "Gemfile",
378
+ "composer.json",
379
+ "pom.xml",
380
+ "build.gradle",
381
+ "build.gradle.kts",
382
+ "codali.config.json",
383
+ ".codalirc",
384
+ ];
385
+ export const resolveWorkspaceRoot = (cwd, explicitRoot) => {
386
+ if (explicitRoot) {
387
+ return path.resolve(cwd, explicitRoot);
388
+ }
389
+ let current = path.resolve(cwd);
390
+ let previous = "";
391
+ while (current !== previous) {
392
+ for (const marker of ROOT_MARKERS) {
393
+ if (existsSync(path.join(current, marker))) {
394
+ return current;
395
+ }
396
+ }
397
+ previous = current;
398
+ current = path.dirname(current);
399
+ }
400
+ return path.resolve(cwd);
401
+ };
402
+ const formatCost = (cost) => {
403
+ if (cost === undefined)
404
+ return "unknown";
405
+ return `$${cost.toFixed(4)}`;
406
+ };
407
+ const toSummaryPhase = (phase) => {
408
+ if (phase === "librarian" || phase === "plan")
409
+ return "plan";
410
+ if (phase === "architect" || phase === "retrieve")
411
+ return "retrieve";
412
+ if (phase === "builder" || phase === "act")
413
+ return "act";
414
+ if (phase === "critic" || phase === "verify" || phase === "architect_review")
415
+ return "verify";
416
+ return undefined;
417
+ };
418
+ const uniqueStrings = (values) => Array.from(new Set(values.map((value) => value.trim()).filter((value) => value.length > 0))).sort((left, right) => left.localeCompare(right));
419
+ const inferFailureClass = (stage, reasons, errorMessage) => {
420
+ const haystack = [stage ?? "", ...reasons, errorMessage ?? ""].join(" ").toLowerCase();
421
+ if (haystack.includes("verification"))
422
+ return "verification_failure";
423
+ if (haystack.includes("policy") || haystack.includes("guardrail"))
424
+ return "policy_failure";
425
+ if (haystack.includes("safety"))
426
+ return "safety_failure";
427
+ if (haystack.includes("patch"))
428
+ return "patch_failure";
429
+ if (haystack.includes("provider") || haystack.includes("rate limit") || haystack.includes("auth")) {
430
+ return "provider_failure";
431
+ }
432
+ if (haystack.includes("execution") || haystack.includes("runner") || haystack.includes("timeout")) {
433
+ return "execution_failure";
434
+ }
435
+ return "unknown_failure";
436
+ };
437
+ const summarizeContext = (context, fallbackContent) => {
438
+ const files = context?.files ?? [];
439
+ const focusCount = files.filter((file) => file.role === "focus").length;
440
+ const peripheryCount = files.filter((file) => file.role === "periphery").length;
441
+ const content = context?.serialized?.content ?? fallbackContent ?? "";
442
+ return {
443
+ focusCount,
444
+ peripheryCount,
445
+ content,
446
+ charCount: content.length,
447
+ };
448
+ };
449
+ const confirmOverage = async (message) => {
450
+ if (!process.stdin.isTTY) {
451
+ return false;
452
+ }
453
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
454
+ try {
455
+ const answer = await rl.question(message);
456
+ const normalized = answer.trim().toLowerCase();
457
+ return normalized === "y" || normalized === "yes";
458
+ }
459
+ finally {
460
+ rl.close();
461
+ }
462
+ };
463
+ const createStreamState = (flushEveryMs, outputStream) => {
464
+ let buffer = "";
465
+ let lastFlush = Date.now();
466
+ let didStream = false;
467
+ const forceColor = process.env.FORCE_COLOR;
468
+ const supportsColor = (forceColor && forceColor !== "0") || (!!process.stderr.isTTY && !process.env.NO_COLOR);
469
+ const colorize = (code, text) => supportsColor ? `\u001b[${code}m${text}\u001b[0m` : text;
470
+ const indent = " ";
471
+ const statusColor = (phase) => {
472
+ if (phase === "executing")
473
+ return "35";
474
+ if (phase === "patching")
475
+ return "33";
476
+ if (phase === "done")
477
+ return "32";
478
+ return "36";
479
+ };
480
+ const tag = (phase) => colorize(statusColor(phase), `[${phase}]`);
481
+ const toolTag = (name) => colorize("34", `[tool:${name}]`);
482
+ const toolLead = () => colorize("34", "[tool]");
483
+ const okTag = () => colorize("32", "ok");
484
+ const errTag = () => colorize("31", "error");
485
+ const errorLine = (message) => colorize("31", message);
486
+ const flush = () => {
487
+ if (buffer.length > 0) {
488
+ process.stdout.write(buffer);
489
+ outputStream?.write(buffer);
490
+ buffer = "";
491
+ }
492
+ lastFlush = Date.now();
493
+ };
494
+ const writeStatus = (line) => {
495
+ flush();
496
+ process.stderr.write(`${line}\n`);
497
+ outputStream?.write(`${line.replace(/\u001b\[[0-9;]*m/g, "")}\n`);
498
+ };
499
+ const onEvent = (event) => {
500
+ if (event.type === "token") {
501
+ didStream = true;
502
+ buffer += event.content;
503
+ const now = Date.now();
504
+ if (now - lastFlush >= flushEveryMs) {
505
+ flush();
506
+ }
507
+ return;
508
+ }
509
+ if (event.type === "status") {
510
+ const suffix = event.message ? ` ${event.message}` : "";
511
+ writeStatus(`${indent}${tag(event.phase)}${suffix}`);
512
+ return;
513
+ }
514
+ if (event.type === "tool_call") {
515
+ writeStatus(`${indent}${toolLead()} ${event.name}`);
516
+ return;
517
+ }
518
+ if (event.type === "tool_result") {
519
+ const outcome = event.ok === false ? errTag() : okTag();
520
+ const suffix = event.ok === false && event.errorCode
521
+ ? ` ${colorize("31", `(${event.errorCode}${event.retryable ? ",retryable" : ""})`)}`
522
+ : "";
523
+ writeStatus(`${indent}${toolTag(event.name)} ${outcome}${suffix}`);
524
+ return;
525
+ }
526
+ if (event.type === "error") {
527
+ writeStatus(`${indent}${colorize("31", "[error]")} ${errorLine(event.message)}`);
528
+ }
529
+ };
530
+ const onToken = (token) => {
531
+ didStream = true;
532
+ buffer += token;
533
+ const now = Date.now();
534
+ if (now - lastFlush >= flushEveryMs) {
535
+ flush();
536
+ }
537
+ };
538
+ return {
539
+ onEvent,
540
+ onToken,
541
+ flush,
542
+ didStream: () => didStream,
543
+ writeOutput: (text) => {
544
+ outputStream?.write(text);
545
+ },
546
+ };
547
+ };
548
+ const createPatchValidator = (workspaceRoot, allowShell, shellAllowlist) => {
549
+ if (!allowShell)
550
+ return undefined;
551
+ const allowlist = new Set(shellAllowlist ?? []);
552
+ return async (filePath) => {
553
+ const ext = path.extname(filePath).toLowerCase();
554
+ if (![".js", ".mjs", ".cjs"].includes(ext)) {
555
+ return;
556
+ }
557
+ if (!allowlist.has("node")) {
558
+ return;
559
+ }
560
+ const result = spawnSync("node", ["--check", filePath], {
561
+ cwd: workspaceRoot,
562
+ encoding: "utf8",
563
+ });
564
+ if (result.error) {
565
+ throw result.error;
566
+ }
567
+ if (result.status !== 0) {
568
+ throw new Error(result.stderr?.toString() || "node --check failed");
569
+ }
570
+ };
571
+ };
572
+ const isPhaseProvider = (value) => value === "librarian" ||
573
+ value === "architect" ||
574
+ value === "builder" ||
575
+ value === "critic" ||
576
+ value === "interpreter";
577
+ const resolveInterpreterRoute = (config, phaseRoutes) => {
578
+ const requestedProvider = config.interpreter.provider?.trim() || "auto";
579
+ const requestedModel = config.interpreter.model?.trim() || "auto";
580
+ const fallbackRoute = phaseRoutes.interpreter ??
581
+ phaseRoutes.critic ??
582
+ phaseRoutes.architect ??
583
+ phaseRoutes.builder ??
584
+ phaseRoutes.librarian;
585
+ const routed = requestedProvider === "auto"
586
+ ? fallbackRoute
587
+ : isPhaseProvider(requestedProvider)
588
+ ? phaseRoutes[requestedProvider]
589
+ : undefined;
590
+ const provider = routed?.provider ?? requestedProvider;
591
+ const baseConfig = routed
592
+ ? { ...routed.config }
593
+ : {
594
+ model: config.model,
595
+ apiKey: config.apiKey,
596
+ baseUrl: config.baseUrl,
597
+ timeoutMs: config.interpreter.timeoutMs,
598
+ };
599
+ if (!baseConfig.baseUrl) {
600
+ const sameProviderBaseUrl = Object.values(phaseRoutes)
601
+ .map((route) => (route.provider === provider ? route.config.baseUrl : undefined))
602
+ .find((value) => typeof value === "string" && value.length > 0);
603
+ baseConfig.baseUrl = sameProviderBaseUrl ?? config.baseUrl ?? baseConfig.baseUrl;
604
+ }
605
+ const resolvedModel = requestedModel !== "auto"
606
+ ? requestedModel
607
+ : baseConfig.model ?? fallbackRoute?.config.model ?? config.model;
608
+ return {
609
+ provider,
610
+ config: {
611
+ ...baseConfig,
612
+ model: resolvedModel,
613
+ timeoutMs: config.interpreter.timeoutMs ?? baseConfig.timeoutMs,
614
+ },
615
+ temperature: routed?.temperature,
616
+ };
617
+ };
618
+ export const isToolEnabled = (name, tools) => {
619
+ if (name === "run_shell" && !tools.allowShell) {
620
+ return false;
621
+ }
622
+ const enabled = tools.enabled?.length ? new Set(tools.enabled) : undefined;
623
+ if (!enabled)
624
+ return true;
625
+ return enabled.has(name);
626
+ };
627
+ const PATCH_JSON_STRUCTURED_CAPABILITIES = [
628
+ "strict_instruction_following",
629
+ "json_formatting",
630
+ "schema_adherence",
631
+ "structured_output",
632
+ ];
633
+ const PATCH_JSON_CODE_CAPABILITIES = [
634
+ "code_write",
635
+ "iterative_coding",
636
+ "simple_refactor",
637
+ "minimal_diff_generation",
638
+ "migration_scripts",
639
+ "debugging",
640
+ "refactor_support",
641
+ ];
642
+ const countCapabilityMatches = (capabilities, required) => required.filter((capability) => capabilities.includes(capability)).length;
643
+ export const assessPhaseFallbackSuitability = (phase, builderMode, selection) => {
644
+ if (phase !== "builder") {
645
+ return { ok: true, reason: "not_builder_phase", builderMode };
646
+ }
647
+ if (builderMode !== "patch_json") {
648
+ return { ok: true, reason: "builder_mode_not_patch_json", builderMode };
649
+ }
650
+ const capabilities = selection.capabilities ?? [];
651
+ const structuredHits = countCapabilityMatches(capabilities, PATCH_JSON_STRUCTURED_CAPABILITIES);
652
+ const codeHits = countCapabilityMatches(capabilities, PATCH_JSON_CODE_CAPABILITIES);
653
+ if (codeHits <= 0) {
654
+ return {
655
+ ok: false,
656
+ reason: "missing_patch_code_capability",
657
+ details: { codeHits },
658
+ };
659
+ }
660
+ if (structuredHits > 0) {
661
+ return {
662
+ ok: true,
663
+ reason: "capability_requirements_met",
664
+ details: { structuredHits, codeHits },
665
+ builderMode: "patch_json",
666
+ };
667
+ }
668
+ const hasToolRunner = capabilities.includes("tool_runner");
669
+ if (selection.supportsTools || hasToolRunner) {
670
+ return {
671
+ ok: true,
672
+ reason: "fallback_patch_json_without_structured_capability",
673
+ details: { structuredHits, codeHits, hasToolRunner: hasToolRunner ? 1 : 0 },
674
+ // Keep patch_json mode so fallback builders stay in the same patch contract path.
675
+ builderMode: "patch_json",
676
+ };
677
+ }
678
+ return {
679
+ ok: false,
680
+ reason: "missing_structured_output_capability",
681
+ details: { structuredHits, codeHits },
682
+ };
683
+ };
684
+ const readStdin = async () => {
685
+ const chunks = [];
686
+ return new Promise((resolve, reject) => {
687
+ process.stdin.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
688
+ process.stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
689
+ process.stdin.on("error", reject);
690
+ });
691
+ };
692
+ const resolveTaskInput = async (parsed) => {
693
+ if (parsed.taskFile) {
694
+ return readFile(parsed.taskFile, "utf8");
695
+ }
696
+ if (parsed.inlineTask) {
697
+ return parsed.inlineTask;
698
+ }
699
+ if (process.stdin.isTTY) {
700
+ return "";
701
+ }
702
+ return readStdin();
703
+ };
704
+ const isTrivialRequest = (request) => {
705
+ const normalized = request.trim().toLowerCase();
706
+ if (normalized.length === 0)
707
+ return false;
708
+ const shortEnough = normalized.length <= 120;
709
+ const signals = ["typo", "spelling", "format", "whitespace", "rename", "readme", "comment"];
710
+ return shortEnough && signals.some((signal) => normalized.includes(signal));
711
+ };
712
+ const buildWorkflowTaskInput = (request, profile) => {
713
+ if (!profile || profile.name === "run") {
714
+ return request;
715
+ }
716
+ const outputInstruction = profile.outputContract === "patch_summary"
717
+ ? "Return a patch/change-focused summary with changed files and verification notes."
718
+ : profile.outputContract === "review_findings"
719
+ ? "Return risk/findings-oriented review output. Do not propose write-oriented changes."
720
+ : profile.outputContract === "verification_summary"
721
+ ? "Return verification-first output with test/validation summary."
722
+ : "Return explanation-first output. Do not propose write-oriented changes.";
723
+ const writePolicy = profile.allowWrites ? "writes_allowed" : "no_writes";
724
+ return [
725
+ `WORKFLOW PROFILE: ${profile.name}`,
726
+ `OUTPUT CONTRACT: ${profile.outputContract}`,
727
+ `VERIFICATION POLICY: ${profile.verificationPolicy}`,
728
+ `VERIFICATION MIN CHECKS: ${profile.verificationMinimumChecks}`,
729
+ `VERIFICATION HIGH-CONFIDENCE ENFORCEMENT: ${profile.verificationEnforceHighConfidence ? "strict" : "off"}`,
730
+ `WRITE POLICY: ${writePolicy}`,
731
+ outputInstruction,
732
+ "",
733
+ "USER TASK:",
734
+ request,
735
+ ].join("\n");
736
+ };
737
+ const collectPhaseDurations = (artifacts) => {
738
+ const durations = {};
739
+ for (const artifact of artifacts) {
740
+ if (artifact.kind !== "summary")
741
+ continue;
742
+ const phase = toSummaryPhase(artifact.phase);
743
+ if (!phase)
744
+ continue;
745
+ if (typeof artifact.duration_ms !== "number" || !Number.isFinite(artifact.duration_ms))
746
+ continue;
747
+ durations[phase] = artifact.duration_ms;
748
+ }
749
+ return durations;
750
+ };
751
+ const buildArtifactReferences = (phaseArtifactEvents, requiredArtifacts) => {
752
+ const references = [];
753
+ for (const event of phaseArtifactEvents) {
754
+ if (!event.phase || !event.kind)
755
+ continue;
756
+ const phase = toSummaryPhase(event.phase) ?? event.phase;
757
+ references.push({
758
+ phase,
759
+ kind: event.kind,
760
+ path: event.path ?? null,
761
+ status: "present",
762
+ });
763
+ }
764
+ const seen = new Set(references.map((entry) => `${entry.phase}:${entry.kind}`));
765
+ const missing = [];
766
+ for (const required of requiredArtifacts) {
767
+ if (seen.has(required))
768
+ continue;
769
+ missing.push(required);
770
+ const [phase, kind] = required.split(":");
771
+ references.push({
772
+ phase: phase ?? "unknown",
773
+ kind: kind ?? "unknown",
774
+ status: "missing",
775
+ reason_code: "artifact_not_emitted",
776
+ });
777
+ }
778
+ references.sort((left, right) => `${left.phase}:${left.kind}:${left.status}`.localeCompare(`${right.phase}:${right.kind}:${right.status}`));
779
+ return { references, missing: uniqueStrings(missing) };
780
+ };
781
+ const buildQualityDimensions = (artifactReferences, disposition) => {
782
+ const hasPresent = (phase) => artifactReferences.some((entry) => entry.phase === phase && entry.status === "present");
783
+ const retrieval = hasPresent("retrieve")
784
+ ? "available"
785
+ : disposition === "pass"
786
+ ? "degraded"
787
+ : "missing";
788
+ const plan = hasPresent("plan")
789
+ ? "available"
790
+ : disposition === "pass"
791
+ ? "degraded"
792
+ : "missing";
793
+ const patch = hasPresent("act")
794
+ ? "available"
795
+ : disposition === "pass"
796
+ ? "degraded"
797
+ : "missing";
798
+ const verification = hasPresent("verify")
799
+ ? "available"
800
+ : disposition === "pass"
801
+ ? "degraded"
802
+ : "missing";
803
+ return {
804
+ plan,
805
+ retrieval,
806
+ patch,
807
+ verification,
808
+ final_disposition: "available",
809
+ };
810
+ };
811
+ const buildPhaseTelemetry = (params) => {
812
+ const phaseOrder = ["plan", "retrieve", "act", "verify"];
813
+ const usage = params.usage;
814
+ const usageTotals = usage
815
+ ? {
816
+ input_tokens: usage.inputTokens,
817
+ output_tokens: usage.outputTokens,
818
+ total_tokens: usage.totalTokens
819
+ ?? ((usage.inputTokens ?? 0) + (usage.outputTokens ?? 0) || undefined),
820
+ }
821
+ : undefined;
822
+ const costTelemetry = estimateUsageCostTelemetry(usage, params.pricingSpec);
823
+ return phaseOrder
824
+ .filter((phase) => {
825
+ const providerInfo = params.phaseProviders[phase];
826
+ return Boolean(providerInfo?.provider || providerInfo?.model || params.phaseDurations[phase] !== undefined);
827
+ })
828
+ .map((phase) => {
829
+ const providerInfo = params.phaseProviders[phase] ?? {};
830
+ if (phase === "act") {
831
+ return {
832
+ run_id: params.runId,
833
+ phase,
834
+ provider: providerInfo.provider,
835
+ model: providerInfo.model,
836
+ duration_ms: params.phaseDurations[phase],
837
+ usage: usageTotals,
838
+ cost: costTelemetry.costUsd !== undefined
839
+ ? {
840
+ usd: costTelemetry.costUsd,
841
+ source: costTelemetry.source,
842
+ pricing_source: params.pricingSource,
843
+ }
844
+ : undefined,
845
+ missing_usage_reason: usageTotals === undefined
846
+ ? "usage_missing"
847
+ : undefined,
848
+ missing_cost_reason: costTelemetry.costUsd === undefined
849
+ ? costTelemetry.reasonCode ?? "cost_missing"
850
+ : undefined,
851
+ };
852
+ }
853
+ return {
854
+ run_id: params.runId,
855
+ phase,
856
+ provider: providerInfo.provider,
857
+ model: providerInfo.model,
858
+ duration_ms: params.phaseDurations[phase],
859
+ missing_usage_reason: "provider_usage_not_exposed",
860
+ missing_cost_reason: "usage_missing",
861
+ };
862
+ });
863
+ };
864
+ class StubProvider {
865
+ constructor() {
866
+ this.name = "stub";
867
+ }
868
+ async generate(request) {
869
+ const last = request.messages[request.messages.length - 1];
870
+ const promptText = request.messages.map((message) => message.content ?? "").join("\n");
871
+ const lowerPrompt = promptText.toLowerCase();
872
+ const isArchitectPrompt = /ROLE:\s*Technical Architect/i.test(promptText);
873
+ const isArchitectReviewPrompt = isArchitectPrompt
874
+ && (/TASK:\s*Review the builder output/i.test(promptText)
875
+ || (/OUTPUT FORMAT \(PLAIN TEXT\):/i.test(promptText) && /STATUS:\s*PASS\|RETRY/i.test(promptText)));
876
+ if (isArchitectReviewPrompt) {
877
+ return {
878
+ message: {
879
+ role: "assistant",
880
+ content: [
881
+ "STATUS: PASS",
882
+ "REASONS:",
883
+ "- Request intent and plan targets are covered.",
884
+ "FEEDBACK:",
885
+ ].join("\n"),
886
+ },
887
+ };
888
+ }
889
+ const isArchitectPlanPrompt = isArchitectPrompt
890
+ && (/TASK:\s*Produce an implementation plan/i.test(promptText)
891
+ || /PREFERRED OUTPUT SHAPE \(PLAIN TEXT\)/i.test(promptText));
892
+ if (isArchitectPlanPrompt) {
893
+ return {
894
+ message: {
895
+ role: "assistant",
896
+ content: [
897
+ "WHAT IS REQUIRED:",
898
+ "- Apply the requested behavior update for the current task.",
899
+ "CURRENT CONTEXT:",
900
+ "- Existing implementation lives in src/index.ts.",
901
+ "FOLDER STRUCTURE:",
902
+ "- src/index.ts",
903
+ "FILES TO TOUCH:",
904
+ "- src/index.ts",
905
+ "IMPLEMENTATION PLAN:",
906
+ "- Update src/index.ts to implement the requested behavior change.",
907
+ "RISK: low scoped single-file update.",
908
+ "VERIFY:",
909
+ "- echo ok",
910
+ ].join("\n"),
911
+ },
912
+ };
913
+ }
914
+ if (lowerPrompt.includes("\"patches\"") || lowerPrompt.includes("search_replace")) {
915
+ return {
916
+ message: {
917
+ role: "assistant",
918
+ content: JSON.stringify({
919
+ patches: [
920
+ {
921
+ action: "replace",
922
+ file: "src/index.ts",
923
+ search_block: "const value = 1;",
924
+ replace_block: "const value = 2;",
925
+ },
926
+ ],
927
+ }),
928
+ },
929
+ };
930
+ }
931
+ if (lowerPrompt.includes("\"files\"") || lowerPrompt.includes("file_writes")) {
932
+ return {
933
+ message: {
934
+ role: "assistant",
935
+ content: JSON.stringify({
936
+ files: [{ path: "src/index.ts", content: "const value = 2;\n" }],
937
+ delete: [],
938
+ }),
939
+ },
940
+ };
941
+ }
942
+ if (request.responseFormat?.type === "json" || request.responseFormat?.type === "gbnf") {
943
+ if (promptText.includes("\"files\"")) {
944
+ return {
945
+ message: {
946
+ role: "assistant",
947
+ content: JSON.stringify({
948
+ files: [{ path: "src/index.ts", content: "const value = 2;\n" }],
949
+ delete: [],
950
+ }),
951
+ },
952
+ };
953
+ }
954
+ if (promptText.includes("\"patches\"")) {
955
+ return {
956
+ message: {
957
+ role: "assistant",
958
+ content: JSON.stringify({
959
+ patches: [
960
+ {
961
+ action: "replace",
962
+ file: "src/index.ts",
963
+ search_block: "const value = 1;",
964
+ replace_block: "const value = 2;",
965
+ },
966
+ ],
967
+ }),
968
+ },
969
+ };
970
+ }
971
+ return {
972
+ message: {
973
+ role: "assistant",
974
+ content: JSON.stringify({
975
+ steps: ["1. Apply change"],
976
+ target_files: ["src/index.ts"],
977
+ risk_assessment: "low",
978
+ verification: ["Run unit tests: pnpm test --filter codali"],
979
+ }),
980
+ },
981
+ };
982
+ }
983
+ return { message: { role: "assistant", content: `stub:${last?.content ?? ""}` } };
984
+ }
985
+ }
986
+ const registerBuiltins = () => {
987
+ try {
988
+ registerProvider("openai-compatible", (config) => new OpenAiCompatibleProvider(config));
989
+ }
990
+ catch {
991
+ // ignore duplicate registrations
992
+ }
993
+ try {
994
+ registerProvider("ollama-remote", (config) => new OllamaRemoteProvider(config));
995
+ }
996
+ catch {
997
+ // ignore duplicate registrations
998
+ }
999
+ try {
1000
+ registerProvider("codex-cli", (config) => new CodexCliProvider(config));
1001
+ }
1002
+ catch {
1003
+ // ignore duplicate registrations
1004
+ }
1005
+ try {
1006
+ registerProvider("stub", () => new StubProvider());
1007
+ }
1008
+ catch {
1009
+ // ignore duplicate registrations
1010
+ }
1011
+ };
1012
+ export class RunCommand {
1013
+ static async run(argv) {
1014
+ registerBuiltins();
1015
+ const parsed = parseArgs(argv);
1016
+ const resolvedWorkspaceRoot = resolveWorkspaceRoot(process.cwd(), parsed.workspaceRoot);
1017
+ const agentRef = parsed.agent ?? parsed.agentId ?? parsed.agentSlug;
1018
+ const resolvedAgent = agentRef
1019
+ ? await resolveAgentConfig(agentRef, {
1020
+ provider: parsed.provider,
1021
+ model: parsed.model,
1022
+ baseUrl: parsed.baseUrl,
1023
+ apiKey: parsed.apiKey,
1024
+ })
1025
+ : undefined;
1026
+ const provider = parsed.provider ?? resolvedAgent?.provider;
1027
+ const model = parsed.model ?? resolvedAgent?.model;
1028
+ const apiKey = parsed.apiKey ?? resolvedAgent?.apiKey;
1029
+ const baseUrl = parsed.baseUrl ?? resolvedAgent?.baseUrl;
1030
+ const agentId = resolvedAgent?.agent.id ?? parsed.agentId;
1031
+ const agentSlug = resolvedAgent?.agent.slug ?? parsed.agentSlug;
1032
+ const cliConfig = {};
1033
+ if (parsed.workspaceRoot)
1034
+ cliConfig.workspaceRoot = parsed.workspaceRoot;
1035
+ if (parsed.project)
1036
+ cliConfig.project = parsed.project;
1037
+ if (parsed.command)
1038
+ cliConfig.command = parsed.command;
1039
+ if (parsed.commandRunId)
1040
+ cliConfig.commandRunId = parsed.commandRunId;
1041
+ if (parsed.jobId)
1042
+ cliConfig.jobId = parsed.jobId;
1043
+ if (parsed.runId)
1044
+ cliConfig.runId = parsed.runId;
1045
+ if (parsed.taskId)
1046
+ cliConfig.taskId = parsed.taskId;
1047
+ if (parsed.taskKey)
1048
+ cliConfig.taskKey = parsed.taskKey;
1049
+ if (agentId)
1050
+ cliConfig.agentId = agentId;
1051
+ if (agentSlug)
1052
+ cliConfig.agentSlug = agentSlug;
1053
+ if (parsed.smart !== undefined)
1054
+ cliConfig.smart = parsed.smart;
1055
+ if (parsed.deepInvestigationEnabled !== undefined) {
1056
+ cliConfig.deepInvestigation = { enabled: parsed.deepInvestigationEnabled };
1057
+ }
1058
+ if (parsed.planHint)
1059
+ cliConfig.planHint = parsed.planHint;
1060
+ if (provider)
1061
+ cliConfig.provider = provider;
1062
+ if (model)
1063
+ cliConfig.model = model;
1064
+ if (apiKey)
1065
+ cliConfig.apiKey = apiKey;
1066
+ if (baseUrl)
1067
+ cliConfig.baseUrl = baseUrl;
1068
+ if (parsed.workflowProfile) {
1069
+ cliConfig.workflow = { profile: parsed.workflowProfile };
1070
+ }
1071
+ const docdexOverrides = {};
1072
+ if (parsed.docdexBaseUrl)
1073
+ docdexOverrides.baseUrl = parsed.docdexBaseUrl;
1074
+ if (parsed.docdexRepoId)
1075
+ docdexOverrides.repoId = parsed.docdexRepoId;
1076
+ if (parsed.docdexRepoRoot)
1077
+ docdexOverrides.repoRoot = parsed.docdexRepoRoot;
1078
+ if (Object.keys(docdexOverrides).length) {
1079
+ cliConfig.docdex = docdexOverrides;
1080
+ }
1081
+ const contextOverrides = {};
1082
+ if (parsed.contextMode)
1083
+ contextOverrides.mode = parsed.contextMode;
1084
+ if (parsed.contextMaxFiles !== undefined)
1085
+ contextOverrides.maxFiles = parsed.contextMaxFiles;
1086
+ if (parsed.contextMaxTotalBytes !== undefined)
1087
+ contextOverrides.maxTotalBytes = parsed.contextMaxTotalBytes;
1088
+ if (parsed.contextTokenBudget !== undefined)
1089
+ contextOverrides.tokenBudget = parsed.contextTokenBudget;
1090
+ if (parsed.contextFocusMaxBytes !== undefined)
1091
+ contextOverrides.focusMaxFileBytes = parsed.contextFocusMaxBytes;
1092
+ if (parsed.contextPeripheryMaxBytes !== undefined)
1093
+ contextOverrides.peripheryMaxBytes = parsed.contextPeripheryMaxBytes;
1094
+ if (parsed.contextIncludeRepoMap !== undefined)
1095
+ contextOverrides.includeRepoMap = parsed.contextIncludeRepoMap;
1096
+ if (parsed.contextIncludeImpact !== undefined)
1097
+ contextOverrides.includeImpact = parsed.contextIncludeImpact;
1098
+ if (parsed.contextIncludeSnippets !== undefined)
1099
+ contextOverrides.includeSnippets = parsed.contextIncludeSnippets;
1100
+ if (parsed.contextReadStrategy)
1101
+ contextOverrides.readStrategy = parsed.contextReadStrategy;
1102
+ if (parsed.contextMaxRefreshes !== undefined)
1103
+ contextOverrides.maxContextRefreshes = parsed.contextMaxRefreshes;
1104
+ if (parsed.contextSkeletonize !== undefined)
1105
+ contextOverrides.skeletonizeLargeFiles = parsed.contextSkeletonize;
1106
+ if (parsed.contextRedactSecrets !== undefined)
1107
+ contextOverrides.redactSecrets = parsed.contextRedactSecrets;
1108
+ if (parsed.contextIgnoreFilesFrom)
1109
+ contextOverrides.ignoreFilesFrom = parsed.contextIgnoreFilesFrom;
1110
+ if (Object.keys(contextOverrides).length) {
1111
+ cliConfig.context = contextOverrides;
1112
+ }
1113
+ const securityOverrides = {};
1114
+ if (parsed.securityRedactPatterns)
1115
+ securityOverrides.redactPatterns = parsed.securityRedactPatterns;
1116
+ if (Object.keys(securityOverrides).length) {
1117
+ cliConfig.security = securityOverrides;
1118
+ }
1119
+ const builderOverrides = {};
1120
+ if (parsed.builderMode)
1121
+ builderOverrides.mode = parsed.builderMode;
1122
+ if (parsed.builderPatchFormat)
1123
+ builderOverrides.patchFormat = parsed.builderPatchFormat;
1124
+ if (Object.keys(builderOverrides).length) {
1125
+ cliConfig.builder = builderOverrides;
1126
+ }
1127
+ const interpreterOverrides = {};
1128
+ if (parsed.interpreterProvider)
1129
+ interpreterOverrides.provider = parsed.interpreterProvider;
1130
+ if (parsed.interpreterModel)
1131
+ interpreterOverrides.model = parsed.interpreterModel;
1132
+ if (parsed.interpreterFormat)
1133
+ interpreterOverrides.format = parsed.interpreterFormat;
1134
+ if (parsed.interpreterGrammar)
1135
+ interpreterOverrides.grammar = parsed.interpreterGrammar;
1136
+ if (parsed.interpreterMaxRetries !== undefined) {
1137
+ interpreterOverrides.maxRetries = parsed.interpreterMaxRetries;
1138
+ }
1139
+ if (parsed.interpreterTimeoutMs !== undefined) {
1140
+ interpreterOverrides.timeoutMs = parsed.interpreterTimeoutMs;
1141
+ }
1142
+ if (Object.keys(interpreterOverrides).length) {
1143
+ cliConfig.interpreter = interpreterOverrides;
1144
+ }
1145
+ const streamingOverrides = {};
1146
+ if (parsed.streamingFlushMs !== undefined)
1147
+ streamingOverrides.flushEveryMs = parsed.streamingFlushMs;
1148
+ if (Object.keys(streamingOverrides).length) {
1149
+ cliConfig.streaming = streamingOverrides;
1150
+ }
1151
+ const costOverrides = {};
1152
+ if (parsed.costMaxPerRun !== undefined)
1153
+ costOverrides.maxCostPerRun = parsed.costMaxPerRun;
1154
+ if (parsed.costCharPerToken !== undefined)
1155
+ costOverrides.charPerToken = parsed.costCharPerToken;
1156
+ if (parsed.costPricingOverrides) {
1157
+ try {
1158
+ costOverrides.pricingOverrides = JSON.parse(parsed.costPricingOverrides);
1159
+ }
1160
+ catch {
1161
+ // ignore malformed pricing overrides
1162
+ }
1163
+ }
1164
+ if (Object.keys(costOverrides).length) {
1165
+ cliConfig.cost = costOverrides;
1166
+ }
1167
+ const routingOverrides = {};
1168
+ const setRoutingOverride = (phase, key, value) => {
1169
+ if (!value)
1170
+ return;
1171
+ routingOverrides[phase] = {
1172
+ ...(routingOverrides[phase] ?? {}),
1173
+ [key]: value,
1174
+ };
1175
+ };
1176
+ setRoutingOverride("librarian", "agent", parsed.agentLibrarian);
1177
+ setRoutingOverride("architect", "agent", parsed.agentArchitect);
1178
+ setRoutingOverride("builder", "agent", parsed.agentBuilder);
1179
+ setRoutingOverride("critic", "agent", parsed.agentCritic);
1180
+ setRoutingOverride("interpreter", "agent", parsed.agentInterpreter);
1181
+ if (Object.keys(routingOverrides).length) {
1182
+ cliConfig.routing = routingOverrides;
1183
+ }
1184
+ const config = await loadConfig({
1185
+ cli: cliConfig,
1186
+ configPath: parsed.configPath,
1187
+ cwd: resolvedWorkspaceRoot,
1188
+ });
1189
+ if (config.deepInvestigation?.enabled && !config.smart) {
1190
+ throw new Error("Deep investigation requires --smart. Enable smart mode or disable deep investigation.");
1191
+ }
1192
+ if (!config.smart && resolvedAgent?.agent) {
1193
+ const { contextWindow, maxOutputTokens, supportsTools } = resolvedAgent.agent;
1194
+ if (contextWindow && model) {
1195
+ config.localContext.modelTokenLimits = {
1196
+ ...config.localContext.modelTokenLimits,
1197
+ [model]: contextWindow,
1198
+ };
1199
+ }
1200
+ if (maxOutputTokens && config.limits.maxTokens === undefined) {
1201
+ config.limits.maxTokens = maxOutputTokens;
1202
+ }
1203
+ if (supportsTools === false && config.builder.mode === "tool_calls") {
1204
+ config.builder.mode = "patch_json";
1205
+ }
1206
+ }
1207
+ const taskInput = await resolveTaskInput(parsed);
1208
+ if (!taskInput.trim()) {
1209
+ throw new Error("Task input is empty; provide --task <file>, inline text, or pass text via stdin.");
1210
+ }
1211
+ const workflowProfile = config.resolvedWorkflowProfile;
1212
+ const writesAllowed = workflowProfile?.allowWrites !== false;
1213
+ const workflowTaskInput = buildWorkflowTaskInput(taskInput, workflowProfile);
1214
+ const runId = config.runId ?? randomUUID();
1215
+ const runContext = new RunContext(runId, config.workspaceRoot, {
1216
+ request: workflowTaskInput,
1217
+ command: config.command,
1218
+ workspaceRoot: config.workspaceRoot,
1219
+ smart: config.smart,
1220
+ provider: config.provider,
1221
+ model: config.model,
1222
+ builderMode: config.builder.mode,
1223
+ maxRetries: config.limits.maxRetries,
1224
+ maxContextRefreshes: config.context.maxContextRefreshes,
1225
+ maxSteps: config.limits.maxSteps,
1226
+ maxToolCalls: config.limits.maxToolCalls,
1227
+ maxTokens: config.limits.maxTokens,
1228
+ timeoutMs: config.limits.timeoutMs,
1229
+ });
1230
+ const storageRoot = getGlobalWorkspaceDir(config.workspaceRoot);
1231
+ const lock = new WorkspaceLock(storageRoot, runId);
1232
+ await lock.acquire();
1233
+ const logger = new RunLogger(storageRoot, config.logging.directory, runId);
1234
+ const outputLogPath = path.join(path.dirname(logger.logPath), `${runId}.output.log`);
1235
+ await mkdir(path.dirname(outputLogPath), { recursive: true });
1236
+ const outputStream = createWriteStream(outputLogPath, { flags: "a" });
1237
+ const unregisterSignals = lock.registerSignalHandlers({
1238
+ onSignal: async (signal) => {
1239
+ try {
1240
+ await logger.log("run_cancelled", {
1241
+ runId,
1242
+ signal,
1243
+ command: config.command,
1244
+ commandRunId: config.commandRunId,
1245
+ jobId: config.jobId,
1246
+ project: config.project,
1247
+ taskId: config.taskId,
1248
+ taskKey: config.taskKey,
1249
+ });
1250
+ }
1251
+ catch {
1252
+ // ignore logging failures during shutdown
1253
+ }
1254
+ },
1255
+ });
1256
+ await logger.log("run_start", {
1257
+ runId,
1258
+ fingerprint: runContext.fingerprint ?? null,
1259
+ command: config.command,
1260
+ commandRunId: config.commandRunId,
1261
+ jobId: config.jobId,
1262
+ project: config.project,
1263
+ taskId: config.taskId,
1264
+ taskKey: config.taskKey,
1265
+ agentId: config.agentId,
1266
+ agentSlug: config.agentSlug,
1267
+ provider: config.provider,
1268
+ model: config.model,
1269
+ workflow: workflowProfile
1270
+ ? {
1271
+ name: workflowProfile.name,
1272
+ source: workflowProfile.source,
1273
+ command: workflowProfile.command,
1274
+ outputContract: workflowProfile.outputContract,
1275
+ verificationPolicy: workflowProfile.verificationPolicy,
1276
+ verificationMinimumChecks: workflowProfile.verificationMinimumChecks,
1277
+ verificationEnforceHighConfidence: workflowProfile.verificationEnforceHighConfidence,
1278
+ allowWrites: workflowProfile.allowWrites,
1279
+ }
1280
+ : null,
1281
+ policy: {
1282
+ allowShell: config.tools.allowShell ?? false,
1283
+ allowDestructiveOperations: config.tools.allowDestructiveOperations ?? false,
1284
+ allowWrites: writesAllowed,
1285
+ },
1286
+ });
1287
+ let finalMessageContent = "";
1288
+ let usage;
1289
+ let toolCallsExecuted = 0;
1290
+ let pricingSpec;
1291
+ let pricingSource;
1292
+ let estimatedCost;
1293
+ let estimatedTokens;
1294
+ let estimatedChars;
1295
+ let estimatedFocus = 0;
1296
+ let estimatedPeriphery = 0;
1297
+ let smartRuntimeSummary;
1298
+ let summaryDisposition = "pass";
1299
+ let summaryFailureClass;
1300
+ let summaryReasonCodes = [];
1301
+ let summaryFailureStage;
1302
+ let summaryRetryable;
1303
+ let summaryVerification;
1304
+ const phaseProviders = {};
1305
+ let summaryEmitted = false;
1306
+ const emitRunSummary = async () => {
1307
+ const reader = new RunLogReader(config.workspaceRoot, config.logging.directory);
1308
+ const phaseArtifacts = await reader.getPhaseArtifacts(runId);
1309
+ const phaseArtifactQuery = await reader.queryEvents({
1310
+ filters: { run_id: runId, event_type: "phase_artifact" },
1311
+ limit: 2000,
1312
+ sort: "asc",
1313
+ });
1314
+ const phaseArtifactEvents = phaseArtifactQuery.events
1315
+ .map((event) => {
1316
+ const data = event.data;
1317
+ return {
1318
+ phase: typeof data.phase === "string" ? data.phase : undefined,
1319
+ kind: typeof data.kind === "string" ? data.kind : undefined,
1320
+ path: typeof data.path === "string" ? data.path : undefined,
1321
+ };
1322
+ });
1323
+ const requiredArtifacts = config.smart
1324
+ ? [
1325
+ "retrieve:summary",
1326
+ "retrieve:retrieval_report",
1327
+ "plan:summary",
1328
+ "act:summary",
1329
+ "verify:plan",
1330
+ "verify:verification_report",
1331
+ ]
1332
+ : [];
1333
+ const { references: artifactReferences, missing } = buildArtifactReferences(phaseArtifactEvents, requiredArtifacts);
1334
+ const phaseDurations = collectPhaseDurations(phaseArtifacts);
1335
+ const phaseTelemetry = buildPhaseTelemetry({
1336
+ runId,
1337
+ phaseProviders,
1338
+ phaseDurations,
1339
+ usage,
1340
+ pricingSpec,
1341
+ pricingSource,
1342
+ });
1343
+ for (const telemetry of phaseTelemetry) {
1344
+ await logger.logPhaseTelemetry(telemetry);
1345
+ }
1346
+ const actualCost = estimateCostFromUsage(usage, pricingSpec);
1347
+ const finalReasonCodes = uniqueStrings(summaryReasonCodes);
1348
+ const finalFailureClass = summaryDisposition === "pass"
1349
+ ? undefined
1350
+ : summaryFailureClass
1351
+ ?? inferFailureClass(summaryFailureStage, finalReasonCodes);
1352
+ const verificationSummary = summaryVerification
1353
+ ? {
1354
+ outcome: summaryVerification.outcome,
1355
+ reasonCodes: summaryVerification.reason_codes,
1356
+ policy: summaryVerification.policy,
1357
+ totals: summaryVerification.totals,
1358
+ }
1359
+ : smartRuntimeSummary?.verification
1360
+ ?? null;
1361
+ await logger.logRunSummary({
1362
+ run_id: runId,
1363
+ runId,
1364
+ fingerprint: runContext.fingerprint ?? null,
1365
+ toolCallsExecuted,
1366
+ touchedFiles: runContext.getTouchedFiles(),
1367
+ durationMs: Date.now() - runContext.startedAt,
1368
+ usage,
1369
+ costEstimate: {
1370
+ charCount: estimatedChars,
1371
+ estimatedTokens,
1372
+ estimatedCost,
1373
+ pricingSource,
1374
+ },
1375
+ actualCost,
1376
+ budget: {
1377
+ maxSteps: config.limits.maxSteps,
1378
+ maxToolCalls: config.limits.maxToolCalls,
1379
+ maxTokens: config.limits.maxTokens ?? null,
1380
+ timeoutMs: config.limits.timeoutMs ?? null,
1381
+ consumedDurationMs: Date.now() - runContext.startedAt,
1382
+ consumedToolCalls: toolCallsExecuted,
1383
+ },
1384
+ quality_dimensions: buildQualityDimensions(artifactReferences, summaryDisposition),
1385
+ final_disposition: {
1386
+ status: summaryDisposition,
1387
+ failure_class: finalFailureClass,
1388
+ reason_codes: finalReasonCodes,
1389
+ stage: summaryFailureStage,
1390
+ retryable: summaryRetryable ?? null,
1391
+ },
1392
+ artifact_references: artifactReferences,
1393
+ phase_telemetry: phaseTelemetry,
1394
+ missing_artifacts: missing,
1395
+ smartRuntime: smartRuntimeSummary ?? null,
1396
+ verification: verificationSummary,
1397
+ workflow: workflowProfile
1398
+ ? {
1399
+ name: workflowProfile.name,
1400
+ source: workflowProfile.source,
1401
+ command: workflowProfile.command,
1402
+ outputContract: workflowProfile.outputContract,
1403
+ verificationPolicy: workflowProfile.verificationPolicy,
1404
+ verificationMinimumChecks: workflowProfile.verificationMinimumChecks,
1405
+ verificationEnforceHighConfidence: workflowProfile.verificationEnforceHighConfidence,
1406
+ allowWrites: workflowProfile.allowWrites,
1407
+ }
1408
+ : null,
1409
+ policy: {
1410
+ allowShell: config.tools.allowShell ?? false,
1411
+ allowDestructiveOperations: config.tools.allowDestructiveOperations ?? false,
1412
+ allowWrites: writesAllowed,
1413
+ },
1414
+ command: config.command,
1415
+ commandRunId: config.commandRunId,
1416
+ jobId: config.jobId,
1417
+ project: config.project,
1418
+ taskId: config.taskId,
1419
+ task_id: config.taskId,
1420
+ taskKey: config.taskKey,
1421
+ agentId: config.agentId,
1422
+ agentSlug: config.agentSlug,
1423
+ smart: config.smart ?? false,
1424
+ });
1425
+ };
1426
+ try {
1427
+ const registry = new ToolRegistry();
1428
+ const registerIfEnabled = (tool) => {
1429
+ if (!writesAllowed && tool.name === "write_file") {
1430
+ return;
1431
+ }
1432
+ if (isToolEnabled(tool.name, config.tools)) {
1433
+ registry.register(tool);
1434
+ }
1435
+ };
1436
+ for (const tool of createFileTools())
1437
+ registerIfEnabled(tool);
1438
+ registerIfEnabled(createDiffTool());
1439
+ registerIfEnabled(createSearchTool());
1440
+ registerIfEnabled(createShellTool());
1441
+ const docdexClient = new DocdexClient({
1442
+ baseUrl: config.docdex.baseUrl,
1443
+ repoId: config.docdex.repoId,
1444
+ repoRoot: config.docdex.repoRoot ?? config.workspaceRoot,
1445
+ dagSessionId: runId,
1446
+ });
1447
+ for (const tool of createDocdexTools(docdexClient))
1448
+ registerIfEnabled(tool);
1449
+ const toolContext = {
1450
+ workspaceRoot: config.workspaceRoot,
1451
+ recordTouchedFile: (filePath) => runContext.recordTouchedFile(filePath),
1452
+ allowOutsideWorkspace: config.tools.allowOutsideWorkspace,
1453
+ allowShell: config.tools.allowShell,
1454
+ allowDestructiveOperations: config.tools.allowDestructiveOperations,
1455
+ shellAllowlist: config.tools.shellAllowlist,
1456
+ };
1457
+ const streamState = createStreamState(config.streaming.flushEveryMs, outputStream);
1458
+ if (config.smart) {
1459
+ const hasRoutingAgent = Object.values(config.routing ?? {}).some((phase) => Boolean(phase?.agent));
1460
+ const hasExplicitProvider = Boolean(parsed.provider || parsed.model || parsed.baseUrl || parsed.apiKey);
1461
+ const shouldForceAgentDefaults = !agentRef && !hasRoutingAgent && !hasExplicitProvider;
1462
+ const shouldSelectAgents = config.provider !== "stub";
1463
+ const emptySelection = (phase) => ({
1464
+ phase,
1465
+ capabilities: [],
1466
+ source: "none",
1467
+ });
1468
+ const phaseOverrides = {
1469
+ librarian: config.routing?.librarian?.agent,
1470
+ architect: config.routing?.architect?.agent,
1471
+ builder: config.routing?.builder?.agent,
1472
+ critic: config.routing?.critic?.agent,
1473
+ interpreter: config.routing?.interpreter?.agent,
1474
+ };
1475
+ const phaseExclusions = {};
1476
+ let phaseSelections = shouldSelectAgents
1477
+ ? await selectPhaseAgents({
1478
+ overrides: phaseOverrides,
1479
+ builderMode: config.builder.mode,
1480
+ fallbackAgent: resolvedAgent,
1481
+ allowCloudModels: config.security.allowCloudModels,
1482
+ excludeAgentIds: phaseExclusions,
1483
+ })
1484
+ : {
1485
+ librarian: emptySelection("librarian"),
1486
+ architect: emptySelection("architect"),
1487
+ builder: emptySelection("builder"),
1488
+ critic: emptySelection("critic"),
1489
+ interpreter: emptySelection("interpreter"),
1490
+ };
1491
+ if (shouldSelectAgents) {
1492
+ const unresolvedPhases = Object.values(phaseSelections)
1493
+ .filter((selection) => !selection.resolved)
1494
+ .map((selection) => selection.phase);
1495
+ if (unresolvedPhases.length > 0) {
1496
+ throw new Error(`No eligible mcoda agents found for phase(s): ${unresolvedPhases.join(", ")}. ` +
1497
+ "Add/configure agents and verify with `mcoda agent list --json`.");
1498
+ }
1499
+ }
1500
+ const fallbackResolved = phaseSelections.builder.resolved ??
1501
+ phaseSelections.architect.resolved ??
1502
+ phaseSelections.critic.resolved ??
1503
+ phaseSelections.librarian.resolved ??
1504
+ phaseSelections.interpreter.resolved ??
1505
+ resolvedAgent;
1506
+ if (shouldForceAgentDefaults) {
1507
+ if (!fallbackResolved) {
1508
+ throw new Error("No eligible agents found in the mcoda agent registry. Run `mcoda agent list` or supply --agent/--provider/--model.");
1509
+ }
1510
+ config.provider = fallbackResolved.provider;
1511
+ config.model = fallbackResolved.model;
1512
+ config.apiKey = fallbackResolved.apiKey;
1513
+ config.baseUrl = fallbackResolved.baseUrl;
1514
+ }
1515
+ else if (!config.provider || !config.model) {
1516
+ if (fallbackResolved) {
1517
+ config.provider = config.provider || fallbackResolved.provider;
1518
+ config.model = config.model || fallbackResolved.model;
1519
+ config.apiKey = config.apiKey ?? fallbackResolved.apiKey;
1520
+ config.baseUrl = config.baseUrl ?? fallbackResolved.baseUrl;
1521
+ }
1522
+ }
1523
+ if (!config.provider || !config.model) {
1524
+ throw new Error("Missing provider/model after agent resolution. Provide --agent or configure routing defaults.");
1525
+ }
1526
+ const defaults = {
1527
+ provider: config.provider,
1528
+ config: {
1529
+ model: config.model,
1530
+ apiKey: config.apiKey,
1531
+ baseUrl: config.baseUrl,
1532
+ timeoutMs: config.limits.timeoutMs,
1533
+ },
1534
+ };
1535
+ const selectedPhaseModels = new Set(Object.values(phaseSelections)
1536
+ .map((selection) => selection.resolved?.model)
1537
+ .filter((value) => Boolean(value)));
1538
+ if (shouldSelectAgents &&
1539
+ config.localContext.summarize.model &&
1540
+ !selectedPhaseModels.has(config.localContext.summarize.model)) {
1541
+ throw new Error(`CODALI_LOCAL_CONTEXT_SUMMARIZE_MODEL (${config.localContext.summarize.model}) ` +
1542
+ "must match a model from selected mcoda agents.");
1543
+ }
1544
+ for (const selection of Object.values(phaseSelections)) {
1545
+ if (!selection.resolved)
1546
+ continue;
1547
+ const contextWindow = selection.resolved.agent.contextWindow;
1548
+ if (contextWindow) {
1549
+ config.localContext.modelTokenLimits = {
1550
+ ...config.localContext.modelTokenLimits,
1551
+ [selection.resolved.model]: contextWindow,
1552
+ };
1553
+ }
1554
+ }
1555
+ const builderSelection = phaseSelections.builder;
1556
+ if (builderSelection.resolved?.agent.maxOutputTokens && config.limits.maxTokens === undefined) {
1557
+ config.limits.maxTokens = builderSelection.resolved.agent.maxOutputTokens;
1558
+ }
1559
+ if (builderSelection.resolved?.agent.supportsTools === false &&
1560
+ config.builder.mode === "tool_calls") {
1561
+ config.builder.mode = "patch_json";
1562
+ }
1563
+ for (const selection of Object.values(phaseSelections)) {
1564
+ if (!selection.resolved)
1565
+ continue;
1566
+ await logger.log("phase_agent_selected", {
1567
+ phase: selection.phase,
1568
+ agentId: selection.resolved.agent.id,
1569
+ agentSlug: selection.resolved.agent.slug,
1570
+ provider: selection.resolved.provider,
1571
+ model: selection.resolved.model,
1572
+ source: selection.source,
1573
+ score: selection.score,
1574
+ reason: selection.reason,
1575
+ });
1576
+ }
1577
+ const buildDefaultsForPhase = (phase) => {
1578
+ const selected = phaseSelections[phase].resolved;
1579
+ return selected
1580
+ ? {
1581
+ provider: selected.provider,
1582
+ config: {
1583
+ model: selected.model,
1584
+ apiKey: selected.apiKey,
1585
+ baseUrl: selected.baseUrl,
1586
+ timeoutMs: config.limits.timeoutMs,
1587
+ },
1588
+ }
1589
+ : defaults;
1590
+ };
1591
+ const librarianDefaults = buildDefaultsForPhase("librarian");
1592
+ const architectDefaults = buildDefaultsForPhase("architect");
1593
+ const builderDefaults = buildDefaultsForPhase("builder");
1594
+ const criticDefaults = buildDefaultsForPhase("critic");
1595
+ const interpreterDefaults = buildDefaultsForPhase("interpreter");
1596
+ const librarianRoute = buildRoutedProvider("librarian", librarianDefaults, config.routing, Boolean(phaseSelections.librarian.resolved));
1597
+ const architectRoute = buildRoutedProvider("architect", architectDefaults, config.routing, Boolean(phaseSelections.architect.resolved));
1598
+ const builderRoute = buildRoutedProvider("builder", builderDefaults, config.routing, Boolean(phaseSelections.builder.resolved));
1599
+ const criticRoute = buildRoutedProvider("critic", criticDefaults, config.routing, Boolean(phaseSelections.critic.resolved));
1600
+ const interpreterPhaseRoute = buildRoutedProvider("interpreter", interpreterDefaults, config.routing, Boolean(phaseSelections.interpreter.resolved));
1601
+ const phaseRoutes = {
1602
+ librarian: librarianRoute,
1603
+ architect: architectRoute,
1604
+ builder: builderRoute,
1605
+ critic: criticRoute,
1606
+ interpreter: interpreterPhaseRoute,
1607
+ };
1608
+ phaseProviders.retrieve = {
1609
+ provider: librarianRoute.provider,
1610
+ model: librarianRoute.config.model,
1611
+ };
1612
+ phaseProviders.plan = {
1613
+ provider: architectRoute.provider,
1614
+ model: architectRoute.config.model,
1615
+ };
1616
+ phaseProviders.act = {
1617
+ provider: builderRoute.provider,
1618
+ model: builderRoute.config.model,
1619
+ };
1620
+ phaseProviders.verify = {
1621
+ provider: criticRoute.provider,
1622
+ model: criticRoute.config.model,
1623
+ };
1624
+ const librarianProvider = createProvider(librarianRoute.provider, librarianRoute.config);
1625
+ const architectProvider = createProvider(architectRoute.provider, architectRoute.config);
1626
+ const builderProvider = createProvider(builderRoute.provider, builderRoute.config);
1627
+ const profileAgentId = config.agentId ??
1628
+ config.agentSlug ??
1629
+ phaseSelections.architect.resolved?.agent.id ??
1630
+ phaseSelections.critic.resolved?.agent.id ??
1631
+ phaseSelections.librarian.resolved?.agent.id ??
1632
+ phaseSelections.builder.resolved?.agent.id ??
1633
+ phaseSelections.interpreter.resolved?.agent.id ??
1634
+ "codali";
1635
+ const store = new ContextStore({
1636
+ workspaceRoot: storageRoot,
1637
+ storageDir: config.localContext.storageDir,
1638
+ });
1639
+ const redactor = config.context.redactSecrets
1640
+ ? new ContextRedactor({
1641
+ workspaceRoot: config.workspaceRoot,
1642
+ ignoreFilesFrom: config.context.ignoreFilesFrom,
1643
+ redactPatterns: config.security.redactPatterns,
1644
+ })
1645
+ : undefined;
1646
+ if (redactor) {
1647
+ await redactor.loadIgnoreMatchers();
1648
+ }
1649
+ let summarizer;
1650
+ if (config.localContext.enabled && config.localContext.summarize.enabled) {
1651
+ const providerKey = config.localContext.summarize.provider;
1652
+ let summarizerProviderName = providerKey;
1653
+ let summarizerConfig = { ...defaults.config };
1654
+ let summarizerTemperature;
1655
+ if (isPhaseProvider(providerKey)) {
1656
+ const route = phaseRoutes[providerKey];
1657
+ summarizerProviderName = route.provider;
1658
+ summarizerConfig = { ...route.config };
1659
+ summarizerTemperature = route.temperature;
1660
+ }
1661
+ if (config.localContext.summarize.model) {
1662
+ summarizerConfig = {
1663
+ ...summarizerConfig,
1664
+ model: config.localContext.summarize.model,
1665
+ };
1666
+ }
1667
+ const summarizerProvider = createProvider(summarizerProviderName, summarizerConfig);
1668
+ summarizer = new ContextSummarizer(summarizerProvider, {
1669
+ maxTokens: config.localContext.summarize.targetTokens,
1670
+ temperature: summarizerTemperature,
1671
+ logger,
1672
+ });
1673
+ }
1674
+ const contextManager = new ContextManager({
1675
+ config: config.localContext,
1676
+ store,
1677
+ redactor,
1678
+ summarizer,
1679
+ logger,
1680
+ charPerToken: config.cost.charPerToken,
1681
+ });
1682
+ const laneScope = {
1683
+ jobId: config.jobId ?? config.commandRunId,
1684
+ runId,
1685
+ taskId: config.taskId,
1686
+ taskKey: config.taskKey,
1687
+ };
1688
+ const deepMode = Boolean(config.deepInvestigation?.enabled);
1689
+ const contextAssembler = new ContextAssembler(docdexClient, {
1690
+ workspaceRoot: config.workspaceRoot,
1691
+ queryProvider: librarianProvider,
1692
+ queryTemperature: librarianRoute?.temperature,
1693
+ agentId: profileAgentId,
1694
+ maxFiles: config.context.maxFiles,
1695
+ maxTotalBytes: config.context.maxTotalBytes,
1696
+ tokenBudget: config.context.tokenBudget,
1697
+ includeRepoMap: config.context.includeRepoMap,
1698
+ includeImpact: config.context.includeImpact,
1699
+ includeSnippets: config.context.includeSnippets,
1700
+ readStrategy: config.context.readStrategy,
1701
+ focusMaxFileBytes: config.context.focusMaxFileBytes,
1702
+ peripheryMaxBytes: config.context.peripheryMaxBytes,
1703
+ skeletonizeLargeFiles: config.context.skeletonizeLargeFiles,
1704
+ serializationMode: config.context.mode,
1705
+ redactSecrets: config.context.redactSecrets,
1706
+ redactPatterns: config.security.redactPatterns,
1707
+ ignoreFilesFrom: config.context.ignoreFilesFrom,
1708
+ preferredFiles: config.context.preferredFiles,
1709
+ recentFiles: config.context.recentFiles,
1710
+ readOnlyPaths: config.security.readOnlyPaths,
1711
+ allowDocEdits: config.security.allowDocEdits,
1712
+ deepMode,
1713
+ contextManager,
1714
+ laneScope,
1715
+ onEvent: streamState.onEvent,
1716
+ logger,
1717
+ });
1718
+ const deepScanPreset = Boolean(config.deepInvestigation?.enabled && config.deepInvestigation?.deepScanPreset);
1719
+ if (deepScanPreset) {
1720
+ contextAssembler.applyDeepScanPreset();
1721
+ }
1722
+ const preflightContext = await contextAssembler.assemble(workflowTaskInput);
1723
+ const pricingResolution = resolvePricing(config.cost.pricingOverrides, builderRoute.provider, builderRoute.config.model);
1724
+ pricingSpec = pricingResolution.pricing;
1725
+ pricingSource = pricingResolution.source;
1726
+ const summary = summarizeContext(preflightContext, workflowTaskInput);
1727
+ estimatedFocus = summary.focusCount;
1728
+ estimatedPeriphery = summary.peripheryCount;
1729
+ const estimate = estimateCostFromChars(summary.charCount, config.cost.charPerToken, pricingSpec, pricingSource);
1730
+ estimatedCost = estimate.estimatedCost;
1731
+ estimatedTokens = estimate.estimatedTotalTokens;
1732
+ estimatedChars = estimate.charCount;
1733
+ await logger.log("cost_estimate", {
1734
+ provider: builderRoute.provider,
1735
+ model: builderRoute.config.model,
1736
+ focusCount: estimatedFocus,
1737
+ peripheryCount: estimatedPeriphery,
1738
+ charCount: estimatedChars,
1739
+ estimatedTokens,
1740
+ estimatedCost,
1741
+ pricingSource,
1742
+ });
1743
+ process.stderr.write(`[codali] Preflight: focus=${estimatedFocus} periphery=${estimatedPeriphery} ` +
1744
+ `chars=${estimatedChars} tokens~${estimatedTokens} est_cost=${formatCost(estimatedCost)}\n`);
1745
+ if (estimatedCost !== undefined && estimatedCost > config.cost.maxCostPerRun) {
1746
+ const proceed = await confirmOverage(`Estimated cost ${formatCost(estimatedCost)} exceeds max ${formatCost(config.cost.maxCostPerRun)}. Continue? [y/N] `);
1747
+ if (!proceed) {
1748
+ throw new Error("Run cancelled due to cost limit");
1749
+ }
1750
+ }
1751
+ const architectPlanner = new ArchitectPlanner(architectProvider, {
1752
+ temperature: architectRoute.temperature,
1753
+ logger,
1754
+ model: architectRoute.config.model,
1755
+ // Architect is intentionally plain-text first; avoid hard response-format constraints.
1756
+ responseFormat: undefined,
1757
+ planHint: config.planHint,
1758
+ stream: config.streaming.enabled,
1759
+ onEvent: streamState.onEvent,
1760
+ });
1761
+ const builderResponseFormat = builderRoute.responseFormat ?? (config.builder.mode === "patch_json" ? { type: "json" } : undefined);
1762
+ const patchValidator = createPatchValidator(config.workspaceRoot, config.tools.allowShell ?? false, config.tools.shellAllowlist ?? []);
1763
+ const needsPatchApplier = config.builder.mode === "patch_json" || config.builder.mode === "freeform" || config.builder.mode === "tool_calls";
1764
+ const patchApplier = needsPatchApplier
1765
+ ? new PatchApplier({
1766
+ workspaceRoot: config.workspaceRoot,
1767
+ validateFile: patchValidator,
1768
+ policy: {
1769
+ allowDestructiveOperations: config.tools.allowDestructiveOperations ?? false,
1770
+ allowWrites: writesAllowed,
1771
+ },
1772
+ })
1773
+ : undefined;
1774
+ const wantsInterpreter = config.builder.mode === "freeform" || config.builder.fallbackToInterpreter === true;
1775
+ const interpreterRoute = wantsInterpreter
1776
+ ? resolveInterpreterRoute(config, phaseRoutes)
1777
+ : undefined;
1778
+ const interpreterProvider = interpreterRoute
1779
+ ? createProvider(interpreterRoute.provider, {
1780
+ ...interpreterRoute.config,
1781
+ timeoutMs: config.interpreter.timeoutMs ??
1782
+ interpreterRoute.config.timeoutMs ??
1783
+ config.limits.timeoutMs,
1784
+ })
1785
+ : undefined;
1786
+ const interpreterResponseFormat = config.interpreter.format
1787
+ ? {
1788
+ type: config.interpreter.format,
1789
+ grammar: config.interpreter.grammar,
1790
+ }
1791
+ : { type: "json" };
1792
+ const patchInterpreter = interpreterProvider && wantsInterpreter
1793
+ ? new PatchInterpreter({
1794
+ provider: interpreterProvider,
1795
+ patchFormat: config.builder.patchFormat,
1796
+ responseFormat: interpreterResponseFormat,
1797
+ maxRetries: config.interpreter.maxRetries,
1798
+ timeoutMs: config.interpreter.timeoutMs,
1799
+ logger,
1800
+ model: interpreterRoute?.config.model,
1801
+ temperature: interpreterRoute?.temperature,
1802
+ })
1803
+ : undefined;
1804
+ const builderRunner = new BuilderRunner({
1805
+ provider: builderProvider,
1806
+ tools: registry,
1807
+ context: toolContext,
1808
+ maxSteps: config.limits.maxSteps,
1809
+ maxToolCalls: config.limits.maxToolCalls,
1810
+ maxTokens: config.limits.maxTokens,
1811
+ timeoutMs: config.limits.timeoutMs,
1812
+ temperature: builderRoute.temperature,
1813
+ responseFormat: builderResponseFormat,
1814
+ mode: config.builder.mode,
1815
+ patchFormat: config.builder.patchFormat,
1816
+ patchApplier,
1817
+ interpreter: patchInterpreter,
1818
+ fallbackToInterpreter: config.builder.fallbackToInterpreter ?? false,
1819
+ allowDestructiveOperations: config.tools.allowDestructiveOperations ?? false,
1820
+ stream: config.streaming.enabled,
1821
+ onEvent: streamState.onEvent,
1822
+ onToken: streamState.onToken,
1823
+ streamFlushMs: config.streaming.flushEveryMs,
1824
+ logger,
1825
+ model: builderRoute.config.model,
1826
+ });
1827
+ const validator = new ValidationRunner({
1828
+ allowShell: config.tools.allowShell ?? false,
1829
+ shellAllowlist: config.tools.shellAllowlist ?? [],
1830
+ workspaceRoot: config.workspaceRoot,
1831
+ docdexClient,
1832
+ defaultPolicyName: workflowProfile?.verificationPolicy,
1833
+ defaultMinimumChecks: workflowProfile?.verificationMinimumChecks,
1834
+ defaultEnforceHighConfidence: workflowProfile?.verificationEnforceHighConfidence,
1835
+ });
1836
+ const criticEvaluator = new CriticEvaluator(validator, {
1837
+ model: criticRoute.config.model,
1838
+ logger,
1839
+ });
1840
+ const memoryWriteback = new MemoryWriteback(docdexClient, {
1841
+ agentId: profileAgentId,
1842
+ workspaceRoot: config.workspaceRoot,
1843
+ learning: config.learning,
1844
+ logger,
1845
+ });
1846
+ const phaseFallbackCounts = {};
1847
+ const maxPhaseFallbacks = 3;
1848
+ const recoverPhaseProvider = async (input) => {
1849
+ if (!shouldSelectAgents)
1850
+ return { switched: false };
1851
+ const phase = input.phase;
1852
+ const currentSelection = phaseSelections[phase];
1853
+ const currentResolved = currentSelection.resolved;
1854
+ if (!currentResolved)
1855
+ return { switched: false };
1856
+ const currentAgentId = currentResolved.agent.id;
1857
+ if (!currentAgentId)
1858
+ return { switched: false };
1859
+ const fallbackCount = phaseFallbackCounts[phase] ?? 0;
1860
+ if (fallbackCount >= maxPhaseFallbacks) {
1861
+ await logger.log("phase_agent_fallback_skipped", {
1862
+ phase,
1863
+ reason: "fallback_limit_reached",
1864
+ limit: maxPhaseFallbacks,
1865
+ error: input.error.message,
1866
+ });
1867
+ return { switched: false };
1868
+ }
1869
+ const excluded = Array.from(new Set([...(phaseExclusions[phase] ?? []), currentAgentId]));
1870
+ phaseExclusions[phase] = excluded;
1871
+ let currentExcluded = excluded;
1872
+ const evaluatedAgentIds = new Set();
1873
+ let reselection;
1874
+ let nextSelection;
1875
+ let nextResolved = undefined;
1876
+ let selectedBuilderMode = config.builder.mode;
1877
+ while (true) {
1878
+ reselection = await selectPhaseAgents({
1879
+ overrides: phaseOverrides,
1880
+ builderMode: config.builder.mode,
1881
+ fallbackAgent: resolvedAgent,
1882
+ allowCloudModels: config.security.allowCloudModels,
1883
+ excludeAgentIds: {
1884
+ ...phaseExclusions,
1885
+ [phase]: currentExcluded,
1886
+ },
1887
+ });
1888
+ nextSelection = reselection[phase];
1889
+ nextResolved = nextSelection.resolved;
1890
+ if (!nextResolved || nextResolved.agent.id === currentAgentId) {
1891
+ await logger.log("phase_agent_fallback_skipped", {
1892
+ phase,
1893
+ reason: "no_alternate_agent",
1894
+ currentAgentId,
1895
+ excluded: currentExcluded,
1896
+ error: input.error.message,
1897
+ });
1898
+ return { switched: false };
1899
+ }
1900
+ const nextAgentId = nextResolved.agent.id;
1901
+ if (evaluatedAgentIds.has(nextAgentId)) {
1902
+ await logger.log("phase_agent_fallback_skipped", {
1903
+ phase,
1904
+ reason: "no_eligible_alternate_agent",
1905
+ currentAgentId,
1906
+ excluded: currentExcluded,
1907
+ error: input.error.message,
1908
+ });
1909
+ return { switched: false };
1910
+ }
1911
+ evaluatedAgentIds.add(nextAgentId);
1912
+ const suitability = assessPhaseFallbackSuitability(phase, config.builder.mode, {
1913
+ capabilities: nextSelection.capabilities,
1914
+ supportsTools: nextResolved.agent.supportsTools ?? false,
1915
+ });
1916
+ if (suitability.ok) {
1917
+ selectedBuilderMode = suitability.builderMode ?? config.builder.mode;
1918
+ break;
1919
+ }
1920
+ currentExcluded = Array.from(new Set([...currentExcluded, nextAgentId]));
1921
+ phaseExclusions[phase] = currentExcluded;
1922
+ await logger.log("phase_agent_fallback_rejected", {
1923
+ phase,
1924
+ reason: suitability.reason,
1925
+ agentId: nextAgentId,
1926
+ agentSlug: nextResolved.agent.slug,
1927
+ currentAgentId,
1928
+ excluded: currentExcluded,
1929
+ details: suitability.details ?? null,
1930
+ error: input.error.message,
1931
+ });
1932
+ }
1933
+ phaseExclusions[phase] = currentExcluded;
1934
+ if (!reselection || !nextSelection || !nextResolved) {
1935
+ await logger.log("phase_agent_fallback_skipped", {
1936
+ phase,
1937
+ reason: "reselection_failed",
1938
+ currentAgentId,
1939
+ excluded: currentExcluded,
1940
+ error: input.error.message,
1941
+ });
1942
+ return { switched: false };
1943
+ }
1944
+ phaseSelections = reselection;
1945
+ phaseFallbackCounts[phase] = fallbackCount + 1;
1946
+ const phaseDefaults = {
1947
+ provider: nextResolved.provider,
1948
+ config: {
1949
+ model: nextResolved.model,
1950
+ apiKey: nextResolved.apiKey,
1951
+ baseUrl: nextResolved.baseUrl,
1952
+ timeoutMs: config.limits.timeoutMs,
1953
+ },
1954
+ };
1955
+ const nextRoute = buildRoutedProvider(phase, phaseDefaults, config.routing, true);
1956
+ const mappedPhase = toSummaryPhase(phase);
1957
+ if (mappedPhase) {
1958
+ phaseProviders[mappedPhase] = {
1959
+ provider: nextRoute.provider,
1960
+ model: nextRoute.config.model,
1961
+ };
1962
+ }
1963
+ if (phase === "builder") {
1964
+ const priorBuilderMode = config.builder.mode;
1965
+ if (selectedBuilderMode !== priorBuilderMode) {
1966
+ config.builder.mode = selectedBuilderMode;
1967
+ await logger.log("phase_agent_fallback_mode_change", {
1968
+ phase,
1969
+ fromMode: priorBuilderMode,
1970
+ toMode: selectedBuilderMode,
1971
+ reason: "fallback_suitability",
1972
+ });
1973
+ }
1974
+ const nextProvider = createProvider(nextRoute.provider, nextRoute.config);
1975
+ const nextResponseFormat = nextRoute.responseFormat
1976
+ ?? (config.builder.mode === "patch_json" ? { type: "json" } : undefined);
1977
+ builderRunner.setProvider(nextProvider, {
1978
+ model: nextRoute.config.model,
1979
+ temperature: nextRoute.temperature,
1980
+ responseFormat: nextResponseFormat,
1981
+ mode: config.builder.mode,
1982
+ });
1983
+ }
1984
+ await logger.log("phase_agent_selected", {
1985
+ phase,
1986
+ agentId: nextResolved.agent.id,
1987
+ agentSlug: nextResolved.agent.slug,
1988
+ provider: nextResolved.provider,
1989
+ model: nextResolved.model,
1990
+ source: "fallback",
1991
+ reason: `provider_failure_recovery:${input.error.message}`,
1992
+ });
1993
+ await logger.log("phase_agent_fallback", {
1994
+ phase,
1995
+ fromAgentId: currentAgentId,
1996
+ toAgentId: nextResolved.agent.id,
1997
+ attempt: input.attempt,
1998
+ fallback_count: phaseFallbackCounts[phase],
1999
+ error: input.error.message,
2000
+ });
2001
+ return {
2002
+ switched: true,
2003
+ note: `Provider failure (${input.error.message}). ` +
2004
+ `Switched ${phase} agent to ${nextResolved.agent.slug ?? nextResolved.agent.id}; continue with current plan.`,
2005
+ };
2006
+ };
2007
+ const pipeline = new SmartPipeline({
2008
+ contextAssembler,
2009
+ initialContext: preflightContext,
2010
+ architectPlanner,
2011
+ builderRunner,
2012
+ criticEvaluator,
2013
+ memoryWriteback,
2014
+ maxRetries: config.limits.maxRetries,
2015
+ maxContextRefreshes: config.context.maxContextRefreshes,
2016
+ fastPath: undefined,
2017
+ deepMode,
2018
+ deepScanPreset,
2019
+ deepInvestigation: config.deepInvestigation,
2020
+ getTouchedFiles: () => runContext.getTouchedFiles(),
2021
+ logger,
2022
+ contextManager,
2023
+ laneScope,
2024
+ verificationPolicyName: workflowProfile?.verificationPolicy,
2025
+ minimumVerificationChecks: workflowProfile?.verificationMinimumChecks,
2026
+ enforceVerificationHighConfidence: workflowProfile?.verificationEnforceHighConfidence,
2027
+ onEvent: streamState.onEvent,
2028
+ onPhaseProviderFailure: recoverPhaseProvider,
2029
+ });
2030
+ const result = await pipeline.run(workflowTaskInput);
2031
+ for (const file of result.builderResult.touchedFiles ?? []) {
2032
+ runContext.recordTouchedFile(file);
2033
+ }
2034
+ smartRuntimeSummary = {
2035
+ attempts: result.attempts,
2036
+ maxRetries: config.limits.maxRetries,
2037
+ maxContextRefreshes: config.context.maxContextRefreshes,
2038
+ contextRefreshTerminationReason: result.contextRefreshTerminationReason ?? null,
2039
+ phaseTrace: result.phaseTrace,
2040
+ verification: result.verification
2041
+ ? {
2042
+ outcome: result.verification.outcome,
2043
+ reasonCodes: result.verification.reason_codes,
2044
+ highConfidence: result.criticResult.report?.high_confidence
2045
+ ?? result.criticResult.high_confidence
2046
+ ?? false,
2047
+ policy: result.verification.policy,
2048
+ totals: result.verification.totals,
2049
+ }
2050
+ : null,
2051
+ };
2052
+ summaryVerification = result.verification;
2053
+ if (result.criticResult.status !== "PASS") {
2054
+ const failureReasons = result.criticResult.reasons?.length
2055
+ ? result.criticResult.reasons
2056
+ : ["smart_pipeline_failed"];
2057
+ summaryDisposition = "fail";
2058
+ summaryFailureStage = "smart_pipeline";
2059
+ summaryRetryable = result.criticResult.retryable ?? null;
2060
+ summaryReasonCodes = uniqueStrings(failureReasons);
2061
+ summaryFailureClass = inferFailureClass(summaryFailureStage, summaryReasonCodes);
2062
+ await logger.log("run_failed", {
2063
+ stage: "smart_pipeline",
2064
+ reasons: failureReasons,
2065
+ failure_class: summaryFailureClass,
2066
+ retryable: result.criticResult.retryable ?? null,
2067
+ report: result.criticResult.report ?? null,
2068
+ });
2069
+ throw new Error(`Smart pipeline failed: ${failureReasons.join("; ")}`);
2070
+ }
2071
+ if (result.verification && result.verification.outcome !== "verified_passed") {
2072
+ summaryDisposition = "degraded";
2073
+ summaryFailureStage = "verify";
2074
+ summaryReasonCodes = uniqueStrings(result.verification.reason_codes.map((code) => `verification_${code}`));
2075
+ summaryFailureClass = "verification_failure";
2076
+ }
2077
+ finalMessageContent = result.builderResult.finalMessage.content;
2078
+ usage = result.builderResult.usage;
2079
+ toolCallsExecuted = result.builderResult.toolCallsExecuted;
2080
+ }
2081
+ else {
2082
+ const pricingResolution = resolvePricing(config.cost.pricingOverrides, config.provider, config.model);
2083
+ pricingSpec = pricingResolution.pricing;
2084
+ pricingSource = pricingResolution.source;
2085
+ phaseProviders.act = {
2086
+ provider: config.provider,
2087
+ model: config.model,
2088
+ };
2089
+ const summary = summarizeContext(undefined, workflowTaskInput);
2090
+ estimatedFocus = summary.focusCount;
2091
+ estimatedPeriphery = summary.peripheryCount;
2092
+ const estimate = estimateCostFromChars(summary.charCount, config.cost.charPerToken, pricingSpec, pricingSource);
2093
+ estimatedCost = estimate.estimatedCost;
2094
+ estimatedTokens = estimate.estimatedTotalTokens;
2095
+ estimatedChars = estimate.charCount;
2096
+ await logger.log("cost_estimate", {
2097
+ provider: config.provider,
2098
+ model: config.model,
2099
+ focusCount: estimatedFocus,
2100
+ peripheryCount: estimatedPeriphery,
2101
+ charCount: estimatedChars,
2102
+ estimatedTokens,
2103
+ estimatedCost,
2104
+ pricingSource,
2105
+ });
2106
+ process.stderr.write(`[codali] Preflight: focus=${estimatedFocus} periphery=${estimatedPeriphery} ` +
2107
+ `chars=${estimatedChars} tokens~${estimatedTokens} est_cost=${formatCost(estimatedCost)}\n`);
2108
+ if (estimatedCost !== undefined && estimatedCost > config.cost.maxCostPerRun) {
2109
+ const proceed = await confirmOverage(`Estimated cost ${formatCost(estimatedCost)} exceeds max ${formatCost(config.cost.maxCostPerRun)}. Continue? [y/N] `);
2110
+ if (!proceed) {
2111
+ throw new Error("Run cancelled due to cost limit");
2112
+ }
2113
+ }
2114
+ const provider = createProvider(config.provider, {
2115
+ model: config.model,
2116
+ apiKey: config.apiKey,
2117
+ baseUrl: config.baseUrl,
2118
+ timeoutMs: config.limits.timeoutMs,
2119
+ });
2120
+ const result = await runCodaliTask({
2121
+ task: workflowTaskInput,
2122
+ workspace: { root: config.workspaceRoot },
2123
+ provider: {
2124
+ name: config.provider,
2125
+ model: config.model,
2126
+ apiKey: config.apiKey,
2127
+ baseUrl: config.baseUrl,
2128
+ timeoutMs: config.limits.timeoutMs,
2129
+ },
2130
+ docdex: {
2131
+ baseUrl: config.docdex.baseUrl,
2132
+ repoId: config.docdex.repoId,
2133
+ repoRoot: config.docdex.repoRoot ?? config.workspaceRoot,
2134
+ dagSessionId: runId,
2135
+ },
2136
+ policy: {
2137
+ allowWrites: writesAllowed,
2138
+ allowShell: config.tools.allowShell ?? false,
2139
+ allowDestructiveOperations: config.tools.allowDestructiveOperations ?? false,
2140
+ allowOutsideWorkspace: config.tools.allowOutsideWorkspace ?? false,
2141
+ maxSteps: config.limits.maxSteps,
2142
+ maxToolCalls: config.limits.maxToolCalls,
2143
+ maxTokens: config.limits.maxTokens,
2144
+ timeoutMs: config.limits.timeoutMs,
2145
+ mode: "tool_loop",
2146
+ },
2147
+ streaming: config.streaming,
2148
+ metadata: {
2149
+ jobId: config.jobId,
2150
+ requestId: runId,
2151
+ tenantId: config.project,
2152
+ agentSlug: config.agentSlug,
2153
+ },
2154
+ providerInstance: provider,
2155
+ toolRegistry: registry,
2156
+ toolContext,
2157
+ logger,
2158
+ onEvent: (event) => {
2159
+ if (event.type === "usage" || event.type === "final") {
2160
+ return;
2161
+ }
2162
+ if (event.type === "subagent_start" || event.type === "subagent_result") {
2163
+ return;
2164
+ }
2165
+ if (event.type === "tool_call") {
2166
+ streamState.onEvent({ type: "tool_call", name: event.name, args: event.args });
2167
+ return;
2168
+ }
2169
+ if (event.type === "tool_result") {
2170
+ streamState.onEvent({
2171
+ type: "tool_result",
2172
+ name: event.name,
2173
+ output: event.output,
2174
+ ok: event.ok,
2175
+ errorCode: event.errorCode,
2176
+ retryable: event.retryable,
2177
+ });
2178
+ return;
2179
+ }
2180
+ streamState.onEvent(event);
2181
+ },
2182
+ });
2183
+ finalMessageContent = result.finalMessage;
2184
+ usage = result.usage;
2185
+ toolCallsExecuted = result.toolCallsExecuted;
2186
+ }
2187
+ streamState.flush();
2188
+ if (streamState.didStream()) {
2189
+ if (!finalMessageContent.endsWith("\n")) {
2190
+ process.stdout.write("\n");
2191
+ streamState.writeOutput("\n");
2192
+ }
2193
+ }
2194
+ else {
2195
+ // eslint-disable-next-line no-console
2196
+ console.log(finalMessageContent);
2197
+ streamState.writeOutput(`${finalMessageContent}\n`);
2198
+ }
2199
+ await emitRunSummary();
2200
+ summaryEmitted = true;
2201
+ const meta = {
2202
+ runId,
2203
+ fingerprint: runContext.fingerprint ?? null,
2204
+ logPath: logger.logPath,
2205
+ outputLogPath,
2206
+ touchedFiles: runContext.getTouchedFiles(),
2207
+ command: config.command,
2208
+ commandRunId: config.commandRunId,
2209
+ jobId: config.jobId,
2210
+ project: config.project,
2211
+ taskId: config.taskId,
2212
+ taskKey: config.taskKey,
2213
+ agentId: config.agentId,
2214
+ agentSlug: config.agentSlug,
2215
+ workflow: workflowProfile
2216
+ ? {
2217
+ name: workflowProfile.name,
2218
+ source: workflowProfile.source,
2219
+ outputContract: workflowProfile.outputContract,
2220
+ allowWrites: workflowProfile.allowWrites,
2221
+ }
2222
+ : null,
2223
+ };
2224
+ try {
2225
+ process.stderr.write(`CODALI_RUN_META ${JSON.stringify(meta)}\n`);
2226
+ }
2227
+ catch {
2228
+ // ignore stderr write failures
2229
+ }
2230
+ }
2231
+ catch (error) {
2232
+ const message = error instanceof Error ? error.message : String(error);
2233
+ summaryDisposition = "fail";
2234
+ summaryFailureStage = summaryFailureStage ?? "run_command";
2235
+ summaryReasonCodes = summaryReasonCodes.length > 0 ? summaryReasonCodes : uniqueStrings([message]);
2236
+ summaryFailureClass = summaryFailureClass ?? inferFailureClass(summaryFailureStage, summaryReasonCodes, message);
2237
+ try {
2238
+ await logger.log("run_failed", {
2239
+ stage: summaryFailureStage,
2240
+ reasons: summaryReasonCodes,
2241
+ failure_class: summaryFailureClass,
2242
+ retryable: summaryRetryable ?? null,
2243
+ error: message,
2244
+ });
2245
+ if (!summaryEmitted) {
2246
+ await emitRunSummary();
2247
+ summaryEmitted = true;
2248
+ }
2249
+ }
2250
+ catch {
2251
+ // Ignore secondary logging failures.
2252
+ }
2253
+ throw error;
2254
+ }
2255
+ finally {
2256
+ outputStream.end();
2257
+ unregisterSignals();
2258
+ await lock.release();
2259
+ }
2260
+ }
2261
+ }