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
package/dist/repos.js ADDED
@@ -0,0 +1,891 @@
1
+ // Workspace repos and per-dot repo sets (docs/MULTI-REPO.md section 1).
2
+ //
3
+ // Every reader of a dot's repos goes through watchRepos() and repoForEvent(). A dot saved before
4
+ // multi-repo support has only `repo`; watchRepos() turns it into one app entry, so old rows and
5
+ // new rows read the same way. `repo` is kept filled from the first app repo on every save so an
6
+ // older build that ignores `repos` still works (section 1.3, Rollback).
7
+ import { get, insert, list, remove, update } from './db.js';
8
+ import { MAX_DEPLOY_URL_MATCH, cleanDeployUrlMatch } from './target-url.js';
9
+ import { getMeta, setMeta } from './connect/store.js';
10
+ import { publish } from './events.js';
11
+ import { MAX_DEPLOY_ENVIRONMENT, MAX_DEPLOY_WAIT_SEC, cleanDeployEnvironment, cleanDeploySec, cleanTestBranches, isBaseUrlEnvName, isSafeBranchName, parseCommand, passEnvError, workingDirectoryError, } from './runner/command.js';
12
+ export const REPO_ROLES = ['app', 'test', 'docs'];
13
+ const OWNER = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})$/;
14
+ const NAME = /^[A-Za-z0-9._-]{1,100}$/;
15
+ const BRANCH = /^(?!\/)(?!.*\.\.)(?!.*\/\/)[A-Za-z0-9._/-]{1,250}(?<!\/)(?<!\.lock)$/;
16
+ /** The workspace id of a repo: "owner/name", lower case. */
17
+ export function repoId(owner, name) {
18
+ return `${owner}/${name}`.toLowerCase();
19
+ }
20
+ /** Reads "owner/name" (also a github.com URL or a trailing .git). null when it is not a repo. */
21
+ export function parseRepoId(v) {
22
+ if (typeof v !== 'string')
23
+ return null;
24
+ const s = v
25
+ .trim()
26
+ .replace(/^https?:\/\/(www\.)?github\.com\//i, '')
27
+ .replace(/\.git$/i, '')
28
+ .replace(/\/+$/, '');
29
+ const parts = s.split('/');
30
+ if (parts.length !== 2)
31
+ return null;
32
+ const [owner, name] = parts;
33
+ if (!OWNER.test(owner) || !NAME.test(name) || name === '.' || name === '..')
34
+ return null;
35
+ return { owner, name };
36
+ }
37
+ export function isBranchName(v) {
38
+ return typeof v === 'string' && BRANCH.test(v);
39
+ }
40
+ const lc = (s) => (s ?? '').toLowerCase();
41
+ /** Workspace repo by id, or undefined. Lookup errors (no table in a bare test db) count as missing. */
42
+ export function getWorkspaceRepo(id) {
43
+ try {
44
+ return get('repos', id.toLowerCase());
45
+ }
46
+ catch {
47
+ return undefined;
48
+ }
49
+ }
50
+ export function listWorkspaceRepos() {
51
+ return list('repos', undefined, { orderBy: 'id ASC' });
52
+ }
53
+ /**
54
+ * The dot's repos with defaults filled in. `repos` when set, else one app entry built from `repo`.
55
+ * A branch left unset reads the workspace repo's default branch, then "main".
56
+ * Entries whose id is not "owner/name" are skipped.
57
+ */
58
+ export function watchRepos(w, lookup = getWorkspaceRepo) {
59
+ if (Array.isArray(w.repos) && w.repos.length) {
60
+ const out = [];
61
+ const seen = new Set();
62
+ for (const e of w.repos) {
63
+ const ref = parseRepoId(e?.repo);
64
+ if (!ref)
65
+ continue;
66
+ const id = repoId(ref.owner, ref.name);
67
+ if (seen.has(id))
68
+ continue;
69
+ seen.add(id);
70
+ const ws = lookup(id);
71
+ // Keep the owner and name casing GitHub uses when the workspace row has it.
72
+ const owner = ws?.owner ?? ref.owner;
73
+ const name = ws?.name ?? ref.name;
74
+ const role = REPO_ROLES.includes(e.role) ? e.role : 'app';
75
+ out.push({
76
+ id,
77
+ owner,
78
+ name,
79
+ role,
80
+ defaultBranch: e.defaultBranch || ws?.defaultBranch || 'main',
81
+ ...(e.pathFilters?.length ? { pathFilters: e.pathFilters } : {}),
82
+ ...(e.test ? { test: e.test } : {}),
83
+ ...(e.targets?.length ? { targets: e.targets.map((t) => t.toLowerCase()) } : {}),
84
+ ...(e.prScope && Object.keys(e.prScope).length ? { prScope: e.prScope } : {}),
85
+ ...(e.runTests === false && role === 'app' ? { runTests: false } : {}),
86
+ ...(role === 'app' ? deployOf(e) : {}),
87
+ });
88
+ }
89
+ return out;
90
+ }
91
+ const r = w.repo;
92
+ if (!r?.owner || !r.name)
93
+ return [];
94
+ return [
95
+ {
96
+ id: repoId(r.owner, r.name),
97
+ owner: r.owner,
98
+ name: r.name,
99
+ role: 'app',
100
+ defaultBranch: r.defaultBranch || 'main',
101
+ ...(r.pathFilters?.length ? { pathFilters: r.pathFilters } : {}),
102
+ ...(r.prScope && Object.keys(r.prScope).length ? { prScope: r.prScope } : {}),
103
+ ...(r.runTests === false ? { runTests: false } : {}),
104
+ ...deployOf(r),
105
+ },
106
+ ];
107
+ }
108
+ /** The deploy wait fields of a repo entry as a read keeps them: a name with text, seconds from 0 up. Unset fields are left out. */
109
+ function deployOf(e) {
110
+ const environment = cleanDeployEnvironment(e.deployEnvironment);
111
+ const sec = e.waitForDeploySec;
112
+ const match = cleanDeployUrlMatch(e.deployUrlMatch);
113
+ return {
114
+ ...(environment ? { deployEnvironment: environment } : {}),
115
+ ...(typeof sec === 'number' && Number.isInteger(sec) && sec >= 0 ? { waitForDeploySec: sec } : {}),
116
+ ...(match ? { deployUrlMatch: match } : {}),
117
+ };
118
+ }
119
+ /** The dot's first app repo: the one `repo` mirrors and the default for work that names no repo. */
120
+ export function primaryRepo(w, lookup) {
121
+ const all = watchRepos(w, lookup);
122
+ return all.find((r) => r.role === 'app') ?? null;
123
+ }
124
+ /** True when the dot holds at least one app repo, the code that reviews and test runs read. */
125
+ export function hasAppRepo(w) {
126
+ return !!primaryRepo(w);
127
+ }
128
+ /** The dot's entry for this repo, or null. */
129
+ export function findRepo(w, ref, lookup) {
130
+ if (!ref?.owner || !ref.name)
131
+ return null;
132
+ const id = repoId(ref.owner, ref.name);
133
+ return watchRepos(w, lookup).find((r) => r.id === id) ?? null;
134
+ }
135
+ /** The dot's entry whose repo is the event's repo, or null (no repo on the event, or not in the set). */
136
+ export function repoForEvent(w, ev, lookup) {
137
+ return findRepo(w, ev?.repo, lookup);
138
+ }
139
+ /**
140
+ * The repo a piece of work acts on: the event's repo when the dot holds it, else the first app repo
141
+ * (the repo a single-repo dot always used). null when the dot holds no app repo and no event repo matches.
142
+ */
143
+ export function targetRepo(w, ev, lookup) {
144
+ return repoForEvent(w, ev, lookup) ?? primaryRepo(w, lookup);
145
+ }
146
+ /**
147
+ * The repo of an event when the dot runs no tests for it (KAT-361): an app repo with `runTests: false`. null when the tests run,
148
+ * including for an event with no repo, which belongs to the first app repo and is judged by that repo's entry.
149
+ */
150
+ export function testsOffRepo(w, ev, lookup) {
151
+ const r = targetRepo(w, ev, lookup);
152
+ return r && r.role === 'app' && r.runTests === false ? r : null;
153
+ }
154
+ /**
155
+ * The repo that keeps a bug apart from the same bug in another repo: "owner/name", lower case, only for a dot with
156
+ * more than one repo. A single-repo dot gets none, so its older bug keys and signatures still match (KAT-324).
157
+ */
158
+ export function bugRepoOf(w, repo) {
159
+ if (!repo || watchRepos(w).length < 2)
160
+ return undefined;
161
+ return `${repo.owner}/${repo.name}`.toLowerCase();
162
+ }
163
+ /**
164
+ * The other repo parts a bug key and signature may have been made with, for a dot that gained or lost a repo (KAT-326).
165
+ * A dot with several repos made them without a repo part (null) while it had one repo. A dot with one repo may have made
166
+ * them with its only repo while it had several.
167
+ */
168
+ export function bugRepoAlts(w, repo) {
169
+ const repos = watchRepos(w);
170
+ if (repos.length >= 2)
171
+ return repo ? [null] : [];
172
+ const only = repo ?? repos[0];
173
+ return only ? [`${only.owner}/${only.name}`.toLowerCase()] : [];
174
+ }
175
+ /** `Watch.repo` as an older build reads it: the first app repo, or null. */
176
+ export function legacyRepo(repos) {
177
+ const a = repos.find((r) => r.role === 'app');
178
+ if (!a)
179
+ return null;
180
+ return {
181
+ owner: a.owner,
182
+ name: a.name,
183
+ defaultBranch: a.defaultBranch,
184
+ ...(a.pathFilters?.length ? { pathFilters: a.pathFilters } : {}),
185
+ ...(a.prScope ? { prScope: a.prScope } : {}),
186
+ ...(a.runTests === false ? { runTests: false } : {}),
187
+ ...deployOf(a),
188
+ };
189
+ }
190
+ /** The repo of an outward action target such as `github:owner/name#12` or `github:owner/name@abc1234`. */
191
+ export function repoFromTarget(target) {
192
+ const m = /^github:([^#@\s]+)/.exec(target ?? '');
193
+ return m ? parseRepoId(m[1]) : null;
194
+ }
195
+ /** "owner/name" for messages. */
196
+ export const fullName = (r) => `${r.owner}/${r.name}`;
197
+ export function sameRepo(a, b) {
198
+ return !!a && !!b && lc(a.owner) === lc(b.owner) && lc(a.name) === lc(b.name);
199
+ }
200
+ // ---------- validation (POST /api/dots, PATCH /api/dots/:id) ----------
201
+ const TEST_FRAMEWORKS = ['playwright', 'cypress', 'webdriverio', 'pytest', 'junit', 'katalon'];
202
+ function validTestConfig(v, at) {
203
+ if (v === undefined)
204
+ return null;
205
+ if (!v || typeof v !== 'object' || Array.isArray(v))
206
+ return `${at}.test must be an object.`;
207
+ const t = v;
208
+ if (!TEST_FRAMEWORKS.includes(t.framework))
209
+ return `${at}.test.framework must be one of ${TEST_FRAMEWORKS.join(', ')}.`;
210
+ const passEnv = passEnvError(t.passEnv);
211
+ if (passEnv)
212
+ return `${at}.test.passEnv ${passEnv}`;
213
+ const text = (key, max) => {
214
+ const x = t[key];
215
+ if (x === undefined || x === null)
216
+ return null;
217
+ if (typeof x !== 'string')
218
+ return `${at}.test.${key} must be text.`;
219
+ return x.length > max ? `${at}.test.${key} must be under ${max} characters.` : null;
220
+ };
221
+ const bad = text('command', 1000) ?? text('setup', 4000) ?? text('label', 40) ?? text('smokeGrep', 100) ?? text('dir', 200);
222
+ if (bad)
223
+ return bad;
224
+ if (typeof t.command === 'string' && t.command.trim()) {
225
+ const p = parseCommand(t.command);
226
+ if (!p.ok)
227
+ return `${at}.test.command: ${p.error}`;
228
+ }
229
+ if (typeof t.dir === 'string') {
230
+ const dir = workingDirectoryError(t.dir);
231
+ if (dir)
232
+ return `${at}.test.dir ${dir}`;
233
+ }
234
+ if (typeof t.label === 'string' && /[\u0000-\u001f\u007f]/.test(t.label))
235
+ return `${at}.test.label must be one line.`;
236
+ if (t.ref !== undefined && t.ref !== null) {
237
+ const ref = t.ref;
238
+ const fixed = ref && typeof ref === 'object' && !Array.isArray(ref) ? ref.fixed : undefined;
239
+ if (ref !== 'default' && ref !== 'match_branch' && !(typeof fixed === 'string' && isSafeBranchName(fixed.trim())))
240
+ return `${at}.test.ref must be "default", "match_branch", or { "fixed": "<branch or tag>" }.`;
241
+ }
242
+ if (t.baseUrlEnv !== undefined && t.baseUrlEnv !== null) {
243
+ const names = t.baseUrlEnv;
244
+ if (!Array.isArray(names) || names.length > 5 || names.some((n) => !isBaseUrlEnvName(n)))
245
+ return `${at}.test.baseUrlEnv must be a list of up to 5 variable names in capital letters, digits and underscores that end in _URL (or are BASE_URL or BASEURL), for example BASE_URL.`;
246
+ }
247
+ if (t.on !== undefined && t.on !== null) {
248
+ if (!Array.isArray(t.on) || t.on.some((j) => j !== 'pr_check' && j !== 'post_merge'))
249
+ return `${at}.test.on must be a list of pr_check and post_merge.`;
250
+ }
251
+ if (t.areas !== undefined && t.areas !== null) {
252
+ const areas = t.areas;
253
+ if (!areas || typeof areas !== 'object' || Array.isArray(areas))
254
+ return `${at}.test.areas must map an area name to a grep text.`;
255
+ const rows = Object.entries(areas);
256
+ if (rows.length > 40)
257
+ return `${at}.test.areas holds at most 40 areas.`;
258
+ for (const [area, grep] of rows) {
259
+ if (!area.trim() || area.length > 60)
260
+ return `${at}.test.areas: an area name is 1 to 60 characters.`;
261
+ if (typeof grep !== 'string' || !grep.trim() || grep.length > 200)
262
+ return `${at}.test.areas["${area.slice(0, 40)}"] must be a grep text of up to 200 characters.`;
263
+ try {
264
+ new RegExp(grep);
265
+ }
266
+ catch {
267
+ return `${at}.test.areas["${area.slice(0, 40)}"] is not a valid grep text.`;
268
+ }
269
+ }
270
+ }
271
+ return null;
272
+ }
273
+ const SCOPE_RULES = ['authors', 'team', 'skipDrafts', 'skipBots', 'linkedIssueLabels'];
274
+ const GITHUB_LOGIN = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})(?:\[bot\])?$/;
275
+ const TEAM_SLUG = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})\/[A-Za-z0-9_.-]{1,100}$/;
276
+ /**
277
+ * Checks a repo's PR scope (KAT-354) and returns it tidy: logins without a leading @, each once (case-insensitive),
278
+ * the team as "org/team", a flag only when true. null or an empty object means no scope.
279
+ */
280
+ export function parsePrScope(v, at) {
281
+ if (v === undefined || v === null)
282
+ return { ok: true, scope: undefined };
283
+ if (typeof v !== 'object' || Array.isArray(v))
284
+ return { ok: false, error: `${at}.prScope must be an object.` };
285
+ const raw = v;
286
+ const stray = Object.keys(raw).find((k) => !SCOPE_RULES.includes(k));
287
+ if (stray)
288
+ return { ok: false, error: `${at}.prScope.${stray} is not a scope rule. Use ${SCOPE_RULES.join(', ')}.` };
289
+ const out = {};
290
+ const words = (key, clean, ok, max, what) => {
291
+ const list = raw[key];
292
+ if (list === undefined || list === null)
293
+ return null;
294
+ if (!Array.isArray(list) || list.some((x) => typeof x !== 'string'))
295
+ return `${at}.prScope.${key} must be a list of ${what}.`;
296
+ const seen = new Set();
297
+ const kept = [];
298
+ for (const x of list) {
299
+ const t = clean(x.trim());
300
+ if (!t)
301
+ continue;
302
+ if (!ok(t))
303
+ return `${at}.prScope.${key}: "${t.slice(0, 40)}" is not valid. Use ${what}.`;
304
+ if (seen.has(t.toLowerCase()))
305
+ continue;
306
+ seen.add(t.toLowerCase());
307
+ kept.push(t);
308
+ }
309
+ if (kept.length > max)
310
+ return `${at}.prScope.${key} holds at most ${max} entries.`;
311
+ if (kept.length)
312
+ out[key] = kept;
313
+ return null;
314
+ };
315
+ const bad = words('authors', (s) => s.replace(/^@/, ''), (s) => GITHUB_LOGIN.test(s), 200, 'GitHub logins') ??
316
+ words('linkedIssueLabels', (s) => s, (s) => s.length <= 100, 50, 'label names');
317
+ if (bad)
318
+ return { ok: false, error: bad };
319
+ if (raw.team !== undefined && raw.team !== null && raw.team !== '') {
320
+ const team = typeof raw.team === 'string' ? raw.team.trim().replace(/^@/, '') : '';
321
+ if (!TEAM_SLUG.test(team))
322
+ return { ok: false, error: `${at}.prScope.team must be a team slug like "acme/web-team".` };
323
+ out.team = team;
324
+ }
325
+ for (const flag of ['skipDrafts', 'skipBots']) {
326
+ if (raw[flag] === undefined || raw[flag] === null)
327
+ continue;
328
+ if (typeof raw[flag] !== 'boolean')
329
+ return { ok: false, error: `${at}.prScope.${flag} must be true or false.` };
330
+ if (raw[flag])
331
+ out[flag] = true;
332
+ }
333
+ return { ok: true, scope: Object.keys(out).length ? out : undefined };
334
+ }
335
+ /** Reads a runTests flag. `off` is true for `false`; true, null, and unset all mean the tests run and are not stored. */
336
+ function parseRunTests(v, at) {
337
+ if (v === undefined || v === null || v === true)
338
+ return { ok: true, off: false };
339
+ if (v === false)
340
+ return { ok: true, off: true };
341
+ return { ok: false, error: `${at}.runTests must be true or false.` };
342
+ }
343
+ /**
344
+ * Reads the deploy wait of a repo (KAT-395): `deployEnvironment` is a name of up to 100 characters on one line, `waitForDeploySec` a whole
345
+ * number of seconds from 0 to 3600. null, an empty name and unset mean the dot's value. 0 is kept: it turns the wait off for this repo.
346
+ */
347
+ function parseRepoDeploy(raw, at) {
348
+ const env = raw.deployEnvironment;
349
+ let deployEnvironment;
350
+ if (env !== undefined && env !== null) {
351
+ if (typeof env !== 'string')
352
+ return { ok: false, error: `${at}.deployEnvironment must be text, the name of a GitHub environment such as qa.` };
353
+ if (env.trim().length > MAX_DEPLOY_ENVIRONMENT || /[\u0000-\u001f\u007f]/.test(env))
354
+ return { ok: false, error: `${at}.deployEnvironment must be a name of up to ${MAX_DEPLOY_ENVIRONMENT} characters on one line.` };
355
+ deployEnvironment = cleanDeployEnvironment(env);
356
+ }
357
+ const sec = raw.waitForDeploySec;
358
+ let waitForDeploySec;
359
+ if (sec !== undefined && sec !== null) {
360
+ if (!(typeof sec === 'number' && Number.isInteger(sec) && sec >= 0 && sec <= MAX_DEPLOY_WAIT_SEC))
361
+ return {
362
+ ok: false,
363
+ error: `${at}.waitForDeploySec must be a whole number of seconds from 0 to ${MAX_DEPLOY_WAIT_SEC}. 0 turns the wait off for this repo.`,
364
+ };
365
+ waitForDeploySec = sec;
366
+ }
367
+ const rawMatch = raw.deployUrlMatch;
368
+ let deployUrlMatch;
369
+ if (rawMatch !== undefined && rawMatch !== null && !(typeof rawMatch === 'string' && !rawMatch.trim())) {
370
+ const match = cleanDeployUrlMatch(rawMatch);
371
+ if (!match)
372
+ return {
373
+ ok: false,
374
+ error: `${at}.deployUrlMatch must be a host such as web.qa.example.com or an origin such as https://web.qa.example.com, up to ${MAX_DEPLOY_URL_MATCH} characters, with no path.`,
375
+ };
376
+ deployUrlMatch = match;
377
+ }
378
+ return {
379
+ ok: true,
380
+ ...(deployEnvironment ? { deployEnvironment } : {}),
381
+ ...(waitForDeploySec !== undefined ? { waitForDeploySec } : {}),
382
+ ...(deployUrlMatch ? { deployUrlMatch } : {}),
383
+ };
384
+ }
385
+ /**
386
+ * Why the deploy waits of a dot's app repos cannot work together, or null (KAT-395): a repo that waits (its own seconds, else the dot's)
387
+ * needs an environment (its own, else the dot's). `dot` holds the dot's two fields as the save leaves them.
388
+ */
389
+ export function repoDeployWaitError(dot, repos) {
390
+ for (const r of repos) {
391
+ if (r.role !== 'app')
392
+ continue;
393
+ const sec = r.waitForDeploySec !== undefined ? cleanDeploySec(r.waitForDeploySec) : cleanDeploySec(dot.waitForDeploySec);
394
+ const env = cleanDeployEnvironment(r.deployEnvironment) ?? cleanDeployEnvironment(dot.deployEnvironment);
395
+ if (sec && !env)
396
+ return `${r.id} waits for a deploy and needs a deploy environment, the GitHub environment its merge deploys to, for example qa.`;
397
+ }
398
+ return null;
399
+ }
400
+ /** The deploy wait fields of each app repo a save would change, as `repos[acme/shop].deployEnvironment`. These are the admin's like the dot's. */
401
+ export function repoDeployChanges(current, body) {
402
+ const res = resolveRepoFields(body, current);
403
+ if (!res.ok || !res.fields)
404
+ return [];
405
+ const was = new Map(watchRepos(current).map((r) => [r.id, r]));
406
+ const out = [];
407
+ for (const r of watchRepos({ repos: res.fields.repos })) {
408
+ if (r.role !== 'app')
409
+ continue;
410
+ const old = was.get(r.id);
411
+ if (old?.deployEnvironment !== r.deployEnvironment)
412
+ out.push(`repos[${r.id}].deployEnvironment`);
413
+ if (old?.waitForDeploySec !== r.waitForDeploySec)
414
+ out.push(`repos[${r.id}].waitForDeploySec`);
415
+ if (old?.deployUrlMatch !== r.deployUrlMatch)
416
+ out.push(`repos[${r.id}].deployUrlMatch`);
417
+ }
418
+ return out;
419
+ }
420
+ /**
421
+ * Checks a `repos` body and returns it normalized (ids lower case, duplicates refused), or an error in words.
422
+ * Rules (section 1.2): ids are "owner/name", roles are app, test or docs, and a test repo needs an app repo.
423
+ */
424
+ export function parseWatchRepos(v) {
425
+ if (v === null)
426
+ return { ok: true, repos: [] };
427
+ if (!Array.isArray(v))
428
+ return { ok: false, error: 'repos must be a list of { repo, role }.' };
429
+ if (v.length > 50)
430
+ return { ok: false, error: 'A dot holds at most 50 repos.' };
431
+ const out = [];
432
+ const seen = new Set();
433
+ for (const [i, raw] of v.entries()) {
434
+ const at = `repos[${i}]`;
435
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw))
436
+ return { ok: false, error: `${at} must be an object with repo and role.` };
437
+ const e = raw;
438
+ const ref = parseRepoId(e.repo);
439
+ if (!ref)
440
+ return { ok: false, error: `${at}.repo must be "owner/name".` };
441
+ const id = repoId(ref.owner, ref.name);
442
+ if (seen.has(id))
443
+ return { ok: false, error: `${id} is in the list twice.` };
444
+ seen.add(id);
445
+ const role = e.role === undefined ? 'app' : e.role;
446
+ if (!REPO_ROLES.includes(role))
447
+ return { ok: false, error: `${at}.role must be app, test or docs.` };
448
+ const entry = { repo: id, role: role };
449
+ if (e.defaultBranch !== undefined && e.defaultBranch !== null && e.defaultBranch !== '') {
450
+ if (!isBranchName(e.defaultBranch))
451
+ return { ok: false, error: `${at}.defaultBranch is not a branch name.` };
452
+ entry.defaultBranch = e.defaultBranch;
453
+ }
454
+ if (e.pathFilters !== undefined && e.pathFilters !== null) {
455
+ if (!Array.isArray(e.pathFilters) || e.pathFilters.some((p) => typeof p !== 'string'))
456
+ return { ok: false, error: `${at}.pathFilters must be a list of paths.` };
457
+ const paths = e.pathFilters.map((p) => p.trim()).filter(Boolean);
458
+ if (paths.length)
459
+ entry.pathFilters = paths;
460
+ }
461
+ const scope = parsePrScope(e.prScope, at);
462
+ if (!scope.ok)
463
+ return scope;
464
+ if (scope.scope) {
465
+ if (role !== 'app')
466
+ return { ok: false, error: `${at}: prScope applies to an app repo only.` };
467
+ entry.prScope = scope.scope;
468
+ }
469
+ const runTests = parseRunTests(e.runTests, at);
470
+ if (!runTests.ok)
471
+ return runTests;
472
+ if (runTests.off) {
473
+ if (role !== 'app')
474
+ return { ok: false, error: `${at}: runTests applies to an app repo only.` };
475
+ entry.runTests = false;
476
+ }
477
+ const deploy = parseRepoDeploy(e, at);
478
+ if (!deploy.ok)
479
+ return deploy;
480
+ if (deploy.deployEnvironment !== undefined || deploy.waitForDeploySec !== undefined || deploy.deployUrlMatch !== undefined) {
481
+ if (role !== 'app')
482
+ return { ok: false, error: `${at}: deployEnvironment, waitForDeploySec and deployUrlMatch apply to an app repo only.` };
483
+ if (deploy.deployEnvironment !== undefined)
484
+ entry.deployEnvironment = deploy.deployEnvironment;
485
+ if (deploy.waitForDeploySec !== undefined)
486
+ entry.waitForDeploySec = deploy.waitForDeploySec;
487
+ if (deploy.deployUrlMatch !== undefined)
488
+ entry.deployUrlMatch = deploy.deployUrlMatch;
489
+ }
490
+ if (role === 'test') {
491
+ const err = validTestConfig(e.test, at);
492
+ if (err)
493
+ return { ok: false, error: err };
494
+ if (e.test)
495
+ entry.test = e.test;
496
+ if (e.targets !== undefined && e.targets !== null) {
497
+ if (!Array.isArray(e.targets) || e.targets.some((t) => !parseRepoId(t)))
498
+ return { ok: false, error: `${at}.targets must be a list of "owner/name".` };
499
+ const targets = e.targets.map((t) => {
500
+ const r = parseRepoId(t);
501
+ return repoId(r.owner, r.name);
502
+ });
503
+ if (targets.length)
504
+ entry.targets = targets;
505
+ }
506
+ }
507
+ else if (e.test !== undefined || e.targets !== undefined) {
508
+ return { ok: false, error: `${at}: test and targets apply to a test repo only.` };
509
+ }
510
+ out.push(entry);
511
+ }
512
+ const apps = new Set(out.filter((r) => r.role === 'app').map((r) => r.repo));
513
+ if (out.some((r) => r.role === 'test') && !apps.size)
514
+ return { ok: false, error: 'A test repo runs against an app, so add an app repo too.' };
515
+ for (const r of out) {
516
+ const bad = r.targets?.find((t) => !apps.has(t));
517
+ if (bad)
518
+ return { ok: false, error: `${r.repo} targets ${bad}, which is not an app repo of this dot.` };
519
+ }
520
+ return { ok: true, repos: out };
521
+ }
522
+ /** Reads a legacy `repo` body: an object with owner and name, or null to clear. */
523
+ export function parseLegacyRepo(v) {
524
+ if (v === null || v === undefined || v === '')
525
+ return { ok: true, repo: null };
526
+ if (typeof v !== 'object' || Array.isArray(v))
527
+ return { ok: false, error: 'repo must be an object with owner and name.' };
528
+ const r = v;
529
+ const ref = parseRepoId(`${String(r.owner ?? '')}/${String(r.name ?? '')}`);
530
+ if (!ref)
531
+ return { ok: false, error: 'repo needs a valid owner and name.' };
532
+ const branch = r.defaultBranch === undefined || r.defaultBranch === null || r.defaultBranch === '' ? 'main' : r.defaultBranch;
533
+ if (!isBranchName(branch))
534
+ return { ok: false, error: 'repo.defaultBranch is not a branch name.' };
535
+ const paths = Array.isArray(r.pathFilters) ? r.pathFilters.filter((p) => typeof p === 'string' && !!p.trim()).map((p) => p.trim()) : [];
536
+ const scope = parsePrScope(r.prScope, 'repo');
537
+ if (!scope.ok)
538
+ return scope;
539
+ const runTests = parseRunTests(r.runTests, 'repo');
540
+ if (!runTests.ok)
541
+ return runTests;
542
+ const deploy = parseRepoDeploy(r, 'repo');
543
+ if (!deploy.ok)
544
+ return deploy;
545
+ return {
546
+ ok: true,
547
+ repo: {
548
+ owner: ref.owner,
549
+ name: ref.name,
550
+ defaultBranch: branch,
551
+ ...(paths.length ? { pathFilters: paths } : {}),
552
+ ...(scope.scope ? { prScope: scope.scope } : {}),
553
+ ...(runTests.off ? { runTests: false } : {}),
554
+ ...(deploy.deployEnvironment ? { deployEnvironment: deploy.deployEnvironment } : {}),
555
+ ...(deploy.waitForDeploySec !== undefined ? { waitForDeploySec: deploy.waitForDeploySec } : {}),
556
+ ...(deploy.deployUrlMatch ? { deployUrlMatch: deploy.deployUrlMatch } : {}),
557
+ },
558
+ };
559
+ }
560
+ /**
561
+ * The `repo` and `repos` fields to store for a save. `repos` in the body wins and `repo` is derived
562
+ * from its first app entry. A body with only `repo` (the single-repo form) replaces the first app
563
+ * entry in its place and keeps the others in their order; `repo: null` drops it.
564
+ */
565
+ export function resolveRepoFields(body, current) {
566
+ const hasRepos = 'repos' in body && body.repos !== undefined;
567
+ const hasRepo = 'repo' in body && body.repo !== undefined;
568
+ if (!hasRepos && !hasRepo)
569
+ return { ok: true, fields: null };
570
+ let repos;
571
+ if (hasRepos) {
572
+ const parsed = parseWatchRepos(body.repos);
573
+ if (!parsed.ok)
574
+ return parsed;
575
+ repos = parsed.repos;
576
+ }
577
+ else {
578
+ const parsed = parseLegacyRepo(body.repo);
579
+ if (!parsed.ok)
580
+ return parsed;
581
+ const held = (current ? watchRepos(current) : []).map(toWatchRepo);
582
+ const firstApp = held.findIndex((r) => r.role === 'app');
583
+ const next = parsed.repo
584
+ ? {
585
+ repo: repoId(parsed.repo.owner, parsed.repo.name),
586
+ role: 'app',
587
+ defaultBranch: parsed.repo.defaultBranch,
588
+ ...(parsed.repo.pathFilters ? { pathFilters: parsed.repo.pathFilters } : {}),
589
+ ...(parsed.repo.prScope ? { prScope: parsed.repo.prScope } : {}),
590
+ ...(parsed.repo.runTests === false ? { runTests: false } : {}),
591
+ ...legacyDeploy(body.repo, parsed.repo, held[firstApp]),
592
+ }
593
+ : null;
594
+ // The new first app entry takes the place of the old one, so a list that holds a docs or test repo first keeps its order.
595
+ // With no app entry yet it goes first. An entry that names the same repo is replaced by it.
596
+ const list = next
597
+ ? firstApp < 0
598
+ ? [next, ...held.filter((r) => r.repo !== next.repo)]
599
+ : held.flatMap((r, i) => (i === firstApp ? [next] : r.repo === next.repo ? [] : [r]))
600
+ : held.filter((_, i) => i !== firstApp);
601
+ const checked = parseWatchRepos(list);
602
+ if (!checked.ok)
603
+ return checked;
604
+ repos = checked.repos;
605
+ }
606
+ return { ok: true, fields: { repo: repoMirror(repos), repos } };
607
+ }
608
+ /**
609
+ * The deploy wait fields the single `repo` form saves for the first app repo (KAT-395). A body that names them sets them, null clears one.
610
+ * A body that leaves them out keeps the ones the repo has, so a client that does not know them does not wipe them.
611
+ */
612
+ function legacyDeploy(body, parsed, held) {
613
+ const sent = body && typeof body === 'object' ? body : {};
614
+ const same = held && held.repo === repoId(parsed.owner, parsed.name);
615
+ return {
616
+ ...('deployEnvironment' in sent
617
+ ? parsed.deployEnvironment
618
+ ? { deployEnvironment: parsed.deployEnvironment }
619
+ : {}
620
+ : same && held.deployEnvironment
621
+ ? { deployEnvironment: held.deployEnvironment }
622
+ : {}),
623
+ ...('waitForDeploySec' in sent
624
+ ? parsed.waitForDeploySec !== undefined
625
+ ? { waitForDeploySec: parsed.waitForDeploySec }
626
+ : {}
627
+ : same && held.waitForDeploySec !== undefined
628
+ ? { waitForDeploySec: held.waitForDeploySec }
629
+ : {}),
630
+ ...('deployUrlMatch' in sent
631
+ ? parsed.deployUrlMatch
632
+ ? { deployUrlMatch: parsed.deployUrlMatch }
633
+ : {}
634
+ : same && held.deployUrlMatch
635
+ ? { deployUrlMatch: held.deployUrlMatch }
636
+ : {}),
637
+ };
638
+ }
639
+ /**
640
+ * `Watch.repo` for a list of `repos`: the first app repo, with the branch a run reads for it now. Call it again once a new repo
641
+ * has joined the workspace, since an entry with no branch reads the workspace default and a new row may hold another one than "main".
642
+ */
643
+ export function repoMirror(repos) {
644
+ return legacyRepo(watchRepos({ repos }));
645
+ }
646
+ /**
647
+ * `Watch.repo` as the dot page shows it: the branch of the first app repo as a run reads it now. The stored mirror keeps the branch
648
+ * from the last save, and the workspace default may have moved since. The form sends this value back, so a save that leaves
649
+ * the branch alone reads as unchanged.
650
+ */
651
+ export function repoAsRun(w) {
652
+ const first = primaryRepo(w);
653
+ if (!w.repo || !first || !sameRepo(w.repo, first) || w.repo.defaultBranch === first.defaultBranch)
654
+ return w.repo;
655
+ return { ...w.repo, defaultBranch: first.defaultBranch };
656
+ }
657
+ // ---------- repo changes only an admin may make (KAT-369) ----------
658
+ /** A list as a save leaves it: trimmed, each entry once, order ignored. */
659
+ const asSet = (v) => JSON.stringify([...new Set(cleanTestBranches(v))].sort());
660
+ /** The ref of a test repo as a run reads it: an unset ref and `default` are the same. */
661
+ const refOf = (t) => JSON.stringify(t?.ref === undefined || t.ref === 'default' ? 'default' : t.ref);
662
+ /**
663
+ * The repo settings a save would change that an editor may not (KAT-369), as `repos[acme/shop].defaultBranch` or `testBranches`.
664
+ * Empty when none. These decide which code a run checks out: the repos of the dot and their roles, their order (the first app repo
665
+ * is the dot's repo), the branch of each, the app repos a test repo exercises, the framework and ref of a test repo, and the test
666
+ * branches. Path filters, PR scope, and the Run tests switch are not here. Both sides are read as a run reads them (`watchRepos`),
667
+ * so a save that sends `repo` alone, or the saved list as it is, changes nothing. A `repos` list the save routes refuse anyway
668
+ * changes nothing here: they answer it with the 400 and write nothing.
669
+ */
670
+ export function repoAdminChanges(current, body) {
671
+ const out = [];
672
+ if (body.testBranches !== undefined && asSet(body.testBranches) !== asSet(current.testBranches))
673
+ out.push('testBranches');
674
+ const res = resolveRepoFields(body, current);
675
+ if (!res.ok) {
676
+ // A `repo` that cannot be stored next to the other repos (a test repo that targets the one it replaces) is still another repo.
677
+ const parsed = body.repos === undefined && body.repo !== undefined ? parseLegacyRepo(body.repo) : null;
678
+ if (parsed?.ok) {
679
+ const first = primaryRepo(current);
680
+ const asked = parsed.repo;
681
+ const same = asked ? !!first && first.id === repoId(asked.owner, asked.name) && first.defaultBranch === asked.defaultBranch : !first;
682
+ if (!same)
683
+ out.push('repo');
684
+ }
685
+ return out;
686
+ }
687
+ if (!res.fields)
688
+ return out;
689
+ const before = watchRepos(current);
690
+ const after = watchRepos({ repos: res.fields.repos });
691
+ const was = new Map(before.map((r) => [r.id, r]));
692
+ const now = new Set(after.map((r) => r.id));
693
+ for (const r of after) {
694
+ const old = was.get(r.id);
695
+ if (!old) {
696
+ out.push(`repos[${r.id}]`);
697
+ continue;
698
+ }
699
+ if (old.role !== r.role)
700
+ out.push(`repos[${r.id}].role`);
701
+ if (old.defaultBranch !== r.defaultBranch)
702
+ out.push(`repos[${r.id}].defaultBranch`);
703
+ if (asSet(old.targets) !== asSet(r.targets))
704
+ out.push(`repos[${r.id}].targets`);
705
+ if (old.test?.framework !== r.test?.framework)
706
+ out.push(`repos[${r.id}].test.framework`);
707
+ if (refOf(old.test) !== refOf(r.test))
708
+ out.push(`repos[${r.id}].test.ref`);
709
+ }
710
+ for (const r of before)
711
+ if (!now.has(r.id))
712
+ out.push(`repos[${r.id}]`);
713
+ // The same repos in another order: the first app repo is the one `repo` mirrors.
714
+ if (!out.length && before.map((r) => r.id).join() !== after.map((r) => r.id).join())
715
+ out.push('repos');
716
+ return out;
717
+ }
718
+ function toWatchRepo(r) {
719
+ return {
720
+ repo: r.id,
721
+ role: r.role,
722
+ defaultBranch: r.defaultBranch,
723
+ ...(r.pathFilters?.length ? { pathFilters: r.pathFilters } : {}),
724
+ ...(r.test ? { test: r.test } : {}),
725
+ ...(r.targets?.length ? { targets: r.targets } : {}),
726
+ ...(r.prScope ? { prScope: r.prScope } : {}),
727
+ ...(r.runTests === false ? { runTests: false } : {}),
728
+ ...deployOf(r),
729
+ };
730
+ }
731
+ // ---------- workspace repo store (section 1.3) ----------
732
+ /** Dots (not archived) that hold this repo. */
733
+ export function dotsUsingRepo(id, watches = list('watches')) {
734
+ const want = id.toLowerCase();
735
+ return watches.filter((w) => !w.archived && watchRepos(w).some((r) => r.id === want));
736
+ }
737
+ /**
738
+ * Adds a workspace repo when missing and returns the row. An existing row keeps its scan state;
739
+ * a known default branch or private flag is updated.
740
+ */
741
+ export function ensureWorkspaceRepo(ref, info = {}) {
742
+ const id = repoId(ref.owner, ref.name);
743
+ const cur = getWorkspaceRepo(id);
744
+ if (cur) {
745
+ const patch = {};
746
+ if (info.defaultBranch && info.defaultBranch !== cur.defaultBranch)
747
+ patch.defaultBranch = info.defaultBranch;
748
+ if (info.private !== undefined && info.private !== cur.private)
749
+ patch.private = info.private;
750
+ if (Object.keys(patch).length) {
751
+ update('repos', id, patch);
752
+ return changed(getWorkspaceRepo(id));
753
+ }
754
+ return cur;
755
+ }
756
+ const now = new Date().toISOString();
757
+ const row = insert('repos', {
758
+ id,
759
+ owner: ref.owner,
760
+ name: ref.name,
761
+ defaultBranch: info.defaultBranch || 'main',
762
+ private: info.private ?? false,
763
+ addedAt: now,
764
+ // New repos wait in queued until a scan is requested.
765
+ scan: { state: 'queued' },
766
+ });
767
+ return changed(row);
768
+ }
769
+ /** Removes a workspace repo. Refused with the dot names while a dot still holds it. */
770
+ export function removeWorkspaceRepo(id) {
771
+ const key = id.toLowerCase();
772
+ if (!getWorkspaceRepo(key))
773
+ return { ok: false, code: 404, error: `${key} is not a workspace repo.` };
774
+ const users = dotsUsingRepo(key);
775
+ if (users.length)
776
+ return {
777
+ ok: false,
778
+ code: 409,
779
+ error: `${key} is used by ${users.map((w) => w.name).join(', ')}. Remove it from those dots first.`,
780
+ dots: users.map((w) => w.name),
781
+ };
782
+ remove('repos', key);
783
+ mirrorSettings();
784
+ return { ok: true };
785
+ }
786
+ /**
787
+ * Writes a workspace repo's scan state and publishes the row so the pages update live. A patch
788
+ * keeps the fields it leaves out (the last profile's sha and time stay while a rescan runs).
789
+ * Returns the row, or undefined when the repo is not in the workspace.
790
+ */
791
+ export function setRepoScan(id, patch) {
792
+ const cur = getWorkspaceRepo(id);
793
+ if (!cur)
794
+ return undefined;
795
+ const scan = { ...cur.scan, ...patch };
796
+ if (patch.state !== 'error')
797
+ delete scan.error;
798
+ update('repos', cur.id, { scan });
799
+ return changed(getWorkspaceRepo(cur.id));
800
+ }
801
+ function changed(row) {
802
+ try {
803
+ publish({ type: 'repo', repo: row });
804
+ }
805
+ catch {
806
+ /* live events are best effort */
807
+ }
808
+ return row;
809
+ }
810
+ /**
811
+ * Writes the GitHub provider's `settings.repos` from the repos table, so the Setup picker shows
812
+ * the workspace list (section 1.3 step 2). Skipped when the stored list already matches.
813
+ */
814
+ export function mirrorSettings() {
815
+ try {
816
+ const ids = listWorkspaceRepos().map((r) => `${r.owner}/${r.name}`);
817
+ const meta = getMeta('github');
818
+ const cur = meta.settings?.repos;
819
+ const have = Array.isArray(cur) ? cur : typeof cur === 'string' && cur ? [cur] : [];
820
+ const same = have.length === ids.length && have.every((x, i) => x.toLowerCase() === ids[i].toLowerCase());
821
+ if (same)
822
+ return;
823
+ const settings = { ...(meta.settings ?? {}) };
824
+ if (ids.length)
825
+ settings.repos = ids;
826
+ else
827
+ delete settings.repos;
828
+ setMeta('github', { settings });
829
+ }
830
+ catch {
831
+ /* the connect store is not ready (no master key): the table stays the source of truth */
832
+ }
833
+ }
834
+ /** The GitHub provider's picked repos, as stored before the workspace table existed. */
835
+ function settingsRepos() {
836
+ try {
837
+ const cur = getMeta('github').settings?.repos;
838
+ const vals = Array.isArray(cur) ? cur : typeof cur === 'string' && cur ? [cur] : [];
839
+ return vals.map(parseRepoId).filter((r) => !!r);
840
+ }
841
+ catch {
842
+ return [];
843
+ }
844
+ }
845
+ /**
846
+ * Boot migration (section 1.3), safe to repeat:
847
+ * 1. a dot with `repo` and no `repos` gets one app entry, and its repo joins the workspace;
848
+ * 2. every repo a dot holds and every repo in the GitHub provider's `settings.repos` joins the workspace;
849
+ * 3. `settings.repos` is rewritten to mirror the workspace.
850
+ * Scans are not queued here, so new rows stay in `queued` until one is requested.
851
+ */
852
+ export function migrateWatchRepos() {
853
+ const out = { watches: [], added: [] };
854
+ const add = (ref, info) => {
855
+ const id = repoId(ref.owner, ref.name);
856
+ if (getWorkspaceRepo(id))
857
+ return;
858
+ ensureWorkspaceRepo(ref, info);
859
+ out.added.push(id);
860
+ };
861
+ for (const w of list('watches')) {
862
+ if (w.repo && !(Array.isArray(w.repos) && w.repos.length)) {
863
+ const ref = parseRepoId(`${w.repo.owner}/${w.repo.name}`);
864
+ if (!ref)
865
+ continue;
866
+ const entry = {
867
+ repo: repoId(ref.owner, ref.name),
868
+ role: 'app',
869
+ defaultBranch: w.repo.defaultBranch || 'main',
870
+ ...(w.repo.pathFilters?.length ? { pathFilters: w.repo.pathFilters } : {}),
871
+ ...(w.repo.prScope ? { prScope: w.repo.prScope } : {}),
872
+ ...(w.repo.runTests === false ? { runTests: false } : {}),
873
+ ...deployOf(w.repo),
874
+ };
875
+ update('watches', w.id, { repos: [entry] });
876
+ out.watches.push(w.id);
877
+ }
878
+ // `repo` first: it keeps the owner and name casing, which a `repos` id (lower case) has lost.
879
+ const legacy = w.repo ? parseRepoId(`${w.repo.owner}/${w.repo.name}`) : null;
880
+ if (legacy)
881
+ add(legacy, { defaultBranch: w.repo.defaultBranch || 'main' });
882
+ const now = get('watches', w.id) ?? w;
883
+ for (const r of watchRepos(now, () => undefined))
884
+ add(r, { defaultBranch: r.defaultBranch });
885
+ }
886
+ for (const ref of settingsRepos())
887
+ add(ref);
888
+ mirrorSettings();
889
+ return out;
890
+ }
891
+ //# sourceMappingURL=repos.js.map