@probelabs/visor 0.1.106 → 0.1.111

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 (530) hide show
  1. package/README.md +71 -2
  2. package/action.yml +1 -1
  3. package/defaults/code-refiner.yaml +114 -0
  4. package/defaults/{.visor.yaml → code-review.yaml} +35 -226
  5. package/defaults/override.yaml +52 -0
  6. package/defaults/task-refinement.yaml +624 -0
  7. package/defaults/visor.tests.yaml +685 -0
  8. package/defaults/visor.yaml +483 -0
  9. package/dist/action-cli-bridge.d.ts +11 -82
  10. package/dist/action-cli-bridge.d.ts.map +1 -1
  11. package/dist/ai-review-service.d.ts +28 -9
  12. package/dist/ai-review-service.d.ts.map +1 -1
  13. package/dist/check-execution-engine.d.ts +19 -331
  14. package/dist/check-execution-engine.d.ts.map +1 -1
  15. package/dist/cli-main.d.ts.map +1 -1
  16. package/dist/cli.d.ts +0 -1
  17. package/dist/cli.d.ts.map +1 -1
  18. package/dist/config.d.ts +16 -0
  19. package/dist/config.d.ts.map +1 -1
  20. package/dist/cron-scheduler.d.ts +3 -3
  21. package/dist/cron-scheduler.d.ts.map +1 -1
  22. package/dist/debug-visualizer/ws-server.d.ts +7 -1
  23. package/dist/debug-visualizer/ws-server.d.ts.map +1 -1
  24. package/dist/defaults/code-refiner.yaml +114 -0
  25. package/dist/defaults/{.visor.yaml → code-review.yaml} +35 -226
  26. package/dist/defaults/override.yaml +52 -0
  27. package/dist/defaults/task-refinement.yaml +624 -0
  28. package/dist/defaults/visor.tests.yaml +685 -0
  29. package/dist/defaults/visor.yaml +483 -0
  30. package/dist/docs/DEPLOYMENT.md +118 -0
  31. package/dist/docs/GITHUB_CHECKS.md +280 -0
  32. package/dist/docs/NPM_USAGE.md +208 -0
  33. package/dist/docs/action-reference.md +19 -0
  34. package/dist/docs/advanced-ai.md +237 -0
  35. package/dist/docs/ai-configuration.md +535 -0
  36. package/dist/docs/ai-custom-tools-usage.md +261 -0
  37. package/dist/docs/ai-custom-tools.md +392 -0
  38. package/dist/docs/author-permissions.md +610 -0
  39. package/dist/docs/bot-transports-rfc.md +23 -0
  40. package/dist/docs/ci-cli-mode.md +34 -0
  41. package/dist/docs/claude-code.md +74 -0
  42. package/dist/docs/command-provider.md +559 -0
  43. package/dist/docs/commands.md +8 -0
  44. package/dist/docs/configuration.md +324 -0
  45. package/dist/docs/custom-tools.md +424 -0
  46. package/dist/docs/dashboards/README.md +23 -0
  47. package/dist/docs/dashboards/grafana-visor-diagrams.json +20 -0
  48. package/dist/docs/dashboards/grafana-visor-overview.json +33 -0
  49. package/dist/docs/debug-visualizer-progress.md +572 -0
  50. package/dist/docs/debug-visualizer-rfc.md +691 -0
  51. package/dist/docs/debug-visualizer.md +114 -0
  52. package/dist/docs/debugging.md +636 -0
  53. package/dist/docs/default-output-schema.md +28 -0
  54. package/dist/docs/dependencies.md +369 -0
  55. package/dist/docs/dev-playbook.md +9 -0
  56. package/dist/docs/engine-pause-resume-rfc.md +192 -0
  57. package/dist/docs/engine-state-machine-plan.md +333 -0
  58. package/dist/docs/event-driven-github-integration-rfc.md +743 -0
  59. package/dist/docs/event-triggers.md +292 -0
  60. package/dist/docs/execution-statistics-rfc.md +290 -0
  61. package/dist/docs/fact-validator-gap-analysis.md +178 -0
  62. package/dist/docs/fact-validator-implementation-plan.md +1235 -0
  63. package/dist/docs/fail-if.md +95 -0
  64. package/dist/docs/failure-conditions-implementation.md +271 -0
  65. package/dist/docs/failure-conditions-schema.md +173 -0
  66. package/dist/docs/failure-routing-rfc.md +193 -0
  67. package/dist/docs/failure-routing.md +507 -0
  68. package/dist/docs/foreach-dependency-propagation.md +473 -0
  69. package/dist/docs/github-ops.md +89 -0
  70. package/dist/docs/goto-forward-run-plan.md +113 -0
  71. package/dist/docs/guides/criticality-modes.md +332 -0
  72. package/dist/docs/guides/fault-management-and-contracts.md +738 -0
  73. package/dist/docs/guides/workflow-style-guide.md +224 -0
  74. package/dist/docs/http.md +299 -0
  75. package/dist/docs/human-input-provider.md +372 -0
  76. package/dist/docs/lifecycle-hooks.md +253 -0
  77. package/dist/docs/limits.md +64 -0
  78. package/dist/docs/liquid-templates.md +490 -0
  79. package/dist/docs/loop-routing-refactor.md +89 -0
  80. package/dist/docs/mcp-provider.md +557 -0
  81. package/dist/docs/mcp.md +124 -0
  82. package/dist/docs/memory.md +903 -0
  83. package/dist/docs/observability.md +12 -0
  84. package/dist/docs/output-formats.md +20 -0
  85. package/dist/docs/output-formatting.md +29 -0
  86. package/dist/docs/output-history.md +383 -0
  87. package/dist/docs/performance.md +6 -0
  88. package/dist/docs/pluggable.md +124 -0
  89. package/dist/docs/proposals/snapshot-scope-execution.md +236 -0
  90. package/dist/docs/providers/git-checkout.md +589 -0
  91. package/dist/docs/recipes.md +474 -0
  92. package/dist/docs/rfc/git-checkout-step.md +601 -0
  93. package/dist/docs/rfc/on_init-hook.md +1294 -0
  94. package/dist/docs/rfc/workspace-isolation.md +216 -0
  95. package/dist/docs/roadmap/criticality-implementation-tasks.md +92 -0
  96. package/dist/docs/router-patterns.md +339 -0
  97. package/dist/docs/schema-next-pr.md +10 -0
  98. package/dist/docs/schema-templates.md +68 -0
  99. package/dist/docs/script.md +34 -0
  100. package/dist/docs/sdk.md +222 -0
  101. package/dist/docs/security.md +7 -0
  102. package/dist/docs/suppressions.md +89 -0
  103. package/dist/docs/tag-filtering.md +258 -0
  104. package/dist/docs/telemetry-setup.md +119 -0
  105. package/dist/docs/telemetry-tracing-rfc.md +275 -0
  106. package/dist/docs/test-framework-rfc.md +680 -0
  107. package/dist/docs/testing/assertions.md +85 -0
  108. package/dist/docs/testing/ci.md +44 -0
  109. package/dist/docs/testing/cli.md +41 -0
  110. package/dist/docs/testing/cookbook.md +172 -0
  111. package/dist/docs/testing/dsl-reference.md +199 -0
  112. package/dist/docs/testing/fixtures-and-mocks.md +91 -0
  113. package/dist/docs/testing/flows.md +92 -0
  114. package/dist/docs/testing/getting-started.md +93 -0
  115. package/dist/docs/testing/troubleshooting.md +55 -0
  116. package/dist/docs/timeouts.md +50 -0
  117. package/dist/docs/troubleshooting.md +7 -0
  118. package/dist/docs/visor-sdk-rfc.md +186 -0
  119. package/dist/docs/workflows.md +569 -0
  120. package/dist/engine/on-finish/orchestrator.d.ts +19 -0
  121. package/dist/engine/on-finish/orchestrator.d.ts.map +1 -0
  122. package/dist/engine/on-finish/utils.d.ts +44 -0
  123. package/dist/engine/on-finish/utils.d.ts.map +1 -0
  124. package/dist/event-bus/event-bus.d.ts +13 -0
  125. package/dist/event-bus/event-bus.d.ts.map +1 -0
  126. package/dist/event-bus/types.d.ts +71 -0
  127. package/dist/event-bus/types.d.ts.map +1 -0
  128. package/dist/examples/.claude/agents/code-reviewer.md +69 -0
  129. package/dist/examples/.mcp.json +34 -0
  130. package/dist/examples/CALCULATOR-SDK.md +364 -0
  131. package/dist/examples/README.md +384 -0
  132. package/dist/examples/ai-custom-tools-example.yaml +206 -0
  133. package/dist/examples/ai-custom-tools-simple.yaml +76 -0
  134. package/dist/examples/ai-retry-fallback-config.yaml +180 -0
  135. package/dist/examples/ai-with-bash.yaml +126 -0
  136. package/dist/examples/ai-with-mcp.yaml +82 -0
  137. package/dist/examples/basic-human-input.yaml +15 -0
  138. package/dist/examples/bedrock-config.yaml +77 -0
  139. package/dist/examples/calculator-config.yaml +133 -0
  140. package/dist/examples/calculator-json-output-guide.md +311 -0
  141. package/dist/examples/calculator-sdk-automated.ts +340 -0
  142. package/dist/examples/calculator-sdk-example.ts +275 -0
  143. package/dist/examples/calculator-sdk-json.ts +331 -0
  144. package/dist/examples/calculator-sdk-real.ts +374 -0
  145. package/dist/examples/calculator-sdk-test.ts +148 -0
  146. package/dist/examples/claude-code-config.yaml +191 -0
  147. package/dist/examples/cron-webhook-config.yaml +215 -0
  148. package/dist/examples/custom-template.liquid +57 -0
  149. package/dist/examples/custom-tools-example.yaml +281 -0
  150. package/dist/examples/enhanced-config.yaml +165 -0
  151. package/dist/examples/environments/visor.base.yaml +92 -0
  152. package/dist/examples/environments/visor.dev.yaml +33 -0
  153. package/dist/examples/environments/visor.prod.yaml +95 -0
  154. package/dist/examples/environments/visor.staging.yaml +46 -0
  155. package/dist/examples/fact-validator.yaml +361 -0
  156. package/dist/examples/fail-if-simple.yaml +90 -0
  157. package/dist/examples/failure-conditions-advanced.yaml +136 -0
  158. package/dist/examples/failure-conditions-basic.yaml +48 -0
  159. package/dist/examples/failure-conditions-github-style.yaml +119 -0
  160. package/dist/examples/failure-conditions-migration.yaml +74 -0
  161. package/dist/examples/for-loop-example.yaml +176 -0
  162. package/dist/examples/forEach-example.yaml +120 -0
  163. package/dist/examples/git-checkout-basic.yaml +32 -0
  164. package/dist/examples/git-checkout-compare.yaml +59 -0
  165. package/dist/examples/git-checkout-cross-repo.yaml +76 -0
  166. package/dist/examples/github-workflow-with-tags.yml +163 -0
  167. package/dist/examples/http-integration-config.yaml +240 -0
  168. package/dist/examples/https-server-config.yaml +209 -0
  169. package/dist/examples/human-input-example.yaml +63 -0
  170. package/dist/examples/if-conditions.yaml +173 -0
  171. package/dist/examples/jira-simple-example.yaml +56 -0
  172. package/dist/examples/jira-single-issue-workflow.yaml +166 -0
  173. package/dist/examples/jira-workflow-mcp.yaml +182 -0
  174. package/dist/examples/mcp/analyzer.py +119 -0
  175. package/dist/examples/mcp-provider-example.yaml +301 -0
  176. package/dist/examples/memory-counter.yaml +99 -0
  177. package/dist/examples/memory-error-collection.yaml +104 -0
  178. package/dist/examples/memory-exec-js.yaml +247 -0
  179. package/dist/examples/memory-namespace-isolation.yaml +184 -0
  180. package/dist/examples/memory-retry-counter.yaml +65 -0
  181. package/dist/examples/memory-state-machine.yaml +170 -0
  182. package/dist/examples/on-init-import-demo.yaml +179 -0
  183. package/dist/examples/outputs-raw-basic.yaml +26 -0
  184. package/dist/examples/project-with-tools.yaml +174 -0
  185. package/dist/examples/prompts/architecture-analysis.liquid +116 -0
  186. package/dist/examples/prompts/security-comprehensive.liquid +107 -0
  187. package/dist/examples/quick-start-tags.yaml +53 -0
  188. package/dist/examples/reusable-tools.yaml +92 -0
  189. package/dist/examples/reusable-workflows.yaml +88 -0
  190. package/dist/examples/routing-basic.yaml +35 -0
  191. package/dist/examples/routing-dynamic-js.yaml +46 -0
  192. package/dist/examples/routing-foreach.yaml +34 -0
  193. package/dist/examples/routing-goto-event.yaml +34 -0
  194. package/dist/examples/routing-on-success.yaml +25 -0
  195. package/dist/examples/run-calculator-demo.sh +71 -0
  196. package/dist/examples/sdk-basic.mjs +10 -0
  197. package/dist/examples/sdk-cjs.cjs +10 -0
  198. package/dist/examples/sdk-comprehensive.mjs +175 -0
  199. package/dist/examples/sdk-manual-config.mjs +65 -0
  200. package/dist/examples/sdk-typescript.js +81 -0
  201. package/dist/examples/sdk-typescript.ts +92 -0
  202. package/dist/examples/session-reuse-config.yaml +151 -0
  203. package/dist/examples/session-reuse-self.yaml +81 -0
  204. package/dist/examples/slack-simple-chat.yaml +775 -0
  205. package/dist/examples/templates/security-report.liquid +137 -0
  206. package/dist/examples/tools-library.yaml +281 -0
  207. package/dist/examples/transform-example.yaml +199 -0
  208. package/dist/examples/visor-with-tags.yaml +198 -0
  209. package/dist/examples/webhook-pipeline-config.yaml +218 -0
  210. package/dist/examples/workflows/calculator-workflow.yaml +163 -0
  211. package/dist/examples/workflows/code-quality.yaml +222 -0
  212. package/dist/examples/workflows/quick-pr-check.yaml +90 -0
  213. package/dist/examples/workflows/workflow-composition-example.yaml +130 -0
  214. package/dist/failure-condition-evaluator.d.ts +3 -0
  215. package/dist/failure-condition-evaluator.d.ts.map +1 -1
  216. package/dist/frontends/github-frontend.d.ts +58 -0
  217. package/dist/frontends/github-frontend.d.ts.map +1 -0
  218. package/dist/frontends/host.d.ts +47 -0
  219. package/dist/frontends/host.d.ts.map +1 -0
  220. package/dist/frontends/ndjson-sink.d.ts +12 -0
  221. package/dist/frontends/ndjson-sink.d.ts.map +1 -0
  222. package/dist/frontends/slack-frontend.d.ts +58 -0
  223. package/dist/frontends/slack-frontend.d.ts.map +1 -0
  224. package/dist/generated/config-schema.d.ts +967 -57
  225. package/dist/generated/config-schema.d.ts.map +1 -1
  226. package/dist/generated/config-schema.json +1033 -56
  227. package/dist/github-check-service.d.ts +4 -6
  228. package/dist/github-check-service.d.ts.map +1 -1
  229. package/dist/github-comments.d.ts +2 -4
  230. package/dist/github-comments.d.ts.map +1 -1
  231. package/dist/index.d.ts.map +1 -1
  232. package/dist/index.js +134327 -99004
  233. package/dist/liquid-extensions.d.ts.map +1 -1
  234. package/dist/logger.d.ts +2 -0
  235. package/dist/logger.d.ts.map +1 -1
  236. package/dist/memory-store.d.ts +6 -0
  237. package/dist/memory-store.d.ts.map +1 -1
  238. package/dist/output/assistant-json/template.liquid +0 -0
  239. package/dist/output/traces/run-2026-01-20T19-22-58-043Z.ndjson +138 -0
  240. package/dist/output/traces/run-2026-01-20T19-23-52-175Z.ndjson +1067 -0
  241. package/dist/output-formatters.d.ts +1 -1
  242. package/dist/output-formatters.d.ts.map +1 -1
  243. package/dist/providers/ai-check-provider.d.ts +12 -0
  244. package/dist/providers/ai-check-provider.d.ts.map +1 -1
  245. package/dist/providers/check-provider-registry.d.ts +6 -0
  246. package/dist/providers/check-provider-registry.d.ts.map +1 -1
  247. package/dist/providers/check-provider.interface.d.ts +43 -1
  248. package/dist/providers/check-provider.interface.d.ts.map +1 -1
  249. package/dist/providers/claude-code-check-provider.d.ts.map +1 -1
  250. package/dist/providers/command-check-provider.d.ts +1 -1
  251. package/dist/providers/command-check-provider.d.ts.map +1 -1
  252. package/dist/providers/custom-tool-executor.d.ts +61 -0
  253. package/dist/providers/custom-tool-executor.d.ts.map +1 -0
  254. package/dist/providers/git-checkout-provider.d.ts +25 -0
  255. package/dist/providers/git-checkout-provider.d.ts.map +1 -0
  256. package/dist/providers/github-ops-provider.d.ts.map +1 -1
  257. package/dist/providers/http-client-provider.d.ts +4 -4
  258. package/dist/providers/http-client-provider.d.ts.map +1 -1
  259. package/dist/providers/human-input-check-provider.d.ts +5 -0
  260. package/dist/providers/human-input-check-provider.d.ts.map +1 -1
  261. package/dist/providers/index.d.ts +1 -0
  262. package/dist/providers/index.d.ts.map +1 -1
  263. package/dist/providers/log-check-provider.d.ts +2 -5
  264. package/dist/providers/log-check-provider.d.ts.map +1 -1
  265. package/dist/providers/mcp-check-provider.d.ts +10 -4
  266. package/dist/providers/mcp-check-provider.d.ts.map +1 -1
  267. package/dist/providers/mcp-custom-sse-server.d.ts +66 -0
  268. package/dist/providers/mcp-custom-sse-server.d.ts.map +1 -0
  269. package/dist/providers/memory-check-provider.d.ts +2 -8
  270. package/dist/providers/memory-check-provider.d.ts.map +1 -1
  271. package/dist/providers/script-check-provider.d.ts +25 -0
  272. package/dist/providers/script-check-provider.d.ts.map +1 -0
  273. package/dist/providers/workflow-check-provider.d.ts +56 -0
  274. package/dist/providers/workflow-check-provider.d.ts.map +1 -0
  275. package/dist/reviewer.d.ts +2 -1
  276. package/dist/reviewer.d.ts.map +1 -1
  277. package/dist/sdk/check-provider-registry-534KL5HT.mjs +27 -0
  278. package/dist/sdk/chunk-23L3QRYX.mjs +16872 -0
  279. package/dist/sdk/chunk-23L3QRYX.mjs.map +1 -0
  280. package/dist/sdk/{chunk-TUTOLSFV.mjs → chunk-3OMWVM6J.mjs} +11 -1
  281. package/dist/sdk/chunk-3OMWVM6J.mjs.map +1 -0
  282. package/dist/sdk/chunk-7UK3NIIT.mjs +482 -0
  283. package/dist/sdk/chunk-7UK3NIIT.mjs.map +1 -0
  284. package/dist/sdk/chunk-AGIZJ4UZ.mjs +173 -0
  285. package/dist/sdk/chunk-AGIZJ4UZ.mjs.map +1 -0
  286. package/dist/sdk/chunk-AIVFBIS4.mjs +1371 -0
  287. package/dist/sdk/chunk-AIVFBIS4.mjs.map +1 -0
  288. package/dist/sdk/chunk-AK6BVWIT.mjs +426 -0
  289. package/dist/sdk/chunk-AK6BVWIT.mjs.map +1 -0
  290. package/dist/sdk/chunk-AUT26LHW.mjs +139 -0
  291. package/dist/sdk/chunk-AUT26LHW.mjs.map +1 -0
  292. package/dist/sdk/chunk-BOVFH3LI.mjs +232 -0
  293. package/dist/sdk/chunk-BOVFH3LI.mjs.map +1 -0
  294. package/dist/sdk/chunk-CNX7V5JK.mjs +89 -0
  295. package/dist/sdk/chunk-CNX7V5JK.mjs.map +1 -0
  296. package/dist/sdk/chunk-HTOKWMPO.mjs +157 -0
  297. package/dist/sdk/chunk-HTOKWMPO.mjs.map +1 -0
  298. package/dist/sdk/chunk-NAW3DB3I.mjs +197 -0
  299. package/dist/sdk/chunk-NAW3DB3I.mjs.map +1 -0
  300. package/dist/sdk/chunk-O5EZDNYL.mjs +274 -0
  301. package/dist/sdk/chunk-O5EZDNYL.mjs.map +1 -0
  302. package/dist/sdk/chunk-QR7MOMJH.mjs +558 -0
  303. package/dist/sdk/chunk-QR7MOMJH.mjs.map +1 -0
  304. package/dist/sdk/chunk-QY2XYPEV.mjs +3556 -0
  305. package/dist/sdk/chunk-QY2XYPEV.mjs.map +1 -0
  306. package/dist/sdk/chunk-S2RUE2RG.mjs +145 -0
  307. package/dist/sdk/chunk-S2RUE2RG.mjs.map +1 -0
  308. package/dist/sdk/chunk-SIWNBRTK.mjs +800 -0
  309. package/dist/sdk/chunk-SIWNBRTK.mjs.map +1 -0
  310. package/dist/sdk/chunk-YSN4G6CI.mjs +146 -0
  311. package/dist/sdk/chunk-YSN4G6CI.mjs.map +1 -0
  312. package/dist/sdk/chunk-ZYAUYXSW.mjs +206 -0
  313. package/dist/sdk/chunk-ZYAUYXSW.mjs.map +1 -0
  314. package/dist/sdk/command-executor-TYUV6HUS.mjs +14 -0
  315. package/dist/sdk/config-YNC2EOOT.mjs +16 -0
  316. package/dist/sdk/config-merger-PX3WIT57.mjs +10 -0
  317. package/dist/sdk/event-bus-5BEVPQ6T.mjs +35 -0
  318. package/dist/sdk/event-bus-5BEVPQ6T.mjs.map +1 -0
  319. package/dist/sdk/failure-condition-evaluator-YGTF2GHG.mjs +17 -0
  320. package/dist/sdk/git-repository-analyzer-HJC4MYW4.mjs +458 -0
  321. package/dist/sdk/git-repository-analyzer-HJC4MYW4.mjs.map +1 -0
  322. package/dist/sdk/github-frontend-SIAEOCON.mjs +1420 -0
  323. package/dist/sdk/github-frontend-SIAEOCON.mjs.map +1 -0
  324. package/dist/sdk/host-DXUYTNMU.mjs +52 -0
  325. package/dist/sdk/host-DXUYTNMU.mjs.map +1 -0
  326. package/dist/sdk/{liquid-extensions-KVL4MKRH.mjs → liquid-extensions-PKWCKK7E.mjs} +8 -2
  327. package/dist/sdk/memory-store-XGBB7LX7.mjs +12 -0
  328. package/dist/sdk/memory-store-XGBB7LX7.mjs.map +1 -0
  329. package/dist/sdk/metrics-7PP3EJUH.mjs +29 -0
  330. package/dist/sdk/metrics-7PP3EJUH.mjs.map +1 -0
  331. package/dist/sdk/ndjson-sink-B4V4NTAQ.mjs +44 -0
  332. package/dist/sdk/ndjson-sink-B4V4NTAQ.mjs.map +1 -0
  333. package/dist/sdk/prompt-state-YRJY6QAL.mjs +16 -0
  334. package/dist/sdk/prompt-state-YRJY6QAL.mjs.map +1 -0
  335. package/dist/sdk/renderer-schema-LPKN5UJS.mjs +51 -0
  336. package/dist/sdk/renderer-schema-LPKN5UJS.mjs.map +1 -0
  337. package/dist/sdk/routing-6N45MJ4F.mjs +24 -0
  338. package/dist/sdk/routing-6N45MJ4F.mjs.map +1 -0
  339. package/dist/sdk/sdk.d.mts +541 -22
  340. package/dist/sdk/sdk.d.ts +541 -22
  341. package/dist/sdk/sdk.js +27963 -16505
  342. package/dist/sdk/sdk.js.map +1 -1
  343. package/dist/sdk/sdk.mjs +1116 -2169
  344. package/dist/sdk/sdk.mjs.map +1 -1
  345. package/dist/sdk/session-registry-4E6YRQ77.mjs +10 -0
  346. package/dist/sdk/session-registry-4E6YRQ77.mjs.map +1 -0
  347. package/dist/sdk/slack-frontend-BVKW3GD5.mjs +735 -0
  348. package/dist/sdk/slack-frontend-BVKW3GD5.mjs.map +1 -0
  349. package/dist/sdk/trace-helpers-VP6QYVBX.mjs +23 -0
  350. package/dist/sdk/trace-helpers-VP6QYVBX.mjs.map +1 -0
  351. package/dist/sdk/{tracer-init-WC75N5NW.mjs → tracer-init-GSLPPLCD.mjs} +2 -2
  352. package/dist/sdk/tracer-init-GSLPPLCD.mjs.map +1 -0
  353. package/dist/sdk/workflow-registry-R6KSACFR.mjs +12 -0
  354. package/dist/sdk/workflow-registry-R6KSACFR.mjs.map +1 -0
  355. package/dist/sdk.d.ts.map +1 -1
  356. package/dist/slack/adapter.d.ts +36 -0
  357. package/dist/slack/adapter.d.ts.map +1 -0
  358. package/dist/slack/cache-prewarmer.d.ts +31 -0
  359. package/dist/slack/cache-prewarmer.d.ts.map +1 -0
  360. package/dist/slack/client.d.ts +77 -0
  361. package/dist/slack/client.d.ts.map +1 -0
  362. package/dist/slack/markdown.d.ts +45 -0
  363. package/dist/slack/markdown.d.ts.map +1 -0
  364. package/dist/slack/prompt-state.d.ts +33 -0
  365. package/dist/slack/prompt-state.d.ts.map +1 -0
  366. package/dist/slack/rate-limiter.d.ts +56 -0
  367. package/dist/slack/rate-limiter.d.ts.map +1 -0
  368. package/dist/slack/signature.d.ts +2 -0
  369. package/dist/slack/signature.d.ts.map +1 -0
  370. package/dist/slack/socket-runner.d.ts +42 -0
  371. package/dist/slack/socket-runner.d.ts.map +1 -0
  372. package/dist/slack/thread-cache.d.ts +51 -0
  373. package/dist/slack/thread-cache.d.ts.map +1 -0
  374. package/dist/snapshot-store.d.ts +59 -0
  375. package/dist/snapshot-store.d.ts.map +1 -0
  376. package/dist/state-machine/context/build-engine-context.d.ts +17 -0
  377. package/dist/state-machine/context/build-engine-context.d.ts.map +1 -0
  378. package/dist/state-machine/dispatch/dependency-gating.d.ts +12 -0
  379. package/dist/state-machine/dispatch/dependency-gating.d.ts.map +1 -0
  380. package/dist/state-machine/dispatch/execution-invoker.d.ts +14 -0
  381. package/dist/state-machine/dispatch/execution-invoker.d.ts.map +1 -0
  382. package/dist/state-machine/dispatch/foreach-processor.d.ts +8 -0
  383. package/dist/state-machine/dispatch/foreach-processor.d.ts.map +1 -0
  384. package/dist/state-machine/dispatch/history-snapshot.d.ts +8 -0
  385. package/dist/state-machine/dispatch/history-snapshot.d.ts.map +1 -0
  386. package/dist/state-machine/dispatch/on-init-handlers.d.ts +43 -0
  387. package/dist/state-machine/dispatch/on-init-handlers.d.ts.map +1 -0
  388. package/dist/state-machine/dispatch/renderer-schema.d.ts +8 -0
  389. package/dist/state-machine/dispatch/renderer-schema.d.ts.map +1 -0
  390. package/dist/state-machine/dispatch/stats-manager.d.ts +15 -0
  391. package/dist/state-machine/dispatch/stats-manager.d.ts.map +1 -0
  392. package/dist/state-machine/dispatch/template-renderer.d.ts +7 -0
  393. package/dist/state-machine/dispatch/template-renderer.d.ts.map +1 -0
  394. package/dist/state-machine/execution/summary.d.ts +8 -0
  395. package/dist/state-machine/execution/summary.d.ts.map +1 -0
  396. package/dist/state-machine/runner.d.ts +79 -0
  397. package/dist/state-machine/runner.d.ts.map +1 -0
  398. package/dist/state-machine/states/check-running.d.ts +14 -0
  399. package/dist/state-machine/states/check-running.d.ts.map +1 -0
  400. package/dist/state-machine/states/completed.d.ts +12 -0
  401. package/dist/state-machine/states/completed.d.ts.map +1 -0
  402. package/dist/state-machine/states/error.d.ts +11 -0
  403. package/dist/state-machine/states/error.d.ts.map +1 -0
  404. package/dist/state-machine/states/init.d.ts +11 -0
  405. package/dist/state-machine/states/init.d.ts.map +1 -0
  406. package/dist/state-machine/states/level-dispatch.d.ts +17 -0
  407. package/dist/state-machine/states/level-dispatch.d.ts.map +1 -0
  408. package/dist/state-machine/states/plan-ready.d.ts +12 -0
  409. package/dist/state-machine/states/plan-ready.d.ts.map +1 -0
  410. package/dist/state-machine/states/routing.d.ts +52 -0
  411. package/dist/state-machine/states/routing.d.ts.map +1 -0
  412. package/dist/state-machine/states/wave-planning.d.ts +14 -0
  413. package/dist/state-machine/states/wave-planning.d.ts.map +1 -0
  414. package/dist/state-machine/workflow-projection.d.ts +47 -0
  415. package/dist/state-machine/workflow-projection.d.ts.map +1 -0
  416. package/dist/state-machine-execution-engine.d.ts +159 -0
  417. package/dist/state-machine-execution-engine.d.ts.map +1 -0
  418. package/dist/telemetry/opentelemetry.d.ts.map +1 -1
  419. package/dist/telemetry/state-capture.d.ts +5 -0
  420. package/dist/telemetry/state-capture.d.ts.map +1 -1
  421. package/dist/test-runner/assertions.d.ts +59 -0
  422. package/dist/test-runner/assertions.d.ts.map +1 -0
  423. package/dist/test-runner/core/environment.d.ts +8 -0
  424. package/dist/test-runner/core/environment.d.ts.map +1 -0
  425. package/dist/test-runner/core/fixture.d.ts +3 -0
  426. package/dist/test-runner/core/fixture.d.ts.map +1 -0
  427. package/dist/test-runner/core/flow-stage.d.ts +32 -0
  428. package/dist/test-runner/core/flow-stage.d.ts.map +1 -0
  429. package/dist/test-runner/core/mocks.d.ts +8 -0
  430. package/dist/test-runner/core/mocks.d.ts.map +1 -0
  431. package/dist/test-runner/core/test-execution-wrapper.d.ts +18 -0
  432. package/dist/test-runner/core/test-execution-wrapper.d.ts.map +1 -0
  433. package/dist/test-runner/evaluators.d.ts +45 -0
  434. package/dist/test-runner/evaluators.d.ts.map +1 -0
  435. package/dist/test-runner/fixture-loader.d.ts +30 -0
  436. package/dist/test-runner/fixture-loader.d.ts.map +1 -0
  437. package/dist/test-runner/index.d.ts +127 -0
  438. package/dist/test-runner/index.d.ts.map +1 -0
  439. package/dist/test-runner/recorders/github-recorder.d.ts +23 -0
  440. package/dist/test-runner/recorders/github-recorder.d.ts.map +1 -0
  441. package/dist/test-runner/recorders/global-recorder.d.ts +4 -0
  442. package/dist/test-runner/recorders/global-recorder.d.ts.map +1 -0
  443. package/dist/test-runner/recorders/slack-recorder.d.ts +17 -0
  444. package/dist/test-runner/recorders/slack-recorder.d.ts.map +1 -0
  445. package/dist/test-runner/utils/selectors.d.ts +2 -0
  446. package/dist/test-runner/utils/selectors.d.ts.map +1 -0
  447. package/dist/test-runner/validator.d.ts +8 -0
  448. package/dist/test-runner/validator.d.ts.map +1 -0
  449. package/dist/traces/run-2026-01-20T19-22-58-043Z.ndjson +138 -0
  450. package/dist/traces/run-2026-01-20T19-23-52-175Z.ndjson +1067 -0
  451. package/dist/types/bot.d.ts +109 -0
  452. package/dist/types/bot.d.ts.map +1 -0
  453. package/dist/types/cli.d.ts +8 -1
  454. package/dist/types/cli.d.ts.map +1 -1
  455. package/dist/types/config.d.ts +459 -9
  456. package/dist/types/config.d.ts.map +1 -1
  457. package/dist/types/engine.d.ts +177 -0
  458. package/dist/types/engine.d.ts.map +1 -0
  459. package/dist/types/execution.d.ts +73 -0
  460. package/dist/types/execution.d.ts.map +1 -0
  461. package/dist/types/git-checkout.d.ts +76 -0
  462. package/dist/types/git-checkout.d.ts.map +1 -0
  463. package/dist/types/github.d.ts +51 -0
  464. package/dist/types/github.d.ts.map +1 -0
  465. package/dist/types/workflow.d.ts +237 -0
  466. package/dist/types/workflow.d.ts.map +1 -0
  467. package/dist/utils/command-executor.d.ts +43 -0
  468. package/dist/utils/command-executor.d.ts.map +1 -0
  469. package/dist/utils/comment-metadata.d.ts +21 -0
  470. package/dist/utils/comment-metadata.d.ts.map +1 -0
  471. package/dist/utils/config-loader.d.ts.map +1 -1
  472. package/dist/utils/config-merger.d.ts.map +1 -1
  473. package/dist/utils/env-exposure.d.ts +3 -0
  474. package/dist/utils/env-exposure.d.ts.map +1 -0
  475. package/dist/utils/file-exclusion.d.ts.map +1 -1
  476. package/dist/utils/interactive-prompt.d.ts +1 -1
  477. package/dist/utils/interactive-prompt.d.ts.map +1 -1
  478. package/dist/utils/json-text-extractor.d.ts +17 -0
  479. package/dist/utils/json-text-extractor.d.ts.map +1 -0
  480. package/dist/utils/sandbox.d.ts +10 -0
  481. package/dist/utils/sandbox.d.ts.map +1 -1
  482. package/dist/utils/script-memory-ops.d.ts +21 -0
  483. package/dist/utils/script-memory-ops.d.ts.map +1 -0
  484. package/dist/utils/template-context.d.ts +8 -0
  485. package/dist/utils/template-context.d.ts.map +1 -0
  486. package/dist/utils/tracer-init.d.ts.map +1 -1
  487. package/dist/utils/workspace-manager.d.ts +118 -0
  488. package/dist/utils/workspace-manager.d.ts.map +1 -0
  489. package/dist/utils/worktree-cleanup.d.ts +33 -0
  490. package/dist/utils/worktree-cleanup.d.ts.map +1 -0
  491. package/dist/utils/worktree-manager.d.ts +153 -0
  492. package/dist/utils/worktree-manager.d.ts.map +1 -0
  493. package/dist/webhook-server.d.ts +3 -3
  494. package/dist/webhook-server.d.ts.map +1 -1
  495. package/dist/workflow-executor.d.ts +81 -0
  496. package/dist/workflow-executor.d.ts.map +1 -0
  497. package/dist/workflow-registry.d.ts +79 -0
  498. package/dist/workflow-registry.d.ts.map +1 -0
  499. package/package.json +12 -5
  500. package/dist/output/traces/run-2025-10-22T18-22-56-873Z.ndjson +0 -218
  501. package/dist/sdk/check-execution-engine-2YYKUUSH.mjs +0 -11
  502. package/dist/sdk/check-execution-engine-6QJXYYON.mjs +0 -11
  503. package/dist/sdk/check-execution-engine-PJZ4ZOKG.mjs +0 -11
  504. package/dist/sdk/chunk-33QVZ2D4.mjs +0 -316
  505. package/dist/sdk/chunk-33QVZ2D4.mjs.map +0 -1
  506. package/dist/sdk/chunk-B5QBV2QJ.mjs +0 -752
  507. package/dist/sdk/chunk-B5QBV2QJ.mjs.map +0 -1
  508. package/dist/sdk/chunk-BVFNRCHT.mjs +0 -14129
  509. package/dist/sdk/chunk-BVFNRCHT.mjs.map +0 -1
  510. package/dist/sdk/chunk-KWZW23FG.mjs +0 -14129
  511. package/dist/sdk/chunk-KWZW23FG.mjs.map +0 -1
  512. package/dist/sdk/chunk-O4RP4BRH.mjs +0 -14092
  513. package/dist/sdk/chunk-O4RP4BRH.mjs.map +0 -1
  514. package/dist/sdk/chunk-TUTOLSFV.mjs.map +0 -1
  515. package/dist/sdk/chunk-U5D2LY66.mjs +0 -245
  516. package/dist/sdk/chunk-U5D2LY66.mjs.map +0 -1
  517. package/dist/sdk/chunk-U7X54EMV.mjs +0 -331
  518. package/dist/sdk/chunk-U7X54EMV.mjs.map +0 -1
  519. package/dist/sdk/config-merger-TWUBWFC2.mjs +0 -8
  520. package/dist/sdk/mermaid-telemetry-SN6A2TKW.mjs +0 -61
  521. package/dist/sdk/mermaid-telemetry-SN6A2TKW.mjs.map +0 -1
  522. package/dist/sdk/mermaid-telemetry-YCTIG76M.mjs +0 -61
  523. package/dist/sdk/mermaid-telemetry-YCTIG76M.mjs.map +0 -1
  524. package/dist/traces/run-2025-10-22T18-22-56-873Z.ndjson +0 -218
  525. /package/dist/sdk/{check-execution-engine-2YYKUUSH.mjs.map → check-provider-registry-534KL5HT.mjs.map} +0 -0
  526. /package/dist/sdk/{check-execution-engine-6QJXYYON.mjs.map → command-executor-TYUV6HUS.mjs.map} +0 -0
  527. /package/dist/sdk/{check-execution-engine-PJZ4ZOKG.mjs.map → config-YNC2EOOT.mjs.map} +0 -0
  528. /package/dist/sdk/{config-merger-TWUBWFC2.mjs.map → config-merger-PX3WIT57.mjs.map} +0 -0
  529. /package/dist/sdk/{liquid-extensions-KVL4MKRH.mjs.map → failure-condition-evaluator-YGTF2GHG.mjs.map} +0 -0
  530. /package/dist/sdk/{tracer-init-WC75N5NW.mjs.map → liquid-extensions-PKWCKK7E.mjs.map} +0 -0
