muonroi-cli 1.8.4 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (562) hide show
  1. package/LICENSE +17 -5
  2. package/dist/packages/agent-harness-core/src/driver.d.ts +27 -1
  3. package/dist/packages/agent-harness-core/src/driver.js +46 -0
  4. package/dist/packages/agent-harness-core/src/event-filter.js +11 -0
  5. package/dist/packages/agent-harness-core/src/event-redact.js +7 -0
  6. package/dist/packages/agent-harness-core/src/event-tee.d.ts +64 -0
  7. package/dist/packages/agent-harness-core/src/event-tee.js +104 -0
  8. package/dist/packages/agent-harness-core/src/mcp-server.d.ts +25 -0
  9. package/dist/packages/agent-harness-core/src/mcp-server.js +169 -21
  10. package/dist/packages/agent-harness-core/src/predicate.d.ts +1 -1
  11. package/dist/packages/agent-harness-core/src/protocol.d.ts +90 -4
  12. package/dist/packages/agent-harness-core/src/protocol.js +15 -0
  13. package/dist/packages/agent-harness-core/src/visual-quality.d.ts +58 -0
  14. package/dist/packages/agent-harness-core/src/visual-quality.js +141 -0
  15. package/dist/packages/agent-harness-opentui/src/agent-mode.d.ts +6 -0
  16. package/dist/packages/agent-harness-opentui/src/agent-mode.js +14 -1
  17. package/dist/packages/agent-harness-opentui/src/input-bridge.d.ts +2 -10
  18. package/dist/packages/agent-harness-opentui/src/input-bridge.js +103 -16
  19. package/dist/packages/agent-harness-opentui/src/install.d.ts +8 -0
  20. package/dist/packages/agent-harness-opentui/src/install.js +10 -0
  21. package/dist/packages/agent-harness-opentui/src/semantic.js +12 -10
  22. package/dist/packages/agent-harness-opentui/src/visual-capture.d.ts +56 -0
  23. package/dist/packages/agent-harness-opentui/src/visual-capture.js +103 -0
  24. package/dist/src/agent-harness/mock-model.d.ts +38 -0
  25. package/dist/src/agent-harness/mock-model.js +69 -3
  26. package/dist/src/agent-harness/test-spawn.js +31 -0
  27. package/dist/src/chat/chat-keychain.d.ts +7 -12
  28. package/dist/src/chat/chat-keychain.js +19 -86
  29. package/dist/src/cli/config/screen-providers.js +1 -1
  30. package/dist/src/cli/cost-forensics.d.ts +10 -0
  31. package/dist/src/cli/cost-forensics.js +18 -3
  32. package/dist/src/cli/keys-bundle.d.ts +1 -1
  33. package/dist/src/cli/keys-bundle.js +1 -1
  34. package/dist/src/cli/keys.d.ts +10 -47
  35. package/dist/src/cli/keys.js +31 -399
  36. package/dist/src/council/clarifier.d.ts +31 -3
  37. package/dist/src/council/clarifier.js +220 -32
  38. package/dist/src/council/context.js +49 -15
  39. package/dist/src/council/debate-checkpoint.d.ts +129 -0
  40. package/dist/src/council/debate-checkpoint.js +176 -0
  41. package/dist/src/council/debate-planner.js +54 -5
  42. package/dist/src/council/debate-summary.d.ts +25 -0
  43. package/dist/src/council/debate-summary.js +85 -0
  44. package/dist/src/council/debate.d.ts +169 -2
  45. package/dist/src/council/debate.js +1265 -135
  46. package/dist/src/council/index.d.ts +108 -1
  47. package/dist/src/council/index.js +670 -197
  48. package/dist/src/council/leader.d.ts +26 -0
  49. package/dist/src/council/leader.js +150 -9
  50. package/dist/src/council/llm.d.ts +94 -0
  51. package/dist/src/council/llm.js +348 -55
  52. package/dist/src/council/panel-select.d.ts +30 -0
  53. package/dist/src/council/panel-select.js +82 -0
  54. package/dist/src/council/planner.js +40 -0
  55. package/dist/src/council/preflight.d.ts +17 -0
  56. package/dist/src/council/preflight.js +50 -2
  57. package/dist/src/council/prompts.d.ts +39 -4
  58. package/dist/src/council/prompts.js +256 -69
  59. package/dist/src/council/stance-recall.d.ts +42 -0
  60. package/dist/src/council/stance-recall.js +57 -0
  61. package/dist/src/council/strip-think.d.ts +17 -0
  62. package/dist/src/council/strip-think.js +33 -0
  63. package/dist/src/council/types.d.ts +138 -0
  64. package/dist/src/ee/artifact-cache.d.ts +16 -0
  65. package/dist/src/ee/artifact-cache.js +32 -0
  66. package/dist/src/ee/auth.d.ts +20 -0
  67. package/dist/src/ee/auth.js +54 -2
  68. package/dist/src/ee/bridge.d.ts +10 -0
  69. package/dist/src/ee/bridge.js +58 -0
  70. package/dist/src/ee/client.js +109 -21
  71. package/dist/src/ee/ee-onboarding.js +6 -26
  72. package/dist/src/ee/export-transcripts.d.ts +1 -0
  73. package/dist/src/ee/export-transcripts.js +8 -10
  74. package/dist/src/ee/extract-session.js +29 -0
  75. package/dist/src/ee/extract-style.d.ts +58 -0
  76. package/dist/src/ee/extract-style.js +270 -0
  77. package/dist/src/ee/recall-ledger.d.ts +9 -0
  78. package/dist/src/ee/recall-ledger.js +3 -0
  79. package/dist/src/ee/scope.d.ts +1 -0
  80. package/dist/src/ee/scope.js +26 -1
  81. package/dist/src/ee/search.d.ts +7 -0
  82. package/dist/src/ee/search.js +24 -0
  83. package/dist/src/ee/transcript-emit.js +2 -0
  84. package/dist/src/ee/types.d.ts +22 -0
  85. package/dist/src/ee/who-am-i-brain.d.ts +35 -0
  86. package/dist/src/ee/who-am-i-brain.js +220 -0
  87. package/dist/src/ee/who-am-i.d.ts +10 -3
  88. package/dist/src/ee/who-am-i.js +12 -0
  89. package/dist/src/ee/workflow-event.d.ts +48 -0
  90. package/dist/src/ee/workflow-event.js +81 -0
  91. package/dist/src/flow/compaction/compress.d.ts +3 -3
  92. package/dist/src/flow/compaction/compress.js +58 -8
  93. package/dist/src/flow/compaction/extract.d.ts +4 -7
  94. package/dist/src/flow/compaction/extract.js +50 -10
  95. package/dist/src/flow/compaction/index.d.ts +14 -1
  96. package/dist/src/flow/compaction/index.js +96 -3
  97. package/dist/src/flow/compaction/input-guard.d.ts +24 -0
  98. package/dist/src/flow/compaction/input-guard.js +43 -0
  99. package/dist/src/flow/compaction/progress.d.ts +35 -0
  100. package/dist/src/flow/compaction/progress.js +35 -0
  101. package/dist/src/flow/fold-planning.d.ts +36 -0
  102. package/dist/src/flow/fold-planning.js +83 -0
  103. package/dist/src/flow/hierarchy.d.ts +146 -0
  104. package/dist/src/flow/hierarchy.js +427 -0
  105. package/dist/src/flow/index.d.ts +1 -0
  106. package/dist/src/flow/index.js +2 -0
  107. package/dist/src/flow/run-artifacts.d.ts +102 -0
  108. package/dist/src/flow/run-artifacts.js +208 -0
  109. package/dist/src/generated/version.d.ts +1 -1
  110. package/dist/src/generated/version.js +1 -1
  111. package/dist/src/gsd/assessment-schema.d.ts +44 -0
  112. package/dist/src/gsd/assessment-schema.js +134 -0
  113. package/dist/src/gsd/capability-registry.d.ts +45 -0
  114. package/dist/src/gsd/capability-registry.js +337 -0
  115. package/dist/src/gsd/complexity-assessor.d.ts +39 -0
  116. package/dist/src/gsd/complexity-assessor.js +152 -0
  117. package/dist/src/gsd/config-bridge.d.ts +7 -0
  118. package/dist/src/gsd/config-bridge.js +114 -0
  119. package/dist/src/gsd/config-loader.d.ts +27 -0
  120. package/dist/src/gsd/config-loader.js +50 -0
  121. package/dist/src/gsd/council-context.d.ts +44 -0
  122. package/dist/src/gsd/council-context.js +114 -0
  123. package/dist/src/gsd/ee-closure.d.ts +28 -0
  124. package/dist/src/gsd/ee-closure.js +49 -0
  125. package/dist/src/gsd/flags.d.ts +66 -0
  126. package/dist/src/gsd/flags.js +102 -0
  127. package/dist/src/gsd/gsd-dispatch.d.ts +58 -0
  128. package/dist/src/gsd/gsd-dispatch.js +131 -0
  129. package/dist/src/gsd/gsd-runtime.d.ts +22 -0
  130. package/dist/src/gsd/gsd-runtime.js +37 -0
  131. package/dist/src/gsd/host-adapter.d.ts +11 -0
  132. package/dist/src/gsd/host-adapter.js +29 -0
  133. package/dist/src/gsd/index.d.ts +24 -1
  134. package/dist/src/gsd/index.js +27 -0
  135. package/dist/src/gsd/loop-host-contract.d.ts +21 -0
  136. package/dist/src/gsd/loop-host-contract.js +39 -0
  137. package/dist/src/gsd/loop-host.d.ts +69 -0
  138. package/dist/src/gsd/loop-host.js +245 -0
  139. package/dist/src/gsd/loop-resolver.d.ts +36 -0
  140. package/dist/src/gsd/loop-resolver.js +79 -0
  141. package/dist/src/gsd/model-tier.d.ts +13 -0
  142. package/dist/src/gsd/model-tier.js +45 -0
  143. package/dist/src/gsd/mutation-gate.d.ts +16 -0
  144. package/dist/src/gsd/mutation-gate.js +41 -0
  145. package/dist/src/gsd/native-roadmap.d.ts +89 -0
  146. package/dist/src/gsd/native-roadmap.js +343 -0
  147. package/dist/src/gsd/native-state.d.ts +47 -0
  148. package/dist/src/gsd/native-state.js +220 -0
  149. package/dist/src/gsd/paths.d.ts +23 -0
  150. package/dist/src/gsd/paths.js +66 -0
  151. package/dist/src/gsd/phase-dag.d.ts +12 -0
  152. package/dist/src/gsd/phase-dag.js +94 -0
  153. package/dist/src/gsd/phase-sync.d.ts +42 -0
  154. package/dist/src/gsd/phase-sync.js +321 -0
  155. package/dist/src/gsd/pil-gate-context.d.ts +13 -0
  156. package/dist/src/gsd/pil-gate-context.js +64 -0
  157. package/dist/src/gsd/pil-gate-critic.d.ts +19 -0
  158. package/dist/src/gsd/pil-gate-critic.js +74 -0
  159. package/dist/src/gsd/plan-council-prompts.d.ts +25 -0
  160. package/dist/src/gsd/plan-council-prompts.js +79 -0
  161. package/dist/src/gsd/plan-council.d.ts +44 -0
  162. package/dist/src/gsd/plan-council.js +283 -0
  163. package/dist/src/gsd/plan-gate-vocabulary.d.ts +40 -0
  164. package/dist/src/gsd/plan-gate-vocabulary.js +64 -0
  165. package/dist/src/gsd/product-workspace.d.ts +13 -0
  166. package/dist/src/gsd/product-workspace.js +124 -0
  167. package/dist/src/gsd/ship-bridge.d.ts +25 -0
  168. package/dist/src/gsd/ship-bridge.js +65 -0
  169. package/dist/src/gsd/state-document.d.ts +40 -0
  170. package/dist/src/gsd/state-document.js +163 -0
  171. package/dist/src/gsd/verdict-schema.d.ts +39 -0
  172. package/dist/src/gsd/verdict-schema.js +144 -0
  173. package/dist/src/gsd/verify-context.d.ts +22 -0
  174. package/dist/src/gsd/verify-context.js +27 -0
  175. package/dist/src/gsd/verify-council-prompts.d.ts +19 -0
  176. package/dist/src/gsd/verify-council-prompts.js +85 -0
  177. package/dist/src/gsd/verify-council.d.ts +25 -0
  178. package/dist/src/gsd/verify-council.js +119 -0
  179. package/dist/src/gsd/verify-gate-vocabulary.d.ts +25 -0
  180. package/dist/src/gsd/verify-gate-vocabulary.js +46 -0
  181. package/dist/src/gsd/workflow-engine.d.ts +60 -0
  182. package/dist/src/gsd/workflow-engine.js +207 -0
  183. package/dist/src/gsd/workflow-tools.d.ts +13 -0
  184. package/dist/src/gsd/workflow-tools.js +277 -0
  185. package/dist/src/headless/council-answers.js +4 -0
  186. package/dist/src/hooks/index.js +1 -1
  187. package/dist/src/index.js +172 -270
  188. package/dist/src/lsp/builtins.js +3 -1
  189. package/dist/src/lsp/manager.d.ts +5 -1
  190. package/dist/src/lsp/manager.js +249 -3
  191. package/dist/src/lsp/npm-cache.d.ts +11 -1
  192. package/dist/src/lsp/npm-cache.js +17 -1
  193. package/dist/src/lsp/runtime.d.ts +6 -1
  194. package/dist/src/lsp/runtime.js +17 -1
  195. package/dist/src/lsp/types.d.ts +83 -1
  196. package/dist/src/lsp/types.js +10 -0
  197. package/dist/src/maintain/pr-builder.js +23 -13
  198. package/dist/src/mcp/auto-setup.js +57 -32
  199. package/dist/src/mcp/client-pool.js +44 -16
  200. package/dist/src/mcp/lsp-tools.d.ts +5 -1
  201. package/dist/src/mcp/lsp-tools.js +93 -2
  202. package/dist/src/mcp/mcp-keychain.d.ts +3 -5
  203. package/dist/src/mcp/mcp-keychain.js +9 -49
  204. package/dist/src/mcp/research-onboarding.js +8 -7
  205. package/dist/src/mcp/runtime.js +34 -2
  206. package/dist/src/mcp/setup-guide-text.d.ts +1 -1
  207. package/dist/src/mcp/setup-guide-text.js +22 -2
  208. package/dist/src/mcp/tools-server.d.ts +10 -0
  209. package/dist/src/mcp/tools-server.js +10 -2
  210. package/dist/src/models/catalog-client.d.ts +87 -0
  211. package/dist/src/models/catalog-client.js +105 -38
  212. package/dist/src/models/catalog.json +528 -265
  213. package/dist/src/models/registry.d.ts +22 -7
  214. package/dist/src/models/registry.js +73 -10
  215. package/dist/src/ops/doctor.js +1 -1
  216. package/dist/src/orchestrator/ask-user.d.ts +61 -0
  217. package/dist/src/orchestrator/ask-user.js +65 -0
  218. package/dist/src/orchestrator/auto-commit.js +1 -1
  219. package/dist/src/orchestrator/batch-turn-runner.js +2 -2
  220. package/dist/src/orchestrator/cache-prefix.d.ts +67 -0
  221. package/dist/src/orchestrator/cache-prefix.js +83 -0
  222. package/dist/src/orchestrator/compact-request.d.ts +32 -0
  223. package/dist/src/orchestrator/compact-request.js +41 -0
  224. package/dist/src/orchestrator/compaction.d.ts +12 -3
  225. package/dist/src/orchestrator/compaction.js +35 -15
  226. package/dist/src/orchestrator/council-manager.d.ts +12 -3
  227. package/dist/src/orchestrator/council-manager.js +74 -32
  228. package/dist/src/orchestrator/council-request.d.ts +49 -0
  229. package/dist/src/orchestrator/council-request.js +62 -0
  230. package/dist/src/orchestrator/cross-turn-dedup.d.ts +6 -0
  231. package/dist/src/orchestrator/cross-turn-dedup.js +22 -1
  232. package/dist/src/orchestrator/error-utils.d.ts +29 -0
  233. package/dist/src/orchestrator/error-utils.js +132 -24
  234. package/dist/src/orchestrator/grounding-check.js +39 -1
  235. package/dist/src/orchestrator/interactive-pause.d.ts +26 -0
  236. package/dist/src/orchestrator/interactive-pause.js +36 -0
  237. package/dist/src/orchestrator/message-processor.d.ts +4 -0
  238. package/dist/src/orchestrator/message-processor.js +268 -41
  239. package/dist/src/orchestrator/orchestrator.d.ts +64 -3
  240. package/dist/src/orchestrator/orchestrator.js +823 -120
  241. package/dist/src/orchestrator/preprocessor.js +3 -3
  242. package/dist/src/orchestrator/proactive-compact-detector.d.ts +26 -0
  243. package/dist/src/orchestrator/proactive-compact-detector.js +36 -0
  244. package/dist/src/orchestrator/prompts.js +17 -17
  245. package/dist/src/orchestrator/reactive-delegation.d.ts +39 -0
  246. package/dist/src/orchestrator/reactive-delegation.js +59 -0
  247. package/dist/src/orchestrator/retry-classifier.d.ts +2 -1
  248. package/dist/src/orchestrator/retry-classifier.js +46 -2
  249. package/dist/src/orchestrator/safety-askcard.d.ts +1 -1
  250. package/dist/src/orchestrator/safety-askcard.js +5 -2
  251. package/dist/src/orchestrator/safety-intercept.d.ts +50 -0
  252. package/dist/src/orchestrator/safety-intercept.js +62 -0
  253. package/dist/src/orchestrator/scope-reminder.js +1 -1
  254. package/dist/src/orchestrator/session-experience.d.ts +2 -1
  255. package/dist/src/orchestrator/session-experience.js +2 -1
  256. package/dist/src/orchestrator/should-run-gate.d.ts +5 -0
  257. package/dist/src/orchestrator/should-run-gate.js +18 -0
  258. package/dist/src/orchestrator/stall-watchdog.d.ts +31 -3
  259. package/dist/src/orchestrator/stall-watchdog.js +65 -10
  260. package/dist/src/orchestrator/stream-runner.d.ts +13 -3
  261. package/dist/src/orchestrator/stream-runner.js +115 -49
  262. package/dist/src/orchestrator/sub-agent-cap.d.ts +13 -1
  263. package/dist/src/orchestrator/sub-agent-cap.js +16 -1
  264. package/dist/src/orchestrator/sub-agent-model-tier.d.ts +13 -1
  265. package/dist/src/orchestrator/sub-agent-model-tier.js +16 -2
  266. package/dist/src/orchestrator/subagent-compactor.d.ts +53 -1
  267. package/dist/src/orchestrator/subagent-compactor.js +126 -15
  268. package/dist/src/orchestrator/tool-engine.d.ts +41 -0
  269. package/dist/src/orchestrator/tool-engine.js +846 -66
  270. package/dist/src/orchestrator/tool-limit-auto-recover.d.ts +22 -0
  271. package/dist/src/orchestrator/tool-limit-auto-recover.js +30 -0
  272. package/dist/src/orchestrator/turn-runner-deps.d.ts +19 -0
  273. package/dist/src/orchestrator/turn-watchdog.d.ts +44 -0
  274. package/dist/src/orchestrator/turn-watchdog.js +84 -0
  275. package/dist/src/pil/agent-operating-contract.d.ts +1 -1
  276. package/dist/src/pil/agent-operating-contract.js +6 -4
  277. package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
  278. package/dist/src/pil/cheap-model-playbook.js +5 -1
  279. package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
  280. package/dist/src/pil/cheap-model-workbooks.js +1 -1
  281. package/dist/src/pil/discovery-types.d.ts +1 -0
  282. package/dist/src/pil/discovery.d.ts +1 -1
  283. package/dist/src/pil/discovery.js +18 -13
  284. package/dist/src/pil/layer1-intent.d.ts +18 -6
  285. package/dist/src/pil/layer1-intent.js +66 -757
  286. package/dist/src/pil/layer15-context-scan.js +15 -1
  287. package/dist/src/pil/layer1_5-complexity-size.d.ts +7 -0
  288. package/dist/src/pil/layer1_5-complexity-size.js +31 -5
  289. package/dist/src/pil/layer3-ee-injection.js +23 -8
  290. package/dist/src/pil/layer4-gsd.js +69 -16
  291. package/dist/src/pil/layer5-context.js +7 -3
  292. package/dist/src/pil/layer6-output.d.ts +23 -0
  293. package/dist/src/pil/layer6-output.js +5 -1
  294. package/dist/src/pil/llm-classify.d.ts +111 -5
  295. package/dist/src/pil/llm-classify.js +421 -189
  296. package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
  297. package/dist/src/pil/native-capabilities-workbook.js +8 -0
  298. package/dist/src/pil/pipeline.js +36 -2
  299. package/dist/src/pil/repo-grounding-probe.d.ts +15 -0
  300. package/dist/src/pil/repo-grounding-probe.js +136 -0
  301. package/dist/src/pil/repo-structure-hints.d.ts +7 -0
  302. package/dist/src/pil/repo-structure-hints.js +45 -0
  303. package/dist/src/pil/response-tools.js +5 -3
  304. package/dist/src/pil/schema.d.ts +1 -0
  305. package/dist/src/pil/schema.js +2 -0
  306. package/dist/src/pil/types.d.ts +18 -0
  307. package/dist/src/playbook/directives.d.ts +4 -0
  308. package/dist/src/playbook/directives.js +17 -5
  309. package/dist/src/product-loop/artifact-io.js +4 -0
  310. package/dist/src/product-loop/backlog-builder.d.ts +14 -1
  311. package/dist/src/product-loop/backlog-builder.js +30 -6
  312. package/dist/src/product-loop/criteria-seed.d.ts +51 -0
  313. package/dist/src/product-loop/criteria-seed.js +200 -0
  314. package/dist/src/product-loop/discovery-context-format.js +3 -1
  315. package/dist/src/product-loop/discovery-ecosystem.js +4 -1
  316. package/dist/src/product-loop/discovery-interview.d.ts +9 -0
  317. package/dist/src/product-loop/discovery-interview.js +60 -12
  318. package/dist/src/product-loop/discovery-recommender.js +2 -1
  319. package/dist/src/product-loop/discovery-schema.js +19 -2
  320. package/dist/src/product-loop/discovery-triage.d.ts +23 -0
  321. package/dist/src/product-loop/discovery-triage.js +109 -0
  322. package/dist/src/product-loop/gather.js +150 -2
  323. package/dist/src/product-loop/ideal-trace.d.ts +7 -0
  324. package/dist/src/product-loop/ideal-trace.js +64 -0
  325. package/dist/src/product-loop/index.d.ts +13 -1
  326. package/dist/src/product-loop/index.js +340 -52
  327. package/dist/src/product-loop/loop-driver.d.ts +7 -0
  328. package/dist/src/product-loop/loop-driver.js +330 -106
  329. package/dist/src/product-loop/phase-plan.d.ts +21 -0
  330. package/dist/src/product-loop/phase-plan.js +81 -6
  331. package/dist/src/product-loop/phase-rituals.d.ts +3 -0
  332. package/dist/src/product-loop/phase-rituals.js +8 -3
  333. package/dist/src/product-loop/phase-runner.js +39 -12
  334. package/dist/src/product-loop/plan-adherence-review.d.ts +26 -0
  335. package/dist/src/product-loop/plan-adherence-review.js +144 -0
  336. package/dist/src/product-loop/sprint-runner.d.ts +173 -0
  337. package/dist/src/product-loop/sprint-runner.js +863 -19
  338. package/dist/src/product-loop/types.d.ts +61 -5
  339. package/dist/src/providers/adapter.d.ts +1 -1
  340. package/dist/src/providers/adapter.js +3 -4
  341. package/dist/src/providers/anthropic.d.ts +9 -8
  342. package/dist/src/providers/anthropic.js +13 -47
  343. package/dist/src/providers/auth/browser-flow.d.ts +1 -1
  344. package/dist/src/providers/auth/browser-flow.js +1 -1
  345. package/dist/src/providers/auth/grok-oauth.d.ts +1 -0
  346. package/dist/src/providers/auth/grok-oauth.js +30 -5
  347. package/dist/src/providers/auth/openai-oauth.d.ts +1 -0
  348. package/dist/src/providers/auth/openai-oauth.js +15 -1
  349. package/dist/src/providers/auth/registry.js +0 -34
  350. package/dist/src/providers/auth/token-store.d.ts +9 -9
  351. package/dist/src/providers/auth/token-store.js +8 -67
  352. package/dist/src/providers/auth/types.d.ts +9 -1
  353. package/dist/src/providers/auth/types.js +1 -1
  354. package/dist/src/providers/capabilities.d.ts +24 -5
  355. package/dist/src/providers/capabilities.js +42 -24
  356. package/dist/src/providers/endpoints.d.ts +2 -2
  357. package/dist/src/providers/endpoints.js +11 -10
  358. package/dist/src/providers/env-store.d.ts +17 -0
  359. package/dist/src/providers/env-store.js +228 -0
  360. package/dist/src/providers/keychain.d.ts +22 -18
  361. package/dist/src/providers/keychain.js +127 -140
  362. package/dist/src/providers/mcp-vision-bridge.js +56 -146
  363. package/dist/src/providers/openai-compatible.js +8 -1
  364. package/dist/src/providers/pricing.d.ts +2 -2
  365. package/dist/src/providers/pricing.js +3 -13
  366. package/dist/src/providers/runtime.d.ts +43 -3
  367. package/dist/src/providers/runtime.js +88 -14
  368. package/dist/src/providers/strategies/base.strategy.d.ts +16 -0
  369. package/dist/src/providers/strategies/base.strategy.js +24 -1
  370. package/dist/src/providers/strategies/{siliconflow.strategy.d.ts → opencode-go.strategy.d.ts} +3 -3
  371. package/dist/src/providers/strategies/opencode-go.strategy.js +83 -0
  372. package/dist/src/providers/strategies/registry.js +4 -4
  373. package/dist/src/providers/strategies/thinking-mode.d.ts +109 -0
  374. package/dist/src/providers/strategies/thinking-mode.js +288 -1
  375. package/dist/src/providers/strategies/xai.strategy.js +27 -0
  376. package/dist/src/providers/strategies/zai.strategy.d.ts +14 -0
  377. package/dist/src/providers/strategies/zai.strategy.js +44 -0
  378. package/dist/src/providers/types.d.ts +5 -6
  379. package/dist/src/providers/types.js +2 -2
  380. package/dist/src/providers/vision-backend.d.ts +47 -0
  381. package/dist/src/providers/vision-backend.js +258 -0
  382. package/dist/src/providers/vision-proxy.d.ts +22 -9
  383. package/dist/src/providers/vision-proxy.js +63 -132
  384. package/dist/src/providers/warm.d.ts +65 -0
  385. package/dist/src/providers/warm.js +145 -0
  386. package/dist/src/providers/wire-debug.js +95 -0
  387. package/dist/src/router/decide.d.ts +13 -0
  388. package/dist/src/router/decide.js +138 -36
  389. package/dist/src/router/peak-hour.d.ts +38 -0
  390. package/dist/src/router/peak-hour.js +107 -0
  391. package/dist/src/router/step-router.js +3 -2
  392. package/dist/src/router/warm.js +4 -5
  393. package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
  394. package/dist/src/scaffold/continuation-prompt.js +26 -0
  395. package/dist/src/scaffold/point-to-existing.d.ts +21 -0
  396. package/dist/src/scaffold/point-to-existing.js +25 -0
  397. package/dist/src/self-qa/agentic-loop.js +6 -5
  398. package/dist/src/{ui/state → state}/active-run.d.ts +19 -0
  399. package/dist/src/{ui/state → state}/active-run.js +21 -0
  400. package/dist/src/{ui/status-bar/store.d.ts → state/status-bar-store.d.ts} +4 -1
  401. package/dist/src/{ui/status-bar/store.js → state/status-bar-store.js} +12 -9
  402. package/dist/src/state/turn-trace.d.ts +43 -0
  403. package/dist/src/state/turn-trace.js +32 -0
  404. package/dist/src/storage/db.js +2 -1
  405. package/dist/src/storage/index.d.ts +1 -1
  406. package/dist/src/storage/index.js +1 -1
  407. package/dist/src/storage/interaction-log.d.ts +1 -1
  408. package/dist/src/storage/migrations.js +71 -1
  409. package/dist/src/storage/sessions.d.ts +28 -10
  410. package/dist/src/storage/sessions.js +78 -21
  411. package/dist/src/storage/transcript-view.js +1 -1
  412. package/dist/src/storage/transcript.d.ts +51 -0
  413. package/dist/src/storage/transcript.js +340 -15
  414. package/dist/src/tools/file.d.ts +15 -0
  415. package/dist/src/tools/file.js +32 -0
  416. package/dist/src/tools/git-safety.d.ts +19 -0
  417. package/dist/src/tools/git-safety.js +168 -0
  418. package/dist/src/tools/native-tools.d.ts +1 -1
  419. package/dist/src/tools/native-tools.js +81 -1
  420. package/dist/src/tools/registry.d.ts +20 -0
  421. package/dist/src/tools/registry.js +576 -23
  422. package/dist/src/tools/research.d.ts +29 -0
  423. package/dist/src/tools/research.js +233 -0
  424. package/dist/src/types/index.d.ts +147 -4
  425. package/dist/src/ui/app.js +0 -0
  426. package/dist/src/ui/cards/product-status-card.js +1 -1
  427. package/dist/src/ui/components/agent-rail-activities.d.ts +26 -0
  428. package/dist/src/ui/components/agent-rail-activities.js +47 -0
  429. package/dist/src/ui/components/bubble-body-guard.d.ts +27 -0
  430. package/dist/src/ui/components/bubble-body-guard.js +50 -0
  431. package/dist/src/ui/components/compact-progress-card.d.ts +24 -0
  432. package/dist/src/ui/components/compact-progress-card.js +42 -0
  433. package/dist/src/ui/components/context-rail.d.ts +26 -0
  434. package/dist/src/ui/components/context-rail.js +33 -0
  435. package/dist/src/ui/components/council-conclusion-card.d.ts +73 -0
  436. package/dist/src/ui/components/council-conclusion-card.js +420 -0
  437. package/dist/src/ui/components/council-debate-pill.d.ts +36 -0
  438. package/dist/src/ui/components/council-debate-pill.js +34 -0
  439. package/dist/src/ui/components/council-info-card.js +2 -2
  440. package/dist/src/ui/components/council-leader-bubble.d.ts +10 -3
  441. package/dist/src/ui/components/council-leader-bubble.js +21 -11
  442. package/dist/src/ui/components/council-message-bubble.d.ts +15 -2
  443. package/dist/src/ui/components/council-message-bubble.js +16 -15
  444. package/dist/src/ui/components/council-phase-timeline.d.ts +9 -1
  445. package/dist/src/ui/components/council-phase-timeline.js +66 -17
  446. package/dist/src/ui/components/council-placeholder-bubble.d.ts +16 -9
  447. package/dist/src/ui/components/council-placeholder-bubble.js +32 -29
  448. package/dist/src/ui/components/council-question-card.js +13 -12
  449. package/dist/src/ui/components/council-rail-rounds.d.ts +26 -0
  450. package/dist/src/ui/components/council-rail-rounds.js +57 -0
  451. package/dist/src/ui/components/council-round-group.d.ts +38 -0
  452. package/dist/src/ui/components/council-round-group.js +88 -0
  453. package/dist/src/ui/components/council-status-list.d.ts +3 -1
  454. package/dist/src/ui/components/council-status-list.js +36 -24
  455. package/dist/src/ui/components/council-synthesis-banner.d.ts +7 -2
  456. package/dist/src/ui/components/council-synthesis-banner.js +20 -5
  457. package/dist/src/ui/components/halt-recovery-card.js +9 -5
  458. package/dist/src/ui/components/jump-to-latest-pill.d.ts +11 -0
  459. package/dist/src/ui/components/jump-to-latest-pill.js +14 -0
  460. package/dist/src/ui/components/message-view.d.ts +15 -0
  461. package/dist/src/ui/components/message-view.js +50 -1
  462. package/dist/src/ui/components/prompt-box.js +18 -16
  463. package/dist/src/ui/components/session-tree-card.d.ts +14 -0
  464. package/dist/src/ui/components/session-tree-card.js +46 -0
  465. package/dist/src/ui/components/slash-inline-menu.d.ts +12 -0
  466. package/dist/src/ui/components/slash-inline-menu.js +26 -5
  467. package/dist/src/ui/components/task-list-panel.d.ts +14 -1
  468. package/dist/src/ui/components/task-list-panel.js +22 -2
  469. package/dist/src/ui/components/tool-group.d.ts +15 -3
  470. package/dist/src/ui/components/tool-group.js +69 -11
  471. package/dist/src/ui/containers/modals-layer.d.ts +4 -2
  472. package/dist/src/ui/containers/modals-layer.js +2 -2
  473. package/dist/src/ui/council-harness-event.d.ts +57 -0
  474. package/dist/src/ui/council-harness-event.js +46 -0
  475. package/dist/src/ui/heartbeat-debug.d.ts +29 -0
  476. package/dist/src/ui/heartbeat-debug.js +45 -0
  477. package/dist/src/ui/hooks/use-session-picker.d.ts +3 -3
  478. package/dist/src/ui/mcp-modal.js +2 -4
  479. package/dist/src/ui/modals/api-key-modal.js +1 -1
  480. package/dist/src/ui/modals/connect-modal.js +4 -3
  481. package/dist/src/ui/modals/model-picker-modal.d.ts +8 -18
  482. package/dist/src/ui/modals/model-picker-modal.js +8 -10
  483. package/dist/src/ui/modals/session-picker-modal.d.ts +2 -2
  484. package/dist/src/ui/modals/session-picker-modal.js +3 -5
  485. package/dist/src/ui/picker-providers.d.ts +1 -1
  486. package/dist/src/ui/picker-providers.js +1 -1
  487. package/dist/src/ui/primitives/index.d.ts +1 -0
  488. package/dist/src/ui/primitives/index.js +2 -0
  489. package/dist/src/ui/primitives/semantic-primitives.d.ts +76 -0
  490. package/dist/src/ui/primitives/semantic-primitives.js +81 -0
  491. package/dist/src/ui/slash/compact.js +5 -7
  492. package/dist/src/ui/slash/cost.js +1 -1
  493. package/dist/src/ui/slash/council.js +19 -1
  494. package/dist/src/ui/slash/debug.d.ts +3 -31
  495. package/dist/src/ui/slash/debug.js +9 -20
  496. package/dist/src/ui/slash/ee.js +81 -0
  497. package/dist/src/ui/slash/ideal.d.ts +6 -2
  498. package/dist/src/ui/slash/ideal.js +97 -7
  499. package/dist/src/ui/slash/menu-items.d.ts +7 -0
  500. package/dist/src/ui/slash/menu-items.js +23 -20
  501. package/dist/src/ui/slash/registry.d.ts +2 -0
  502. package/dist/src/ui/slash/registry.js +4 -0
  503. package/dist/src/ui/status-bar/cache-hit.d.ts +6 -0
  504. package/dist/src/ui/status-bar/cache-hit.js +9 -0
  505. package/dist/src/ui/status-bar/index.d.ts +1 -1
  506. package/dist/src/ui/status-bar/index.js +7 -3
  507. package/dist/src/ui/status-bar/usd-meter.d.ts +5 -4
  508. package/dist/src/ui/status-bar/usd-meter.js +6 -4
  509. package/dist/src/ui/theme.d.ts +1 -0
  510. package/dist/src/ui/theme.js +2 -0
  511. package/dist/src/ui/types.d.ts +7 -0
  512. package/dist/src/ui/use-app-logic.js +0 -0
  513. package/dist/src/ui/utils/agent-activities.d.ts +39 -0
  514. package/dist/src/ui/utils/agent-activities.js +96 -0
  515. package/dist/src/ui/utils/format.d.ts +14 -0
  516. package/dist/src/ui/utils/format.js +23 -3
  517. package/dist/src/ui/utils/group-tool-entries.d.ts +26 -0
  518. package/dist/src/ui/utils/group-tool-entries.js +111 -0
  519. package/dist/src/ui/utils/tool-summary.d.ts +21 -0
  520. package/dist/src/ui/utils/tool-summary.js +91 -0
  521. package/dist/src/usage/downgrade.js +2 -2
  522. package/dist/src/usage/product-ledger.js +2 -2
  523. package/dist/src/utils/event-loop-monitor.d.ts +85 -0
  524. package/dist/src/utils/event-loop-monitor.js +107 -0
  525. package/dist/src/utils/install-manager.js +2 -1
  526. package/dist/src/utils/llm-deadline.d.ts +14 -0
  527. package/dist/src/utils/llm-deadline.js +19 -0
  528. package/dist/src/utils/logger.js +2 -2
  529. package/dist/src/utils/loop-profiler.d.ts +102 -0
  530. package/dist/src/utils/loop-profiler.js +202 -0
  531. package/dist/src/utils/permission-mode.js +5 -3
  532. package/dist/src/utils/redactor.js +1 -1
  533. package/dist/src/utils/settings.d.ts +180 -5
  534. package/dist/src/utils/settings.js +271 -31
  535. package/dist/src/utils/side-question.d.ts +1 -2
  536. package/dist/src/utils/side-question.js +2 -2
  537. package/dist/src/utils/visible-retry.d.ts +11 -0
  538. package/dist/src/utils/visible-retry.js +10 -1
  539. package/dist/src/verify/entrypoint.d.ts +1 -1
  540. package/dist/src/verify/entrypoint.js +52 -17
  541. package/dist/src/verify/orchestrator.d.ts +1 -1
  542. package/dist/src/verify/orchestrator.js +20 -3
  543. package/dist/src/verify/recipes.d.ts +13 -0
  544. package/dist/src/verify/recipes.js +15 -0
  545. package/package.json +134 -132
  546. package/dist/src/cli/bw-vault.d.ts +0 -55
  547. package/dist/src/cli/bw-vault.js +0 -133
  548. package/dist/src/mcp/ee-tools.d.ts +0 -46
  549. package/dist/src/mcp/ee-tools.js +0 -193
  550. package/dist/src/providers/auth/gcloud.d.ts +0 -28
  551. package/dist/src/providers/auth/gcloud.js +0 -102
  552. package/dist/src/providers/auth/gemini-oauth.d.ts +0 -82
  553. package/dist/src/providers/auth/gemini-oauth.js +0 -472
  554. package/dist/src/providers/gemini.d.ts +0 -11
  555. package/dist/src/providers/gemini.js +0 -45
  556. package/dist/src/providers/siliconflow-sse-repair.d.ts +0 -58
  557. package/dist/src/providers/siliconflow-sse-repair.js +0 -177
  558. package/dist/src/providers/strategies/google.strategy.d.ts +0 -22
  559. package/dist/src/providers/strategies/google.strategy.js +0 -174
  560. package/dist/src/providers/strategies/siliconflow.strategy.js +0 -29
  561. package/dist/src/ui/containers/chat-feed.d.ts +0 -40
  562. package/dist/src/ui/containers/chat-feed.js +0 -66
