tinybeeai 0.0.0-stage → 0.16.1

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 (1034) hide show
  1. package/.railway/railway.ts +83 -0
  2. package/.railway/tsconfig.json +13 -0
  3. package/AGENTS.md +102 -0
  4. package/Dockerfile +108 -0
  5. package/LICENSE +21 -0
  6. package/README.md +275 -2
  7. package/bin/localdost.js +29 -0
  8. package/bin/tinybeeai.js +28 -0
  9. package/compose.yml +63 -0
  10. package/demo/payloads/ci_failure.json +46 -0
  11. package/demo/payloads/outage.json +18 -0
  12. package/demo/payloads/pr_comment_edited.json +50 -0
  13. package/demo/payloads/pr_merged.json +80 -0
  14. package/demo/payloads/pr_opened.json +69 -0
  15. package/demo/payloads/pr_synchronize.json +69 -0
  16. package/demo/payloads/ticket_created.json +138 -0
  17. package/demo/sample-app/playwright.config.ts +20 -0
  18. package/demo/sample-app/server.ts +163 -0
  19. package/demo/sample-app/tests/checkout.spec.ts +13 -0
  20. package/demo/sample-app/tests/smoke.spec.ts +8 -0
  21. package/dist/agent/approval-retries.js +59 -0
  22. package/dist/agent/approval-retries.js.map +1 -0
  23. package/dist/agent/approvals.js +390 -0
  24. package/dist/agent/approvals.js.map +1 -0
  25. package/dist/agent/chat-bridge.js +154 -0
  26. package/dist/agent/chat-bridge.js.map +1 -0
  27. package/dist/agent/chat-lead.js +475 -0
  28. package/dist/agent/chat-lead.js.map +1 -0
  29. package/dist/agent/chat-loop.js +106 -0
  30. package/dist/agent/chat-loop.js.map +1 -0
  31. package/dist/agent/chat-mcp.js +49 -0
  32. package/dist/agent/chat-mcp.js.map +1 -0
  33. package/dist/agent/chat-tool-blocks.js +453 -0
  34. package/dist/agent/chat-tool-blocks.js.map +1 -0
  35. package/dist/agent/chat-view.js +94 -0
  36. package/dist/agent/chat-view.js.map +1 -0
  37. package/dist/agent/chat-views.js +781 -0
  38. package/dist/agent/chat-views.js.map +1 -0
  39. package/dist/agent/chat.js +1703 -0
  40. package/dist/agent/chat.js.map +1 -0
  41. package/dist/agent/destinations.js +150 -0
  42. package/dist/agent/destinations.js.map +1 -0
  43. package/dist/agent/llm-cli.js +451 -0
  44. package/dist/agent/llm-cli.js.map +1 -0
  45. package/dist/agent/llm-codex.js +493 -0
  46. package/dist/agent/llm-codex.js.map +1 -0
  47. package/dist/agent/llm-openai.js +211 -0
  48. package/dist/agent/llm-openai.js.map +1 -0
  49. package/dist/agent/llm.js +1464 -0
  50. package/dist/agent/llm.js.map +1 -0
  51. package/dist/agent/memory.js +33 -0
  52. package/dist/agent/memory.js.map +1 -0
  53. package/dist/agent/mock-views.js +93 -0
  54. package/dist/agent/mock-views.js.map +1 -0
  55. package/dist/agent/model-availability.js +207 -0
  56. package/dist/agent/model-availability.js.map +1 -0
  57. package/dist/agent/model-errors.js +188 -0
  58. package/dist/agent/model-errors.js.map +1 -0
  59. package/dist/agent/model-guard.js +311 -0
  60. package/dist/agent/model-guard.js.map +1 -0
  61. package/dist/agent/prompts.js +374 -0
  62. package/dist/agent/prompts.js.map +1 -0
  63. package/dist/agent/qa-lenses/qa-auth.md +32 -0
  64. package/dist/agent/qa-lenses/qa-check-then-act.md +33 -0
  65. package/dist/agent/qa-lenses/qa-control-has-no-effect.md +32 -0
  66. package/dist/agent/qa-lenses/qa-dates.md +31 -0
  67. package/dist/agent/qa-lenses/qa-double-submit.md +34 -0
  68. package/dist/agent/qa-lenses/qa-feature-flag.md +29 -0
  69. package/dist/agent/qa-lenses/qa-migration.md +35 -0
  70. package/dist/agent/qa-lenses/qa-money.md +38 -0
  71. package/dist/agent/qa-lenses/qa-response-shape-break.md +33 -0
  72. package/dist/agent/qa-lenses/qa-validation.md +29 -0
  73. package/dist/agent/qa-prompts.js +660 -0
  74. package/dist/agent/qa-prompts.js.map +1 -0
  75. package/dist/agent/reasoning.js +55 -0
  76. package/dist/agent/reasoning.js.map +1 -0
  77. package/dist/agent/redact.js +48 -0
  78. package/dist/agent/redact.js.map +1 -0
  79. package/dist/agent/rules.js +927 -0
  80. package/dist/agent/rules.js.map +1 -0
  81. package/dist/agent/runs.js +440 -0
  82. package/dist/agent/runs.js.map +1 -0
  83. package/dist/agent/send-retry.js +62 -0
  84. package/dist/agent/send-retry.js.map +1 -0
  85. package/dist/agent/team-notes.js +288 -0
  86. package/dist/agent/team-notes.js.map +1 -0
  87. package/dist/agent/token-meter.js +31 -0
  88. package/dist/agent/token-meter.js.map +1 -0
  89. package/dist/agent/triage.js +506 -0
  90. package/dist/agent/triage.js.map +1 -0
  91. package/dist/api.js +1047 -0
  92. package/dist/api.js.map +1 -0
  93. package/dist/approval-targets.js +107 -0
  94. package/dist/approval-targets.js.map +1 -0
  95. package/dist/bee/cloudflared.js +108 -0
  96. package/dist/bee/cloudflared.js.map +1 -0
  97. package/dist/bee/health.js +99 -0
  98. package/dist/bee/health.js.map +1 -0
  99. package/dist/bee/hive-client.js +75 -0
  100. package/dist/bee/hive-client.js.map +1 -0
  101. package/dist/bee/identity.js +39 -0
  102. package/dist/bee/identity.js.map +1 -0
  103. package/dist/bee/models.js +510 -0
  104. package/dist/bee/models.js.map +1 -0
  105. package/dist/bee/pairing.js +351 -0
  106. package/dist/bee/pairing.js.map +1 -0
  107. package/dist/bee/relay-client.js +50 -0
  108. package/dist/bee/relay-client.js.map +1 -0
  109. package/dist/bee/routes.js +214 -0
  110. package/dist/bee/routes.js.map +1 -0
  111. package/dist/bee/setup-page.js +223 -0
  112. package/dist/bee/setup-page.js.map +1 -0
  113. package/dist/bee/state.js +41 -0
  114. package/dist/bee/state.js.map +1 -0
  115. package/dist/bee/status.js +117 -0
  116. package/dist/bee/status.js.map +1 -0
  117. package/dist/bee/tunnel-manager.js +245 -0
  118. package/dist/bee/tunnel-manager.js.map +1 -0
  119. package/dist/bee/updater.js +268 -0
  120. package/dist/bee/updater.js.map +1 -0
  121. package/dist/boot.js +41 -0
  122. package/dist/boot.js.map +1 -0
  123. package/dist/call/index.js +145 -0
  124. package/dist/call/index.js.map +1 -0
  125. package/dist/case-folders.js +294 -0
  126. package/dist/case-folders.js.map +1 -0
  127. package/dist/cases.js +554 -0
  128. package/dist/cases.js.map +1 -0
  129. package/dist/chat-blocks.js +709 -0
  130. package/dist/chat-blocks.js.map +1 -0
  131. package/dist/chat-parse-util.js +38 -0
  132. package/dist/chat-parse-util.js.map +1 -0
  133. package/dist/chat-results.js +96 -0
  134. package/dist/chat-results.js.map +1 -0
  135. package/dist/chat-stats.js +193 -0
  136. package/dist/chat-stats.js.map +1 -0
  137. package/dist/chat-view-specs.js +186 -0
  138. package/dist/chat-view-specs.js.map +1 -0
  139. package/dist/cli/doctor-ops.js +361 -0
  140. package/dist/cli/doctor-ops.js.map +1 -0
  141. package/dist/cli/doctor.js +289 -0
  142. package/dist/cli/doctor.js.map +1 -0
  143. package/dist/cli/dogfood.js +70 -0
  144. package/dist/cli/dogfood.js.map +1 -0
  145. package/dist/cli/env-file.js +34 -0
  146. package/dist/cli/env-file.js.map +1 -0
  147. package/dist/cli/eval-chat-cases.js +359 -0
  148. package/dist/cli/eval-chat-cases.js.map +1 -0
  149. package/dist/cli/eval-chat-results.js +85 -0
  150. package/dist/cli/eval-chat-results.js.map +1 -0
  151. package/dist/cli/eval-chat.js +508 -0
  152. package/dist/cli/eval-chat.js.map +1 -0
  153. package/dist/cli/eval-designer.js +67 -0
  154. package/dist/cli/eval-designer.js.map +1 -0
  155. package/dist/cli/eval-qa-review.js +284 -0
  156. package/dist/cli/eval-qa-review.js.map +1 -0
  157. package/dist/cli/golden-export.js +35 -0
  158. package/dist/cli/golden-export.js.map +1 -0
  159. package/dist/cli/index.js +90 -0
  160. package/dist/cli/index.js.map +1 -0
  161. package/dist/cli/init.js +746 -0
  162. package/dist/cli/init.js.map +1 -0
  163. package/dist/cli/scan-repo.js +199 -0
  164. package/dist/cli/scan-repo.js.map +1 -0
  165. package/dist/cli/seed.js +108 -0
  166. package/dist/cli/seed.js.map +1 -0
  167. package/dist/cli/tinybee.js +247 -0
  168. package/dist/cli/tinybee.js.map +1 -0
  169. package/dist/config.js +138 -0
  170. package/dist/config.js.map +1 -0
  171. package/dist/connect/aivision-local.js +833 -0
  172. package/dist/connect/aivision-local.js.map +1 -0
  173. package/dist/connect/aivision-token.js +84 -0
  174. package/dist/connect/aivision-token.js.map +1 -0
  175. package/dist/connect/crypto.js +65 -0
  176. package/dist/connect/crypto.js.map +1 -0
  177. package/dist/connect/deps.js +110 -0
  178. package/dist/connect/deps.js.map +1 -0
  179. package/dist/connect/engines.js +144 -0
  180. package/dist/connect/engines.js.map +1 -0
  181. package/dist/connect/github-access.js +74 -0
  182. package/dist/connect/github-access.js.map +1 -0
  183. package/dist/connect/github-app.js +129 -0
  184. package/dist/connect/github-app.js.map +1 -0
  185. package/dist/connect/index.js +9 -0
  186. package/dist/connect/index.js.map +1 -0
  187. package/dist/connect/model-choices.js +201 -0
  188. package/dist/connect/model-choices.js.map +1 -0
  189. package/dist/connect/providers.js +900 -0
  190. package/dist/connect/providers.js.map +1 -0
  191. package/dist/connect/readiness.js +232 -0
  192. package/dist/connect/readiness.js.map +1 -0
  193. package/dist/connect/redact.js +16 -0
  194. package/dist/connect/redact.js.map +1 -0
  195. package/dist/connect/registry.js +406 -0
  196. package/dist/connect/registry.js.map +1 -0
  197. package/dist/connect/store.js +283 -0
  198. package/dist/connect/store.js.map +1 -0
  199. package/dist/connect/tunnel.js +134 -0
  200. package/dist/connect/tunnel.js.map +1 -0
  201. package/dist/connect/types.js +8 -0
  202. package/dist/connect/types.js.map +1 -0
  203. package/dist/connections/index.js +5 -0
  204. package/dist/connections/index.js.map +1 -0
  205. package/dist/connections/manager.js +223 -0
  206. package/dist/connections/manager.js.map +1 -0
  207. package/dist/connections/presets.js +264 -0
  208. package/dist/connections/presets.js.map +1 -0
  209. package/dist/connections/store.js +132 -0
  210. package/dist/connections/store.js.map +1 -0
  211. package/dist/connections/tools.js +206 -0
  212. package/dist/connections/tools.js.map +1 -0
  213. package/dist/db-schema.js +355 -0
  214. package/dist/db-schema.js.map +1 -0
  215. package/dist/db.js +379 -0
  216. package/dist/db.js.map +1 -0
  217. package/dist/delivery.js +49 -0
  218. package/dist/delivery.js.map +1 -0
  219. package/dist/deploy-wait.js +701 -0
  220. package/dist/deploy-wait.js.map +1 -0
  221. package/dist/disk.js +243 -0
  222. package/dist/disk.js.map +1 -0
  223. package/dist/dot-health.js +966 -0
  224. package/dist/dot-health.js.map +1 -0
  225. package/dist/dot-remove.js +246 -0
  226. package/dist/dot-remove.js.map +1 -0
  227. package/dist/events.js +38 -0
  228. package/dist/events.js.map +1 -0
  229. package/dist/evidence-pack.js +423 -0
  230. package/dist/evidence-pack.js.map +1 -0
  231. package/dist/flows/answers.js +289 -0
  232. package/dist/flows/answers.js.map +1 -0
  233. package/dist/flows/change.js +811 -0
  234. package/dist/flows/change.js.map +1 -0
  235. package/dist/flows/checkStatus.js +524 -0
  236. package/dist/flows/checkStatus.js.map +1 -0
  237. package/dist/flows/ci.js +236 -0
  238. package/dist/flows/ci.js.map +1 -0
  239. package/dist/flows/ciFailure.js +76 -0
  240. package/dist/flows/ciFailure.js.map +1 -0
  241. package/dist/flows/common.js +522 -0
  242. package/dist/flows/common.js.map +1 -0
  243. package/dist/flows/default-branch.js +29 -0
  244. package/dist/flows/default-branch.js.map +1 -0
  245. package/dist/flows/defectDraft.js +447 -0
  246. package/dist/flows/defectDraft.js.map +1 -0
  247. package/dist/flows/defects.js +623 -0
  248. package/dist/flows/defects.js.map +1 -0
  249. package/dist/flows/digest.js +295 -0
  250. package/dist/flows/digest.js.map +1 -0
  251. package/dist/flows/impact.js +82 -0
  252. package/dist/flows/impact.js.map +1 -0
  253. package/dist/flows/index.js +23 -0
  254. package/dist/flows/index.js.map +1 -0
  255. package/dist/flows/intent-sources.js +72 -0
  256. package/dist/flows/intent-sources.js.map +1 -0
  257. package/dist/flows/mergeCases.js +169 -0
  258. package/dist/flows/mergeCases.js.map +1 -0
  259. package/dist/flows/nightlyRun.js +82 -0
  260. package/dist/flows/nightlyRun.js.map +1 -0
  261. package/dist/flows/outage.js +64 -0
  262. package/dist/flows/outage.js.map +1 -0
  263. package/dist/flows/postMerge.js +5 -0
  264. package/dist/flows/postMerge.js.map +1 -0
  265. package/dist/flows/prCheck.js +5 -0
  266. package/dist/flows/prCheck.js.map +1 -0
  267. package/dist/flows/prTarget.js +66 -0
  268. package/dist/flows/prTarget.js.map +1 -0
  269. package/dist/flows/qa.js +363 -0
  270. package/dist/flows/qa.js.map +1 -0
  271. package/dist/flows/questions.js +160 -0
  272. package/dist/flows/questions.js.map +1 -0
  273. package/dist/flows/recovery.js +64 -0
  274. package/dist/flows/recovery.js.map +1 -0
  275. package/dist/flows/rerun.js +50 -0
  276. package/dist/flows/rerun.js.map +1 -0
  277. package/dist/flows/testDesign.js +294 -0
  278. package/dist/flows/testDesign.js.map +1 -0
  279. package/dist/flows/testDesignJob.js +46 -0
  280. package/dist/flows/testDesignJob.js.map +1 -0
  281. package/dist/flows/testRepo.js +228 -0
  282. package/dist/flows/testRepo.js.map +1 -0
  283. package/dist/flows/testSavings.js +381 -0
  284. package/dist/flows/testSavings.js.map +1 -0
  285. package/dist/flows/testStatus.js +343 -0
  286. package/dist/flows/testStatus.js.map +1 -0
  287. package/dist/flows/ticketContext.js +425 -0
  288. package/dist/flows/ticketContext.js.map +1 -0
  289. package/dist/flows/ticketReview.js +249 -0
  290. package/dist/flows/ticketReview.js.map +1 -0
  291. package/dist/flows/ticks.js +73 -0
  292. package/dist/flows/ticks.js.map +1 -0
  293. package/dist/hive/admin.js +122 -0
  294. package/dist/hive/admin.js.map +1 -0
  295. package/dist/hive/auth.js +130 -0
  296. package/dist/hive/auth.js.map +1 -0
  297. package/dist/hive/billing.js +278 -0
  298. package/dist/hive/billing.js.map +1 -0
  299. package/dist/hive/config.js +63 -0
  300. package/dist/hive/config.js.map +1 -0
  301. package/dist/hive/db.js +186 -0
  302. package/dist/hive/db.js.map +1 -0
  303. package/dist/hive/embed.js +76 -0
  304. package/dist/hive/embed.js.map +1 -0
  305. package/dist/hive/errors.js +17 -0
  306. package/dist/hive/errors.js.map +1 -0
  307. package/dist/hive/google.js +75 -0
  308. package/dist/hive/google.js.map +1 -0
  309. package/dist/hive/index.js +25 -0
  310. package/dist/hive/index.js.map +1 -0
  311. package/dist/hive/jwt.js +57 -0
  312. package/dist/hive/jwt.js.map +1 -0
  313. package/dist/hive/keys.js +61 -0
  314. package/dist/hive/keys.js.map +1 -0
  315. package/dist/hive/mail.js +27 -0
  316. package/dist/hive/mail.js.map +1 -0
  317. package/dist/hive/native-push.js +255 -0
  318. package/dist/hive/native-push.js.map +1 -0
  319. package/dist/hive/pairing.js +342 -0
  320. package/dist/hive/pairing.js.map +1 -0
  321. package/dist/hive/presence.js +121 -0
  322. package/dist/hive/presence.js.map +1 -0
  323. package/dist/hive/push.js +185 -0
  324. package/dist/hive/push.js.map +1 -0
  325. package/dist/hive/relay.js +205 -0
  326. package/dist/hive/relay.js.map +1 -0
  327. package/dist/hive/routes.js +228 -0
  328. package/dist/hive/routes.js.map +1 -0
  329. package/dist/hive/server.js +12 -0
  330. package/dist/hive/server.js.map +1 -0
  331. package/dist/hive/session.js +28 -0
  332. package/dist/hive/session.js.map +1 -0
  333. package/dist/hive/tenants.js +287 -0
  334. package/dist/hive/tenants.js.map +1 -0
  335. package/dist/hive/tunnel/cloudflare.js +160 -0
  336. package/dist/hive/tunnel/cloudflare.js.map +1 -0
  337. package/dist/hive/tunnel/mock.js +52 -0
  338. package/dist/hive/tunnel/mock.js.map +1 -0
  339. package/dist/hive/tunnel/provider.js +19 -0
  340. package/dist/hive/tunnel/provider.js.map +1 -0
  341. package/dist/hive/updates.js +61 -0
  342. package/dist/hive/updates.js.map +1 -0
  343. package/dist/http-error.js +11 -0
  344. package/dist/http-error.js.map +1 -0
  345. package/dist/impact/classify.js +226 -0
  346. package/dist/impact/classify.js.map +1 -0
  347. package/dist/impact/find.js +259 -0
  348. package/dist/impact/find.js.map +1 -0
  349. package/dist/impact/pr.js +54 -0
  350. package/dist/impact/pr.js.map +1 -0
  351. package/dist/impact/store.js +365 -0
  352. package/dist/impact/store.js.map +1 -0
  353. package/dist/impact/text.js +158 -0
  354. package/dist/impact/text.js.map +1 -0
  355. package/dist/index.js +288 -0
  356. package/dist/index.js.map +1 -0
  357. package/dist/integrations/adf.js +397 -0
  358. package/dist/integrations/adf.js.map +1 -0
  359. package/dist/integrations/bot-marker.js +103 -0
  360. package/dist/integrations/bot-marker.js.map +1 -0
  361. package/dist/integrations/github-issues.js +705 -0
  362. package/dist/integrations/github-issues.js.map +1 -0
  363. package/dist/integrations/github.js +1284 -0
  364. package/dist/integrations/github.js.map +1 -0
  365. package/dist/integrations/issue-create.js +60 -0
  366. package/dist/integrations/issue-create.js.map +1 -0
  367. package/dist/integrations/jira.js +279 -0
  368. package/dist/integrations/jira.js.map +1 -0
  369. package/dist/integrations/linear.js +273 -0
  370. package/dist/integrations/linear.js.map +1 -0
  371. package/dist/integrations/own-identity-warm.js +47 -0
  372. package/dist/integrations/own-identity-warm.js.map +1 -0
  373. package/dist/integrations/own-identity.js +39 -0
  374. package/dist/integrations/own-identity.js.map +1 -0
  375. package/dist/integrations/status-change.js +42 -0
  376. package/dist/integrations/status-change.js.map +1 -0
  377. package/dist/lead-defects.js +202 -0
  378. package/dist/lead-defects.js.map +1 -0
  379. package/dist/lead-digest.js +333 -0
  380. package/dist/lead-digest.js.map +1 -0
  381. package/dist/lead-release.js +286 -0
  382. package/dist/lead-release.js.map +1 -0
  383. package/dist/lead.js +328 -0
  384. package/dist/lead.js.map +1 -0
  385. package/dist/legacy-names.js +51 -0
  386. package/dist/legacy-names.js.map +1 -0
  387. package/dist/limits.js +44 -0
  388. package/dist/limits.js.map +1 -0
  389. package/dist/link-trust.js +224 -0
  390. package/dist/link-trust.js.map +1 -0
  391. package/dist/links.js +219 -0
  392. package/dist/links.js.map +1 -0
  393. package/dist/loopback.js +35 -0
  394. package/dist/loopback.js.map +1 -0
  395. package/dist/model-cap.js +60 -0
  396. package/dist/model-cap.js.map +1 -0
  397. package/dist/model-usage.js +173 -0
  398. package/dist/model-usage.js.map +1 -0
  399. package/dist/monitor/backfill.js +39 -0
  400. package/dist/monitor/backfill.js.map +1 -0
  401. package/dist/monitor/browser-probe.js +198 -0
  402. package/dist/monitor/browser-probe.js.map +1 -0
  403. package/dist/monitor/catch-up.js +31 -0
  404. package/dist/monitor/catch-up.js.map +1 -0
  405. package/dist/monitor/pollers.js +1606 -0
  406. package/dist/monitor/pollers.js.map +1 -0
  407. package/dist/monitor/probes.js +178 -0
  408. package/dist/monitor/probes.js.map +1 -0
  409. package/dist/monitor/self-health.js +228 -0
  410. package/dist/monitor/self-health.js.map +1 -0
  411. package/dist/monitor/statuspage.js +105 -0
  412. package/dist/monitor/statuspage.js.map +1 -0
  413. package/dist/nightly-scheduler.js +127 -0
  414. package/dist/nightly-scheduler.js.map +1 -0
  415. package/dist/nightly.js +141 -0
  416. package/dist/nightly.js.map +1 -0
  417. package/dist/notify/headline.js +114 -0
  418. package/dist/notify/headline.js.map +1 -0
  419. package/dist/notify/push.js +174 -0
  420. package/dist/notify/push.js.map +1 -0
  421. package/dist/object-cards.js +585 -0
  422. package/dist/object-cards.js.map +1 -0
  423. package/dist/object-links.js +47 -0
  424. package/dist/object-links.js.map +1 -0
  425. package/dist/onboarding-checks.js +141 -0
  426. package/dist/onboarding-checks.js.map +1 -0
  427. package/dist/onboarding.js +401 -0
  428. package/dist/onboarding.js.map +1 -0
  429. package/dist/path-filters.js +62 -0
  430. package/dist/path-filters.js.map +1 -0
  431. package/dist/phone/alerts.js +67 -0
  432. package/dist/phone/alerts.js.map +1 -0
  433. package/dist/phone/auth.js +240 -0
  434. package/dist/phone/auth.js.map +1 -0
  435. package/dist/phone/pairing.js +442 -0
  436. package/dist/phone/pairing.js.map +1 -0
  437. package/dist/phone/prefs.js +27 -0
  438. package/dist/phone/prefs.js.map +1 -0
  439. package/dist/phone/tailscale.js +161 -0
  440. package/dist/phone/tailscale.js.map +1 -0
  441. package/dist/pr-scope.js +441 -0
  442. package/dist/pr-scope.js.map +1 -0
  443. package/dist/proc.js +156 -0
  444. package/dist/proc.js.map +1 -0
  445. package/dist/profile/cache.js +108 -0
  446. package/dist/profile/cache.js.map +1 -0
  447. package/dist/profile/ci.js +216 -0
  448. package/dist/profile/ci.js.map +1 -0
  449. package/dist/profile/index.js +8 -0
  450. package/dist/profile/index.js.map +1 -0
  451. package/dist/profile/job.js +135 -0
  452. package/dist/profile/job.js.map +1 -0
  453. package/dist/profile/queries/go-tags.scm +47 -0
  454. package/dist/profile/queries/java-tags.scm +25 -0
  455. package/dist/profile/queries/javascript-tags.scm +104 -0
  456. package/dist/profile/queries/python-tags.scm +19 -0
  457. package/dist/profile/queries/typescript-tags.scm +28 -0
  458. package/dist/profile/scan-thread.js +42 -0
  459. package/dist/profile/scan-thread.js.map +1 -0
  460. package/dist/profile/scan-worker.js +16 -0
  461. package/dist/profile/scan-worker.js.map +1 -0
  462. package/dist/profile/scan.js +351 -0
  463. package/dist/profile/scan.js.map +1 -0
  464. package/dist/profile/stack.js +528 -0
  465. package/dist/profile/stack.js.map +1 -0
  466. package/dist/profile/store.js +35 -0
  467. package/dist/profile/store.js.map +1 -0
  468. package/dist/profile/tests.js +399 -0
  469. package/dist/profile/tests.js.map +1 -0
  470. package/dist/queue.js +350 -0
  471. package/dist/queue.js.map +1 -0
  472. package/dist/refs.js +756 -0
  473. package/dist/refs.js.map +1 -0
  474. package/dist/release-notes.js +272 -0
  475. package/dist/release-notes.js.map +1 -0
  476. package/dist/reports/build.js +243 -0
  477. package/dist/reports/build.js.map +1 -0
  478. package/dist/reports/index.js +211 -0
  479. package/dist/reports/index.js.map +1 -0
  480. package/dist/reports/store.js +150 -0
  481. package/dist/reports/store.js.map +1 -0
  482. package/dist/reports/ticket-titles.js +124 -0
  483. package/dist/reports/ticket-titles.js.map +1 -0
  484. package/dist/reports/trace-map.js +1278 -0
  485. package/dist/reports/trace-map.js.map +1 -0
  486. package/dist/reports/traceability.js +422 -0
  487. package/dist/reports/traceability.js.map +1 -0
  488. package/dist/repos/mirror.js +356 -0
  489. package/dist/repos/mirror.js.map +1 -0
  490. package/dist/repos-github.js +108 -0
  491. package/dist/repos-github.js.map +1 -0
  492. package/dist/repos.js +891 -0
  493. package/dist/repos.js.map +1 -0
  494. package/dist/review/backend-anthropic.js +90 -0
  495. package/dist/review/backend-anthropic.js.map +1 -0
  496. package/dist/review/backend-cli.js +248 -0
  497. package/dist/review/backend-cli.js.map +1 -0
  498. package/dist/review/backend-codex.js +81 -0
  499. package/dist/review/backend-codex.js.map +1 -0
  500. package/dist/review/backend-mock.js +686 -0
  501. package/dist/review/backend-mock.js.map +1 -0
  502. package/dist/review/backend-only.js +168 -0
  503. package/dist/review/backend-only.js.map +1 -0
  504. package/dist/review/backend.js +105 -0
  505. package/dist/review/backend.js.map +1 -0
  506. package/dist/review/baseline/render-v1.js +483 -0
  507. package/dist/review/baseline/render-v1.js.map +1 -0
  508. package/dist/review/change-summary.js +197 -0
  509. package/dist/review/change-summary.js.map +1 -0
  510. package/dist/review/changelog.js +40 -0
  511. package/dist/review/changelog.js.map +1 -0
  512. package/dist/review/check.js +494 -0
  513. package/dist/review/check.js.map +1 -0
  514. package/dist/review/checkout.js +185 -0
  515. package/dist/review/checkout.js.map +1 -0
  516. package/dist/review/classify.js +178 -0
  517. package/dist/review/classify.js.map +1 -0
  518. package/dist/review/coverage.js +347 -0
  519. package/dist/review/coverage.js.map +1 -0
  520. package/dist/review/decision-eval.js +121 -0
  521. package/dist/review/decision-eval.js.map +1 -0
  522. package/dist/review/deliver.js +104 -0
  523. package/dist/review/deliver.js.map +1 -0
  524. package/dist/review/designer-eval.js +280 -0
  525. package/dist/review/designer-eval.js.map +1 -0
  526. package/dist/review/dogfood-digest.js +136 -0
  527. package/dist/review/dogfood-digest.js.map +1 -0
  528. package/dist/review/dogfood-eval.js +486 -0
  529. package/dist/review/dogfood-eval.js.map +1 -0
  530. package/dist/review/environment.js +109 -0
  531. package/dist/review/environment.js.map +1 -0
  532. package/dist/review/eval.js +405 -0
  533. package/dist/review/eval.js.map +1 -0
  534. package/dist/review/glob.js +110 -0
  535. package/dist/review/glob.js.map +1 -0
  536. package/dist/review/golden-export.js +219 -0
  537. package/dist/review/golden-export.js.map +1 -0
  538. package/dist/review/impact.js +406 -0
  539. package/dist/review/impact.js.map +1 -0
  540. package/dist/review/imports.js +542 -0
  541. package/dist/review/imports.js.map +1 -0
  542. package/dist/review/index.js +512 -0
  543. package/dist/review/index.js.map +1 -0
  544. package/dist/review/intent.js +128 -0
  545. package/dist/review/intent.js.map +1 -0
  546. package/dist/review/lenses.js +167 -0
  547. package/dist/review/lenses.js.map +1 -0
  548. package/dist/review/linked-tickets.js +293 -0
  549. package/dist/review/linked-tickets.js.map +1 -0
  550. package/dist/review/merge.js +370 -0
  551. package/dist/review/merge.js.map +1 -0
  552. package/dist/review/on-demand.js +218 -0
  553. package/dist/review/on-demand.js.map +1 -0
  554. package/dist/review/prompt-eval.js +299 -0
  555. package/dist/review/prompt-eval.js.map +1 -0
  556. package/dist/review/prompt-variants.js +37 -0
  557. package/dist/review/prompt-variants.js.map +1 -0
  558. package/dist/review/readability-eval.js +217 -0
  559. package/dist/review/readability-eval.js.map +1 -0
  560. package/dist/review/readability.js +295 -0
  561. package/dist/review/readability.js.map +1 -0
  562. package/dist/review/render.js +2409 -0
  563. package/dist/review/render.js.map +1 -0
  564. package/dist/review/repo.js +194 -0
  565. package/dist/review/repo.js.map +1 -0
  566. package/dist/review/report-plan.js +90 -0
  567. package/dist/review/report-plan.js.map +1 -0
  568. package/dist/review/routes.js +195 -0
  569. package/dist/review/routes.js.map +1 -0
  570. package/dist/review/run-summary.js +34 -0
  571. package/dist/review/run-summary.js.map +1 -0
  572. package/dist/review/run.js +245 -0
  573. package/dist/review/run.js.map +1 -0
  574. package/dist/review/scope.js +454 -0
  575. package/dist/review/scope.js.map +1 -0
  576. package/dist/review/security.js +432 -0
  577. package/dist/review/security.js.map +1 -0
  578. package/dist/review/signals.js +550 -0
  579. package/dist/review/signals.js.map +1 -0
  580. package/dist/review/specs.js +150 -0
  581. package/dist/review/specs.js.map +1 -0
  582. package/dist/review/ste.js +133 -0
  583. package/dist/review/ste.js.map +1 -0
  584. package/dist/review/test-repo-file.js +18 -0
  585. package/dist/review/test-repo-file.js.map +1 -0
  586. package/dist/review/test-repo-lines.js +53 -0
  587. package/dist/review/test-repo-lines.js.map +1 -0
  588. package/dist/review/ticket-on-demand.js +232 -0
  589. package/dist/review/ticket-on-demand.js.map +1 -0
  590. package/dist/review/yaml.js +298 -0
  591. package/dist/review/yaml.js.map +1 -0
  592. package/dist/room.js +361 -0
  593. package/dist/room.js.map +1 -0
  594. package/dist/routes/activity.js +219 -0
  595. package/dist/routes/activity.js.map +1 -0
  596. package/dist/routes/call.js +29 -0
  597. package/dist/routes/call.js.map +1 -0
  598. package/dist/routes/cards.js +40 -0
  599. package/dist/routes/cards.js.map +1 -0
  600. package/dist/routes/cases.js +133 -0
  601. package/dist/routes/cases.js.map +1 -0
  602. package/dist/routes/connect.js +268 -0
  603. package/dist/routes/connect.js.map +1 -0
  604. package/dist/routes/connection-presets.js +32 -0
  605. package/dist/routes/connection-presets.js.map +1 -0
  606. package/dist/routes/connections.js +177 -0
  607. package/dist/routes/connections.js.map +1 -0
  608. package/dist/routes/disk.js +19 -0
  609. package/dist/routes/disk.js.map +1 -0
  610. package/dist/routes/docs.js +71 -0
  611. package/dist/routes/docs.js.map +1 -0
  612. package/dist/routes/dot-suggest.js +1002 -0
  613. package/dist/routes/dot-suggest.js.map +1 -0
  614. package/dist/routes/evidence-pack.js +16 -0
  615. package/dist/routes/evidence-pack.js.map +1 -0
  616. package/dist/routes/health.js +121 -0
  617. package/dist/routes/health.js.map +1 -0
  618. package/dist/routes/impact.js +48 -0
  619. package/dist/routes/impact.js.map +1 -0
  620. package/dist/routes/lead.js +50 -0
  621. package/dist/routes/lead.js.map +1 -0
  622. package/dist/routes/links.js +13 -0
  623. package/dist/routes/links.js.map +1 -0
  624. package/dist/routes/markdown.js +62 -0
  625. package/dist/routes/markdown.js.map +1 -0
  626. package/dist/routes/onboarding.js +47 -0
  627. package/dist/routes/onboarding.js.map +1 -0
  628. package/dist/routes/phone.js +231 -0
  629. package/dist/routes/phone.js.map +1 -0
  630. package/dist/routes/release-notes.js +30 -0
  631. package/dist/routes/release-notes.js.map +1 -0
  632. package/dist/routes/reports.js +102 -0
  633. package/dist/routes/reports.js.map +1 -0
  634. package/dist/routes/repos.js +91 -0
  635. package/dist/routes/repos.js.map +1 -0
  636. package/dist/routes/review.js +283 -0
  637. package/dist/routes/review.js.map +1 -0
  638. package/dist/routes/roles.js +114 -0
  639. package/dist/routes/roles.js.map +1 -0
  640. package/dist/routes/room.js +21 -0
  641. package/dist/routes/room.js.map +1 -0
  642. package/dist/routes/runner.js +156 -0
  643. package/dist/routes/runner.js.map +1 -0
  644. package/dist/routes/runs.js +84 -0
  645. package/dist/routes/runs.js.map +1 -0
  646. package/dist/routes/setup.js +18 -0
  647. package/dist/routes/setup.js.map +1 -0
  648. package/dist/routes/test-runs.js +220 -0
  649. package/dist/routes/test-runs.js.map +1 -0
  650. package/dist/routes/ticket-status.js +17 -0
  651. package/dist/routes/ticket-status.js.map +1 -0
  652. package/dist/routes/traceability.js +143 -0
  653. package/dist/routes/traceability.js.map +1 -0
  654. package/dist/routes/true.js +142 -0
  655. package/dist/routes/true.js.map +1 -0
  656. package/dist/routes/updates.js +70 -0
  657. package/dist/routes/updates.js.map +1 -0
  658. package/dist/runner/adapters/index.js +12 -0
  659. package/dist/runner/adapters/index.js.map +1 -0
  660. package/dist/runner/adapters/playwright.js +68 -0
  661. package/dist/runner/adapters/playwright.js.map +1 -0
  662. package/dist/runner/aivision/cases.js +172 -0
  663. package/dist/runner/aivision/cases.js.map +1 -0
  664. package/dist/runner/aivision/cli.js +201 -0
  665. package/dist/runner/aivision/cli.js.map +1 -0
  666. package/dist/runner/aivision/index.js +281 -0
  667. package/dist/runner/aivision/index.js.map +1 -0
  668. package/dist/runner/aivision/server.js +394 -0
  669. package/dist/runner/aivision/server.js.map +1 -0
  670. package/dist/runner/aivision/shared.js +140 -0
  671. package/dist/runner/aivision/shared.js.map +1 -0
  672. package/dist/runner/artifact-cap.js +189 -0
  673. package/dist/runner/artifact-cap.js.map +1 -0
  674. package/dist/runner/artifacts.js +433 -0
  675. package/dist/runner/artifacts.js.map +1 -0
  676. package/dist/runner/command.js +564 -0
  677. package/dist/runner/command.js.map +1 -0
  678. package/dist/runner/copyfiles.js +221 -0
  679. package/dist/runner/copyfiles.js.map +1 -0
  680. package/dist/runner/engines.js +32 -0
  681. package/dist/runner/engines.js.map +1 -0
  682. package/dist/runner/evidence.js +114 -0
  683. package/dist/runner/evidence.js.map +1 -0
  684. package/dist/runner/host-env.js +160 -0
  685. package/dist/runner/host-env.js.map +1 -0
  686. package/dist/runner/index.js +1221 -0
  687. package/dist/runner/index.js.map +1 -0
  688. package/dist/runner/observe.js +603 -0
  689. package/dist/runner/observe.js.map +1 -0
  690. package/dist/runner/playwright-json.js +108 -0
  691. package/dist/runner/playwright-json.js.map +1 -0
  692. package/dist/runner/pwgen/exec.js +192 -0
  693. package/dist/runner/pwgen/exec.js.map +1 -0
  694. package/dist/runner/pwgen/explore.js +111 -0
  695. package/dist/runner/pwgen/explore.js.map +1 -0
  696. package/dist/runner/pwgen/index.js +423 -0
  697. package/dist/runner/pwgen/index.js.map +1 -0
  698. package/dist/runner/pwgen/propose.js +69 -0
  699. package/dist/runner/pwgen/propose.js.map +1 -0
  700. package/dist/runner/pwgen/source.js +632 -0
  701. package/dist/runner/pwgen/source.js.map +1 -0
  702. package/dist/runner/setup.js +222 -0
  703. package/dist/runner/setup.js.map +1 -0
  704. package/dist/runner/step-reporter.js +107 -0
  705. package/dist/runner/step-reporter.js.map +1 -0
  706. package/dist/runner/test-repo.js +326 -0
  707. package/dist/runner/test-repo.js.map +1 -0
  708. package/dist/runner/typed-value.js +46 -0
  709. package/dist/runner/typed-value.js.map +1 -0
  710. package/dist/runner/verify.js +133 -0
  711. package/dist/runner/verify.js.map +1 -0
  712. package/dist/runner/worktree.js +349 -0
  713. package/dist/runner/worktree.js.map +1 -0
  714. package/dist/sandbox.js +61 -0
  715. package/dist/sandbox.js.map +1 -0
  716. package/dist/server.js +262 -0
  717. package/dist/server.js.map +1 -0
  718. package/dist/shadow-week.js +126 -0
  719. package/dist/shadow-week.js.map +1 -0
  720. package/dist/shutdown.js +92 -0
  721. package/dist/shutdown.js.map +1 -0
  722. package/dist/slack/index.js +645 -0
  723. package/dist/slack/index.js.map +1 -0
  724. package/dist/stages/config.js +147 -0
  725. package/dist/stages/config.js.map +1 -0
  726. package/dist/stages/index.js +41 -0
  727. package/dist/stages/index.js.map +1 -0
  728. package/dist/suites.js +293 -0
  729. package/dist/suites.js.map +1 -0
  730. package/dist/target-url.js +116 -0
  731. package/dist/target-url.js.map +1 -0
  732. package/dist/test-runs.js +662 -0
  733. package/dist/test-runs.js.map +1 -0
  734. package/dist/ticket-keys.js +97 -0
  735. package/dist/ticket-keys.js.map +1 -0
  736. package/dist/ticket-supersede.js +105 -0
  737. package/dist/ticket-supersede.js.map +1 -0
  738. package/dist/tinybee/ed25519.js +99 -0
  739. package/dist/tinybee/ed25519.js.map +1 -0
  740. package/dist/tinybee/models-routes.js +19 -0
  741. package/dist/tinybee/models-routes.js.map +1 -0
  742. package/dist/tinybee/pair-payload.js +41 -0
  743. package/dist/tinybee/pair-payload.js.map +1 -0
  744. package/dist/tinybee/update-manifest.js +77 -0
  745. package/dist/tinybee/update-manifest.js.map +1 -0
  746. package/dist/tinybee/well-known.js +64 -0
  747. package/dist/tinybee/well-known.js.map +1 -0
  748. package/dist/tinybee/workflows/activity.js +23 -0
  749. package/dist/tinybee/workflows/activity.js.map +1 -0
  750. package/dist/tinybee/workflows/cron.js +210 -0
  751. package/dist/tinybee/workflows/cron.js.map +1 -0
  752. package/dist/tinybee/workflows/engine.js +371 -0
  753. package/dist/tinybee/workflows/engine.js.map +1 -0
  754. package/dist/tinybee/workflows/from-text.js +203 -0
  755. package/dist/tinybee/workflows/from-text.js.map +1 -0
  756. package/dist/tinybee/workflows/routes.js +189 -0
  757. package/dist/tinybee/workflows/routes.js.map +1 -0
  758. package/dist/tinybee/workflows/scheduler.js +100 -0
  759. package/dist/tinybee/workflows/scheduler.js.map +1 -0
  760. package/dist/tinybee/workflows/skills.js +227 -0
  761. package/dist/tinybee/workflows/skills.js.map +1 -0
  762. package/dist/tinybee/workflows/store.js +205 -0
  763. package/dist/tinybee/workflows/store.js.map +1 -0
  764. package/dist/tinybee/workflows/types.js +180 -0
  765. package/dist/tinybee/workflows/types.js.map +1 -0
  766. package/dist/tinybee/workflows/yaml.js +323 -0
  767. package/dist/tinybee/workflows/yaml.js.map +1 -0
  768. package/dist/true/api.js +495 -0
  769. package/dist/true/api.js.map +1 -0
  770. package/dist/true/client.js +292 -0
  771. package/dist/true/client.js.map +1 -0
  772. package/dist/true/clock.js +36 -0
  773. package/dist/true/clock.js.map +1 -0
  774. package/dist/true/events.js +125 -0
  775. package/dist/true/events.js.map +1 -0
  776. package/dist/true/hosts.js +98 -0
  777. package/dist/true/hosts.js.map +1 -0
  778. package/dist/true/index.js +29 -0
  779. package/dist/true/index.js.map +1 -0
  780. package/dist/true/key.js +54 -0
  781. package/dist/true/key.js.map +1 -0
  782. package/dist/true/line.js +69 -0
  783. package/dist/true/line.js.map +1 -0
  784. package/dist/true/mask.js +31 -0
  785. package/dist/true/mask.js.map +1 -0
  786. package/dist/true/names.js +114 -0
  787. package/dist/true/names.js.map +1 -0
  788. package/dist/true/outbox.js +233 -0
  789. package/dist/true/outbox.js.map +1 -0
  790. package/dist/true/replay.js +164 -0
  791. package/dist/true/replay.js.map +1 -0
  792. package/dist/true/settings.js +123 -0
  793. package/dist/true/settings.js.map +1 -0
  794. package/dist/true/status.js +189 -0
  795. package/dist/true/status.js.map +1 -0
  796. package/dist/true/sync-cases.js +222 -0
  797. package/dist/true/sync-cases.js.map +1 -0
  798. package/dist/true/sync-manual.js +295 -0
  799. package/dist/true/sync-manual.js.map +1 -0
  800. package/dist/true/sync-runs.js +109 -0
  801. package/dist/true/sync-runs.js.map +1 -0
  802. package/dist/true/worker.js +414 -0
  803. package/dist/true/worker.js.map +1 -0
  804. package/dist/types.js +32 -0
  805. package/dist/types.js.map +1 -0
  806. package/dist/updates/asks.js +38 -0
  807. package/dist/updates/asks.js.map +1 -0
  808. package/dist/updates/index.js +835 -0
  809. package/dist/updates/index.js.map +1 -0
  810. package/dist/updates/owner.js +24 -0
  811. package/dist/updates/owner.js.map +1 -0
  812. package/dist/updates/prefs.js +118 -0
  813. package/dist/updates/prefs.js.map +1 -0
  814. package/dist/updates/route.js +78 -0
  815. package/dist/updates/route.js.map +1 -0
  816. package/dist/updates/sources.js +345 -0
  817. package/dist/updates/sources.js.map +1 -0
  818. package/dist/updates/words.js +452 -0
  819. package/dist/updates/words.js.map +1 -0
  820. package/dist/version.js +53 -0
  821. package/dist/version.js.map +1 -0
  822. package/dist/view-compute.js +382 -0
  823. package/dist/view-compute.js.map +1 -0
  824. package/dist/view-spec.js +894 -0
  825. package/dist/view-spec.js.map +1 -0
  826. package/dist/web/apple-touch-icon.png +0 -0
  827. package/dist/web/assets/ApprovalCard-Br_z5z7G.css +1 -0
  828. package/dist/web/assets/ApprovalCard-CfGhGFo_.js +3 -0
  829. package/dist/web/assets/CardFromRef-BaTGmZ9c.js +2 -0
  830. package/dist/web/assets/CardFromRef-DO7i2uDd.css +1 -0
  831. package/dist/web/assets/Cases-8l_6UcLh.js +2 -0
  832. package/dist/web/assets/Cases-CpfED0uB.css +1 -0
  833. package/dist/web/assets/Chat-BKDiR0qt.js +3 -0
  834. package/dist/web/assets/Chat-DxjdyYUu.css +1 -0
  835. package/dist/web/assets/ConfirmDialog-CIMveD-b.js +2 -0
  836. package/dist/web/assets/ConnectSheet-Cm5vbZdR.js +4 -0
  837. package/dist/web/assets/Docs-HKGuY0WE.js +2 -0
  838. package/dist/web/assets/Docs-fodKx8S7.css +1 -0
  839. package/dist/web/assets/DotDetail-DskS3NWe.js +2 -0
  840. package/dist/web/assets/DotDetail-OWRSD_1x.css +1 -0
  841. package/dist/web/assets/DotStage-BZDclfzV.css +1 -0
  842. package/dist/web/assets/DotStage-CtMNzCN3.js +2 -0
  843. package/dist/web/assets/Dots-BqCsS34m.js +2 -0
  844. package/dist/web/assets/EvidencePack-DQ3kCJX4.js +2 -0
  845. package/dist/web/assets/EvidencePack-DV_9ETsA.css +1 -0
  846. package/dist/web/assets/FailedDeliveries-1F2kFcs9.js +2 -0
  847. package/dist/web/assets/FailedDeliveries-DXa2_VvI.css +1 -0
  848. package/dist/web/assets/Feed-5wiHRTFK.js +2 -0
  849. package/dist/web/assets/GfmView-C-NYaduC.js +4 -0
  850. package/dist/web/assets/ImpactList-C-RNuDB0.js +2 -0
  851. package/dist/web/assets/ImpactList-C612dFdw.css +1 -0
  852. package/dist/web/assets/Inbox-kc1bKVL_.js +2 -0
  853. package/dist/web/assets/JoinScreen-C3L4wmP3.js +2 -0
  854. package/dist/web/assets/JoinScreen-COeAUv5v.css +1 -0
  855. package/dist/web/assets/LeadDialog-N3Zul9Rw.js +8 -0
  856. package/dist/web/assets/LeadDialog-xyWjAuAS.css +1 -0
  857. package/dist/web/assets/ListeningLine-BRFNaczY.js +2 -0
  858. package/dist/web/assets/ListeningLine-pN8CgyiK.css +1 -0
  859. package/dist/web/assets/Mascots-pIyGpxtD.js +2 -0
  860. package/dist/web/assets/ModelChoices-BxO1zyyr.js +2 -0
  861. package/dist/web/assets/ModelChoices-DQJnVxfs.css +1 -0
  862. package/dist/web/assets/NewDotDialog-CDPUWmgN.js +2 -0
  863. package/dist/web/assets/NewDotDialog-DrPPqkSZ.css +1 -0
  864. package/dist/web/assets/NewTestRunDialog-BQBthVHE.js +2 -0
  865. package/dist/web/assets/NoBreakNames-Csxdqdt6.js +2 -0
  866. package/dist/web/assets/Pair-omex_K7H.js +2 -0
  867. package/dist/web/assets/PushSection-CmqHlE_2.js +2 -0
  868. package/dist/web/assets/ReleaseNotes-B6VqFewP.js +2 -0
  869. package/dist/web/assets/ReleaseNotes-DBJUL7Vm.css +1 -0
  870. package/dist/web/assets/ReportPage-BHS1xWEt.js +162 -0
  871. package/dist/web/assets/Reports-BEHnDIb1.js +2 -0
  872. package/dist/web/assets/ReviewChangeDialog-BVSt-cw-.js +2 -0
  873. package/dist/web/assets/ReviewChangeDialog-BbIlHRx0.css +1 -0
  874. package/dist/web/assets/Room-BoG_uge4.js +2 -0
  875. package/dist/web/assets/Room-evAfiW_e.css +1 -0
  876. package/dist/web/assets/RunActions-ZY7yf1AF.js +2 -0
  877. package/dist/web/assets/RunDetail-C8St20GQ.css +1 -0
  878. package/dist/web/assets/RunDetail-qADXjBvd.js +9 -0
  879. package/dist/web/assets/RunRow-BKEJv8ib.js +2 -0
  880. package/dist/web/assets/RunnerTry-Dgpp67-s.js +6 -0
  881. package/dist/web/assets/RunnerTry-DsweWOfO.css +1 -0
  882. package/dist/web/assets/Settings-fs-QJwNM.js +2 -0
  883. package/dist/web/assets/Setup-DI6hBEP-.js +2 -0
  884. package/dist/web/assets/TestRows-wh03T5Li.js +4 -0
  885. package/dist/web/assets/TestRun-DTOyF-Pv.js +2 -0
  886. package/dist/web/assets/TestRuns-ggDjm1Q8.js +2 -0
  887. package/dist/web/assets/TinyBeeAddLaptop-bc3pmh3T.js +2 -0
  888. package/dist/web/assets/TinyBeeAi-CkyOzhm5.js +2 -0
  889. package/dist/web/assets/TinyBeeConnections-B2K_P38u.js +2 -0
  890. package/dist/web/assets/TinyBeeHome-DSpxX5KS.js +3 -0
  891. package/dist/web/assets/TinyBeePlan-BamiLziu.js +2 -0
  892. package/dist/web/assets/TinyBeeSignup-vHcz0Wen.js +2 -0
  893. package/dist/web/assets/TinyBeeSkills-By9RLUse.js +2 -0
  894. package/dist/web/assets/TinyBeeWorkflow-DeNO7Jsh.js +2 -0
  895. package/dist/web/assets/TinyBeeWorkflowEditor-B6OGC2OT.js +2 -0
  896. package/dist/web/assets/TinyBeeWorkflows-BN4-h6lt.js +2 -0
  897. package/dist/web/assets/Trace-BBCI1aIB.css +1 -0
  898. package/dist/web/assets/Trace-aF92UWaH.js +2 -0
  899. package/dist/web/assets/UpdatesSection-CCWEbkue.js +2 -0
  900. package/dist/web/assets/Welcome-CCcy558Q.js +2 -0
  901. package/dist/web/assets/activity-C3qilrDm.css +1 -0
  902. package/dist/web/assets/activity-CBfTSxqw.js +2 -0
  903. package/dist/web/assets/authedMedia-BTYt_tyu.js +2 -0
  904. package/dist/web/assets/beeApi-BHW8Tx1s.js +2 -0
  905. package/dist/web/assets/data-CmXvx3Mj.js +2 -0
  906. package/dist/web/assets/engines-CfdJODFj.css +1 -0
  907. package/dist/web/assets/format-BBZ8vFyT.js +2 -0
  908. package/dist/web/assets/forms-Coc7p2UF.css +1 -0
  909. package/dist/web/assets/hivePush-DZJDokj7.js +2 -0
  910. package/dist/web/assets/impactModel-MY1OFuiP.js +2 -0
  911. package/dist/web/assets/index-B6qKm1NW.js +13 -0
  912. package/dist/web/assets/index-BvKyT1X7.css +1 -0
  913. package/dist/web/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  914. package/dist/web/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  915. package/dist/web/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  916. package/dist/web/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  917. package/dist/web/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  918. package/dist/web/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  919. package/dist/web/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  920. package/dist/web/assets/lead-BL_P_kri.css +1 -0
  921. package/dist/web/assets/model-BIQy5IVG.js +2 -0
  922. package/dist/web/assets/modelsApi-PUSySRQw.js +2 -0
  923. package/dist/web/assets/newDotModel-BaLLyw57.js +2 -0
  924. package/dist/web/assets/onboarding-bfKqnM4Z.css +1 -0
  925. package/dist/web/assets/phone-Rs7FoyG0.css +1 -0
  926. package/dist/web/assets/phoneApi-BG_1-M-D.js +3 -0
  927. package/dist/web/assets/releaseModel-EynYMVOC.js +2 -0
  928. package/dist/web/assets/releaseNotesModel-A1Rtv3cV.js +2 -0
  929. package/dist/web/assets/reports-BWaA1HhM.js +37 -0
  930. package/dist/web/assets/reports-DXwdWQsB.css +1 -0
  931. package/dist/web/assets/router-W6nZsQ33.js +2 -0
  932. package/dist/web/assets/runs-BY0Owv93.css +1 -0
  933. package/dist/web/assets/shadowWeekModel-BUUiww09.js +2 -0
  934. package/dist/web/assets/storage-yvL36AWt.js +2 -0
  935. package/dist/web/assets/store-IqrqHuFR.js +2 -0
  936. package/dist/web/assets/testruns-BzIZ0cR0.css +1 -0
  937. package/dist/web/assets/testruns-DyaqX4ji.js +2 -0
  938. package/dist/web/assets/true-9Q68cs5b.js +2 -0
  939. package/dist/web/assets/true-DPGBpoir.css +1 -0
  940. package/dist/web/assets/ui-DcmhYyYp.js +13 -0
  941. package/dist/web/assets/ui-DxEDgbIx.css +1 -0
  942. package/dist/web/assets/usePauseDot-BV60ZVy1.js +2 -0
  943. package/dist/web/assets/usePauseDot-NrSzMI1C.css +1 -0
  944. package/dist/web/assets/usePush-Dsm-TjlG.js +2 -0
  945. package/dist/web/assets/useRefChips-CbafNx59.js +68 -0
  946. package/dist/web/assets/useRestoreDot-D0B6W82H.js +2 -0
  947. package/dist/web/assets/view-worker-pyeVAhUT.js +2 -0
  948. package/dist/web/assets/workflowUi-QYsd3n9J.js +2 -0
  949. package/dist/web/favicon.png +0 -0
  950. package/dist/web/icon-192.png +0 -0
  951. package/dist/web/icon-512.png +0 -0
  952. package/dist/web/icon-maskable-512.png +0 -0
  953. package/dist/web/index.html +45 -0
  954. package/dist/web/manifest.webmanifest +23 -0
  955. package/dist/web/mascots/argus-attention.svg +7 -0
  956. package/dist/web/mascots/argus-ok.svg +7 -0
  957. package/dist/web/mascots/argus-outage.svg +7 -0
  958. package/dist/web/mascots/argus-running.svg +7 -0
  959. package/dist/web/mascots/bolt-attention.svg +7 -0
  960. package/dist/web/mascots/bolt-ok.svg +7 -0
  961. package/dist/web/mascots/bolt-outage.svg +7 -0
  962. package/dist/web/mascots/bolt-running.svg +7 -0
  963. package/dist/web/mascots/echo-attention.svg +7 -0
  964. package/dist/web/mascots/echo-ok.svg +7 -0
  965. package/dist/web/mascots/echo-outage.svg +7 -0
  966. package/dist/web/mascots/echo-running.svg +7 -0
  967. package/dist/web/mascots/lens-attention.svg +7 -0
  968. package/dist/web/mascots/lens-ok.svg +7 -0
  969. package/dist/web/mascots/lens-outage.svg +7 -0
  970. package/dist/web/mascots/lens-running.svg +7 -0
  971. package/dist/web/mascots/moss-attention.svg +7 -0
  972. package/dist/web/mascots/moss-ok.svg +7 -0
  973. package/dist/web/mascots/moss-outage.svg +7 -0
  974. package/dist/web/mascots/moss-running.svg +7 -0
  975. package/dist/web/mascots/nit-attention.svg +7 -0
  976. package/dist/web/mascots/nit-ok.svg +7 -0
  977. package/dist/web/mascots/nit-outage.svg +7 -0
  978. package/dist/web/mascots/nit-running.svg +7 -0
  979. package/dist/web/mascots/nova-attention.svg +7 -0
  980. package/dist/web/mascots/nova-ok.svg +7 -0
  981. package/dist/web/mascots/nova-outage.svg +7 -0
  982. package/dist/web/mascots/nova-running.svg +7 -0
  983. package/dist/web/mascots/penn-attention.svg +7 -0
  984. package/dist/web/mascots/penn-ok.svg +7 -0
  985. package/dist/web/mascots/penn-outage.svg +7 -0
  986. package/dist/web/mascots/penn-running.svg +7 -0
  987. package/dist/web/mascots/pip-attention.svg +7 -0
  988. package/dist/web/mascots/pip-ok.svg +7 -0
  989. package/dist/web/mascots/pip-outage.svg +7 -0
  990. package/dist/web/mascots/pip-running.svg +7 -0
  991. package/dist/web/mascots/ward-attention.svg +7 -0
  992. package/dist/web/mascots/ward-ok.svg +7 -0
  993. package/dist/web/mascots/ward-outage.svg +7 -0
  994. package/dist/web/mascots/ward-running.svg +7 -0
  995. package/dist/web/sw.js +98 -0
  996. package/dist/webhook-seen.js +53 -0
  997. package/dist/webhook-seen.js.map +1 -0
  998. package/dist/webhooks.js +625 -0
  999. package/dist/webhooks.js.map +1 -0
  1000. package/dist/zip.js +63 -0
  1001. package/dist/zip.js.map +1 -0
  1002. package/docs/API-V2.md +532 -0
  1003. package/docs/CHAT-EVAL.md +130 -0
  1004. package/docs/CHAT-UI.md +416 -0
  1005. package/docs/CONNECTIONS.md +89 -0
  1006. package/docs/DATA-MODEL.md +518 -0
  1007. package/docs/DEPLOY.md +577 -0
  1008. package/docs/DOGFOOD-LEDGER.md +81 -0
  1009. package/docs/GITHUB.md +148 -0
  1010. package/docs/INTEGRATION-MODEL.md +200 -0
  1011. package/docs/LEAD-DOT.md +553 -0
  1012. package/docs/LIST-PATTERNS.md +52 -0
  1013. package/docs/MULTI-REPO.md +766 -0
  1014. package/docs/PARITY.md +276 -0
  1015. package/docs/PR-REVIEW-QA.md +1266 -0
  1016. package/docs/PR-REVIEW.md +357 -0
  1017. package/docs/SANDBOX.md +320 -0
  1018. package/docs/SETUP.md +776 -0
  1019. package/docs/SLACK.md +80 -0
  1020. package/docs/STAGES.md +619 -0
  1021. package/docs/TRACE-MAP.md +89 -0
  1022. package/docs/TRACKERS.md +225 -0
  1023. package/docs/VOICE.md +36 -0
  1024. package/docs/tinybee/00-README.md +45 -0
  1025. package/docs/tinybee/01-PRD.md +216 -0
  1026. package/docs/tinybee/02-architecture-pairing.md +199 -0
  1027. package/docs/tinybee/03-local-agent.md +222 -0
  1028. package/docs/tinybee/04-local-setup-ui.md +128 -0
  1029. package/docs/tinybee/05-mobile-app-ux.md +199 -0
  1030. package/docs/tinybee/06-environments-and-delivery.md +148 -0
  1031. package/docs/tinybee/07-coding-agent-handoff.md +116 -0
  1032. package/docs/tinybee/OPEN-QUESTIONS.md +26 -0
  1033. package/docs/tinybee/PROGRESS.md +134 -0
  1034. package/package.json +111 -4