@@ -0,0 +1,743 @@
1
+ # RFC: Event-Driven Integrations via Frontends (GitHub, Slack, …)
2
+
3
+ **Status**: Proposed
4
+ **Created**: 2025-11-19
5
+ **Author**: Architecture Planning
6
+
7
+ ## Abstract
8
+
9
+ This RFC proposes moving to a fully event‑driven architecture for integrations using a pluggable “frontends” system that reacts to neutral engine events. The legacy dependency‑injection (DI) GitHub path remains in the codebase for backward compatibility, but new functionality—including the new GitHub integration—will be implemented as frontends on the event bus.
10
+
11
+ ## Motivation
12
+
13
+ ### Current Architecture
14
+
15
+ The state machine currently uses **dependency injection** for GitHub integration:
16
+
17
+ - `GitHubCheckService` is created externally by main engine
18
+ - Service is injected via `EngineContext.gitHubChecks`
19
+ - State handlers call service methods directly (e.g., `context.gitHubChecks.createCheck()`)
20
+ - Main engine handles initialization and finalization
21
+
22
+ **Advantages**:
23
+ - Simple and direct
24
+ - Easy to trace control flow
25
+ - Minimal complexity for single integration point
26
+
27
+ **Limitations**:
28
+ - Tight coupling to GitHub as the only platform
29
+ - Testing requires mocking service methods
30
+ - No natural extension point for additional platforms (Slack, webhooks, metrics)
31
+ - GitHub-specific code leaks into state machine logic
32
+
33
+ ### Goals of Event-Driven Approach
34
+
35
+ 1. **Platform Agnostic**: State machine emits generic events; adapters translate to platform-specific operations
36
+ 2. **Multi-Platform Support**: Add Slack, webhooks, metrics without modifying state machine
37
+ 3. **Improved Testability**: Assert on events instead of mocking service calls
38
+ 4. **Replay Support**: Event log becomes complete audit trail for time-travel debugging
39
+ 5. **Observability**: Central event bus for logging, metrics, tracing
40
+
41
+ ## Proposed Architecture
42
+
43
+ ### 1. Neutral Event Envelope & Taxonomy (Platform‑agnostic)
44
+
45
+ Instead of GitHub‑specific core events, define a neutral event payload taxonomy and wrap every payload in a common envelope that carries correlation/observability metadata.
46
+
47
+ ```typescript
48
+ // Neutral domain payloads (core)
49
+ export type EngineEvent =
50
+ // ... existing engine events (StateTransition, CheckScheduled, CheckCompleted, etc.) ...
51
+ | {
52
+ type: 'CheckStatusRequested';
53
+ checkId?: string; // stable id if available (external_id, run key)
54
+ checkName: string; // human name
55
+ status: 'queued' | 'in_progress' | 'completed' | 'cancelled';
56
+ conclusion?: 'success' | 'failure' | 'neutral' | 'skipped';
57
+ output?: { title?: string; summary?: string; text?: string; annotations?: any[] };
58
+ idempotencyKey?: string; // required for side effects (see delivery policy)
59
+ }
60
+ | {
61
+ type: 'CommentRequested';
62
+ body: string;
63
+ threadKey?: string; // adapter can group updates by logical thread
64
+ commentId?: string; // update if present
65
+ idempotencyKey?: string; // for safe retries
66
+ }
67
+ // Adapter feedback (generic)
68
+ | {
69
+ type: 'CheckStatusCompleted';
70
+ checkId?: string;
71
+ success: boolean;
72
+ error?: SerializedError;
73
+ }
74
+ | {
75
+ type: 'CommentPosted';
76
+ threadKey?: string;
77
+ commentId: string;
78
+ success: boolean;
79
+ error?: SerializedError;
80
+ };
81
+
82
+ // Event envelope (common metadata for all events)
83
+ export interface EventEnvelope<T extends EngineEvent = EngineEvent> {
84
+ id: string; // uuid
85
+ version: 1; // envelope version
86
+ timestamp: string; // ISO8601
87
+ // Correlation
88
+ runId: string; // engine run id
89
+ workflowId?: string; // active workflow/config id
90
+ caseId?: string; // test/case id (when under runner)
91
+ wave?: number; // wave counter
92
+ attempt?: number; // retries for the check
93
+ checkId?: string; // convenience copy if available
94
+ traceId?: string; // tracing correlation
95
+ spanId?: string; // tracing correlation
96
+ causationId?: string; // which event caused this
97
+ correlationId?: string; // stable id for a log/thread/check group
98
+ payload: T; // the actual domain event
99
+ }
100
+ ```
101
+
102
+ Adapter‑specific payloads (e.g., GitHubCheckAnnotationRequested) should live under adapter namespaces and must be created by adapters in response to neutral core events, not emitted by the state machine core.
103
+
104
+ **Design Decisions**:
105
+ - Core stays platform‑agnostic (CheckStatusRequested, CommentRequested, …)
106
+ - Envelope carries correlation/idempotency/observability metadata
107
+ - Feedback events are generic (Completed/Posted) and do not leak provider names
108
+
109
+ ### 2. Event Bus Architecture
110
+
111
+ **File**: `src/event-bus/event-bus.ts`
112
+
113
+ ```typescript
114
+ export type EventHandler<T extends EngineEvent> = (event: T) => void | Promise<void>;
115
+ export type EventFilter<T extends EngineEvent> = (event: T) => boolean;
116
+
117
+ export interface Subscription {
118
+ unsubscribe(): void;
119
+ }
120
+
121
+ export class EventBus {
122
+ private handlers: Map<string, Set<EventHandler<any>>> = new Map();
123
+ private globalHandlers: Set<EventHandler<any>> = new Set();
124
+
125
+ /**
126
+ * Subscribe to specific event type
127
+ */
128
+ on<T extends EngineEvent['type']>(
129
+ eventType: T,
130
+ handler: EventHandler<Extract<EngineEvent, { type: T }>>,
131
+ filter?: EventFilter<Extract<EngineEvent, { type: T }>>
132
+ ): Subscription;
133
+
134
+ /**
135
+ * Subscribe to all events
136
+ */
137
+ onAny(handler: EventHandler<EngineEvent>): Subscription;
138
+
139
+ /**
140
+ * Emit event (handles both sync and async handlers)
141
+ */
142
+ emit(event: EngineEvent | EventEnvelope): Promise<void>;
143
+
144
+ /**
145
+ * Emit and wait for completion event
146
+ * Useful for request/response patterns
147
+ */
148
+ emitAndWait<T extends EngineEvent>(
149
+ event: T | EventEnvelope<T>,
150
+ completionType: EngineEvent['type'],
151
+ timeout?: number
152
+ ): Promise<EventEnvelope<Extract<EngineEvent, { type: typeof completionType }>>>;
153
+ }
154
+ ```
155
+
156
+ **Integration with StateMachineRunner**:
157
+
158
+ Modify `src/state-machine/runner.ts`:
159
+
160
+ ```typescript
161
+ export class StateMachineRunner {
162
+ private context: EngineContext;
163
+ private state: RunState;
164
+ private debugServer?: DebugVisualizerServer;
165
+ private eventBus?: EventBus; // NEW: optional for backward compatibility
166
+
167
+ constructor(
168
+ context: EngineContext,
169
+ debugServer?: DebugVisualizerServer,
170
+ eventBus?: EventBus // NEW
171
+ ) {
172
+ this.context = context;
173
+ this.state = this.initializeState();
174
+ this.debugServer = debugServer;
175
+ this.eventBus = eventBus;
176
+ }
177
+
178
+ private emitEvent(event: EngineEvent): void {
179
+ // Existing behavior
180
+ this.state.historyLog.push(event);
181
+
182
+ if (event.type === 'ForwardRunRequested' || event.type === 'WaveRetry') {
183
+ this.state.eventQueue.push(event);
184
+ }
185
+
186
+ if (this.debugServer) {
187
+ try {
188
+ this.streamEventToDebugServer(event);
189
+ } catch (_err) {}
190
+ }
191
+
192
+ // NEW: Emit to event bus if available (wrapped in envelope)
193
+ if (this.eventBus) {
194
+ const envelope: EventEnvelope = {
195
+ id: uuidv4(),
196
+ version: 1,
197
+ timestamp: new Date().toISOString(),
198
+ runId: this.state.runId,
199
+ workflowId: this.state.workflowId,
200
+ wave: this.state.wave,
201
+ payload: event,
202
+ };
203
+ this.eventBus.emit(envelope).catch(err => {
204
+ logger.error(`[EventBus] Error emitting ${event.type}:`, err);
205
+ });
206
+ }
207
+
208
+ if (this.context.debug && event.type !== 'StateTransition') {
209
+ logger.debug(`[StateMachine] Event: ${event.type}`);
210
+ }
211
+ }
212
+ }
213
+ ```
214
+
215
+ ### 3. GitHub Frontend Implementation (example)
216
+
217
+ **File**: `src/event-bus/adapters/github-adapter.ts`
218
+
219
+ ```typescript
220
+ export class GitHubEventAdapter {
221
+ private eventBus: EventBus;
222
+ private gitHubService: GitHubCheckService;
223
+ private subscriptions: Subscription[] = [];
224
+
225
+ constructor(eventBus: EventBus, gitHubService: GitHubCheckService) {
226
+ this.eventBus = eventBus;
227
+ this.gitHubService = gitHubService;
228
+ }
229
+
230
+ start(): void {
231
+ // Subscribe to neutral request events
232
+ this.subscriptions.push(
233
+ this.eventBus.on('CheckStatusRequested', this.handleCheckStatus.bind(this))
234
+ );
235
+ this.subscriptions.push(
236
+ this.eventBus.on('CommentRequested', this.handleCommentRequest.bind(this))
237
+ );
238
+
239
+ // Subscribe to state transitions for automatic status updates
240
+ this.subscriptions.push(
241
+ this.eventBus.on('StateTransition', this.handleStateTransition.bind(this))
242
+ );
243
+ this.subscriptions.push(
244
+ this.eventBus.on('CheckCompleted', this.handleCheckCompleted.bind(this))
245
+ );
246
+ }
247
+
248
+ stop(): void {
249
+ this.subscriptions.forEach(sub => sub.unsubscribe());
250
+ this.subscriptions = [];
251
+ }
252
+
253
+ private async handleCheckStatus(
254
+ event: Extract<EngineEvent, { type: 'CheckStatusRequested' }>
255
+ ): Promise<void> {
256
+ try {
257
+ // Map neutral request to GitHub API (create/update by external_id)
258
+ await this.gitHubService.upsertCheck({
259
+ externalId: event.checkId || event.idempotencyKey,
260
+ name: event.checkName,
261
+ status: event.status,
262
+ conclusion: event.conclusion,
263
+ output: event.output,
264
+ });
265
+
266
+ // Emit completion event
267
+ await this.eventBus.emit({ type: 'CheckStatusCompleted', checkId: event.checkId, success: true });
268
+ } catch (error) {
269
+ await this.eventBus.emit({ type: 'CheckStatusCompleted', checkId: event.checkId, success: false, error: {
270
+ message: error instanceof Error ? error.message : String(error),
271
+ stack: error instanceof Error ? error.stack : undefined,
272
+ name: error instanceof Error ? error.name : undefined,
273
+ }});
274
+ }
275
+ }
276
+
277
+ private async handleCommentRequest(
278
+ event: Extract<EngineEvent, { type: 'CommentRequested' }>
279
+ ): Promise<void> {
280
+ try {
281
+ const commentId = event.commentId
282
+ ? await this.gitHubService.updateComment(event.commentId, event.body)
283
+ : await this.gitHubService.createComment(event.body);
284
+ await this.eventBus.emit({ type: 'CommentPosted', commentId, success: true });
285
+ } catch (error) {
286
+ await this.eventBus.emit({ type: 'CommentPosted', commentId: event.commentId || '', success: false, error: {
287
+ message: error instanceof Error ? error.message : String(error),
288
+ stack: error instanceof Error ? error.stack : undefined,
289
+ name: error instanceof Error ? error.name : undefined,
290
+ }});
291
+ }
292
+ }
293
+
294
+ private async handleStateTransition(
295
+ event: Extract<EngineEvent, { type: 'StateTransition' }>
296
+ ): Promise<void> {
297
+ // Auto-update check status based on state transitions (derive names from context)
298
+ if (event.to === 'CheckRunning') {
299
+ await this.eventBus.emit({ type: 'CheckStatusRequested', checkName: event.checkName || 'run', status: 'in_progress', output: { title: 'Running checks...', summary: `State: ${event.to}` } });
300
+ } else if (event.to === 'Completed') {
301
+ await this.eventBus.emit({ type: 'CheckStatusRequested', checkName: event.checkName || 'run', status: 'completed', conclusion: 'success', output: { title: 'Completed', summary: 'All checks completed successfully' } });
302
+ } else if (event.to === 'Error') {
303
+ await this.eventBus.emit({ type: 'CheckStatusRequested', checkName: event.checkName || 'run', status: 'completed', conclusion: 'failure', output: { title: 'Failed', summary: 'Execution encountered an error' } });
304
+ }
305
+ }
306
+
307
+ private async handleCheckCompleted(
308
+ event: Extract<EngineEvent, { type: 'CheckCompleted' }>
309
+ ): Promise<void> {
310
+ // Optionally update GitHub with individual check results
311
+ // This would aggregate results and post comments/annotations
312
+ }
313
+ }
314
+ ```
315
+
316
+ #### 3.1 Comment Grouping & Incremental Updates (GitHub)
317
+
318
+ Goal: keep a single evolving PR comment that summarizes the run, grouped by check/step, and update it incrementally without spamming new comments.
319
+
320
+ Default strategy (no new knobs):
321
+
322
+ - Thread key: `threadKey = <repo>#<pull_number>@<head_sha>[:<workflowId>]` (or `runId` when PR metadata is unavailable).
323
+ - Hidden markers: the adapter renders HTML comment markers to delineate the “visor group” and each step section. GitHub preserves these markers but does not display them.
324
+ - Single comment policy: create once, then update in place using `commentId`. Adapter discovers an existing comment by scanning for the `visor:thread` header marker.
325
+ - Partial update (logical): the adapter parses the existing body into sections (by markers), replaces only changed sections in memory, and re-renders the full body for the GitHub update API call.
326
+ - Debounce & coalescing: updates are debounced (e.g., 300–500 ms) to batch bursts of events and respect rate limits.
327
+ - Idempotency: for each update, compute `idempotencyKey = hash(threadKey + revision)`. Retries reuse the same key.
328
+
329
+ Markers and layout:
330
+
331
+ ```markdown
332
+ <!-- visor:thread={
333
+ "key":"<threadKey>",
334
+ "runId":"<runId>",
335
+ "workflowId":"<workflowId>",
336
+ "headSha":"<sha>",
337
+ "revision": 7,
338
+ "generatedAt": "2025-11-19T12:34:56Z"
339
+ } -->
340
+
341
+ ## Visor Summary — <status icon> <conclusion>
342
+ SHA: <shortSha> • Checks: <passed>/<total> • Duration: <h:mm:ss>
343
+
344
+ <!-- visor:section={"id":"overview","name":"overview"} -->
345
+ ### Overview <status>
346
+ …overview summary…
347
+ <!-- visor:section-end id="overview" -->
348
+
349
+ <!-- visor:section={"id":"security","name":"security"} -->
350
+ ### Security <status>
351
+ …security summary and key failures…
352
+ <!-- visor:section-end id="security" -->
353
+
354
+ <!-- visor:thread-end key="<threadKey>" -->
355
+ ```
356
+
357
+ Aggregation model (maintained in adapter):
358
+
359
+ ```ts
360
+ type StepStatus = 'queued'|'in_progress'|'completed';
361
+ type StepConclusion = 'success'|'failure'|'neutral'|'skipped'|undefined;
362
+
363
+ interface StepModel {
364
+ name: string;
365
+ status: StepStatus;
366
+ conclusion?: StepConclusion;
367
+ startedAt?: string;
368
+ completedAt?: string;
369
+ annotations?: number; // count only
370
+ summary?: string; // brief human text
371
+ }
372
+
373
+ interface ThreadModel {
374
+ threadKey: string;
375
+ runId: string;
376
+ workflowId?: string;
377
+ headSha?: string;
378
+ revision: number; // increments on each render
379
+ steps: Record<string, StepModel>;
380
+ totals: { passed: number; failed: number; skipped: number; total: number };
381
+ }
382
+ ```
383
+
384
+ Update cycle (pseudocode):
385
+
386
+ ```ts
387
+ onEvent(envelope) {
388
+ switch (envelope.payload.type) {
389
+ case 'CheckStatusRequested':
390
+ case 'CheckCompleted':
391
+ updateThreadModel(model, envelope); // update steps/totals
392
+ scheduleRender(threadKey);
393
+ break;
394
+ case 'StateTransition':
395
+ if (to === 'Completed' || to === 'Error') scheduleRender(threadKey);
396
+ }
397
+ }
398
+
399
+ async renderThread(threadKey) {
400
+ const comment = await findOrCreateComment(threadKey); // scan once per run; cache commentId
401
+ const existing = comment?.body || '';
402
+ const parsed = parseSections(existing); // read markers into a dictionary
403
+ const next = mergeSections(parsed, buildSectionsFromModel()); // replace only changed sections
404
+ const body = serialize(next); // full markdown body
405
+ const idempotencyKey = hash(threadKey + model.revision);
406
+ await github.updateComment(comment.id, body, { idempotencyKey });
407
+ model.revision++;
408
+ }
409
+ ```
410
+
411
+ Notes:
412
+
413
+ - findOrCreateComment: search the PR for a comment containing `<!-- visor:thread={..."key":"<threadKey>"...} -->`; if none found, create one and include the header marker.
414
+ - parseSections/mergeSections/serialize: simple utilities that treat the comment as a set of named blocks framed by section markers; unknown blocks are preserved unmodified.
415
+ - Failure safety: if parsing fails (e.g., user edited the comment and removed markers), the adapter falls back to re‑creating the comment with fresh markers and updates the cached `commentId`.
416
+ - Multiple workflows: include `workflowId` in `threadKey` to separate comments per workflow if desired; default behavior is one summary per PR/headSha.
417
+
418
+ ##### 3.1.1 Section‑Level Metadata & Override Semantics
419
+
420
+ Each rendered section carries compact JSON metadata in the start marker to enable precise partial replacement without touching other sections. Recommended fields:
421
+
422
+ - `id`: stable logical id (e.g., step id: `overview`, `security`)
423
+ - `name`: human label (optional)
424
+ - `runId`: engine run id that produced this section
425
+ - `wave`: wave counter when the section was updated (optional)
426
+ - `revision`: monotonically increasing integer maintained by the adapter per section
427
+
428
+ Replacement rules:
429
+
430
+ - On each render, the adapter compares the incoming section’s `{ id, runId }` against what exists in the current comment body. If found, it replaces the entire block between `section` and `section-end`. If not found, it appends the new block before `thread-end`.
431
+ - The `revision` is incremented after a successful update and recorded in the marker JSON to support idempotent retries (same `{id, runId, revision}` should be a no‑op).
432
+ - When a step disappears (e.g., configuration change), the adapter may either preserve the last known block (default) or remove it if a `pruneMissingSections` policy is enabled.
433
+
434
+ Idempotency and dedupe:
435
+
436
+ - The update call uses `idempotencyKey = hash(threadKey + sectionId + revision)` to ensure safe retries.
437
+ - If GitHub returns 409/412 (conflict/precondition), the adapter re‑fetches, re‑parses, merges, and retries once.
438
+
439
+ Slack mapping:
440
+
441
+ - Use Slack thread messages with a single parent message keyed by `threadKey`; per‑section updates edit a dedicated child message whose `ts` is cached by `{threadKey, sectionId}`. This mirrors the GitHub marker approach without HTML comments.
442
+
443
+ #### 3.2 Frontends API (Pluggable Integrations)
444
+
445
+ Contracts (reference shapes to implement):
446
+
447
+ ```ts
448
+ export interface Frontend {
449
+ readonly name: string; // e.g., "github", "slack", "ndjson-sink"
450
+ readonly subscriptions?: Array<EngineEvent['type']>; // optional; host may wire defaults
451
+ start(ctx: FrontendContext): Promise<void> | void;
452
+ stop(): Promise<void> | void;
453
+ }
454
+
455
+ export interface FrontendContext {
456
+ eventBus: EventBus;
457
+ logger: Logger;
458
+ config: unknown; // decoded user config for this frontend only
459
+ run: { runId: string; workflowId?: string; repo?: string; pr?: number; headSha?: string };
460
+ }
461
+
462
+ export interface FrontendSpec {
463
+ name: string; // "github"
464
+ package?: string; // external package name for discovery; omitted for built-ins
465
+ config?: unknown; // serialized config to hand to the frontend
466
+ features?: string[]; // claims, e.g., ["checks","summary-comment","annotations"]
467
+ }
468
+
469
+ export class FrontendsHost {
470
+ constructor(private bus: EventBus, private log: Logger) {}
471
+ async load(specs: FrontendSpec[]): Promise<void> { /* resolve built-ins or dynamic import */ }
472
+ async startAll(ctxFactory: () => FrontendContext): Promise<void> { /* wire subs; start */ }
473
+ async stopAll(): Promise<void> { /* unsubscribe; stop */ }
474
+ }
475
+ ```
476
+
477
+ Feature ownership and conflicts
478
+ - A single feature for a provider must have a single owner (e.g., exactly one GitHub frontend owns "checks").
479
+ - The host enforces exclusivity; the first claimant wins by config order and a warning is logged for subsequent claimants.
480
+ - Legacy DI is bypassed when a frontend claims a feature to prevent double posting.
481
+
482
+ Minimal default configuration (illustrative; no extra knobs needed):
483
+
484
+ ```yaml
485
+ frontends:
486
+ - name: github
487
+ features: [checks, summary-comment]
488
+ # config: {} # optional, sane defaults
489
+ - name: ndjson-sink
490
+ # config: { file: ".visor-events.ndjson" } # optional
491
+ # - name: slack # example future frontend
492
+ # features: [notifications]
493
+ ```
494
+
495
+ #### 3.3 Comment Markers — Mini Grammar & Utilities
496
+
497
+ Markers (regular expressions shown informally):
498
+ - Thread header: `<!--\s*visor:thread=(?<json>\{[^]*?\})\s*-->`
499
+ - Section start: `<!--\s*visor:section=(?<json>\{[^]*?\})\s*-->`
500
+ - Section end: `<!--\s*visor:section-end\s+id=\"(?<id>[^\"]+)\"\s*-->`
501
+ - Thread end: `<!--\s*visor:thread-end\s+key=\"(?<key>[^\"]+)\"\s*-->`
502
+
503
+ Utilities (sketch):
504
+
505
+ ```ts
506
+ interface SectionDoc { header: ThreadHeader; sections: Record<string,string>; tail?: string }
507
+
508
+ function parseSections(body: string): SectionDoc { /* scan markers; collect text blocks by id */ }
509
+ function mergeSections(prev: SectionDoc, nextBlocks: Record<string,string>): SectionDoc { /* replace changed */ }
510
+ function serialize(doc: SectionDoc): string { /* stitch header + blocks + thread-end */ }
511
+ ```
512
+
513
+ Persistence keys in header JSON:
514
+ - `key` (threadKey), `runId`, `workflowId`, `headSha`, `revision`, `generatedAt`.
515
+
516
+ NDJSON sink line shape (for reference):
517
+
518
+ ```json
519
+ { "id":"...", "ts":"2025-11-19T12:34:56Z", "runId":"...", "payload": { "type":"CheckStatusRequested", "checkName":"...", "status":"in_progress" }, "safe": true }
520
+ ```
521
+
522
+
523
+ ### 4. Delivery, Ordering, Idempotency & Failure Policy
524
+
525
+ Defaults (no extra knobs required):
526
+
527
+ - Quality of Service: in‑process, at‑least‑once delivery.
528
+ - Ordering: FIFO per `checkId` (or `checkName` fallback) and per `runId`.
529
+ - Idempotency: All side‑effecting requests MUST include `idempotencyKey` or a stable `checkId`. Adapters must deduplicate.
530
+ - Timeouts: `emitAndWait` defaults to 10s; failure triggers a non‑blocking warning for optional sinks and a retry for critical sinks.
531
+ - Retries: Exponential backoff with jitter for HTTP 5xx/429; up to 3 attempts. 4xx except 409/412 are not retried.
532
+ - Rate limits: Adapters throttle using provider budgets; surface “deferred” state via `CheckStatusRequested` with `queued`.
533
+ - Dead‑letter: A global hook `onEventDeliveryFailure(envelope, error)` logs NDJSON entries for forensics.
534
+
535
+ Critical vs optional adapters:
536
+
537
+ - Critical (GitHub checks/comments): fail fast after bounded retries → engine surfaces error.
538
+ - Optional (metrics, logs): never block engine; best‑effort with warnings.
539
+
540
+ ### 5. Security & Redaction
541
+
542
+ - Redact tokens/PII by default in envelopes and adapter payloads.
543
+ - Provide `safeSummary`/`safeText` fields for public sinks; adapters prefer safe fields when present.
544
+ - Sampling for large payloads and bounded annotation batching.
545
+
546
+ ### 6. Event Persistence & Replay
547
+
548
+ - Optional `EventSink` writes `EventEnvelope` to NDJSON (one line per envelope) with rotation.
549
+ - Replay modes:
550
+ - Inspect‑only (no side effects): adapters ignore side‑effecting requests.
551
+ - With‑effects (debug only): adapters re‑issue idempotent requests.
552
+ - Envelopes include `causationId`/`correlationId` enabling time‑travel visualization.
553
+
554
+ ### 7. Frontend Contracts (GitHub example)
555
+
556
+ - Upsert check via `external_id` (prefer) or `(name+head_sha)`.
557
+ - Handle secondary rate limits and abuse detection by exponential backoff and budget throttling.
558
+ - Batch annotations to provider limits; retry partial failures.
559
+ - Error classification: 4xx (caller issue), 5xx/429 (transient).
560
+
561
+ ### 8. Testing Utilities
562
+
563
+ - `captureEvents(eventBus)` returns in‑memory array of envelopes.
564
+ - `expectEvents(events).toContainInOrder([...])` asserts ordered subsequences per `checkId`.
565
+ - Use neutral events in tests; adapter unit tests validate mapping and idempotency.
566
+
567
+ ### 9. Migration Strategy (to Full Event‑Driven via Frontends)
568
+
569
+ Phase 1 — Foundations (no breaking changes)
570
+ - Add `EventBus` + `EventEnvelope`.
571
+ - Introduce `FrontendsHost` and `Frontend` API; ship a built‑in NDJSON sink frontend.
572
+ - Keep legacy DI GitHub path untouched.
573
+
574
+ Phase 2 — Frontends‑first (opt‑in)
575
+ - Implement GitHub frontend (checks + summary comment) using neutral events, grouping, idempotency.
576
+ - Add Slack and Metrics frontends as examples.
577
+ - Configuration enables frontends mode; when the GitHub frontend is active, it owns checks/comments and the legacy DI is bypassed to avoid double posting.
578
+
579
+ Phase 3 — Default to frontends
580
+ - Make frontends mode the default once stable; legacy DI remains available but off by default.
581
+
582
+ Phase 4 — Remove legacy (future breaking change)
583
+ - After a deprecation window, remove the DI GitHub path and keep frontends as the single integration layer.
584
+
585
+ ## Benefits
586
+
587
+ ### Multi-Platform Support
588
+
589
+ Add new platforms without touching state machine:
590
+
591
+ ```typescript
592
+ // Slack adapter
593
+ export class SlackEventAdapter {
594
+ constructor(eventBus: EventBus, slackClient: SlackClient) { }
595
+
596
+ start(): void {
597
+ this.eventBus.on('CheckCompleted', this.postSummaryToSlack.bind(this));
598
+ this.eventBus.on('StateTransition', this.updateSlackThread.bind(this));
599
+ }
600
+ }
601
+
602
+ // Metrics adapter
603
+ export class MetricsEventAdapter {
604
+ constructor(eventBus: EventBus, metricsClient: PrometheusClient) { }
605
+
606
+ start(): void {
607
+ this.eventBus.on('CheckCompleted', this.recordCheckDuration.bind(this));
608
+ this.eventBus.on('StateTransition', this.recordStateTransition.bind(this));
609
+ }
610
+ }
611
+ ```
612
+
613
+ ### Testing Improvements
614
+
615
+ Replace mock-based testing with assertion-based testing:
616
+
617
+ ```typescript
618
+ // Before: Mock-based (brittle)
619
+ it('should create GitHub check when entering CheckRunning state', async () => {
620
+ const mockGitHub = {
621
+ createCheck: jest.fn(),
622
+ };
623
+ const context = { gitHubChecks: mockGitHub };
624
+
625
+ await runner.run();
626
+
627
+ expect(mockGitHub.createCheck).toHaveBeenCalledWith({
628
+ name: 'visor-review',
629
+ status: 'in_progress',
630
+ });
631
+ });
632
+
633
+ // After: Event assertion (clear, neutral)
634
+ it('should create GitHub check when entering CheckRunning state', async () => {
635
+ const eventBus = new EventBus();
636
+ const events: EventEnvelope[] = [];
637
+
638
+ eventBus.onAny(env => events.push(env));
639
+
640
+ const runner = new StateMachineRunner(context, undefined, eventBus);
641
+ await runner.run();
642
+
643
+ const checkCreateEvent = events.find(
644
+ e => e.payload.type === 'CheckStatusRequested' && e.payload.status === 'in_progress'
645
+ );
646
+
647
+ expect(checkCreateEvent).toBeDefined();
648
+ expect(checkCreateEvent?.payload.checkName).toBe('visor-review');
649
+ });
650
+ ```
651
+
652
+ ### Replay/Resume Support
653
+
654
+ - `historyLog` already captures all events
655
+ - To resume: replay events through `EventBus`
656
+ - Adapters can be idempotent (skip already-created GitHub checks)
657
+ - Enables time-travel debugging
658
+
659
+ ### Observability
660
+
661
+ - Central point to add logging, metrics, tracing
662
+ - Debug visualizer becomes an adapter that subscribes to all events
663
+ - Prometheus metrics adapter counts event types
664
+ - Audit logger writes events to file
665
+
666
+ ## Trade-offs
667
+
668
+ ### Pros
669
+
670
+ - ✅ Clean separation: state machine focuses on workflow logic, adapters handle I/O
671
+ - ✅ Testability: assert on events instead of mocking services
672
+ - ✅ Extensibility: add new platforms without modifying state machine
673
+ - ✅ Replay: `historyLog` becomes complete audit trail
674
+ - ✅ Future-proof: aligns with RFC Section 5 goals
675
+
676
+ ### Cons
677
+
678
+ - ❌ Increased complexity: event bus, subscription management, adapter lifecycle
679
+ - ❌ Asynchronous errors harder to handle (adapter fails, how does state machine know?)
680
+ - ❌ Timing issues: what if GitHub check creation fails mid-execution?
681
+ - ❌ Debugging: event flow harder to trace than direct calls
682
+ - ❌ Performance: extra layer of indirection
683
+
684
+ ### When This Makes Sense
685
+
686
+ - ✅ Multiple output destinations (GitHub + Slack + webhooks + metrics)
687
+ - ✅ Complex retry/resilience requirements
688
+ - ✅ Need for event replay/time-travel debugging
689
+ - ✅ Strict platform-agnostic requirements
690
+
691
+ ### When Current Pattern Is Better
692
+
693
+ - ✅ Single integration point (GitHub only)
694
+ - ✅ Simple success/failure reporting
695
+ - ✅ Direct control flow easier to reason about
696
+ - ✅ Team unfamiliar with event-driven patterns
697
+
698
+ ## Recommendation: Full Event‑Driven with Frontends
699
+
700
+ Adopt the event bus and frontends as the primary, pluggable integration layer. Keep the legacy DI GitHub code path in the repository for backward compatibility, but new functionality (GitHub and beyond) should be built as frontends. Roll out by enabling the GitHub frontend alongside the bus, then make it the default once stable.
701
+
702
+ ## Open Questions
703
+
704
+ Kept intentionally small after adopting defaults above:
705
+
706
+ 1. Should we persist envelopes by default in local dev (NDJSON) and disable in CI, or the reverse?
707
+ 2. Per‑run adapters vs shared process‑wide adapters: we currently recommend shared with per‑run correlation; confirm for multi‑repo runners.
708
+ 3. Priority delivery: do we need priority channels for UI feedback vs background telemetry?
709
+
710
+ ## Implementation Checklist
711
+
712
+ ### Phase 1: Foundation
713
+ - [ ] Implement `EventBus` class with subscription management
714
+ - [ ] Add `eventBus` optional parameter to `StateMachineRunner`
715
+ - [ ] Modify `emitEvent()` to publish to event bus
716
+ - [ ] Add unit tests for `EventBus`
717
+
718
+ ### Phase 2: GitHub Adapter
719
+ - [ ] Implement `GitHubEventAdapter` with request handlers
720
+ - [ ] Add feature flag `experimental.eventDrivenGitHub`
721
+ - [ ] Wire up adapter in `state-machine-execution-engine.ts`
722
+ - [ ] Add integration tests for dual-mode operation
723
+
724
+ ### Phase 3: Multi-Platform Examples
725
+ - [ ] Implement `SlackEventAdapter` (example)
726
+ - [ ] Implement `MetricsEventAdapter` (example)
727
+ - [ ] Document adapter API and patterns
728
+
729
+ ### Phase 4: Migration (Breaking Change)
730
+ - [ ] Remove `gitHubChecks` from `EngineContext`
731
+ - [ ] Make `eventBus` required parameter
732
+ - [ ] Update all state handlers to emit events
733
+ - [ ] Update all tests to new pattern
734
+
735
+ ## References
736
+
737
+ - [State Machine RFC](./engine-state-machine-plan.md) - Section 5: Toward NASA-style guarantees
738
+ - [Debug Visualizer RFC](./debug-visualizer-rfc.md) - Event streaming for time-travel debugging
739
+ - [Telemetry Tracing RFC](./telemetry-tracing-rfc.md) - Observability integration
740
+
741
+ ## Conclusion
742
+
743
+ Move integrations to a fully event‑driven model using neutral events and pluggable frontends. Keep the legacy DI path for compatibility but direct new development to frontends. This gives a clean core, scales to additional platforms (Slack, metrics) without touching the engine, and unlocks robust replay and observability.