@oscharko-dev/keiko 0.1.0-beta.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 (450) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +7 -0
  3. package/README.md +621 -0
  4. package/TRADEMARKS.md +41 -0
  5. package/dist/audit/aggregate.d.ts +5 -0
  6. package/dist/audit/aggregate.js +25 -0
  7. package/dist/audit/build.d.ts +2 -0
  8. package/dist/audit/build.js +224 -0
  9. package/dist/audit/errors.d.ts +25 -0
  10. package/dist/audit/errors.js +39 -0
  11. package/dist/audit/index-api.d.ts +14 -0
  12. package/dist/audit/index-api.js +131 -0
  13. package/dist/audit/index.d.ts +12 -0
  14. package/dist/audit/index.js +17 -0
  15. package/dist/audit/persist.d.ts +8 -0
  16. package/dist/audit/persist.js +40 -0
  17. package/dist/audit/redaction.d.ts +3 -0
  18. package/dist/audit/redaction.js +61 -0
  19. package/dist/audit/report.d.ts +18 -0
  20. package/dist/audit/report.js +50 -0
  21. package/dist/audit/retention.d.ts +3 -0
  22. package/dist/audit/retention.js +95 -0
  23. package/dist/audit/runid.d.ts +1 -0
  24. package/dist/audit/runid.js +29 -0
  25. package/dist/audit/side-file.d.ts +12 -0
  26. package/dist/audit/side-file.js +82 -0
  27. package/dist/audit/store.d.ts +12 -0
  28. package/dist/audit/store.js +198 -0
  29. package/dist/audit/types.d.ts +188 -0
  30. package/dist/audit/types.js +8 -0
  31. package/dist/audit/workflow-evidence.d.ts +27 -0
  32. package/dist/audit/workflow-evidence.js +145 -0
  33. package/dist/cli/context.d.ts +2 -0
  34. package/dist/cli/context.js +102 -0
  35. package/dist/cli/evaluate.d.ts +7 -0
  36. package/dist/cli/evaluate.js +207 -0
  37. package/dist/cli/evidence.d.ts +8 -0
  38. package/dist/cli/evidence.js +88 -0
  39. package/dist/cli/gateway-config.d.ts +10 -0
  40. package/dist/cli/gateway-config.js +12 -0
  41. package/dist/cli/gen-tests.d.ts +7 -0
  42. package/dist/cli/gen-tests.js +208 -0
  43. package/dist/cli/index.d.ts +2 -0
  44. package/dist/cli/index.js +14 -0
  45. package/dist/cli/investigate.d.ts +8 -0
  46. package/dist/cli/investigate.js +242 -0
  47. package/dist/cli/models.d.ts +3 -0
  48. package/dist/cli/models.js +64 -0
  49. package/dist/cli/run.d.ts +7 -0
  50. package/dist/cli/run.js +187 -0
  51. package/dist/cli/runner.d.ts +6 -0
  52. package/dist/cli/runner.js +83 -0
  53. package/dist/cli/ui.d.ts +31 -0
  54. package/dist/cli/ui.js +240 -0
  55. package/dist/cli/verify.d.ts +2 -0
  56. package/dist/cli/verify.js +103 -0
  57. package/dist/evaluations/fixtures/bug-investigation/happy-path.d.ts +2 -0
  58. package/dist/evaluations/fixtures/bug-investigation/happy-path.js +66 -0
  59. package/dist/evaluations/fixtures/bug-investigation/investigation-only.d.ts +2 -0
  60. package/dist/evaluations/fixtures/bug-investigation/investigation-only.js +39 -0
  61. package/dist/evaluations/fixtures/bug-investigation/unsafe-action.d.ts +2 -0
  62. package/dist/evaluations/fixtures/bug-investigation/unsafe-action.js +37 -0
  63. package/dist/evaluations/fixtures/index.d.ts +7 -0
  64. package/dist/evaluations/fixtures/index.js +35 -0
  65. package/dist/evaluations/fixtures/support.d.ts +5 -0
  66. package/dist/evaluations/fixtures/support.js +42 -0
  67. package/dist/evaluations/fixtures/unit-tests/happy-path.d.ts +2 -0
  68. package/dist/evaluations/fixtures/unit-tests/happy-path.js +40 -0
  69. package/dist/evaluations/fixtures/unit-tests/retry-then-accept.d.ts +2 -0
  70. package/dist/evaluations/fixtures/unit-tests/retry-then-accept.js +39 -0
  71. package/dist/evaluations/fixtures/unit-tests/unsafe-action.d.ts +2 -0
  72. package/dist/evaluations/fixtures/unit-tests/unsafe-action.js +32 -0
  73. package/dist/evaluations/index.d.ts +12 -0
  74. package/dist/evaluations/index.js +12 -0
  75. package/dist/evaluations/manifest-check.d.ts +1 -0
  76. package/dist/evaluations/manifest-check.js +48 -0
  77. package/dist/evaluations/model-provider.d.ts +12 -0
  78. package/dist/evaluations/model-provider.js +26 -0
  79. package/dist/evaluations/render.d.ts +2 -0
  80. package/dist/evaluations/render.js +59 -0
  81. package/dist/evaluations/runner-support.d.ts +27 -0
  82. package/dist/evaluations/runner-support.js +163 -0
  83. package/dist/evaluations/runner.d.ts +20 -0
  84. package/dist/evaluations/runner.js +174 -0
  85. package/dist/evaluations/scorer.d.ts +14 -0
  86. package/dist/evaluations/scorer.js +131 -0
  87. package/dist/evaluations/scripted-model.d.ts +6 -0
  88. package/dist/evaluations/scripted-model.js +26 -0
  89. package/dist/evaluations/surface-parity.d.ts +2 -0
  90. package/dist/evaluations/surface-parity.js +184 -0
  91. package/dist/evaluations/types.d.ts +74 -0
  92. package/dist/evaluations/types.js +16 -0
  93. package/dist/gateway/capabilities.d.ts +11 -0
  94. package/dist/gateway/capabilities.data.d.ts +2 -0
  95. package/dist/gateway/capabilities.data.js +203 -0
  96. package/dist/gateway/capabilities.js +41 -0
  97. package/dist/gateway/config.d.ts +15 -0
  98. package/dist/gateway/config.js +154 -0
  99. package/dist/gateway/errors.d.ts +72 -0
  100. package/dist/gateway/errors.js +82 -0
  101. package/dist/gateway/gateway.d.ts +19 -0
  102. package/dist/gateway/gateway.js +94 -0
  103. package/dist/gateway/index.d.ts +10 -0
  104. package/dist/gateway/index.js +11 -0
  105. package/dist/gateway/model-selection.d.ts +9 -0
  106. package/dist/gateway/model-selection.js +36 -0
  107. package/dist/gateway/normalize.d.ts +7 -0
  108. package/dist/gateway/normalize.js +93 -0
  109. package/dist/gateway/openai-adapter.d.ts +20 -0
  110. package/dist/gateway/openai-adapter.js +263 -0
  111. package/dist/gateway/redaction.d.ts +1 -0
  112. package/dist/gateway/redaction.js +51 -0
  113. package/dist/gateway/resilience.d.ts +24 -0
  114. package/dist/gateway/resilience.js +166 -0
  115. package/dist/gateway/types.d.ts +108 -0
  116. package/dist/gateway/types.js +2 -0
  117. package/dist/harness/adapters.d.ts +23 -0
  118. package/dist/harness/adapters.js +38 -0
  119. package/dist/harness/context.d.ts +33 -0
  120. package/dist/harness/context.js +21 -0
  121. package/dist/harness/emitter.d.ts +15 -0
  122. package/dist/harness/emitter.js +72 -0
  123. package/dist/harness/errors.d.ts +21 -0
  124. package/dist/harness/errors.js +39 -0
  125. package/dist/harness/executor.d.ts +3 -0
  126. package/dist/harness/executor.js +211 -0
  127. package/dist/harness/fingerprint.d.ts +6 -0
  128. package/dist/harness/fingerprint.js +43 -0
  129. package/dist/harness/index.d.ts +9 -0
  130. package/dist/harness/index.js +13 -0
  131. package/dist/harness/loop.d.ts +3 -0
  132. package/dist/harness/loop.js +159 -0
  133. package/dist/harness/patcher.d.ts +4 -0
  134. package/dist/harness/patcher.js +49 -0
  135. package/dist/harness/planner.d.ts +3 -0
  136. package/dist/harness/planner.js +21 -0
  137. package/dist/harness/ports.d.ts +61 -0
  138. package/dist/harness/ports.js +4 -0
  139. package/dist/harness/session.d.ts +25 -0
  140. package/dist/harness/session.js +116 -0
  141. package/dist/harness/sinks.d.ts +30 -0
  142. package/dist/harness/sinks.js +72 -0
  143. package/dist/harness/tasks/explain-plan.d.ts +3 -0
  144. package/dist/harness/tasks/explain-plan.js +29 -0
  145. package/dist/harness/tasks/generate-unit-tests.d.ts +3 -0
  146. package/dist/harness/tasks/generate-unit-tests.js +28 -0
  147. package/dist/harness/tasks/investigate-bug.d.ts +3 -0
  148. package/dist/harness/tasks/investigate-bug.js +31 -0
  149. package/dist/harness/tasks/policy.d.ts +11 -0
  150. package/dist/harness/tasks/policy.js +22 -0
  151. package/dist/harness/tasks/verify.d.ts +3 -0
  152. package/dist/harness/tasks/verify.js +16 -0
  153. package/dist/harness/types.d.ts +270 -0
  154. package/dist/harness/types.js +33 -0
  155. package/dist/index.d.ts +11 -0
  156. package/dist/index.js +36 -0
  157. package/dist/sdk/index.d.ts +9 -0
  158. package/dist/sdk/index.js +37 -0
  159. package/dist/sdk/run-agent.d.ts +16 -0
  160. package/dist/sdk/run-agent.js +56 -0
  161. package/dist/tools/browser/cdp-client.d.ts +35 -0
  162. package/dist/tools/browser/cdp-client.js +218 -0
  163. package/dist/tools/browser/errors.d.ts +25 -0
  164. package/dist/tools/browser/errors.js +55 -0
  165. package/dist/tools/browser/index.d.ts +5 -0
  166. package/dist/tools/browser/index.js +6 -0
  167. package/dist/tools/browser/session.d.ts +44 -0
  168. package/dist/tools/browser/session.js +748 -0
  169. package/dist/tools/browser/types.d.ts +48 -0
  170. package/dist/tools/browser/types.js +2 -0
  171. package/dist/tools/browser/validators.d.ts +5 -0
  172. package/dist/tools/browser/validators.js +97 -0
  173. package/dist/tools/errors.d.ts +59 -0
  174. package/dist/tools/errors.js +94 -0
  175. package/dist/tools/exec.d.ts +42 -0
  176. package/dist/tools/exec.js +327 -0
  177. package/dist/tools/index.d.ts +11 -0
  178. package/dist/tools/index.js +14 -0
  179. package/dist/tools/patch-content.d.ts +10 -0
  180. package/dist/tools/patch-content.js +126 -0
  181. package/dist/tools/patch-normalize.d.ts +1 -0
  182. package/dist/tools/patch-normalize.js +80 -0
  183. package/dist/tools/patch-parse.d.ts +8 -0
  184. package/dist/tools/patch-parse.js +201 -0
  185. package/dist/tools/patch.d.ts +18 -0
  186. package/dist/tools/patch.js +403 -0
  187. package/dist/tools/registry.d.ts +36 -0
  188. package/dist/tools/registry.js +231 -0
  189. package/dist/tools/sandbox.d.ts +8 -0
  190. package/dist/tools/sandbox.js +121 -0
  191. package/dist/tools/schemas.d.ts +2 -0
  192. package/dist/tools/schemas.js +51 -0
  193. package/dist/tools/terminal-policy.d.ts +9 -0
  194. package/dist/tools/terminal-policy.js +313 -0
  195. package/dist/tools/types.d.ts +99 -0
  196. package/dist/tools/types.js +103 -0
  197. package/dist/tools/writer.d.ts +7 -0
  198. package/dist/tools/writer.js +20 -0
  199. package/dist/ui/browser.d.ts +10 -0
  200. package/dist/ui/browser.js +231 -0
  201. package/dist/ui/chat-handlers.d.ts +4 -0
  202. package/dist/ui/chat-handlers.js +281 -0
  203. package/dist/ui/csp-hashes.json +17 -0
  204. package/dist/ui/csp.d.ts +2 -0
  205. package/dist/ui/csp.js +66 -0
  206. package/dist/ui/deps.d.ts +34 -0
  207. package/dist/ui/deps.js +137 -0
  208. package/dist/ui/evidence.d.ts +27 -0
  209. package/dist/ui/evidence.js +142 -0
  210. package/dist/ui/files-deny.d.ts +2 -0
  211. package/dist/ui/files-deny.js +12 -0
  212. package/dist/ui/files.d.ts +65 -0
  213. package/dist/ui/files.js +492 -0
  214. package/dist/ui/headers.d.ts +2 -0
  215. package/dist/ui/headers.js +21 -0
  216. package/dist/ui/host-check.d.ts +2 -0
  217. package/dist/ui/host-check.js +58 -0
  218. package/dist/ui/index.d.ts +20 -0
  219. package/dist/ui/index.js +23 -0
  220. package/dist/ui/load-csp.d.ts +1 -0
  221. package/dist/ui/load-csp.js +28 -0
  222. package/dist/ui/read-handlers.d.ts +8 -0
  223. package/dist/ui/read-handlers.js +247 -0
  224. package/dist/ui/routes.d.ts +36 -0
  225. package/dist/ui/routes.js +129 -0
  226. package/dist/ui/run-engine.d.ts +20 -0
  227. package/dist/ui/run-engine.js +345 -0
  228. package/dist/ui/run-handlers.d.ts +8 -0
  229. package/dist/ui/run-handlers.js +431 -0
  230. package/dist/ui/run-request.d.ts +13 -0
  231. package/dist/ui/run-request.js +219 -0
  232. package/dist/ui/runs.d.ts +43 -0
  233. package/dist/ui/runs.js +92 -0
  234. package/dist/ui/server.d.ts +11 -0
  235. package/dist/ui/server.js +143 -0
  236. package/dist/ui/sink.d.ts +27 -0
  237. package/dist/ui/sink.js +80 -0
  238. package/dist/ui/sse.d.ts +7 -0
  239. package/dist/ui/sse.js +27 -0
  240. package/dist/ui/static/404.html +1 -0
  241. package/dist/ui/static/_next/static/ca-A01hy9W98aRvMZKdAw/_buildManifest.js +1 -0
  242. package/dist/ui/static/_next/static/ca-A01hy9W98aRvMZKdAw/_ssgManifest.js +1 -0
  243. package/dist/ui/static/_next/static/chunks/255-d47fd57964443afe.js +1 -0
  244. package/dist/ui/static/_next/static/chunks/4-be1fef693af8e088.js +1 -0
  245. package/dist/ui/static/_next/static/chunks/4bd1b696-c023c6e3521b1417.js +1 -0
  246. package/dist/ui/static/_next/static/chunks/app/_not-found/page-75825b09bcecad97.js +1 -0
  247. package/dist/ui/static/_next/static/chunks/app/launch/page-9c86a13c29884245.js +1 -0
  248. package/dist/ui/static/_next/static/chunks/app/layout-bdea63fe87947d50.js +1 -0
  249. package/dist/ui/static/_next/static/chunks/app/page-4168c12c68b7a853.js +1 -0
  250. package/dist/ui/static/_next/static/chunks/framework-a6e0b7e30f98059a.js +1 -0
  251. package/dist/ui/static/_next/static/chunks/main-778a50aebff02192.js +1 -0
  252. package/dist/ui/static/_next/static/chunks/main-app-30679af7240d63e9.js +1 -0
  253. package/dist/ui/static/_next/static/chunks/pages/_app-7d307437aca18ad4.js +1 -0
  254. package/dist/ui/static/_next/static/chunks/pages/_error-cb2a52f75f2162e2.js +1 -0
  255. package/dist/ui/static/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  256. package/dist/ui/static/_next/static/chunks/webpack-4a462cecab786e93.js +1 -0
  257. package/dist/ui/static/_next/static/css/be7cb54d5c5673b6.css +1 -0
  258. package/dist/ui/static/assets/editors/goland.svg +35 -0
  259. package/dist/ui/static/assets/editors/intellij.svg +39 -0
  260. package/dist/ui/static/assets/editors/pycharm.svg +58 -0
  261. package/dist/ui/static/assets/editors/rustrover.svg +19 -0
  262. package/dist/ui/static/assets/editors/vscode.svg +1 -0
  263. package/dist/ui/static/assets/editors/webstorm.svg +21 -0
  264. package/dist/ui/static/assets/icons/anthropic.svg +1 -0
  265. package/dist/ui/static/assets/icons/brave.svg +1 -0
  266. package/dist/ui/static/assets/icons/css3.svg +1 -0
  267. package/dist/ui/static/assets/icons/docker.svg +1 -0
  268. package/dist/ui/static/assets/icons/git.svg +1 -0
  269. package/dist/ui/static/assets/icons/github.svg +1 -0
  270. package/dist/ui/static/assets/icons/go.svg +1 -0
  271. package/dist/ui/static/assets/icons/gradle.svg +1 -0
  272. package/dist/ui/static/assets/icons/grafana.svg +1 -0
  273. package/dist/ui/static/assets/icons/graphql.svg +1 -0
  274. package/dist/ui/static/assets/icons/html5.svg +1 -0
  275. package/dist/ui/static/assets/icons/image.svg +1 -0
  276. package/dist/ui/static/assets/icons/java.svg +1 -0
  277. package/dist/ui/static/assets/icons/javascript.svg +1 -0
  278. package/dist/ui/static/assets/icons/json.svg +1 -0
  279. package/dist/ui/static/assets/icons/kafka.svg +1 -0
  280. package/dist/ui/static/assets/icons/kubernetes.svg +1 -0
  281. package/dist/ui/static/assets/icons/linear.svg +1 -0
  282. package/dist/ui/static/assets/icons/markdown.svg +1 -0
  283. package/dist/ui/static/assets/icons/nginx.svg +1 -0
  284. package/dist/ui/static/assets/icons/nodejs.svg +1 -0
  285. package/dist/ui/static/assets/icons/notion.svg +1 -0
  286. package/dist/ui/static/assets/icons/openai.svg +1 -0
  287. package/dist/ui/static/assets/icons/playwright.svg +1 -0
  288. package/dist/ui/static/assets/icons/postgresql.svg +1 -0
  289. package/dist/ui/static/assets/icons/prometheus.svg +1 -0
  290. package/dist/ui/static/assets/icons/properties.svg +1 -0
  291. package/dist/ui/static/assets/icons/puppeteer.svg +1 -0
  292. package/dist/ui/static/assets/icons/python.svg +1 -0
  293. package/dist/ui/static/assets/icons/react.svg +1 -0
  294. package/dist/ui/static/assets/icons/redis.svg +1 -0
  295. package/dist/ui/static/assets/icons/rust.svg +1 -0
  296. package/dist/ui/static/assets/icons/sentry.svg +1 -0
  297. package/dist/ui/static/assets/icons/slack.svg +1 -0
  298. package/dist/ui/static/assets/icons/spring.svg +1 -0
  299. package/dist/ui/static/assets/icons/typescript.svg +1 -0
  300. package/dist/ui/static/assets/icons/upstash.svg +1 -0
  301. package/dist/ui/static/assets/icons/yaml.svg +1 -0
  302. package/dist/ui/static/assets/keiko-logo.svg +10 -0
  303. package/dist/ui/static/index.html +1 -0
  304. package/dist/ui/static/index.txt +19 -0
  305. package/dist/ui/static/keiko-logo.svg +10 -0
  306. package/dist/ui/static/launch.html +1 -0
  307. package/dist/ui/static/launch.txt +19 -0
  308. package/dist/ui/static.d.ts +3 -0
  309. package/dist/ui/static.js +72 -0
  310. package/dist/ui/store/chats.d.ts +14 -0
  311. package/dist/ui/store/chats.js +110 -0
  312. package/dist/ui/store/db.d.ts +6 -0
  313. package/dist/ui/store/db.js +182 -0
  314. package/dist/ui/store/errors.d.ts +12 -0
  315. package/dist/ui/store/errors.js +30 -0
  316. package/dist/ui/store/index.d.ts +6 -0
  317. package/dist/ui/store/index.js +6 -0
  318. package/dist/ui/store/messages.d.ts +5 -0
  319. package/dist/ui/store/messages.js +137 -0
  320. package/dist/ui/store/paths.d.ts +4 -0
  321. package/dist/ui/store/paths.js +69 -0
  322. package/dist/ui/store/projects.d.ts +7 -0
  323. package/dist/ui/store/projects.js +61 -0
  324. package/dist/ui/store/schema.d.ts +3 -0
  325. package/dist/ui/store/schema.js +77 -0
  326. package/dist/ui/store/types.d.ts +80 -0
  327. package/dist/ui/store/types.js +3 -0
  328. package/dist/ui/store/validation.d.ts +4 -0
  329. package/dist/ui/store/validation.js +72 -0
  330. package/dist/ui/store-handlers.d.ts +16 -0
  331. package/dist/ui/store-handlers.js +465 -0
  332. package/dist/ui/terminal-errors.d.ts +21 -0
  333. package/dist/ui/terminal-errors.js +45 -0
  334. package/dist/ui/terminal-evidence.d.ts +20 -0
  335. package/dist/ui/terminal-evidence.js +65 -0
  336. package/dist/ui/terminal-routes.d.ts +9 -0
  337. package/dist/ui/terminal-routes.js +219 -0
  338. package/dist/ui/terminal.d.ts +67 -0
  339. package/dist/ui/terminal.js +835 -0
  340. package/dist/verification/classify.d.ts +10 -0
  341. package/dist/verification/classify.js +53 -0
  342. package/dist/verification/detect.d.ts +4 -0
  343. package/dist/verification/detect.js +81 -0
  344. package/dist/verification/errors.d.ts +11 -0
  345. package/dist/verification/errors.js +21 -0
  346. package/dist/verification/index.d.ts +17 -0
  347. package/dist/verification/index.js +13 -0
  348. package/dist/verification/limits.d.ts +3 -0
  349. package/dist/verification/limits.js +40 -0
  350. package/dist/verification/monitor.d.ts +4 -0
  351. package/dist/verification/monitor.js +58 -0
  352. package/dist/verification/orchestrator.d.ts +16 -0
  353. package/dist/verification/orchestrator.js +363 -0
  354. package/dist/verification/plan.d.ts +9 -0
  355. package/dist/verification/plan.js +125 -0
  356. package/dist/verification/summary.d.ts +40 -0
  357. package/dist/verification/summary.js +67 -0
  358. package/dist/verification/types.d.ts +63 -0
  359. package/dist/verification/types.js +13 -0
  360. package/dist/workflows/bug-investigation/context.d.ts +7 -0
  361. package/dist/workflows/bug-investigation/context.js +119 -0
  362. package/dist/workflows/bug-investigation/descriptor.d.ts +3 -0
  363. package/dist/workflows/bug-investigation/descriptor.js +46 -0
  364. package/dist/workflows/bug-investigation/emit.d.ts +12 -0
  365. package/dist/workflows/bug-investigation/emit.js +35 -0
  366. package/dist/workflows/bug-investigation/events.d.ts +81 -0
  367. package/dist/workflows/bug-investigation/events.js +9 -0
  368. package/dist/workflows/bug-investigation/failure-parse.d.ts +3 -0
  369. package/dist/workflows/bug-investigation/failure-parse.js +154 -0
  370. package/dist/workflows/bug-investigation/guard.d.ts +2 -0
  371. package/dist/workflows/bug-investigation/guard.js +69 -0
  372. package/dist/workflows/bug-investigation/index.d.ts +7 -0
  373. package/dist/workflows/bug-investigation/index.js +13 -0
  374. package/dist/workflows/bug-investigation/internal.d.ts +37 -0
  375. package/dist/workflows/bug-investigation/internal.js +64 -0
  376. package/dist/workflows/bug-investigation/model-loop.d.ts +4 -0
  377. package/dist/workflows/bug-investigation/model-loop.js +223 -0
  378. package/dist/workflows/bug-investigation/parse.d.ts +3 -0
  379. package/dist/workflows/bug-investigation/parse.js +123 -0
  380. package/dist/workflows/bug-investigation/prompt.d.ts +4 -0
  381. package/dist/workflows/bug-investigation/prompt.js +107 -0
  382. package/dist/workflows/bug-investigation/report.d.ts +23 -0
  383. package/dist/workflows/bug-investigation/report.js +151 -0
  384. package/dist/workflows/bug-investigation/stages.d.ts +13 -0
  385. package/dist/workflows/bug-investigation/stages.js +242 -0
  386. package/dist/workflows/bug-investigation/types.d.ts +91 -0
  387. package/dist/workflows/bug-investigation/types.js +14 -0
  388. package/dist/workflows/bug-investigation/verify-stage.d.ts +10 -0
  389. package/dist/workflows/bug-investigation/verify-stage.js +91 -0
  390. package/dist/workflows/bug-investigation/workflow.d.ts +2 -0
  391. package/dist/workflows/bug-investigation/workflow.js +74 -0
  392. package/dist/workflows/descriptor.d.ts +20 -0
  393. package/dist/workflows/descriptor.js +8 -0
  394. package/dist/workflows/index.d.ts +3 -0
  395. package/dist/workflows/index.js +2 -0
  396. package/dist/workflows/unit-tests/context.d.ts +7 -0
  397. package/dist/workflows/unit-tests/context.js +129 -0
  398. package/dist/workflows/unit-tests/conventions.d.ts +4 -0
  399. package/dist/workflows/unit-tests/conventions.js +87 -0
  400. package/dist/workflows/unit-tests/descriptor.d.ts +4 -0
  401. package/dist/workflows/unit-tests/descriptor.js +43 -0
  402. package/dist/workflows/unit-tests/emit.d.ts +12 -0
  403. package/dist/workflows/unit-tests/emit.js +35 -0
  404. package/dist/workflows/unit-tests/events.d.ts +78 -0
  405. package/dist/workflows/unit-tests/events.js +7 -0
  406. package/dist/workflows/unit-tests/index.d.ts +6 -0
  407. package/dist/workflows/unit-tests/index.js +10 -0
  408. package/dist/workflows/unit-tests/internal.d.ts +35 -0
  409. package/dist/workflows/unit-tests/internal.js +43 -0
  410. package/dist/workflows/unit-tests/model-loop.d.ts +4 -0
  411. package/dist/workflows/unit-tests/model-loop.js +95 -0
  412. package/dist/workflows/unit-tests/parse.d.ts +6 -0
  413. package/dist/workflows/unit-tests/parse.js +68 -0
  414. package/dist/workflows/unit-tests/prompt.d.ts +4 -0
  415. package/dist/workflows/unit-tests/prompt.js +71 -0
  416. package/dist/workflows/unit-tests/report.d.ts +21 -0
  417. package/dist/workflows/unit-tests/report.js +90 -0
  418. package/dist/workflows/unit-tests/stages.d.ts +9 -0
  419. package/dist/workflows/unit-tests/stages.js +155 -0
  420. package/dist/workflows/unit-tests/types.d.ts +70 -0
  421. package/dist/workflows/unit-tests/types.js +11 -0
  422. package/dist/workflows/unit-tests/verify-stage.d.ts +9 -0
  423. package/dist/workflows/unit-tests/verify-stage.js +56 -0
  424. package/dist/workflows/unit-tests/workflow.d.ts +2 -0
  425. package/dist/workflows/unit-tests/workflow.js +58 -0
  426. package/dist/workspace/contextPack.d.ts +9 -0
  427. package/dist/workspace/contextPack.js +94 -0
  428. package/dist/workspace/detect.d.ts +3 -0
  429. package/dist/workspace/detect.js +135 -0
  430. package/dist/workspace/discovery.d.ts +9 -0
  431. package/dist/workspace/discovery.js +167 -0
  432. package/dist/workspace/errors.d.ts +39 -0
  433. package/dist/workspace/errors.js +66 -0
  434. package/dist/workspace/fs.d.ts +21 -0
  435. package/dist/workspace/fs.js +36 -0
  436. package/dist/workspace/ignore.d.ts +14 -0
  437. package/dist/workspace/ignore.js +176 -0
  438. package/dist/workspace/index.d.ts +11 -0
  439. package/dist/workspace/index.js +13 -0
  440. package/dist/workspace/paths.d.ts +2 -0
  441. package/dist/workspace/paths.js +38 -0
  442. package/dist/workspace/realpath.d.ts +7 -0
  443. package/dist/workspace/realpath.js +72 -0
  444. package/dist/workspace/retrieval.d.ts +9 -0
  445. package/dist/workspace/retrieval.js +74 -0
  446. package/dist/workspace/summary.d.ts +3 -0
  447. package/dist/workspace/summary.js +54 -0
  448. package/dist/workspace/types.d.ts +103 -0
  449. package/dist/workspace/types.js +27 -0
  450. package/package.json +58 -0