@@ -0,0 +1,51 @@
1
+ import type { CouncilLLM } from "../council/types.js";
2
+ /**
3
+ * Extract acceptance-criteria strings from a council synthesis blob. The synthesis
4
+ * is `<json>---READABLE---<prose>` (see council/planner.parseOutcome); the JSON
5
+ * block carries `acceptance_criteria: string[]`. Falls back to a markdown
6
+ * "Acceptance Criteria" bullet section when JSON is absent/malformed so a
7
+ * readable-only plan still seeds something.
8
+ */
9
+ export declare function extractAcceptanceCriteria(planSynthesis: string): string[];
10
+ /**
11
+ * Stable, single-line id for a criterion (used as the gray-areas.md section
12
+ * heading). Deterministic so re-seeding the same criterion is idempotent.
13
+ */
14
+ export declare function criterionIdFromText(text: string): string;
15
+ /**
16
+ * Merge the plan's acceptance criteria into gray-areas.md as unmet Criterion rows.
17
+ * Idempotent and non-clobbering: criteria already present (any status) are left
18
+ * untouched so a re-plan/retry never resets progress.
19
+ * Returns the count of NEW criteria seeded.
20
+ */
21
+ export declare function seedCriteriaFromPlan(flowDir: string, runId: string, criteriaTexts: string[], sprintN: number): Promise<number>;
22
+ /**
23
+ * Non-blocking plan-quality check. The per-sprint plan is auto-approved (there is
24
+ * no plan-check gate by design, to avoid stranding the loop), so a weak plan reaches
25
+ * the implementer silently. This surfaces the two failure modes that let Sprint 1
26
+ * diverge undetected: (1) no acceptance_criteria → done-gate can't score/gate,
27
+ * (2) no file_edits → the plan is prose, not an executable target list. Callers
28
+ * emit these as warnings and may inject a corrective note; they never halt.
29
+ */
30
+ export declare function planQualityIssues(planSynthesis: string, seededCriteriaCount: number): string[];
31
+ /**
32
+ * Judge the still-unmet criteria against the sprint's verify output + a diff
33
+ * summary, using a single bounded LLM call, then persist met/partial statuses
34
+ * with evidence. This is what lets the done-gate score reflect what was actually
35
+ * implemented (and blocks ship when the impl diverged from the plan).
36
+ *
37
+ * Fail-open: any parse/LLM error leaves criteria unmet (conservative — a sprint
38
+ * cannot pass on a judging failure). Returns the number of criteria upgraded.
39
+ */
40
+ export declare function judgeCriteriaAgainstVerify(args: {
41
+ flowDir: string;
42
+ runId: string;
43
+ llm: CouncilLLM;
44
+ modelId: string;
45
+ verifyVerdict: string;
46
+ verifyOutput: string;
47
+ diffSummary: string;
48
+ }): Promise<{
49
+ judged: number;
50
+ total: number;
51
+ }>;
@@ -0,0 +1,200 @@
1
+ import { readCriteria, updateCriteria } from "./artifact-io.js";
2
+ /**
3
+ * Slice fidelity fix (2026-07-11): the per-sprint council synthesis (planSynthesis)
4
+ * already carries a rich `acceptance_criteria` array, but nothing extracted it into
5
+ * the criteria store (gray-areas.md). readCriteria therefore returned [], the
6
+ * done-gate's calculateScore returned 0, and every sprint scored 0.00 — the
7
+ * implementation could diverge from the plan (wrong LSP op, stub tools) with no
8
+ * gate to catch it. This module closes that gap: seed the plan's acceptance
9
+ * criteria as real Criterion rows, then judge them against the verify output so the
10
+ * score reflects what was actually built and a failing criterion forces a retry.
11
+ */
12
+ const MAX_CRITERIA_PER_SPRINT = 24;
13
+ const ID_MAX_LEN = 70;
14
+ /**
15
+ * Extract acceptance-criteria strings from a council synthesis blob. The synthesis
16
+ * is `<json>---READABLE---<prose>` (see council/planner.parseOutcome); the JSON
17
+ * block carries `acceptance_criteria: string[]`. Falls back to a markdown
18
+ * "Acceptance Criteria" bullet section when JSON is absent/malformed so a
19
+ * readable-only plan still seeds something.
20
+ */
21
+ export function extractAcceptanceCriteria(planSynthesis) {
22
+ if (!planSynthesis || !planSynthesis.trim())
23
+ return [];
24
+ // 1) Prefer the JSON block before the ---READABLE--- separator.
25
+ const jsonPart = planSynthesis.includes("---READABLE---") ? planSynthesis.split("---READABLE---")[0] : planSynthesis;
26
+ const jsonMatch = jsonPart.match(/\{[\s\S]*\}/);
27
+ if (jsonMatch) {
28
+ try {
29
+ const parsed = JSON.parse(jsonMatch[0]);
30
+ const raw = parsed.acceptance_criteria ?? parsed.acceptanceCriteria;
31
+ if (Array.isArray(raw)) {
32
+ const items = raw
33
+ .map((c) => (typeof c === "string" ? c : typeof c === "object" && c ? JSON.stringify(c) : ""))
34
+ .map((s) => s.trim())
35
+ .filter((s) => s.length > 0);
36
+ if (items.length > 0)
37
+ return dedupe(items).slice(0, MAX_CRITERIA_PER_SPRINT);
38
+ }
39
+ }
40
+ catch {
41
+ /* fall through to markdown */
42
+ }
43
+ }
44
+ // 2) Markdown fallback: bullets under an "Acceptance Criteria" heading.
45
+ const lines = planSynthesis.split("\n");
46
+ const out = [];
47
+ let inSection = false;
48
+ for (const line of lines) {
49
+ const trimmed = line.trim();
50
+ if (/^#{1,6}\s|^\*\*/.test(trimmed) && /acceptance\s+criteria/i.test(trimmed)) {
51
+ inSection = true;
52
+ continue;
53
+ }
54
+ if (inSection) {
55
+ if (/^#{1,6}\s/.test(trimmed) || /^\*\*[A-Z]/.test(trimmed))
56
+ break; // next heading
57
+ const bullet = trimmed.match(/^[-*]\s+(.*)$/) ?? trimmed.match(/^\d+\.\s+(.*)$/);
58
+ if (bullet && bullet[1].trim())
59
+ out.push(bullet[1].trim());
60
+ }
61
+ }
62
+ return dedupe(out).slice(0, MAX_CRITERIA_PER_SPRINT);
63
+ }
64
+ function dedupe(items) {
65
+ const seen = new Set();
66
+ const out = [];
67
+ for (const it of items) {
68
+ const key = it.toLowerCase().replace(/\s+/g, " ");
69
+ if (!seen.has(key)) {
70
+ seen.add(key);
71
+ out.push(it);
72
+ }
73
+ }
74
+ return out;
75
+ }
76
+ /**
77
+ * Stable, single-line id for a criterion (used as the gray-areas.md section
78
+ * heading). Deterministic so re-seeding the same criterion is idempotent.
79
+ */
80
+ export function criterionIdFromText(text) {
81
+ const oneLine = text.replace(/\s+/g, " ").trim();
82
+ if (oneLine.length <= ID_MAX_LEN)
83
+ return oneLine;
84
+ // Truncate but append a short hash so two long criteria that share a prefix
85
+ // don't collapse to the same heading.
86
+ let hash = 0;
87
+ for (let i = 0; i < oneLine.length; i++)
88
+ hash = (hash * 31 + oneLine.charCodeAt(i)) | 0;
89
+ const suffix = (hash >>> 0).toString(36).slice(0, 6);
90
+ return `${oneLine.slice(0, ID_MAX_LEN - 8).trim()}… #${suffix}`;
91
+ }
92
+ /**
93
+ * Merge the plan's acceptance criteria into gray-areas.md as unmet Criterion rows.
94
+ * Idempotent and non-clobbering: criteria already present (any status) are left
95
+ * untouched so a re-plan/retry never resets progress.
96
+ * Returns the count of NEW criteria seeded.
97
+ */
98
+ export async function seedCriteriaFromPlan(flowDir, runId, criteriaTexts, sprintN) {
99
+ if (criteriaTexts.length === 0)
100
+ return 0;
101
+ const existing = await readCriteria(flowDir, runId);
102
+ const existingIds = new Set(existing.map((c) => c.id.trim()));
103
+ const fresh = [];
104
+ for (const text of criteriaTexts) {
105
+ const id = criterionIdFromText(text);
106
+ if (existingIds.has(id.trim()))
107
+ continue;
108
+ existingIds.add(id.trim());
109
+ fresh.push({ id, status: "unmet", sprint: sprintN });
110
+ }
111
+ if (fresh.length === 0)
112
+ return 0;
113
+ await updateCriteria(flowDir, runId, fresh);
114
+ return fresh.length;
115
+ }
116
+ /**
117
+ * Non-blocking plan-quality check. The per-sprint plan is auto-approved (there is
118
+ * no plan-check gate by design, to avoid stranding the loop), so a weak plan reaches
119
+ * the implementer silently. This surfaces the two failure modes that let Sprint 1
120
+ * diverge undetected: (1) no acceptance_criteria → done-gate can't score/gate,
121
+ * (2) no file_edits → the plan is prose, not an executable target list. Callers
122
+ * emit these as warnings and may inject a corrective note; they never halt.
123
+ */
124
+ export function planQualityIssues(planSynthesis, seededCriteriaCount) {
125
+ const issues = [];
126
+ if (seededCriteriaCount === 0) {
127
+ issues.push("plan carries no acceptance_criteria — the done-gate cannot score this sprint against the plan");
128
+ }
129
+ if (!/"?file_edits"?\s*:/.test(planSynthesis) && !/##\s*file edits/i.test(planSynthesis)) {
130
+ issues.push("plan lists no file_edits — implementation has no concrete target files to follow");
131
+ }
132
+ return issues;
133
+ }
134
+ /**
135
+ * Judge the still-unmet criteria against the sprint's verify output + a diff
136
+ * summary, using a single bounded LLM call, then persist met/partial statuses
137
+ * with evidence. This is what lets the done-gate score reflect what was actually
138
+ * implemented (and blocks ship when the impl diverged from the plan).
139
+ *
140
+ * Fail-open: any parse/LLM error leaves criteria unmet (conservative — a sprint
141
+ * cannot pass on a judging failure). Returns the number of criteria upgraded.
142
+ */
143
+ export async function judgeCriteriaAgainstVerify(args) {
144
+ const criteria = await readCriteria(args.flowDir, args.runId);
145
+ const unmet = criteria.filter((c) => c.status !== "met");
146
+ if (unmet.length === 0)
147
+ return { judged: 0, total: criteria.length };
148
+ // Evidence must be verifiable (done-gate condition #2 rejects criteria marked
149
+ // met/partial without a valid evidence string), so only allow upgrades when
150
+ // verify did not hard-fail. On FAIL/ERROR, leave everything unmet.
151
+ if (args.verifyVerdict !== "PASS") {
152
+ return { judged: 0, total: criteria.length };
153
+ }
154
+ const list = unmet.map((c, i) => `${i + 1}. [${c.id}] ${c.id}`).join("\n");
155
+ const prompt = `You are grading whether each acceptance criterion is satisfied by a sprint's ` +
156
+ `actual work. Be strict: mark "met" ONLY when the diff + verify output show it ` +
157
+ `is truly satisfied; "partial" if started but incomplete; "unmet" otherwise.\n\n` +
158
+ `Verify verdict: ${args.verifyVerdict}\n` +
159
+ `Verify output (truncated):\n${args.verifyOutput.slice(0, 4000)}\n\n` +
160
+ `Changed files / diff summary (truncated):\n${args.diffSummary.slice(0, 4000)}\n\n` +
161
+ `Criteria:\n${list}\n\n` +
162
+ `Return ONLY a JSON array: [{"n": <number>, "status": "met"|"partial"|"unmet", ` +
163
+ `"evidence": "<one concrete sentence citing a file/test/output; required for met/partial>"}]`;
164
+ let raw;
165
+ try {
166
+ raw = await args.llm.generate(args.modelId, "You are a strict acceptance-criteria grader.", prompt);
167
+ }
168
+ catch {
169
+ return { judged: 0, total: criteria.length };
170
+ }
171
+ const jsonMatch = raw.match(/\[[\s\S]*\]/);
172
+ if (!jsonMatch)
173
+ return { judged: 0, total: criteria.length };
174
+ let verdicts;
175
+ try {
176
+ verdicts = JSON.parse(jsonMatch[0]);
177
+ }
178
+ catch {
179
+ return { judged: 0, total: criteria.length };
180
+ }
181
+ const updates = [];
182
+ for (const v of verdicts) {
183
+ if (typeof v.n !== "number" || v.n < 1 || v.n > unmet.length)
184
+ continue;
185
+ const target = unmet[v.n - 1];
186
+ const status = v.status === "met" || v.status === "partial" ? v.status : "unmet";
187
+ const evidence = typeof v.evidence === "string" ? v.evidence.trim() : "";
188
+ // Don't upgrade without evidence — the done-gate would reject it anyway.
189
+ if ((status === "met" || status === "partial") && evidence.length < 8)
190
+ continue;
191
+ if (status === "unmet")
192
+ continue;
193
+ updates.push({ id: target.id, status, evidence, sprint: target.sprint });
194
+ }
195
+ if (updates.length > 0) {
196
+ await updateCriteria(args.flowDir, args.runId, updates);
197
+ }
198
+ return { judged: updates.length, total: criteria.length };
199
+ }
200
+ //# sourceMappingURL=criteria-seed.js.map
@@ -34,7 +34,9 @@ export function formatProjectContextForPrompt(ctx) {
34
34
  lines.push(`Backend stack: ${lang} / ${fw}${runtime}`);
35
35
  }
36
36
  if (c.dbStrategy) {
37
- lines.push(`Database: ${c.dbStrategy.mode ?? "(unspecified)"} ${c.dbStrategy.engine ?? ""}`.trimEnd());
37
+ lines.push(c.dbStrategy.mode === "none"
38
+ ? "Database: none (stateless — no persistent storage)"
39
+ : `Database: ${c.dbStrategy.mode ?? "(unspecified)"} ${c.dbStrategy.engine ?? ""}`.trimEnd());
38
40
  }
39
41
  if (c.frontendApproach) {
40
42
  const harness = c.frontendApproach.agentHarness
@@ -164,7 +164,10 @@ export function buildEcosystemPreamble() {
164
164
  "- Angular with @muonroi/agent-harness-angular directive.",
165
165
  'When recommending `frontendApproach`, ALWAYS fill the optional `agentHarness` slot — pick "react" for React/Next, "angular" for Angular, "opentui" for terminal UI, "core" for non-DOM integration. Only use "none" when the project has no UI at all.',
166
166
  "",
167
- "Recommend non-ecosystem options ONLY when the user's prompt explicitly opts out (e.g. mentions Node.js/Express/Django by name).",
167
+ "Strongest-default, still extensible:",
168
+ "- Keep the Muonroi/.NET path as the PRIMARY recommendation — it is the ecosystem's strongest, best-supported option.",
169
+ "- BUT for stack choices (architecture/stack/platform) ALWAYS include at least one mainstream NON-ecosystem alternative in `alternatives` (pick what genuinely fits the task — e.g. Python for data/ML/scripting, Go or Rust for a fast static-binary CLI, Node/TypeScript for JS-native tooling), with a one-line rationale. A user outside the Muonroi ecosystem must always see a real, viable path — never a .NET-only menu.",
170
+ "- Promote the non-ecosystem option to PRIMARY only when the prompt names another stack, or the task is a poor fit for .NET (e.g. a shell-glue one-liner, a data-science notebook, an npm-ecosystem plugin). Otherwise it stays a first-class alternative, not the default.",
168
171
  ].join("\n");
169
172
  }
170
173
  /**
@@ -1,4 +1,5 @@
1
1
  import { type RecommendInput, type RecommendOutput } from "./discovery-recommender.js";
2
+ import type { InterviewTriage } from "./discovery-triage.js";
2
3
  import type { ExistingProjectSignals, ProjectContext } from "./types.js";
3
4
  export type UserPromptResult = {
4
5
  action: "accept";
@@ -62,5 +63,13 @@ export interface IterateOpts {
62
63
  * sandboxed temp dir to exercise existing-project paths deterministically.
63
64
  */
64
65
  cwd?: string;
66
+ /**
67
+ * Model-decided interview triage (see discovery-triage.ts). When present it is
68
+ * the PRIMARY signal for how deep to interview — replacing the legacy keyword
69
+ * `computePromptSpecificity` heuristic (kept only as the graceful-degrade
70
+ * fallback inside `triageInterview`). Absent → the old specificity behaviour is
71
+ * used verbatim, so existing callers/tests are unaffected.
72
+ */
73
+ triage?: InterviewTriage;
65
74
  }