@@ -0,0 +1,927 @@
1
+ // Custom Rules gate. Every outward action passes through gate(); the rule level for its kind
2
+ // decides whether it runs, waits for approval, or goes to a person.
3
+ import { get, insert, update } from '../db.js';
4
+ import { publish } from '../events.js';
5
+ import { config } from '../config.js';
6
+ import { DEFECT_LABEL, hasStickyMarker, isDefectLabel, githubFor, githubMode } from '../integrations/github.js';
7
+ import { issueApi, parseIssueRef, STATUS_LABELS } from '../integrations/github-issues.js';
8
+ import { executeTicketStatus } from '../integrations/status-change.js';
9
+ import { createTrackerIssue, withDefectMarker } from '../integrations/issue-create.js';
10
+ import { recordDefectLinks } from '../links.js';
11
+ import { unreadRules } from '../pr-scope.js';
12
+ import { jiraFor } from '../integrations/jira.js';
13
+ import { linearFor } from '../integrations/linear.js';
14
+ import { notify } from '../notify/push.js';
15
+ import { adoptPush, updatesOwnDelivery } from '../updates/owner.js';
16
+ import { executeMcpTool } from '../connections/index.js';
17
+ import { executeSlackPost } from '../slack/index.js';
18
+ import { executeReportEdit } from '../reports/index.js';
19
+ import { executeCaseRetire } from '../impact/store.js';
20
+ import { OUTWARD_KINDS, refuseOutward, sandboxOn } from '../sandbox.js';
21
+ import { enqueue } from '../queue.js';
22
+ import { DEFAULT_RULES, } from '../types.js';
23
+ import { checkDestination, CONTENT_RISK_REASON, DESTINATION_REASON } from './destinations.js';
24
+ import { getLlm, MockLlm } from './llm.js';
25
+ import { ModelUnavailableError } from './model-errors.js';
26
+ import { classifySendError, nextRetry, RETRY_WINDOW_MS, waitText } from './send-retry.js';
27
+ import { redactCode } from './redact.js';
28
+ import { clipCheckTitle } from '../review/render.js';
29
+ import { addAction, addStep, isRunCancelled, isRunGone, updateActionResult } from './runs.js';
30
+ import { repoFromTarget } from '../repos.js';
31
+ import { shadowLevel } from '../shadow-week.js';
32
+ import { safeRepoSpecPath } from '../runner/pwgen/propose.js';
33
+ import { classifyEscalation, setCheckCloseHook, supersedeBySent, supersedeOlder } from './approvals.js';
34
+ /** `/Users/<name>/...` and `/home/<name>/...` become `~/...`, so a posted log line does not name the host user. */
35
+ export function redactHomePaths(text) {
36
+ return text.replace(/(^|[\s(`'"=:])\/(?:Users|home)\/[A-Za-z0-9._-]+(?=\/|[\s)`'"]|$)/gm, '$1~');
37
+ }
38
+ /** Title, body, and a check run's long text and annotations, with home directories shown as ~. */
39
+ function redactActionHomePaths(action) {
40
+ const out = { ...action, title: redactHomePaths(action.title), body: redactHomePaths(action.body) };
41
+ const meta = action.meta;
42
+ if (meta && action.kind === 'check_run') {
43
+ const m = { ...meta };
44
+ if (typeof meta.text === 'string')
45
+ m.text = redactHomePaths(meta.text);
46
+ if (Array.isArray(meta.annotations))
47
+ m.annotations = meta.annotations.map((a) => a && typeof a === 'object'
48
+ ? {
49
+ ...a,
50
+ ...(typeof a.message === 'string' ? { message: redactHomePaths(a.message) } : {}),
51
+ ...(typeof a.title === 'string' ? { title: redactHomePaths(a.title) } : {}),
52
+ }
53
+ : a);
54
+ out.meta = m;
55
+ }
56
+ return out;
57
+ }
58
+ /** Kinds that leave the building and are worth a second look before they go. */
59
+ const REVIEWED = ['check_run', 'pr_comment', 'ticket_comment', 'ticket_status', 'open_pr', 'revert', 'slack_post', 'file_defect', 'issue_create'];
60
+ /**
61
+ * A Slack post may go out under rule `act` only when its producer built it from fixed strings plus
62
+ * verdict fields and marked it `meta.templated: true`. Any other Slack text can carry model output
63
+ * shaped by untrusted ticket, PR, or log content, so `act` is treated as `ask` for it.
64
+ */
65
+ export function slackPostTemplated(action) {
66
+ return action.kind === 'slack_post' && action.meta?.templated === true;
67
+ }
68
+ /** The level gate() applies: the watch rule, tightened from act to ask for a Slack post that is not templated. */
69
+ export function effectiveLevel(watch, action) {
70
+ const level = ruleFor(watch, action.kind);
71
+ if (action.kind === 'slack_post' && level === 'act' && !slackPostTemplated(action))
72
+ return 'ask';
73
+ // A case is never retired on its own (KAT-304): whatever the rule says, a person approves it, or does it by hand.
74
+ if (action.kind === 'case_retire' && level !== 'hand_off')
75
+ return 'ask';
76
+ return level;
77
+ }
78
+ /**
79
+ * A check-run status write built only from fixed strings and run progress: queued, in progress,
80
+ * superseded, or a closing note. The producer sets `meta.templated: true`. These skip auto-review
81
+ * (there is no model text in them to check), but they still follow the check_run rule.
82
+ */
83
+ export function templatedStatusWrite(action) {
84
+ return action.kind === 'check_run' && action.meta?.templated === true;
85
+ }
86
+ /** Why a first look waits for a person. */
87
+ export const FIRST_LOOK_REASON = "First look at a PR that was already open. A person approves the post. Name authors, a team or issue labels in the repo's PR scope to post on its own.";
88
+ /** Why a ticket comment or status label of a backfilled review waits for a person. */
89
+ export const BACKFILL_REASON = 'Ticket review from before the dot started. Nobody asked for it, so a person approves the comment or status label before it is posted.';
90
+ /**
91
+ * Why a PR comment or check of this run waits for a person under rule `act`, or null (KAT-352, KAT-363).
92
+ *
93
+ * A first look (the first poll): nobody asked for that review, and the PR may belong to another team of a shared repo.
94
+ *
95
+ * A PR whose scope rule could not be read: the PR ran because the dot could not tell whose it is, so what it posts waits
96
+ * until a person has looked. The reason names the rule.
97
+ *
98
+ * A review a person asked for is never held.
99
+ */
100
+ function holdReason(action, watch, runId) {
101
+ if (!runId)
102
+ return null;
103
+ const ticketWrite = action.kind === 'ticket_comment' || action.kind === 'ticket_status';
104
+ if (action.kind !== 'pr_comment' && action.kind !== 'check_run' && !ticketWrite)
105
+ return null;
106
+ const trigger = get('runs', runId)?.trigger;
107
+ if (!trigger || trigger.requestedBy)
108
+ return null;
109
+ // A ticket that was open before the dot started: nobody asked for the review, so its comment and status label wait (KAT-381).
110
+ if (ticketWrite)
111
+ return trigger.backfill === true ? BACKFILL_REASON : null;
112
+ if (trigger.firstLook === true)
113
+ return FIRST_LOOK_REASON;
114
+ const unread = unreadRules(watch, trigger);
115
+ return unread.length ? scopeUnreadReason(unread) : null;
116
+ }
117
+ /** Why a PR whose scope rule could not be read waits for a person. */
118
+ export function scopeUnreadReason(unread) {
119
+ return `PR scope not applied: could not read ${unread.join(' and ')}, so this PR was let in unchecked. A person approves the post.`;
120
+ }
121
+ export function ruleFor(watch, kind) {
122
+ // A shadow week that ended reads as the saved level at once, before the sweep writes it back (src/shadow-week.ts).
123
+ return shadowLevel(watch, kind) ?? watch.rules?.[kind] ?? DEFAULT_RULES[kind];
124
+ }
125
+ /** The rules a review of this event runs with. A review asked for without posting holds the PR comment and the check run in the Inbox (KAT-357). */
126
+ export function rulesForEvent(watch, ev) {
127
+ if (!ev.outboxOnly)
128
+ return watch;
129
+ const rules = { ...watch.rules };
130
+ for (const kind of ['pr_comment', 'check_run'])
131
+ if (ruleFor(watch, kind) === 'act')
132
+ rules[kind] = 'ask';
133
+ return { ...watch, rules };
134
+ }
135
+ function askedByUser(action) {
136
+ return action.meta?.askedBy === 'user';
137
+ }
138
+ /** No GitHub credentials means a demo install: pushes are mirrored to the outbox too. */
139
+ function demoInstall() {
140
+ return githubMode() === 'demo';
141
+ }
142
+ function runLink(runId) {
143
+ return runId ? `/#/runs/${runId}` : undefined;
144
+ }
145
+ /** A deep link the flow built (for example the run's "What to test" section). Only in-app hash links are kept. */
146
+ export function pushLink(url, runId) {
147
+ return typeof url === 'string' && /^\/#\/[\w\-/?=&.%]*$/.test(url) ? url : runLink(runId);
148
+ }
149
+ function checkAnnotations(v) {
150
+ if (!Array.isArray(v))
151
+ return undefined;
152
+ const out = v.filter((a) => !!a &&
153
+ typeof a === 'object' &&
154
+ typeof a.path === 'string' &&
155
+ Number.isInteger(a.startLine) &&
156
+ typeof a.message === 'string' &&
157
+ ['notice', 'warning', 'failure'].includes(a.level));
158
+ return out.length ? out.slice(0, 500) : undefined;
159
+ }
160
+ /** Longest body an automatic post may have before a person looks at it. The QA report summary comment has no limit. */
161
+ export const AUTO_POST_MAX_CHARS = 8000;
162
+ /** Check runs stop at GitHub's own summary limit. */
163
+ const CHECK_RUN_MAX_CHARS = 65_000;
164
+ /**
165
+ * The QA report summary comment: the one sticky PR comment that holds the full report and is edited in place. It is
166
+ * long by design (every risk, the What to test checklist, the test totals), so no length limit applies to it.
167
+ */
168
+ export function isQaReportSummary(action) {
169
+ return action.kind === 'pr_comment' && (action.meta?.sticky === true || action.meta?.reportSummary === true);
170
+ }
171
+ /** The length limit for a kind, or undefined when none applies. */
172
+ export function lengthLimit(action) {
173
+ if (isQaReportSummary(action))
174
+ return undefined;
175
+ return action.kind === 'check_run' ? CHECK_RUN_MAX_CHARS : AUTO_POST_MAX_CHARS;
176
+ }
177
+ /** A model reason about how long a draft is. Code applies the limit, so the model's view of length is not a finding. */
178
+ const LENGTH_REASON = /\b(?:unusually|too|very|overly|excessively|extremely)\s+(?:long|lengthy|large|verbose)\b|\blength\b|\bcharacters long\b/i;
179
+ const NUM = '(?:\\d+|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)';
180
+ const THING = '(?:bugs?|checks?|tests?|risks?|questions?|defects?|gaps?|issues?|findings?)';
181
+ /**
182
+ * A model reason about how many bugs, checks, tests, risks or questions a QA report states against what it records
183
+ * ("says eight checks were not tested but the records list six", "check the untested count"). Code checks the
184
+ * report counts before drafting (reportFacts, reportRefused), so the model's view of them is not a finding.
185
+ */
186
+ const COUNT_REASON = new RegExp(`\\b(?:counts?|number of|totals?)\\b|\\b${NUM}\\s+(?:[\\w-]+\\s+){0,2}${THING}\\b|\\b(?:records?|lists?|listed|lists|states?|says?|has|have|marks?|shows?|counts?)\\s+(?:only\\s+)?(?:[\\w-]+\\s+){0,2}${NUM}\\b|\\b${NUM}\\s+(?:as\\s+)?(?:not run|not tested|untested|skipped)\\b`, 'i');
187
+ /** A claim about a result (a test failed, a check passed): a person judges it, even when it holds a number. */
188
+ const RESULT_CLAIM = /\b(?:fail(?:s|ed|ing|ure|ures)?|pass(?:es|ed|ing)?|broken|breaks?|regress\w*|errors?|crash\w*|no bugs?|zero bugs?)\b/i;
189
+ /** QA report kinds: the report summary comment and a check run. Their counts are checked by code. */
190
+ export function isQaReportKind(action) {
191
+ return action.kind === 'check_run' || isQaReportSummary(action);
192
+ }
193
+ /**
194
+ * The clauses of a model reason: sentences, and the parts a comma, semicolon, "and", "but", "while", "plus" or
195
+ * "as well as" joins. "Contains a token and the body length looks odd" is two clauses, one of them a finding.
196
+ */
197
+ export function reasonClauses(reason) {
198
+ return reason
199
+ .split(/[.!?;]+(?=\s|$)|,|\b(?:and|but|while|plus|as well as)\b/i)
200
+ .map((c) => c.trim())
201
+ .filter((c) => /[\p{L}\p{N}]/u.test(c));
202
+ }
203
+ /**
204
+ * What a model reason is about when code already checked all of it: the destination, the length, or both (and, for a QA report, counts). Null
205
+ * when any clause is about something else, or names a content risk (CONTENT_RISK_REASON), because that clause
206
+ * is a real finding. Such a reason keeps its escalation.
207
+ */
208
+ export function clearableKinds(reason, opts = {}) {
209
+ const clauses = reasonClauses(reason);
210
+ if (!clauses.length)
211
+ return null;
212
+ const kinds = new Set();
213
+ for (const c of clauses) {
214
+ if (CONTENT_RISK_REASON.test(c))
215
+ return null;
216
+ if (DESTINATION_REASON.test(c))
217
+ kinds.add('destination');
218
+ else if (LENGTH_REASON.test(c))
219
+ kinds.add('length');
220
+ else if (opts.counts && COUNT_REASON.test(c) && !RESULT_CLAIM.test(c))
221
+ kinds.add('counts');
222
+ else
223
+ return null;
224
+ }
225
+ return kinds;
226
+ }
227
+ /**
228
+ * The checks code makes on every reviewed draft, before the model sees it: the destination is one of the
229
+ * dot's places to post (src/agent/destinations.ts), and the body fits the limit of its kind. Returns the
230
+ * escalation, or null when the draft passes.
231
+ */
232
+ export function deterministicReview(action, watch) {
233
+ const dest = checkDestination(action, watch);
234
+ if (!dest.ok)
235
+ return { ok: true, escalate: true, reason: dest.reason, category: 'must_not_rule' };
236
+ const limit = lengthLimit(action);
237
+ if (limit !== undefined && action.body.length > limit)
238
+ return {
239
+ ok: true,
240
+ escalate: true,
241
+ reason: `The draft is ${action.body.length} characters, over the ${limit} a ${action.kind.replace('_', ' ')} may have without a person.`,
242
+ category: 'other',
243
+ };
244
+ return null;
245
+ }
246
+ /** Why a draft waits when the review model could not answer and the code checks alone are not enough for its kind. */
247
+ export const MODEL_UNAVAILABLE_WAIT_REASON = 'Review model unavailable, waiting for a person';
248
+ /**
249
+ * What may go out on the code checks alone while the review model is down: the QA report summary comment (a
250
+ * pr_comment that carries the localdost:pr-summary marker) and a check run or commit status (kind check_run), both
251
+ * only on a GitHub repo the dot may post to. Everything else (defects, issues, ticket comments, Slack, push,
252
+ * Linear, Jira, open_pr, any other write) waits for a person. A new kind is outside this list until it is added.
253
+ */
254
+ export function mayGoOnCodeChecksAlone(action, watch) {
255
+ const dest = checkDestination(action, watch);
256
+ if (!dest.ok || dest.destination.system !== 'github')
257
+ return false;
258
+ if (action.kind === 'check_run')
259
+ return true;
260
+ return action.kind === 'pr_comment' && hasStickyMarker(action.body);
261
+ }
262
+ /**
263
+ * The review when the model could not answer (a spend cap, a quota, no usable reply). It used to escalate every
264
+ * draft (40 escalations in the dogfood ledger). Now the code checks decide, with the rule-based reviewer for
265
+ * credentials, copied instructions, destructive kinds and the must-not rule, but only for the kinds in
266
+ * mayGoOnCodeChecksAlone; every other kind waits in the Inbox. The result says the model was unavailable, and
267
+ * gate() records that on the draft.
268
+ */
269
+ async function reviewWithoutModel(action, watch, why) {
270
+ const modelUnavailable = why.trim() || 'no reply';
271
+ const ruled = await new MockLlm().review(action, watch);
272
+ const waits = () => ({
273
+ ok: true,
274
+ escalate: true,
275
+ reason: MODEL_UNAVAILABLE_WAIT_REASON,
276
+ category: 'reviewer_unavailable',
277
+ modelUnavailable,
278
+ });
279
+ // A finding about the draft itself (a credential, copied instructions, the must-not rule) keeps its own reason. A
280
+ // destructive kind (open_pr, revert) always waits, and without the model that is the reason to show.
281
+ if (ruled.escalate || !ruled.ok)
282
+ return ruled.category === 'destructive' ? waits() : { ...ruled, modelUnavailable };
283
+ if (!mayGoOnCodeChecksAlone(action, watch))
284
+ return waits();
285
+ return {
286
+ ok: true,
287
+ escalate: false,
288
+ reason: `The review model was unavailable (${modelUnavailable}); the code checks passed, so the rule decides.`,
289
+ modelUnavailable,
290
+ };
291
+ }
292
+ /** Auto-review for an outward draft: the code checks, then the model on the content. */
293
+ export async function safeReview(action, watch) {
294
+ const fixed = deterministicReview(action, watch);
295
+ if (fixed)
296
+ return fixed;
297
+ let review;
298
+ try {
299
+ review = await getLlm().review(action, watch);
300
+ }
301
+ catch (err) {
302
+ const why = err instanceof ModelUnavailableError ? err.reason : err instanceof Error ? err.message : String(err);
303
+ console.warn(`[rules] auto-review got no model answer: ${why}`);
304
+ return reviewWithoutModel(action, watch, why);
305
+ }
306
+ // A backend that got no usable decision (no reply, unreadable replies) says so with this category.
307
+ if (review.category === 'reviewer_unavailable')
308
+ return reviewWithoutModel(action, watch, review.reason.replace(/\.$/, ''));
309
+ // The model judges the content only. Code already checked the destination and the length, so a reason that is
310
+ // wholly about where the draft goes ("outside the permitted project") or how long it is is not a finding. A
311
+ // reason with any other clause (a token, a customer, anything else) keeps the escalation (KAT-305).
312
+ if (review.ok && review.escalate) {
313
+ const kinds = clearableKinds(review.reason, { counts: isQaReportKind(action) });
314
+ if (kinds) {
315
+ const parts = [];
316
+ if (kinds.has('destination')) {
317
+ const dest = checkDestination(action, watch);
318
+ console.warn(`[rules] auto-review judged the destination, which code checks (${dest.label}): ${review.reason}`);
319
+ parts.push(`Destination checked by code: ${dest.label}.`);
320
+ }
321
+ if (kinds.has('length')) {
322
+ console.warn(`[rules] auto-review judged the length, which code checks: ${review.reason}`);
323
+ parts.push(`Length checked by code: ${action.body.length} characters${isQaReportSummary(action) ? ', the QA report summary has no limit' : ''}.`);
324
+ }
325
+ if (kinds.has('counts')) {
326
+ console.warn(`[rules] auto-review judged report counts, which code checks: ${review.reason}`);
327
+ parts.push('Counts checked by code before drafting: the report counts match its records.');
328
+ }
329
+ return { ok: true, escalate: false, reason: parts.join(' ') };
330
+ }
331
+ }
332
+ return review;
333
+ }
334
+ /**
335
+ * A templated status write goes out only under rule `act` (or `act_when_asked` when a person asked).
336
+ * Any other level sends nothing: asking a person to approve "Queued, 2 ahead" would only produce a stale
337
+ * approval, and the final report still goes through the full gate. The write leaves no step or action on
338
+ * the run, so a progress update every 30 s does not fill the run page. A failed write is logged, never thrown.
339
+ */
340
+ async function gateStatusWrite(action, watch, runId) {
341
+ const level = ruleFor(watch, 'check_run');
342
+ if (level === 'hand_off')
343
+ return 'handed_off';
344
+ if (level !== 'act' && !(level === 'act_when_asked' && askedByUser(action)))
345
+ return 'blocked';
346
+ // A first look and a PR whose scope was not applied wait for a person, and a "queued" status is not worth an approval: it is not written.
347
+ if (level === 'act' && holdReason(action, watch, runId))
348
+ return 'blocked';
349
+ if (runId && isRunCancelled(runId) && action.meta?.status !== 'completed')
350
+ return 'blocked';
351
+ const safe = redactActionHomePaths({ ...action, title: redactCode(action.title), body: redactCode(action.body) });
352
+ try {
353
+ await execute(safe, watch, runId || undefined);
354
+ }
355
+ catch (err) {
356
+ console.warn(`[rules] check status write failed: ${String(err)}`);
357
+ return 'blocked';
358
+ }
359
+ // What execute learned (the new check run id) goes back to the caller's object.
360
+ if (safe.meta)
361
+ action.meta = safe.meta;
362
+ return 'executed';
363
+ }
364
+ /**
365
+ * A push from outside a run, for a job that has no run yet. Follows the push_notify rule: only `act`
366
+ * sends. Mirrored to the outbox on a demo install, like the gate's own notices. Returns whether it went out.
367
+ */
368
+ export async function notifyOwner(n, watch) {
369
+ if (ruleFor(watch, 'push_notify') !== 'act')
370
+ return false;
371
+ await sendNotice(n, watch, '');
372
+ return true;
373
+ }
374
+ export async function gate(action, watch, runId) {
375
+ if (templatedStatusWrite(action))
376
+ return gateStatusWrite(action, watch, runId);
377
+ // Redaction below copies the action; what execute() learns (a filed URL) is copied back onto the caller's object.
378
+ const caller = action;
379
+ const holdWhy = holdReason(action, watch, runId);
380
+ const held = holdWhy !== null && effectiveLevel(watch, action) === 'act';
381
+ const level = held ? 'ask' : effectiveLevel(watch, action);
382
+ // A templated Slack notice still has verdict fields in it: mask secret shapes before review and send.
383
+ if (slackPostTemplated(action))
384
+ action = { ...action, title: redactCode(action.title), body: redactCode(action.body) };
385
+ // Runner output can carry the host's home directory (and with it a username): show it as ~ instead.
386
+ if (REVIEWED.includes(action.kind))
387
+ action = redactActionHomePaths(action);
388
+ const record = (result, approvalId) => {
389
+ addAction(runId, approvalId ? { action, result, approvalId } : { action, result });
390
+ return result;
391
+ };
392
+ // A cancelled run sends nothing outward, even when its flow was already past the test stage.
393
+ if (runId && isRunCancelled(runId))
394
+ return record('blocked');
395
+ if (level === 'hand_off') {
396
+ addStep(runId, `Handed off: ${action.title}`, `Rule for ${action.kind} is hand_off; a person does this.`, 'warn');
397
+ await sendNotice({
398
+ key: `handoff:${runId}:${action.kind}`,
399
+ title: `Over to you: ${action.title}`,
400
+ body: `Your rules say a person does "${action.kind.replace('_', ' ')}". The draft is in the run.`,
401
+ url: runLink(runId),
402
+ urgency: 'normal',
403
+ }, watch, runId);
404
+ return record('handed_off');
405
+ }
406
+ if (level === 'act_when_asked' && !askedByUser(action)) {
407
+ addStep(runId, `Skipped: ${action.title}`, `Rule for ${action.kind} is act_when_asked and nobody asked.`, 'info');
408
+ return record('blocked');
409
+ }
410
+ const review = REVIEWED.includes(action.kind)
411
+ ? await safeReview(action, watch)
412
+ : { ok: true, escalate: false, reason: 'Internal action, no review needed.' };
413
+ // The review took time: the run may have been cancelled, or the dot deleted with its run row. Nothing
414
+ // below awaits before the approval insert or execute(), so this check holds until they run.
415
+ if (runId && isRunGone(runId))
416
+ return 'blocked';
417
+ if (runId && isRunCancelled(runId))
418
+ return record('blocked');
419
+ if (!get('watches', watch.id))
420
+ return 'blocked';
421
+ // No review model answered: the draft says so, on the run, in the Inbox and on the sent action.
422
+ if (review.modelUnavailable) {
423
+ action = { ...action, meta: { ...action.meta, reviewModelUnavailable: review.modelUnavailable } };
424
+ if (runId)
425
+ addStep(runId, 'Review model unavailable', `${review.modelUnavailable}. The code checks and the rule for ${action.kind} decided.`, 'warn');
426
+ }
427
+ if (level === 'ask' || review.escalate || !review.ok) {
428
+ const tightened = level === 'ask' && ruleFor(watch, action.kind) === 'act';
429
+ // A draft held only because the review model is down says so in plain words, whatever its rule level.
430
+ const modelDown = review.modelUnavailable !== undefined && review.category === 'reviewer_unavailable';
431
+ const reason = modelDown
432
+ ? MODEL_UNAVAILABLE_WAIT_REASON
433
+ : level !== 'ask'
434
+ ? `The safety check wants a person to look first. ${review.reason}`.trim()
435
+ : held
436
+ ? `${holdWhy} ${review.reason}`.trim()
437
+ : tightened
438
+ ? `Slack posts with written text wait for approval; only templated notices post on their own. ${review.reason}`.trim()
439
+ : `Rule for ${action.kind} is ask. ${review.reason}`.trim();
440
+ const escalated = review.escalate || !review.ok;
441
+ const escalation = escalated
442
+ ? { by: level === 'ask' ? 'rule' : 'auto_review', category: review.category ?? classifyEscalation(review.reason) }
443
+ : { by: 'rule', category: 'rule_ask' };
444
+ const approval = requestApproval(action, watch, runId, reason, escalation);
445
+ if (approval.status === 'superseded') {
446
+ addStep(runId, `Superseded: ${action.title}`, approval.closedReason, 'info');
447
+ return record('blocked', approval.id);
448
+ }
449
+ addStep(runId, `Waiting for approval: ${action.title}`, reason, 'warn');
450
+ await sendNotice({
451
+ key: `approval:${approval.id}`,
452
+ title: `Approve? ${action.title}`,
453
+ body: reason,
454
+ url: '/#/inbox',
455
+ urgency: 'normal',
456
+ category: 'drafts',
457
+ }, watch, runId);
458
+ // A newer draft can supersede this one while the notice is in flight.
459
+ const now = get('approvals', approval.id);
460
+ return record(now && now.status !== 'pending' ? 'blocked' : 'pending_approval', approval.id);
461
+ }
462
+ try {
463
+ await execute(action, watch, runId);
464
+ }
465
+ catch (err) {
466
+ addStep(runId, `Failed: ${action.title}`, String(err), 'error');
467
+ return record('blocked');
468
+ }
469
+ if (caller !== action && action.meta)
470
+ caller.meta = action.meta;
471
+ addStep(runId, `Sent: ${action.title}`, action.target, 'ok');
472
+ supersedeBySent(watch.id, action, runId);
473
+ return record('executed');
474
+ }
475
+ /** Pending approvals expire after this long (API v2 default 24 h); deciding one later returns 410. */
476
+ export const APPROVAL_TTL_MS = Math.max(60_000, Number(process.env.LOCALDOST_APPROVAL_TTL_MS) || 24 * 3600_000);
477
+ export function approvalExpired(a, now = Date.now()) {
478
+ return a.status === 'expired' || (a.status === 'pending' && !!a.expiresAt && Date.parse(a.expiresAt) <= now);
479
+ }
480
+ function requestApproval(action, watch, runId, reason, escalation) {
481
+ const expiresAt = new Date(Date.now() + APPROVAL_TTL_MS).toISOString();
482
+ const approval = insert('approvals', { watchId: watch.id, runId, action, reason, status: 'pending', expiresAt, escalation });
483
+ // One pending draft per (action kind, target): the newer one replaces the older ones (KAT-94).
484
+ const closed = supersedeOlder(approval);
485
+ const self = closed.find((a) => a.id === approval.id);
486
+ if (self)
487
+ return self;
488
+ publish({ type: 'approval', approval });
489
+ return approval;
490
+ }
491
+ /** Gate-internal pushes (approval requests, hand-offs). Mirrored to the outbox on demo installs. */
492
+ async function sendNotice(n, watch, runId) {
493
+ // With the update router running, it sends the decision or hand-off once, on every channel (KAT-143).
494
+ if (!updatesOwnDelivery()) {
495
+ try {
496
+ await notify({ watchId: watch.id, ...n });
497
+ }
498
+ catch (err) {
499
+ console.warn('[rules] push failed', err);
500
+ }
501
+ }
502
+ if (demoInstall())
503
+ toOutbox({ kind: 'push_notify', target: 'push', title: n.title, body: n.body, meta: { urgency: n.urgency, key: n.key } }, watch, runId);
504
+ }
505
+ function toOutbox(action, watch, runId) {
506
+ const item = insert('outbox', runId ? { watchId: watch.id, runId, action } : { watchId: watch.id, action });
507
+ publish({ type: 'outbox', item });
508
+ return item;
509
+ }
510
+ function num(v) {
511
+ const n = Number(v);
512
+ if (!Number.isFinite(n))
513
+ throw new Error(`expected a number, got ${String(v)}`);
514
+ return n;
515
+ }
516
+ const CONCLUSIONS = ['success', 'failure', 'neutral', 'action_required', 'cancelled', 'skipped', 'timed_out'];
517
+ function checkConclusion(meta) {
518
+ return CONCLUSIONS.find((c) => c === meta.conclusion) ?? 'neutral';
519
+ }
520
+ /** The check run for a `check_run` action: conclusion, the QA review text and its line annotations. */
521
+ export function checkRunInput(action, runId) {
522
+ const meta = action.meta ?? {};
523
+ // A queued or in-progress write has no conclusion; everything else completes the check.
524
+ const status = meta.status === 'queued' || meta.status === 'in_progress' ? meta.status : 'completed';
525
+ // GitHub cuts a check title that is longer than CHECK_TITLE_MAX, so every title is cut at a word here (KAT-376).
526
+ const input = { name: 'localdost', status, title: clipCheckTitle(action.title), summary: action.body };
527
+ if (status === 'completed')
528
+ input.conclusion = checkConclusion(meta);
529
+ if (meta.superseded === true)
530
+ input.superseded = true;
531
+ if (meta.runFailed === true)
532
+ input.runFailed = true;
533
+ if (typeof meta.statusDescription === 'string' && meta.statusDescription)
534
+ input.statusDescription = redactHomePaths(redactCode(meta.statusDescription));
535
+ if (typeof meta.text === 'string' && meta.text)
536
+ input.text = meta.text;
537
+ const annotations = checkAnnotations(meta.annotations);
538
+ if (annotations)
539
+ input.annotations = annotations;
540
+ if (config.publicUrl && runId)
541
+ input.detailsUrl = `${config.publicUrl.replace(/\/$/, '')}/#/runs/${runId}`;
542
+ return input;
543
+ }
544
+ /** Sends one action through the integration client, or to the outbox when the client is in demo mode. */
545
+ export async function execute(action, watch, runId) {
546
+ // Sandbox mode (KAT-286): every gated write, an approval's send included, ends here before any network call.
547
+ // It throws, so a run records a failure and an approval stays in the Inbox with the reason.
548
+ if (sandboxOn() && OUTWARD_KINDS.has(action.kind))
549
+ refuseOutward(action.kind, action.target);
550
+ const meta = action.meta ?? {};
551
+ switch (action.kind) {
552
+ case 'push_notify': {
553
+ const urgency = meta.urgency === 'high' || meta.urgency === 'low' ? meta.urgency : 'normal';
554
+ const url = pushLink(meta.url, runId);
555
+ const notice = {
556
+ key: String(meta.key ?? `${action.target}:${runId ?? action.title}`),
557
+ title: action.title,
558
+ body: action.body,
559
+ ...(url ? { url } : {}),
560
+ urgency,
561
+ watchId: watch.id,
562
+ };
563
+ // The update router turns the same run into one message per channel (KAT-143). It does not make a message
564
+ // for every push a flow asks for (a digest ready, a rerun that passed, a QA review alert), so it takes the
565
+ // push over and sends it once (KAT-281). Nothing else sends it then.
566
+ if (updatesOwnDelivery())
567
+ await adoptPush({ ...notice, watchId: watch.id, ...(runId ? { runId } : {}) });
568
+ else
569
+ await notify(notice);
570
+ if (demoInstall())
571
+ toOutbox(action, watch, runId);
572
+ return;
573
+ }
574
+ case 'run_tests': {
575
+ enqueue({ kind: 'rerun', watchId: watch.id, payload: { ...meta, requestedBy: meta.askedBy === 'user' ? 'user' : 'rule', sourceRunId: runId } });
576
+ return;
577
+ }
578
+ case 'pr_comment': {
579
+ // The target names the repo (github:owner/name#12), so a dot with several repos comments on the right one.
580
+ const gh = githubFor(watch, { repo: repoFromTarget(action.target) ?? undefined });
581
+ if (gh.mode === 'demo') {
582
+ toOutbox(action, watch, runId);
583
+ return;
584
+ }
585
+ // A comment a person wrote on an object card (KAT-136) is a new comment; the sticky QA report is never edited with it.
586
+ if (meta.plain === true)
587
+ await gh.addComment(num(meta.pr), action.body);
588
+ else
589
+ await gh.upsertStickyComment(num(meta.pr), action.body);
590
+ return;
591
+ }
592
+ case 'check_run': {
593
+ const gh = githubFor(watch, { repo: repoFromTarget(action.target) ?? undefined });
594
+ if (gh.mode === 'demo') {
595
+ toOutbox(action, watch, runId);
596
+ return;
597
+ }
598
+ const sha = String(meta.sha ?? '');
599
+ const input = checkRunInput(action, runId);
600
+ // A check that was queued or started earlier is changed in place; otherwise a new one is created.
601
+ const known = Number(meta.checkRunId);
602
+ if (Number.isInteger(known) && known > 0)
603
+ await gh.updateCheckRun(known, sha, input);
604
+ else {
605
+ const id = await gh.createCheckRun(sha, input);
606
+ if (id !== undefined)
607
+ action.meta = { ...meta, checkRunId: id };
608
+ }
609
+ return;
610
+ }
611
+ case 'ticket_comment': {
612
+ const tracker = meta.tracker ?? watch.tracker?.kind ?? 'jira';
613
+ const key = String(meta.key ?? action.target.replace(/^\w+:/, ''));
614
+ if (tracker === 'github' && meta.defectComment === true) {
615
+ // New evidence on a defect the dot or a person filed: a plain comment, never the sticky review comment.
616
+ const ref = parseIssueRef(key);
617
+ if (!ref)
618
+ throw new Error(`not a GitHub issue key: ${key}`);
619
+ const gh = githubFor(watch);
620
+ if (gh.mode === 'demo') {
621
+ toOutbox(action, watch, runId);
622
+ return;
623
+ }
624
+ await gh.addComment(ref.number, action.body);
625
+ return;
626
+ }
627
+ if (tracker === 'github') {
628
+ // One sticky review comment per issue; a re-review edits it in place.
629
+ const ref = parseIssueRef(key);
630
+ if (!ref)
631
+ throw new Error(`not a GitHub issue key: ${key}`);
632
+ if (demoInstall()) {
633
+ toOutbox(action, watch, runId);
634
+ return;
635
+ }
636
+ const api = issueApi(ref.full);
637
+ // A test status label: set the label, post nothing.
638
+ if (meta.statusLabel !== undefined) {
639
+ const label = STATUS_LABELS.find((l) => l === meta.statusLabel);
640
+ if (!label)
641
+ throw new Error(`not a status label: ${String(meta.statusLabel)}`);
642
+ await api.setStatusLabel(ref.number, label);
643
+ return;
644
+ }
645
+ // A note on the issue (Seen again in run ...): its own comment, so the sticky review is not overwritten.
646
+ if (meta.append === true) {
647
+ await api.addComment(ref.number, action.body);
648
+ return;
649
+ }
650
+ await api.upsertReviewComment(ref.number, action.body);
651
+ return;
652
+ }
653
+ const client = tracker === 'linear' ? linearFor(watch) : jiraFor(watch);
654
+ if (client.mode === 'demo') {
655
+ toOutbox(action, watch, runId);
656
+ return;
657
+ }
658
+ // Linear's addComment takes the issue id; Jira takes the key
659
+ await client.addComment(tracker === 'linear' ? String(meta.ticketId ?? key) : key, action.body);
660
+ return;
661
+ }
662
+ case 'ticket_status': {
663
+ // A status a person picked on an object card (KAT-136). A tracker in demo mode has nothing to change.
664
+ if ((await executeTicketStatus(action, watch)) === 'demo')
665
+ toOutbox(action, watch, runId);
666
+ return;
667
+ }
668
+ case 'open_pr': {
669
+ // Generated Playwright specs carry their files; a live GitHub client opens a draft PR with them.
670
+ const files = proposedFiles(meta.files);
671
+ const gh = githubFor(watch);
672
+ if (files && typeof meta.base === 'string' && typeof meta.branch === 'string' && gh.mode !== 'demo' && gh.openPullWithFiles) {
673
+ const url = await gh.openPullWithFiles({ base: meta.base, branch: meta.branch, title: action.title, body: action.body, files });
674
+ if (runId)
675
+ addStep(runId, 'Opened a pull request', url || action.title, 'ok');
676
+ return;
677
+ }
678
+ toOutbox(action, watch, runId);
679
+ return;
680
+ }
681
+ case 'revert':
682
+ // No client support yet: record the draft so a person can carry it out.
683
+ toOutbox(action, watch, runId);
684
+ return;
685
+ case 'mcp_tool':
686
+ await executeMcpTool(action);
687
+ return;
688
+ case 'slack_post':
689
+ await executeSlackPost(action, watch, runId);
690
+ return;
691
+ case 'case_retire':
692
+ // Retires the case and accepts its impact row. Its results stay.
693
+ executeCaseRetire(action);
694
+ return;
695
+ case 'report_edit':
696
+ // store.updateReport publishes the saved page as a `report` live event.
697
+ executeReportEdit(action);
698
+ return;
699
+ case 'file_defect':
700
+ case 'issue_create': {
701
+ // The filed URL and key go on the action, so the run, the approval and the next comment can link it.
702
+ const filed = await fileIssue(action, watch);
703
+ if (!filed) {
704
+ toOutbox(action, watch, runId);
705
+ return;
706
+ }
707
+ action.meta = { ...meta, filedUrl: filed.url, filedKey: filed.key };
708
+ if (action.kind === 'issue_create') {
709
+ const relates = Array.isArray(meta.relates) ? meta.relates.map(String) : [];
710
+ recordDefectLinks({ watchId: watch.id, defect: filed.key, requirements: relates, sig: typeof meta.sig === 'string' ? meta.sig : undefined });
711
+ }
712
+ return;
713
+ }
714
+ }
715
+ }
716
+ /** The files of an open_pr action when every path is a safe repo spec path, else null. */
717
+ export function proposedFiles(v) {
718
+ if (!Array.isArray(v) || !v.length || v.length > 20)
719
+ return null;
720
+ const out = [];
721
+ for (const f of v) {
722
+ if (!f || typeof f !== 'object')
723
+ return null;
724
+ const { path, content } = f;
725
+ if (!safeRepoSpecPath(path) || typeof content !== 'string' || content.length > 50_000)
726
+ return null;
727
+ out.push({ path, content });
728
+ }
729
+ return out;
730
+ }
731
+ const strings = (v) => (Array.isArray(v) ? v.map(String).filter(Boolean) : undefined);
732
+ /**
733
+ * Opens the defect in the tracker named by meta.tracker, through the one creator every tracker shares.
734
+ * null in demo mode: the draft goes to the outbox. A body keeps its signature marker even when an
735
+ * edit in the Inbox removed it, so the duplicate guard can still find the issue.
736
+ */
737
+ async function fileIssue(action, watch) {
738
+ const meta = action.meta ?? {};
739
+ // A person may have edited the draft in the Inbox, so the text is redacted again right before it is posted.
740
+ const title = redactCode(action.title);
741
+ // meta is frozen at draft time; a person may have corrected the tracker since, so the watch as it is now wins.
742
+ const t = watch.tracker;
743
+ const tracker = meta.tracker === 'jira' || meta.tracker === 'linear' ? meta.tracker : 'github';
744
+ let project = String(meta.project ?? '');
745
+ let projectName;
746
+ if (tracker === 'jira' && t?.kind === 'jira' && t.projectKeys[0])
747
+ project = t.projectKeys[0];
748
+ if (tracker === 'linear') {
749
+ if (t?.kind === 'linear' && t.teamKeys[0])
750
+ project = t.teamKeys[0];
751
+ const frozen = typeof meta.projectName === 'string' && meta.projectName ? meta.projectName : undefined;
752
+ projectName = (t?.kind === 'linear' && t.projectName) || frozen;
753
+ }
754
+ if (tracker === 'github' && !project && watch.repo)
755
+ project = `${watch.repo.owner}/${watch.repo.name}`;
756
+ if (!project)
757
+ throw new Error(`no ${tracker} project to file "${title}" in`);
758
+ const sig = typeof meta.sig === 'string' && meta.sig ? meta.sig : undefined;
759
+ const redacted = redactCode(action.body);
760
+ const body = sig ? withDefectMarker(redacted, sig) : redacted;
761
+ const issueType = typeof meta.issueType === 'string' && meta.issueType ? meta.issueType : undefined;
762
+ const milestone = typeof meta.milestone === 'string' && meta.milestone ? meta.milestone : undefined;
763
+ // A defect from the PR review always carries the localdost label that the duplicate guard searches for.
764
+ const labels = strings(meta.labels) ?? [];
765
+ if (action.kind === 'file_defect' && !labels.some(isDefectLabel))
766
+ labels.push(DEFECT_LABEL);
767
+ return createTrackerIssue(tracker, project, { title, body, labels: labels.length ? labels : undefined, issueType, milestone, projectName }, { watch });
768
+ }
769
+ /** A person approved a draft whose automatic retry is still waiting out its backoff (KAT-178). The API answers 409. */
770
+ export class RetryingError extends Error {
771
+ approvalId;
772
+ nextAt;
773
+ constructor(approvalId, nextAt) {
774
+ super(`approval ${approvalId} is retrying on its own; the next try is at ${nextAt}`);
775
+ this.approvalId = approvalId;
776
+ this.nextAt = nextAt;
777
+ }
778
+ }
779
+ /**
780
+ * Approves a pending draft and sends it. A send that fails with a transient error (5xx, timeout, reset, 429) stays pending
781
+ * with a `retry` state and is returned, not thrown: approval-retries.ts sends it again by itself (KAT-178), and a person can
782
+ * approve again only once that backoff has passed. Any other failure puts the draft back in the Inbox with the error and
783
+ * throws, so a person decides again. `auto` marks the retry loop's own call; `now` is for tests. `by` names the
784
+ * person who decided (a paired device's name, a Slack user); the record keeps it as `decidedBy` (KAT-356).
785
+ */
786
+ export async function approveAction(approvalId, edit, opts = {}) {
787
+ const now = opts.now ?? Date.now;
788
+ const approval = get('approvals', approvalId);
789
+ if (!approval)
790
+ throw new Error(`approval ${approvalId} not found`);
791
+ if (approval.status !== 'pending')
792
+ throw new Error(`approval ${approvalId} is already ${approval.status}`);
793
+ if (!opts.auto && approval.retry && Date.parse(approval.retry.nextAt) > now())
794
+ throw new RetryingError(approvalId, approval.retry.nextAt);
795
+ const watch = get('watches', approval.watchId);
796
+ if (!watch)
797
+ throw new Error(`watch ${approval.watchId} not found`);
798
+ const action = edit && edit.trim() ? { ...approval.action, body: edit } : approval.action;
799
+ const decidedAt = new Date(now()).toISOString();
800
+ // The retry loop's own call carries no person: the one who approved first stays on the record.
801
+ const decidedBy = opts.by ?? (opts.auto ? approval.decidedBy : undefined);
802
+ // 'approved' marks the send in flight; a failed send goes back to pending with the error, so it can be retried.
803
+ update('approvals', approvalId, { status: 'approved', decidedAt, action, ...(decidedBy ? { decidedBy } : {}) });
804
+ try {
805
+ await execute(action, watch, approval.runId);
806
+ }
807
+ catch (err) {
808
+ const error = err instanceof Error ? err.message : String(err);
809
+ const kind = classifySendError(err, now());
810
+ const retry = kind.transient ? nextRetry(approval.retry, error, kind.retryAfterMs, now()) : null;
811
+ const patch = { status: 'pending', error, retry };
812
+ // The time to decide starts again from the failure, so a draft retried for a day is not swept as expired.
813
+ if (retry && !approval.retry)
814
+ patch.expiresAt = new Date(Math.max(Date.parse(approval.expiresAt ?? '') || 0, now() + RETRY_WINDOW_MS + APPROVAL_TTL_MS)).toISOString();
815
+ update('approvals', approvalId, patch);
816
+ const pending = get('approvals', approvalId);
817
+ publish({ type: 'approval', approval: pending });
818
+ const detail = retry
819
+ ? `${error} Retrying on its own (attempt ${retry.attempt}, next try in ${waitText(Date.parse(retry.nextAt) - now())}).`
820
+ : kind.transient && approval.retry
821
+ ? `${error} Gave up retrying after 24 h. The draft is back in the Inbox.`
822
+ : `${error} The draft is back in the Inbox.`;
823
+ try {
824
+ addStep(approval.runId, `Send failed: ${action.title}`, detail, retry ? 'warn' : 'error');
825
+ }
826
+ catch {
827
+ /* run may be gone */
828
+ }
829
+ if (retry)
830
+ return pending;
831
+ throw err;
832
+ }
833
+ const executedAt = new Date(now()).toISOString();
834
+ update('approvals', approvalId, { status: 'executed', executedAt, action, retry: null });
835
+ const done = { ...approval, action, status: 'executed', decidedAt, executedAt, retry: null, ...(decidedBy ? { decidedBy } : {}) };
836
+ publish({ type: 'approval', approval: done });
837
+ try {
838
+ updateActionResult(approval.runId, approvalId, 'executed', action);
839
+ const detail = [decidedBy ? `Approved by ${decidedBy}.` : '', edit ? 'Sent with your edits.' : ''].filter(Boolean).join(' ');
840
+ addStep(approval.runId, `Approved and sent: ${action.title}`, detail || undefined, 'ok');
841
+ }
842
+ catch (err) {
843
+ console.warn('[rules] could not update run after approval', err);
844
+ }
845
+ return done;
846
+ }
847
+ /** Closing writes still in flight, so a test or a shutdown can wait for them. */
848
+ const closing = new Set();
849
+ /** Resolves when every closing write started so far has finished. */
850
+ export async function closingChecksIdle() {
851
+ while (closing.size)
852
+ await Promise.all([...closing]);
853
+ }
854
+ /**
855
+ * A report that waited in the Inbox left its commit's check at "Report waiting for approval" (KAT-285). When
856
+ * a person rejects it, or it expires, that note is closed: neutral on an App check, a success status on a
857
+ * token (a commit status has no neutral). The write follows from the decision, so it skips the gate and the
858
+ * auto-review. A failed write is logged and never undoes the decision; a re-review of the same head writes
859
+ * its own check or status afterwards and replaces this one.
860
+ */
861
+ export async function closeCheckAfterDecision(approval, decision) {
862
+ const { action } = approval;
863
+ if (action.kind !== 'check_run' || action.meta?.templated === true)
864
+ return;
865
+ const sha = String(action.meta?.sha ?? '');
866
+ if (!sha)
867
+ return;
868
+ const watch = get('watches', approval.watchId);
869
+ if (!watch)
870
+ return;
871
+ const verb = decision === 'rejected' ? 'Rejected' : 'Expired';
872
+ const runUrl = config.publicUrl && approval.runId ? `${config.publicUrl.replace(/\/$/, '')}/#/runs/${approval.runId}` : undefined;
873
+ const meta = {
874
+ sha,
875
+ templated: true,
876
+ status: 'completed',
877
+ conclusion: 'neutral',
878
+ statusDescription: `Report not posted: ${verb.toLowerCase()} in localdost`,
879
+ ...(action.meta?.checkRunId ? { checkRunId: action.meta.checkRunId } : {}),
880
+ };
881
+ const closeAction = {
882
+ kind: 'check_run',
883
+ target: action.target,
884
+ title: 'Report not posted',
885
+ body: `${verb} in localdost${runUrl ? `\n\nRun: ${runUrl}` : ''}`,
886
+ meta,
887
+ };
888
+ try {
889
+ await execute(closeAction, watch, approval.runId || undefined);
890
+ }
891
+ catch (err) {
892
+ console.warn(`[rules] could not close the check of approval ${approval.id}: ${String(err)}`);
893
+ }
894
+ }
895
+ /** Starts a closing write without making the caller wait for GitHub. */
896
+ function closeCheckInBackground(approval, decision) {
897
+ const p = closeCheckAfterDecision(approval, decision).finally(() => closing.delete(p));
898
+ closing.add(p);
899
+ }
900
+ setCheckCloseHook((approval, status) => closeCheckInBackground(approval, status));
901
+ /**
902
+ * Rejects a pending approval. With `closedReason` the server is closing it, not a person: the reason is
903
+ * stored on the approval and shown in the run's step instead of "You rejected this draft." `by` names the
904
+ * person who rejected it (KAT-356); the step then says who instead of "You".
905
+ */
906
+ export async function rejectAction(approvalId, closedReason, opts = {}) {
907
+ const approval = get('approvals', approvalId);
908
+ if (!approval)
909
+ throw new Error(`approval ${approvalId} not found`);
910
+ if (approval.status !== 'pending')
911
+ throw new Error(`approval ${approvalId} is already ${approval.status}`);
912
+ const decidedAt = new Date().toISOString();
913
+ const decidedBy = closedReason ? undefined : opts.by;
914
+ update('approvals', approvalId, { status: 'rejected', decidedAt, ...(closedReason ? { closedReason } : {}), ...(decidedBy ? { decidedBy } : {}) });
915
+ const done = { ...approval, status: 'rejected', decidedAt, ...(closedReason ? { closedReason } : {}), ...(decidedBy ? { decidedBy } : {}) };
916
+ publish({ type: 'approval', approval: done });
917
+ try {
918
+ updateActionResult(approval.runId, approvalId, 'blocked');
919
+ addStep(approval.runId, `Rejected: ${approval.action.title}`, closedReason ?? (decidedBy ? `Rejected by ${decidedBy}.` : 'You rejected this draft.'), 'info');
920
+ }
921
+ catch (err) {
922
+ console.warn('[rules] could not update run after rejection', err);
923
+ }
924
+ await closeCheckAfterDecision(approval, 'rejected');
925
+ return done;
926
+ }
927
+ //# sourceMappingURL=rules.js.map