@@ -0,0 +1,64 @@
1
+ // Shared internal types and small pure helpers used across the bug-investigation pipeline stages
2
+ // (the model loop, the verify stage, the report stages). Kept private to the module — none of these
3
+ // are re-exported from index.ts. Splitting them out keeps each pipeline file under the LOC limit
4
+ // while leaving a single source of truth for the resolved BugRunState and the loop result shape.
5
+ import { createBugEventEmitter } from "./emit.js";
6
+ import { DEFAULT_BUG_WORKFLOW_LIMITS, } from "./types.js";
7
+ // A no-op sink used when the caller injects none. emit is synchronous (ADR-0004 EventSink contract).
8
+ export const NO_OP_SINK = { emit: () => undefined };
9
+ // The zero-progress loop used to assemble a cancelled/failed report before the model loop ran.
10
+ export const EMPTY_BUG_LOOP = {
11
+ accepted: undefined,
12
+ investigationOnly: undefined,
13
+ modelCallCount: 0,
14
+ patchRetryCount: 0,
15
+ lastRejectionCode: undefined,
16
+ };
17
+ export function resolveBugLimits(input) {
18
+ return { ...DEFAULT_BUG_WORKFLOW_LIMITS, ...input.limits };
19
+ }
20
+ // The #6 PatchLimits view derived from the resolved workflow limits (D6 bound 1). Passed into
21
+ // validatePatch/applyPatch via their `limits` override seam — #6's defaults stay untouched.
22
+ export function patchLimitsFrom(limits) {
23
+ return {
24
+ maxFilesChanged: limits.maxFilesChanged,
25
+ maxChangedLines: limits.maxChangedLines,
26
+ maxPatchBytes: limits.maxPatchBytes,
27
+ };
28
+ }
29
+ export function buildBugRunState(input, deps, fingerprint) {
30
+ const now = deps.now ?? Date.now;
31
+ const idSource = deps.idSource ?? (() => crypto.randomUUID());
32
+ return {
33
+ input,
34
+ deps,
35
+ limits: resolveBugLimits(input),
36
+ signal: deps.signal ?? new AbortController().signal,
37
+ now,
38
+ emitter: createBugEventEmitter(deps.sink ?? NO_OP_SINK, idSource(), fingerprint, now),
39
+ startedAt: now(),
40
+ progress: { modelCallCount: 0, patchRetryCount: 0 },
41
+ };
42
+ }
43
+ // UI-renderable next actions for the report. Pure. `elevated` lists changed manifest/config paths
44
+ // that warrant elevated review (D6).
45
+ export function nextActionsFor(applied, files, elevated) {
46
+ const first = files[0] ?? "the proposed fix";
47
+ const base = applied
48
+ ? [`Review the applied fix in ${first}`, "Run `keiko verify` to confirm the suite is green"]
49
+ : [`Review the proposed fix for ${first}`, "Re-run with --apply to write the fix and verify"];
50
+ if (elevated.length > 0) {
51
+ return [
52
+ ...base,
53
+ `This fix modifies build/manifest configuration (${elevated.join(", ")}) — review with elevated scrutiny before applying`,
54
+ ];
55
+ }
56
+ return base;
57
+ }
58
+ // The next-actions list for the investigation-only outcome (no patch produced).
59
+ export function investigationNextActions() {
60
+ return [
61
+ "No safe fix was proposed; review the root-cause hypothesis and uncertainty",
62
+ "Provide more evidence (full failing output, stack trace, or suspected files) and re-run",
63
+ ];
64
+ }
@@ -0,0 +1,4 @@
1
+ import type { ContextPack, WorkspaceInfo } from "../../workspace/index.js";
2
+ import { type BugModelLoopResult, type BugRunState } from "./internal.js";
3
+ import type { BugReportInput, FailureEvidence } from "./types.js";
4
+ export declare function runBugModelLoop(state: BugRunState, workspace: WorkspaceInfo, report: BugReportInput, evidence: FailureEvidence, pack: ContextPack): Promise<BugModelLoopResult>;
@@ -0,0 +1,223 @@
1
+ // The bounded model/validate/scope-guard retry loop (ADR-0009 D6/D10). Each attempt builds the
2
+ // prompt, calls the injected ModelPort, parses the output, and classifies the result. The KEY
3
+ // behavioural difference from #8: an EMPTY diff with a root-cause hypothesis is a VALID
4
+ // investigation-only outcome (NOT a retry); only a malformed/oversized/out-of-scope NON-empty patch
5
+ // retries. The change budget (D6 bound 1) is enforced by passing a workflow-owned PatchLimits into
6
+ // #6 validatePatch; the sensitive-path guard (D6 bound 2) runs on validation.files[].path. The
7
+ // model call is the one IO boundary here; its failure propagates to the workflow catch boundary.
8
+ import { nodeWorkspaceFs } from "../../workspace/fs.js";
9
+ import { validatePatch } from "../../tools/index.js";
10
+ import { isTestPath } from "../unit-tests/conventions.js";
11
+ import { isSensitivePath } from "./guard.js";
12
+ import { parseBugModelOutputCandidates } from "./parse.js";
13
+ import { buildBugPrompt } from "./prompt.js";
14
+ import { patchLimitsFrom, } from "./internal.js";
15
+ // The sensitive-path scope guard (D6 bound 2): every changed path must NOT be sensitive. Returns
16
+ // "out-of-scope" when any path is traversal/.github/.husky/lockfile, else undefined. The change
17
+ // budget (bound 1) is enforced by #6 itself via the limits passed to validatePatch.
18
+ function scopeGuard(validation) {
19
+ const offending = validation.files.some((file) => isSensitivePath(file.path));
20
+ return offending ? "out-of-scope" : undefined;
21
+ }
22
+ function emitValidation(state, validation, code) {
23
+ const ok = code === undefined && validation.ok;
24
+ state.emitter.emit({
25
+ type: "bug:patch:validated",
26
+ ok,
27
+ patchBytes: validation.totalBytes,
28
+ filesChanged: validation.files.length,
29
+ ...(ok ? {} : { rejectionCode: code ?? validation.reasons[0]?.code }),
30
+ });
31
+ }
32
+ function hypothesisOf(parsed) {
33
+ return {
34
+ rootCause: parsed.rootCause,
35
+ regressionTestStrategy: parsed.regressionTestStrategy,
36
+ uncertainty: parsed.uncertainty,
37
+ confidence: parsed.confidence,
38
+ };
39
+ }
40
+ // True when the parsed output carries at least one prose section (any hypothesis content).
41
+ function hasProse(parsed) {
42
+ return (parsed.rootCause !== undefined ||
43
+ parsed.regressionTestStrategy !== undefined ||
44
+ parsed.uncertainty !== undefined ||
45
+ parsed.confidence !== undefined);
46
+ }
47
+ async function callModel(state, messages, attempt, contextBytes) {
48
+ state.progress.modelCallCount = Math.max(state.progress.modelCallCount, attempt);
49
+ state.emitter.emit({ type: "bug:model:call:started", attempt, contextBytes });
50
+ const response = await state.deps.model.call({ modelId: state.input.modelId, messages }, state.signal);
51
+ state.emitter.emit({
52
+ type: "bug:model:call:completed",
53
+ attempt,
54
+ finishReason: response.finishReason,
55
+ promptTokens: response.usage.promptTokens,
56
+ completionTokens: response.usage.completionTokens,
57
+ latencyMs: response.usage.latencyMs,
58
+ });
59
+ return response.content;
60
+ }
61
+ function classifyEmptyDiff(parsed) {
62
+ // Empty diff + a hypothesis -> investigation-only (NOT a retry). Empty diff + no prose -> retry.
63
+ if (hasProse(parsed)) {
64
+ return {
65
+ accepted: undefined,
66
+ investigationOnly: hypothesisOf(parsed),
67
+ rejectionCode: undefined,
68
+ rejectionReason: undefined,
69
+ };
70
+ }
71
+ return {
72
+ accepted: undefined,
73
+ investigationOnly: undefined,
74
+ rejectionCode: "empty",
75
+ rejectionReason: "empty: no diff or root-cause hypothesis was provided",
76
+ };
77
+ }
78
+ function validationRejectionReason(validation, code) {
79
+ if (code === undefined) {
80
+ return undefined;
81
+ }
82
+ const message = validation.reasons[0]?.message;
83
+ if (message !== undefined) {
84
+ return `${code}: ${message}`;
85
+ }
86
+ if (code === "test-only") {
87
+ return "test-only: a source bug fix must include a minimal non-test source change; tests may be added in the same diff";
88
+ }
89
+ const conflict = validation.conflicts[0];
90
+ if (conflict !== undefined) {
91
+ return `${code}: ${conflict.path} hunk#${String(conflict.hunkIndex)} ${conflict.reason}`;
92
+ }
93
+ return code;
94
+ }
95
+ function sourceBugRequiresSourcePatch(workspace, report, evidence) {
96
+ const paths = [
97
+ ...(report.targetFiles ?? []),
98
+ ...evidence.frames.map((frame) => frame.file),
99
+ ];
100
+ return paths.some((path) => !isTestPath(workspace, path));
101
+ }
102
+ function semanticGuard(workspace, validation, requiresSourcePatch) {
103
+ if (validation.files.length === 0) {
104
+ return "malformed";
105
+ }
106
+ const scopeCode = scopeGuard(validation);
107
+ if (scopeCode !== undefined) {
108
+ return scopeCode;
109
+ }
110
+ return requiresSourcePatch && validation.files.every((file) => isTestPath(workspace, file.path))
111
+ ? "test-only"
112
+ : undefined;
113
+ }
114
+ function emptyParsedOutput() {
115
+ return {
116
+ diff: "",
117
+ rootCause: undefined,
118
+ regressionTestStrategy: undefined,
119
+ uncertainty: undefined,
120
+ confidence: undefined,
121
+ };
122
+ }
123
+ function classifyValidated(workspace, parsed, validation, requiresSourcePatch) {
124
+ const guardCode = validation.ok
125
+ ? semanticGuard(workspace, validation, requiresSourcePatch)
126
+ : validation.reasons[0]?.code;
127
+ if (validation.ok && guardCode === undefined) {
128
+ const accepted = {
129
+ diff: parsed.diff,
130
+ validation,
131
+ hypothesis: hypothesisOf(parsed),
132
+ };
133
+ return {
134
+ accepted,
135
+ investigationOnly: undefined,
136
+ rejectionCode: undefined,
137
+ rejectionReason: undefined,
138
+ };
139
+ }
140
+ const rejectionCode = guardCode ?? "malformed";
141
+ return {
142
+ accepted: undefined,
143
+ investigationOnly: undefined,
144
+ rejectionCode,
145
+ rejectionReason: validationRejectionReason(validation, rejectionCode),
146
+ };
147
+ }
148
+ function validateCandidate(state, workspace, parsed, requiresSourcePatch) {
149
+ const validation = validatePatch(workspace, parsed.diff, {
150
+ fs: state.deps.fs ?? nodeWorkspaceFs,
151
+ limits: patchLimitsFrom(state.limits),
152
+ });
153
+ const result = classifyValidated(workspace, { ...parsed, diff: validation.normalizedDiff ?? parsed.diff }, validation, requiresSourcePatch);
154
+ return { result, validation };
155
+ }
156
+ function classifyPatchCandidates(state, workspace, report, evidence, candidates) {
157
+ const patchCandidates = candidates.filter((candidate) => candidate.diff.length > 0);
158
+ if (patchCandidates.length === 0) {
159
+ return classifyEmptyDiff(candidates[0] ?? emptyParsedOutput());
160
+ }
161
+ const requiresSourcePatch = sourceBugRequiresSourcePatch(workspace, report, evidence);
162
+ let last;
163
+ for (const parsed of patchCandidates) {
164
+ const next = validateCandidate(state, workspace, parsed, requiresSourcePatch);
165
+ if (next.result.accepted !== undefined) {
166
+ emitValidation(state, next.validation, next.result.rejectionCode);
167
+ return next.result;
168
+ }
169
+ last = next;
170
+ }
171
+ if (last === undefined) {
172
+ return classifyEmptyDiff(emptyParsedOutput());
173
+ }
174
+ emitValidation(state, last.validation, last.result.rejectionCode);
175
+ return last.result;
176
+ }
177
+ async function attemptOnce(state, workspace, report, evidence, pack, attempt, rejectionReason) {
178
+ const messages = buildBugPrompt(report, evidence, pack, workspace.testFramework, rejectionReason);
179
+ const content = await callModel(state, messages, attempt, pack.usedBytes);
180
+ const candidates = parseBugModelOutputCandidates(content);
181
+ state.emitter.emit({
182
+ type: "bug:rootcause:proposed",
183
+ hasPatch: candidates.some((candidate) => candidate.diff.length > 0),
184
+ ...(candidates[0]?.confidence === undefined ? {} : { confidence: candidates[0].confidence }),
185
+ });
186
+ return classifyPatchCandidates(state, workspace, report, evidence, candidates);
187
+ }
188
+ // True when the attempt produced a terminal outcome (accepted patch or investigation-only); a
189
+ // retryable rejection is the only non-terminal case.
190
+ function isTerminal(result) {
191
+ return result.accepted !== undefined || result.investigationOnly !== undefined;
192
+ }
193
+ export async function runBugModelLoop(state, workspace, report, evidence, pack) {
194
+ let modelCallCount = 0;
195
+ let patchRetryCount = 0;
196
+ let rejectionReason;
197
+ let lastRejectionCode;
198
+ while (modelCallCount < state.limits.maxModelCalls &&
199
+ patchRetryCount <= state.limits.maxRetries) {
200
+ modelCallCount += 1;
201
+ const r = await attemptOnce(state, workspace, report, evidence, pack, modelCallCount, rejectionReason);
202
+ if (isTerminal(r)) {
203
+ return {
204
+ accepted: r.accepted,
205
+ investigationOnly: r.investigationOnly,
206
+ modelCallCount,
207
+ patchRetryCount,
208
+ lastRejectionCode: undefined,
209
+ };
210
+ }
211
+ patchRetryCount += 1;
212
+ state.progress.patchRetryCount = patchRetryCount;
213
+ lastRejectionCode = r.rejectionCode;
214
+ rejectionReason = r.rejectionReason ?? r.rejectionCode;
215
+ }
216
+ return {
217
+ accepted: undefined,
218
+ investigationOnly: undefined,
219
+ modelCallCount,
220
+ patchRetryCount,
221
+ lastRejectionCode,
222
+ };
223
+ }
@@ -0,0 +1,3 @@
1
+ import type { ParsedBugOutput } from "./types.js";
2
+ export declare function parseBugModelOutput(content: string): ParsedBugOutput;
3
+ export declare function parseBugModelOutputCandidates(content: string): readonly ParsedBugOutput[];
@@ -0,0 +1,123 @@
1
+ // Defensive parser for the model-output contract (ADR-0009 D9). The model is instructed (see
2
+ // prompt.ts) to emit an OPTIONAL fenced ```diff block followed by labeled prose sections
3
+ // `## Root cause`, `## Regression test`, `## Uncertainty`, `## Confidence`. This parser extracts
4
+ // those parts WITHOUT trusting the model to comply: a missing diff yields an empty string (a valid
5
+ // investigation-only signal, D10) and any missing section yields undefined. All extraction uses
6
+ // plain string ops (line splitting, startsWith, trim, toLowerCase) — ZERO regex, so there is no
7
+ // ReDoS surface. Redaction happens at the report boundary, not here.
8
+ const FENCE = "```";
9
+ const ROOT_CAUSE_HEADING = "## root cause";
10
+ const REGRESSION_HEADING = "## regression test";
11
+ const UNCERTAINTY_HEADING = "## uncertainty";
12
+ const CONFIDENCE_HEADING = "## confidence";
13
+ const CONFIDENCE_LEVELS = ["high", "medium", "low"];
14
+ function isFence(line) {
15
+ return line.trimStart().startsWith(FENCE);
16
+ }
17
+ function isDiffFence(line) {
18
+ const trimmed = line.trimStart();
19
+ return trimmed.startsWith("```diff") || trimmed.startsWith("```patch");
20
+ }
21
+ function closeFenceIndex(lines, openIndex) {
22
+ const closeIndex = lines.findIndex((line, idx) => idx > openIndex && isFence(line));
23
+ return closeIndex === -1 ? undefined : closeIndex;
24
+ }
25
+ function fenceBody(lines, openIndex, closeIndex) {
26
+ const bodyLines = closeIndex === undefined ? lines.slice(openIndex + 1) : lines.slice(openIndex + 1, closeIndex);
27
+ return bodyLines.join("\n").trim();
28
+ }
29
+ function appendNonDiffFence(restLines, lines, openIndex, closeIndex) {
30
+ restLines.push(...lines.slice(openIndex, closeIndex === undefined ? lines.length : closeIndex + 1));
31
+ }
32
+ function nextFenceScanIndex(lines, closeIndex) {
33
+ return closeIndex === undefined ? lines.length : closeIndex + 1;
34
+ }
35
+ // Returns the contents of the first fenced block that is explicitly a diff/patch fence or whose
36
+ // body starts like a unified diff. Other Markdown code examples before the patch are ignored.
37
+ // When the content has NO diff fence AND does not look like a diff, the whole content is treated as
38
+ // prose (empty diff) so prose-only investigation output parses cleanly.
39
+ function extractFencedDiffs(content) {
40
+ const lines = content.split("\n");
41
+ let openIndex = 0;
42
+ const diffs = [];
43
+ const restLines = [];
44
+ while (openIndex < lines.length) {
45
+ const line = lines[openIndex] ?? "";
46
+ if (!isFence(line)) {
47
+ restLines.push(line);
48
+ openIndex += 1;
49
+ continue;
50
+ }
51
+ const closeIndex = closeFenceIndex(lines, openIndex);
52
+ const body = fenceBody(lines, openIndex, closeIndex);
53
+ if (isDiffFence(lines[openIndex] ?? "") || looksLikeDiff(body)) {
54
+ diffs.push(body);
55
+ }
56
+ else {
57
+ appendNonDiffFence(restLines, lines, openIndex, closeIndex);
58
+ }
59
+ openIndex = nextFenceScanIndex(lines, closeIndex);
60
+ }
61
+ if (diffs.length > 0) {
62
+ return { diffs, rest: restLines.join("\n") };
63
+ }
64
+ // No recognised diff fence: if the whole content looks like a raw diff, treat it as one;
65
+ // otherwise it is prose.
66
+ return looksLikeDiff(content) ? { diffs: [content.trim()], rest: "" } : { diffs: [""], rest: content };
67
+ }
68
+ // A cheap unfenced-diff heuristic: a unified diff begins with a `diff --git`, `--- `, or `+++ `
69
+ // marker. Used only for the no-fence fallback. Plain prefix checks; no regex.
70
+ function looksLikeDiff(content) {
71
+ const trimmed = content.trimStart();
72
+ return (trimmed.startsWith("diff --git") || trimmed.startsWith("--- ") || trimmed.startsWith("+++ "));
73
+ }
74
+ // Extracts the body of a labeled section: lines after the matching `## heading` up to the next
75
+ // `## ` heading (or end). Returns undefined when the heading is absent or the body is empty.
76
+ function extractSection(text, heading) {
77
+ const lines = text.split("\n");
78
+ const start = lines.findIndex((line) => line.trim().toLowerCase() === heading);
79
+ if (start === -1) {
80
+ return undefined;
81
+ }
82
+ const body = [];
83
+ for (const line of lines.slice(start + 1)) {
84
+ if (line.trim().startsWith("## ")) {
85
+ break;
86
+ }
87
+ body.push(line);
88
+ }
89
+ const joined = body.join("\n").trim();
90
+ return joined.length === 0 ? undefined : joined;
91
+ }
92
+ // Parses a confidence level from the section body: the first of high/medium/low it contains
93
+ // (lower-cased). Returns undefined when the section is absent or names no known level.
94
+ function parseConfidence(rest) {
95
+ const body = extractSection(rest, CONFIDENCE_HEADING);
96
+ if (body === undefined) {
97
+ return undefined;
98
+ }
99
+ const lower = body.toLowerCase();
100
+ return CONFIDENCE_LEVELS.find((level) => lower.includes(level));
101
+ }
102
+ export function parseBugModelOutput(content) {
103
+ return parseBugModelOutputCandidates(content)[0] ?? {
104
+ diff: "",
105
+ rootCause: undefined,
106
+ regressionTestStrategy: undefined,
107
+ uncertainty: undefined,
108
+ confidence: undefined,
109
+ };
110
+ }
111
+ export function parseBugModelOutputCandidates(content) {
112
+ const { diffs, rest } = extractFencedDiffs(content);
113
+ const base = {
114
+ rootCause: extractSection(rest, ROOT_CAUSE_HEADING),
115
+ regressionTestStrategy: extractSection(rest, REGRESSION_HEADING),
116
+ uncertainty: extractSection(rest, UNCERTAINTY_HEADING),
117
+ confidence: parseConfidence(rest),
118
+ };
119
+ return diffs.map((diff) => ({
120
+ diff,
121
+ ...base,
122
+ }));
123
+ }
@@ -0,0 +1,4 @@
1
+ import type { ChatMessage } from "../../gateway/types.js";
2
+ import type { ContextPack } from "../../workspace/index.js";
3
+ import type { BugReportInput, FailureEvidence } from "./types.js";
4
+ export declare function buildBugPrompt(report: BugReportInput, evidence: FailureEvidence, pack: ContextPack, framework: string, rejectionReason?: string): readonly ChatMessage[];
@@ -0,0 +1,107 @@
1
+ // Prompt construction (ADR-0009 D9). Builds the system + user ChatMessage array for the single
2
+ // investigation call. PURE: no IO, no clock, no randomness — the same inputs always yield the same
3
+ // messages. The system message specifies the model-output contract (an OPTIONAL fenced ```diff
4
+ // block plus labeled prose sections) that parse.ts consumes, and explicitly tells the model to OMIT
5
+ // the diff when evidence is insufficient (the investigation-only outcome, D10). Context excerpts and
6
+ // failure messages handed in may originate from CLI/UI input, so every free-text report field is
7
+ // redacted and byte-capped before it enters the model prompt.
8
+ import { TextDecoder } from "node:util";
9
+ import { redact } from "../../gateway/redaction.js";
10
+ const MAX_PROMPT_TEXT_BYTES = 16_384;
11
+ const REDACTION_LOOKAHEAD_BYTES = 512;
12
+ const OUTPUT_CONTRACT = "Respond with an OPTIONAL minimal fix as a unified diff inside a single fenced code block opened " +
13
+ "with ```diff and closed with ```. Touch only what is necessary; you MAY add a regression test " +
14
+ "in the same diff. For a source-file bug, the diff MUST include at least one non-test source " +
15
+ "change; a regression test alone is NOT a fix and will be rejected. After the block, add these prose sections: `## Root cause`, " +
16
+ "`## Regression test`, `## Uncertainty`, `## Confidence` (one of low/medium/high). If the " +
17
+ "evidence is INSUFFICIENT to propose a safe fix, OMIT the diff entirely and explain in " +
18
+ "`## Uncertainty` what additional information is needed — do NOT invent a fix. When you include " +
19
+ "a diff, the first non-empty line inside the fence MUST be `--- a/<path>` or `--- /dev/null`, " +
20
+ "followed by `+++ b/<path>` and at least one `@@` hunk. Do not output `*** Begin Patch`, file " +
21
+ "trees, prose, or escaped newline markers like `\\n+`/`\\n-` inside the diff fence; every diff " +
22
+ "line must be separated by a real newline. If you include a diff, it must be the FIRST fenced " +
23
+ "code block in the response. Do not include code examples, TypeScript snippets, or alternative " +
24
+ "patches in any other fence; output exactly one diff fence followed by the required prose sections.";
25
+ const SCOPE_RULE = "The fix must be minimal and must NOT modify CI configuration (.github/), git hooks (.husky/), " +
26
+ "lockfiles, or unrelated files.";
27
+ function systemContent(framework) {
28
+ return [
29
+ "You are a senior engineer performing root-cause analysis on a reported bug.",
30
+ `Test framework: ${framework}.`,
31
+ "Ground your hypothesis in the provided evidence; distinguish what the evidence shows from what you infer.",
32
+ SCOPE_RULE,
33
+ OUTPUT_CONTRACT,
34
+ ].join("\n");
35
+ }
36
+ function descriptionBlock(description) {
37
+ const safe = safePromptText(description);
38
+ return safe !== undefined
39
+ ? `Bug description:\n${safe}`
40
+ : "No free-text description was provided.";
41
+ }
42
+ function clampToBytes(text, maxBytes) {
43
+ if (Buffer.byteLength(text, "utf8") <= maxBytes) {
44
+ return { text, truncated: false };
45
+ }
46
+ const buffer = Buffer.from(text, "utf8").subarray(0, maxBytes);
47
+ const decoded = new TextDecoder("utf-8", { fatal: false }).decode(buffer).replace(/�+$/u, "");
48
+ return { text: `${decoded}\n[TRUNCATED]`, truncated: true };
49
+ }
50
+ function safePromptText(value) {
51
+ if (value === undefined) {
52
+ return undefined;
53
+ }
54
+ const trimmed = value.trim();
55
+ if (trimmed.length === 0) {
56
+ return undefined;
57
+ }
58
+ const bounded = clampToBytes(trimmed, MAX_PROMPT_TEXT_BYTES + REDACTION_LOOKAHEAD_BYTES).text;
59
+ return clampToBytes(redact(bounded), MAX_PROMPT_TEXT_BYTES).text;
60
+ }
61
+ function evidenceBlock(report, evidence) {
62
+ const parts = [];
63
+ const failingOutput = safePromptText(report.failingOutput);
64
+ if (failingOutput !== undefined) {
65
+ parts.push(`Failing output:\n${failingOutput}`);
66
+ }
67
+ const stackTrace = safePromptText(report.stackTrace);
68
+ if (stackTrace !== undefined) {
69
+ parts.push(`Stack trace:\n${stackTrace}`);
70
+ }
71
+ if (evidence.frames.length > 0) {
72
+ const frames = evidence.frames
73
+ .map((frame) => frame.line === undefined ? frame.file : `${frame.file}:${String(frame.line)}`)
74
+ .join(", ");
75
+ parts.push(`Implicated locations: ${frames}`);
76
+ }
77
+ return parts.join("\n\n");
78
+ }
79
+ function contextBlock(pack) {
80
+ if (pack.selected.length === 0) {
81
+ return "";
82
+ }
83
+ const entries = pack.selected
84
+ .map((entry) => `--- ${entry.path} ---\n${entry.excerpt}`)
85
+ .join("\n\n");
86
+ return `\n\nRepository context:\n${entries}`;
87
+ }
88
+ function retryBlock(rejectionReason) {
89
+ const safe = safePromptText(rejectionReason);
90
+ return safe === undefined
91
+ ? ""
92
+ : `\n\nThe previous diff was rejected: ${safe}. Produce a corrected, in-scope ` +
93
+ "minimal diff, or omit the diff if no safe fix is possible.";
94
+ }
95
+ function userContent(report, evidence, pack, rejectionReason) {
96
+ const evidenceText = evidenceBlock(report, evidence);
97
+ const evidenceSection = evidenceText.length === 0 ? "" : `\n\n${evidenceText}`;
98
+ return `${descriptionBlock(report.description)}${evidenceSection}${contextBlock(pack)}${retryBlock(rejectionReason)}`;
99
+ }
100
+ // rejectionReason is appended on a retry (D10) so the model can correct an invalid/out-of-scope
101
+ // diff; it is undefined on the first attempt.
102
+ export function buildBugPrompt(report, evidence, pack, framework, rejectionReason) {
103
+ return [
104
+ { role: "system", content: systemContent(framework) },
105
+ { role: "user", content: userContent(report, evidence, pack, rejectionReason) },
106
+ ];
107
+ }
@@ -0,0 +1,23 @@
1
+ import type { PatchFileChange } from "../../tools/index.js";
2
+ import type { VerificationAuditSummary } from "../../verification/index.js";
3
+ import type { BugInvestigationReport, BugWorkflowStatus, FailureFrame, Hypothesis } from "./types.js";
4
+ export interface BugReportParts {
5
+ readonly status: BugWorkflowStatus;
6
+ readonly modelId: string;
7
+ readonly durationMs: number;
8
+ readonly patchFiles: readonly PatchFileChange[];
9
+ readonly patchValidates: boolean;
10
+ readonly patchApplied: boolean;
11
+ readonly verification: VerificationAuditSummary | undefined;
12
+ readonly failureFrames: readonly FailureFrame[];
13
+ readonly hypothesis: Hypothesis;
14
+ readonly proposedDiff: string | undefined;
15
+ readonly dryRunPreview: string | undefined;
16
+ readonly verificationSkipReason: string | undefined;
17
+ readonly nextActions: readonly string[];
18
+ readonly failureReason?: string | undefined;
19
+ readonly modelCallCount: number;
20
+ readonly patchRetryCount: number;
21
+ }
22
+ export declare function assembleBugReport(parts: BugReportParts): BugInvestigationReport;
23
+ export declare function renderBugMarkdownReport(report: BugInvestigationReport): string;