66
75
  export declare function iterateInterview(opts: IterateOpts): Promise<ProjectContext>;
@@ -3,6 +3,13 @@ import { appendUserOverride, buildProjectContextFromState, markDone, markUserGat
3
3
  import { computePromptSpecificity, toEntry, } from "./discovery-recommender.js";
4
4
  import { DISCOVERY_QUESTIONS, isFePolicyAccepted, isRequiredForPlatform, REQUIRED_QUESTION_IDS, validateAnswer, } from "./discovery-schema.js";
5
5
  import { buildRepoBrief } from "./repo-brief.js";
6
+ /**
7
+ * Under existing-repo collapse, keep ONLY these questions as interactive
8
+ * per-field cards — they are the fields whose answers actually shape the
9
+ * technical change. Everything else in DISCOVERY_QUESTIONS is auto-filled and
10
+ * surfaced together on the compact __user_gate__ confirm card.
11
+ */
12
+ const KEEP_CARD_FOR_EXISTING = new Set(["backendArchitecture"]);
6
13
  export async function iterateInterview(opts) {
7
14
  const { flowDir, runId, detection } = opts;
8
15
  const _itvDbg = process.env.MUONROI_DEBUG_LEADER === "1";
@@ -20,17 +27,47 @@ export async function iterateInterview(opts) {
20
27
  // but optional ones (baStatus, designStatus, deployment, frontendApproach when
21
28
  // not web) are deferred unless the user explicitly re-runs with more context.
22
29
  const specificity = computePromptSpecificity(opts.idea);
23
- const skipOptionalForMinimal = specificity === "minimal";
24
- // G2-b: for a minimal OR well-specified ("detailed") prompt the recommender's
25
- // primary is high-confidence minimal picks smallest-scope defaults, detailed
26
- // respects the stated context. In both cases surfacing a card for EVERY
27
- // required question (productType/targetPlatform/audience/…) is over-asking the
28
- // user already complained about: they accept by reflex. Instead auto-accept
29
- // the recommender primary for required questions and surface ONE summary card
30
- // (the user gate) listing the assumptions so the user can proceed or adjust.
31
- // "moderate" prompts keep the per-question cards (genuinely ambiguous). Escape
32
- // hatch: MUONROI_DISCOVERY_AUTOFILL=0 restores per-question cards everywhere.
33
- const autoFillRequired = (specificity === "minimal" || specificity === "detailed") && process.env.MUONROI_DISCOVERY_AUTOFILL !== "0";
30
+ // Interview-depth tier. PRIMARY signal is the model-decided triage
31
+ // (opts.triage); the legacy keyword specificity is used ONLY when no triage was
32
+ // supplied (older callers / tests), mapped: minimal→trivial, else→standard.
33
+ // "detailed" no longer force-collapses on the heuristic alone a precise-but-
34
+ // complex idea should be triaged as complex by the model, not auto-filled blind.
35
+ const tier = opts.triage?.complexity ?? (specificity === "minimal" ? "trivial" : "standard");
36
+ // Existing-codebase work (refactor / migration / feature-add on a repo that
37
+ // already has source) should NOT re-run the full greenfield product-scoping
38
+ // questionnaire. productType/audience/targetPlatform/frontend/design/deployment
39
+ // are derivable from the codebase and inert for the technical change — asking
40
+ // them per-field is the over-ask users complained about. For any non-greenfield
41
+ // classification (existing OR ambiguous polyglot) we collapse to the ONE
42
+ // decision-relevant card (backendArchitecture) plus the compact "assumed from
43
+ // codebase" confirm gate (the same __user_gate__ path used for minimal/detailed
44
+ // prompts). This mirrors the repoBrief-build condition below. Escape hatch:
45
+ // MUONROI_DISCOVERY_EXISTING_COLLAPSE=0 restores the full per-field interview.
46
+ const collapseForExisting = detection.classification !== "greenfield" && process.env.MUONROI_DISCOVERY_EXISTING_COLLAPSE !== "0";
47
+ const skipOptionalForMinimal = tier === "trivial" || collapseForExisting;
48
+ // Which REQUIRED questions stay as interactive per-question cards. Everything
49
+ // else auto-fills the recommender primary and is surfaced together on the ONE
50
+ // summary confirm card (__user_gate__). This is the crux of the "sharper, less
51
+ // hardcoded" interview:
52
+ // - existing-repo collapse → only the decision-relevant field(s)
53
+ // - trivial → NONE (e.g. a hello-world script: don't interrogate audience
54
+ // scale / backend architecture / db strategy — just confirm the defaults)
55
+ // - complex → ONLY the questions the model flagged as genuinely shaping this
56
+ // build (triage.relevant); auto-fill the rest
57
+ // - standard (or model unavailable) → ALL required stay cards (unchanged UX)
58
+ const interactiveRequired = collapseForExisting
59
+ ? new Set(KEEP_CARD_FOR_EXISTING)
60
+ : tier === "trivial"
61
+ ? new Set()
62
+ : tier === "complex" && opts.triage
63
+ ? new Set(opts.triage.relevant)
64
+ : new Set(REQUIRED_QUESTION_IDS);
65
+ // Auto-accept the recommender primary for required questions NOT kept interactive
66
+ // above, and surface ONE summary card listing the assumptions so the user can
67
+ // proceed or adjust. Enabled whenever ANY required question is being auto-filled
68
+ // (i.e. the interactive set is a strict subset of the required set). Escape hatch:
69
+ // MUONROI_DISCOVERY_AUTOFILL=0 restores per-question cards everywhere.
70
+ const autoFillRequired = process.env.MUONROI_DISCOVERY_AUTOFILL !== "0" && REQUIRED_QUESTION_IDS.some((id) => !interactiveRequired.has(id));
34
71
  const assumed = [];
35
72
  // G1 follow-up: keep the recommendation behind each auto-filled assumption so
36
73
  // the user-gate "edit: <field>" path can re-render the SAME per-question card
@@ -94,7 +131,18 @@ export async function iterateInterview(opts) {
94
131
  // policy) so a malformed recommendation falls back to the normal card flow.
95
132
  // The assumed answers are surfaced together on the single user-gate card.
96
133
  let autoAccepted = false;
97
- if (autoFillRequired && effectivelyRequired && recommendation.primary?.value != null) {
134
+ // Keep the interview-relevant fields interactive (existing-repo
135
+ // backendArchitecture; complex → the model-flagged `triage.relevant`), and
136
+ // NEVER silently auto-accept a weakly-grounded recommendation (synthFailed =
137
+ // the rationale failed the repo-brief citation check twice) — fall through to a
138
+ // per-question card so the user can catch a hallucinated value instead of it
139
+ // being assumed.
140
+ const keepInteractive = interactiveRequired.has(question.id);
141
+ if (autoFillRequired &&
142
+ effectivelyRequired &&
143
+ recommendation.primary?.value != null &&
144
+ !recommendation.synthFailed &&
145
+ !keepInteractive) {
98
146
  const v = recommendation.primary.value;
99
147
  const validation = validateAnswer(question.id, v);
100
148
  const feLib = question.id === "frontendApproach" ? v?.library : undefined;
@@ -79,7 +79,8 @@ const LEADER_SYSTEM = "You are a product context recommender. Output ONE JSON ob
79
79
  "## Scope-sizing discipline\n" +
80
80
  "You will be told the user's original prompt and its specificity bucket (minimal/moderate/detailed).\n" +
81
81
  '- When specificity is "minimal" (e.g. user typed "build a todo app" or "tạo wiki"), pick the SMALLEST-SCOPE primary that still works: ' +
82
- 'productType="other" or "consumer-app" (NOT "saas"), audience scale="1-100" (NOT "100-1k" or above), ' +
82
+ 'productType="consumer-app" for a small app, or "cli-tool"/"script"/"library" for a stand-alone tool/snippet ' +
83
+ '(prefer these over the catch-all "other" — a hello-world script is a "script", not "other"), audience scale="1-100" (NOT "100-1k" or above), ' +
83
84
  "single-user / no auth / web-only / simplest stack. Put richer multi-tenant/team-scale alternatives in `alternatives`, NOT primary. " +
84
85
  "Rationale: short prompts mean the user has NOT asked for enterprise complexity. Inflating scope here cascades into wasted debate and over-built code.\n" +
85
86
  '- When specificity is "moderate", pick pragmatic defaults grounded in any stated context; surface ONE richer alternative.\n' +
@@ -18,7 +18,7 @@ export const DISCOVERY_QUESTIONS = [
18
18
  id: "dbStrategy",
19
19
  required: true,
20
20
  recommendMode: "council",
21
- prompt: "Database strategy: greenfield, existing schema, or migration?",
21
+ prompt: "Database strategy: none (stateless — no persistent storage), greenfield, existing schema, or migration? Choose none for a CLI/tool/filter that keeps no data.",
22
22
  },
23
23
  {
24
24
  id: "frontendApproach",
@@ -48,7 +48,20 @@ export function isRequiredForPlatform(questionId, platforms) {
48
48
  }
49
49
  return false;
50
50
  }
51
- const PRODUCT_TYPES = new Set(["saas", "internal-tool", "consumer-app", "b2b-platform", "marketplace", "other"]);
51
+ const PRODUCT_TYPES = new Set([
52
+ "saas",
53
+ "internal-tool",
54
+ "consumer-app",
55
+ "b2b-platform",
56
+ "marketplace",
57
+ // Small-scope builds that previously had no home in the enum and so were
58
+ // forced to "other" — the exact "recommend other" bad UX users hit for a
59
+ // hello-world script. A trivial CLI/script/library now maps cleanly.
60
+ "cli-tool",
61
+ "script",
62
+ "library",
63
+ "other",
64
+ ]);
52
65
  const SCALES = new Set(["1-100", "100-1k", "1k-100k", "100k-1M", "1M+"]);
53
66
  /**
54
67
  * Schema hint for the leader prompt — surfaces the enum/shape that
@@ -74,6 +87,10 @@ export function getSchemaHintForLeader(questionId) {
74
87
  return `value MUST be an object {"persona": string, "scale": one of ${Array.from(SCALES)
75
88
  .map((s) => JSON.stringify(s))
76
89
  .join("|")}, "geography": string}`;
90
+ case "dbStrategy":
91
+ // F7 — give the recommender an explicit "no persistence" option so it
92
+ // stops mis-ranking "greenfield" for stateless products (CLI/tool/filter).
93
+ return `value MUST be an object {"mode": one of "none"|"greenfield"|"existing-schema"|"migrate-from", "engine": string, "notes"?: string}. Pick "mode":"none" with "engine":"" when the product keeps NO persistent data (e.g. a stateless CLI, filter, or one-shot tool) — do NOT default to "greenfield" in that case.`;
77
94
  case "frontendApproach":
78
95
  return `value MUST be an object {"library": one of ${Array.from(ACCEPTED_FE_LIBRARIES)
79
96
  .map((l) => JSON.stringify(l))
@@ -0,0 +1,23 @@
1
+ import type { LeaderLike } from "./discovery-prompt-parser.js";
2
+ import { type DiscoveryQuestion } from "./discovery-schema.js";
3
+ export type ComplexityTier = "trivial" | "standard" | "complex";
4
+ export interface InterviewTriage {
5
+ complexity: ComplexityTier;
6
+ /**
7
+ * Required question ids (subset of REQUIRED_QUESTION_IDS) whose answers
8
+ * genuinely shape THIS build and must stay interactive cards. Only meaningful
9
+ * for `complexity === "complex"`; empty for trivial (auto-fill all) and ignored
10
+ * for standard (keep all cards).
11
+ */
12
+ relevant: string[];
13
+ rationale: string;
14
+ source: "model" | "fallback";
15
+ }
16
+ /** Graceful-degrade triage derived from the legacy specificity heuristic. */
17
+ export declare function fallbackTriage(idea: string): InterviewTriage;
18
+ /**
19
+ * Triage the interview depth for `idea` via one leader call. Never throws —
20
+ * returns a fallback triage on any LLM/parse failure. Skips the call entirely
21
+ * (and returns the fallback) when the idea is empty.
22
+ */
23
+ export declare function triageInterview(idea: string, leader: LeaderLike, requiredQuestions: DiscoveryQuestion[]): Promise<InterviewTriage>;
@@ -0,0 +1,109 @@
1
+ // src/product-loop/discovery-triage.ts
2
+ //
3
+ // Model-decided interview triage.
4
+ //
5
+ // The discover/gather interview used to size itself off `computePromptSpecificity`
6
+ // — a hardcoded word-count + keyword-list heuristic. That misclassifies precise-
7
+ // but-trivial ideas: "build a Python script hello.py that prints … and a pytest
8
+ // test" is ~18 words with no keyword hit → "moderate" → the user is dragged
9
+ // through 6 generic cards (productType/platform/audience/architecture/stack/db)
10
+ // and the productType recommender falls back to "other". That is the "hời hợt /
11
+ // hardcode" UX users complained about, and it violates the project's
12
+ // agent-first-no-regex principle (interview depth must be model-decided).
13
+ //
14
+ // This module asks the leader model to triage the idea into a complexity tier and,
15
+ // for genuinely complex ideas, name which of the fixed required questions actually
16
+ // shape the build. The interview then:
17
+ // - trivial → auto-fill every required answer → ONE summary confirm card
18
+ // - complex → keep only the model-relevant questions as cards, auto-fill the rest
19
+ // - standard → unchanged per-question flow
20
+ //
21
+ // Fail-safe: any parse/LLM failure returns a `fallback` triage derived from the
22
+ // old specificity heuristic, so the interview degrades to today's behaviour rather
23
+ // than breaking. Pure decision + one bounded LLM call → unit-testable.
24
+ import { computePromptSpecificity } from "./discovery-recommender.js";
25
+ import { REQUIRED_QUESTION_IDS } from "./discovery-schema.js";
26
+ const TRIAGE_SYSTEM = "You triage a software build request to decide how much of an interview it warrants. " +
27
+ "Output ONE JSON object, no prose, no code fences: " +
28
+ '{"complexity":"trivial"|"standard"|"complex","relevant":[<question-id>...],"rationale":"<short>"}.\n\n' +
29
+ "Tiers:\n" +
30
+ '- "trivial": a self-contained script, snippet, one-off tool, or exercise with ONE obvious stack and NO ' +
31
+ "persistence / scale / architecture / integration decisions. Examples: a hello-world script + a test, " +
32
+ "a regex to validate an email, a bash one-liner, a single pure function + unit test. The user should just " +
33
+ "confirm sensible defaults — asking about audience scale, backend architecture, or database strategy is noise.\n" +
34
+ '- "standard": a real but conventional app with a few genuine but well-trodden choices. Examples: a todo web ' +
35
+ "app, a CRUD REST API, a small CLI with a couple of subcommands.\n" +
36
+ '- "complex": multiple non-obvious architecture / scale / integration / security decisions. Examples: a ' +
37
+ "multi-tenant SaaS, an OAuth / SSO service, an event-driven pipeline, anything naming enterprise scale.\n\n" +
38
+ 'For "complex" ONLY, set `relevant` to the question ids (from the provided list) whose answers genuinely ' +
39
+ "shape this build and MUST be asked; auto-filled defaults are fine for the rest. For trivial/standard, " +
40
+ "set `relevant` to []. Bias toward FEWER questions: every card the user accepts by reflex becomes locked-in spec.";
41
+ function buildTriagePrompt(idea, requiredQuestions) {
42
+ const qList = requiredQuestions.map((q) => `- ${q.id}: ${q.prompt}`).join("\n");
43
+ return [
44
+ `Build request: ${JSON.stringify(idea)}`,
45
+ "",
46
+ "Required question ids you may cite in `relevant`:",
47
+ qList,
48
+ ].join("\n");
49
+ }
50
+ function stripFences(s) {
51
+ return s
52
+ .trim()
53
+ .replace(/^```(?:json)?\s*/, "")
54
+ .replace(/\s*```$/, "");
55
+ }
56
+ const TIERS = new Set(["trivial", "standard", "complex"]);
57
+ /** Graceful-degrade triage derived from the legacy specificity heuristic. */
58
+ export function fallbackTriage(idea) {
59
+ const specificity = computePromptSpecificity(idea);
60
+ // minimal prompt → treat as trivial (collapse to one confirm card, matching the
61
+ // old minimal-autofill path); everything else stays "standard" so the current
62
+ // per-question behaviour is preserved when the model is unavailable.
63
+ const complexity = specificity === "minimal" ? "trivial" : "standard";
64
+ return { complexity, relevant: [], rationale: `fallback from specificity=${specificity}`, source: "fallback" };
65
+ }
66
+ function parseTriage(raw) {
67
+ let parsed;
68
+ try {
69
+ parsed = JSON.parse(stripFences(raw));
70
+ }
71
+ catch {
72
+ return null;
73
+ }
74
+ const obj = parsed;
75
+ if (typeof obj?.complexity !== "string" || !TIERS.has(obj.complexity))
76
+ return null;
77
+ const requiredSet = new Set(REQUIRED_QUESTION_IDS);
78
+ const relevant = Array.isArray(obj.relevant)
79
+ ? obj.relevant.filter((r) => typeof r === "string" && requiredSet.has(r))
80
+ : [];
81
+ const rationale = typeof obj.rationale === "string" ? obj.rationale : "";
82
+ return { complexity: obj.complexity, relevant, rationale };
83
+ }
84
+ /**
85
+ * Triage the interview depth for `idea` via one leader call. Never throws —
86
+ * returns a fallback triage on any LLM/parse failure. Skips the call entirely
87
+ * (and returns the fallback) when the idea is empty.
88
+ */
89
+ export async function triageInterview(idea, leader, requiredQuestions) {
90
+ if (!idea || idea.trim().length === 0)
91
+ return fallbackTriage(idea);
92
+ try {
93
+ const res = await leader.generate({
94
+ system: TRIAGE_SYSTEM,
95
+ prompt: buildTriagePrompt(idea, requiredQuestions),
96
+ maxTokens: 1024,
97
+ });
98
+ const parsed = parseTriage(res?.content ?? "");
99
+ if (!parsed)
100
+ return fallbackTriage(idea);
101
+ // `relevant` is only meaningful for complex; normalize the others to [].
102
+ const relevant = parsed.complexity === "complex" ? parsed.relevant : [];
103
+ return { complexity: parsed.complexity, relevant, rationale: parsed.rationale, source: "model" };
104
+ }
105
+ catch {
106
+ return fallbackTriage(idea);
107
+ }
108
+ }
109
+ //# sourceMappingURL=discovery-triage.js.map