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,900 @@
1
+ // Providers for native connections (KAT-66): what each service needs, how to test it, and the pickers
2
+ // it serves. Every test runs against candidate values (the form) layered over the live settings, so
3
+ // nothing is saved until it works. Messages never include a secret.
4
+ import { existsSync } from 'node:fs';
5
+ import path from 'node:path';
6
+ import { config, liveEnv, setting, settingSource } from '../config.js';
7
+ import { reviewChildEnv } from '../review/backend-cli.js';
8
+ import { deps, fetchT } from './deps.js';
9
+ import { apiBase, appAuth, ghHeaders, installUrl } from './github-app.js';
10
+ import { getMeta, setRuntimeValue } from './store.js';
11
+ import { stopTunnel, tunnelState } from './tunnel.js';
12
+ import { detectedActive } from './aivision-local.js';
13
+ import { aivisionTokenFor, originOf, tokenWithheldReason, TOKEN_KEY } from './aivision-token.js';
14
+ import { accessMessage, checkRepoWith } from './github-access.js';
15
+ import { list } from '../db.js';
16
+ const ANALYSIS_MODEL = 'claude-sonnet-5-5';
17
+ const FAST_MODEL = 'claude-haiku-4-5-20251001';
18
+ const ok = (message, account) => (account ? { ok: true, message, account } : { ok: true, message });
19
+ const fail = (message) => ({ ok: false, message });
20
+ function errText(err) {
21
+ if (err instanceof Error && err.name === 'TimeoutError')
22
+ return 'timed out';
23
+ return err instanceof Error ? err.message : String(err);
24
+ }
25
+ /** Runs `fn`, turning a thrown network error into a failed test with `what` in the message. */
26
+ async function guarded(what, fn) {
27
+ try {
28
+ return await fn();
29
+ }
30
+ catch (err) {
31
+ return fail(`Could not reach ${what}: ${errText(err)}.`);
32
+ }
33
+ }
34
+ async function json(res) {
35
+ try {
36
+ return (await res.json());
37
+ }
38
+ catch {
39
+ return undefined;
40
+ }
41
+ }
42
+ // ---------- model ----------
43
+ const anthropicBase = () => (liveEnv.ANTHROPIC_BASE_URL ?? 'https://api.anthropic.com').replace(/\/$/, '');
44
+ async function anthropicModels(key) {
45
+ const res = await fetchT(`${anthropicBase()}/v1/models?limit=100`, { headers: { 'x-api-key': key, 'anthropic-version': '2023-06-01' } });
46
+ if (!res.ok)
47
+ return { status: res.status, models: [] };
48
+ const body = await json(res);
49
+ return { status: res.status, models: body?.data ?? [] };
50
+ }
51
+ /** Allowlisted env for a Claude CLI child, adjusted to test one method. */
52
+ function cliEnv(get, method) {
53
+ const env = reviewChildEnv();
54
+ if (method === 'claude-token') {
55
+ const token = get('CLAUDE_CODE_OAUTH_TOKEN');
56
+ if (token)
57
+ env.CLAUDE_CODE_OAUTH_TOKEN = token;
58
+ // An API key in the env would win over the token, so the test would not prove the token works.
59
+ delete env.ANTHROPIC_API_KEY;
60
+ }
61
+ else if (settingSource('CLAUDE_CODE_OAUTH_TOKEN') !== 'env')
62
+ delete env.CLAUDE_CODE_OAUTH_TOKEN;
63
+ return env;
64
+ }
65
+ /** One tool-less turn through `claude -p`. Proves the login or token works end to end. */
66
+ export async function claudeRoundTrip(get, method) {
67
+ const bin = get('LOCALDOST_CLAUDE_BIN')?.trim() || 'claude';
68
+ if (!deps.which(bin))
69
+ return fail(`The Claude CLI ("${bin}") is not installed on this server.`);
70
+ const model = get('LOCALDOST_FAST_MODEL')?.trim() || 'haiku';
71
+ const args = [
72
+ '-p',
73
+ '--output-format',
74
+ 'json',
75
+ '--model',
76
+ model,
77
+ '--tools',
78
+ '',
79
+ '--strict-mcp-config',
80
+ '--setting-sources',
81
+ '',
82
+ '--no-session-persistence',
83
+ '--max-turns',
84
+ '1',
85
+ ];
86
+ const r = await deps.run(bin, args, { input: 'Reply with the single word OK.', env: cliEnv(get, method), timeoutMs: 90_000, tempCwd: true });
87
+ if (r.timedOut)
88
+ return fail('The Claude CLI did not answer within 90 seconds.');
89
+ let parsed;
90
+ try {
91
+ parsed = JSON.parse(r.stdout);
92
+ }
93
+ catch {
94
+ parsed = undefined;
95
+ }
96
+ if (r.code !== 0 || parsed?.is_error) {
97
+ const why = typeof parsed?.result === 'string' ? parsed.result : r.stderr;
98
+ if (/log ?in|auth|token|401|credential/i.test(why))
99
+ return fail(method === 'claude-token'
100
+ ? 'Claude rejected the token. Run claude setup-token again and paste the new token.'
101
+ : 'The Claude CLI is not signed in. Run claude auth login on this server, or paste a token.');
102
+ return fail(`The Claude CLI failed (exit ${r.code ?? 'none'}).`);
103
+ }
104
+ return ok(method === 'claude-token' ? 'Claude answered with the subscription token.' : 'Claude answered through the signed-in CLI.');
105
+ }
106
+ /** `codex login status` on this server: spends no usage, proves a ChatGPT login exists. */
107
+ export async function codexLoginCheck(get) {
108
+ const bin = get('LOCALDOST_CODEX_BIN')?.trim() || 'codex';
109
+ if (!deps.which(bin))
110
+ return fail(`The Codex CLI ("${bin}") is not installed on this server.`);
111
+ const r = await deps.run(bin, ['login', 'status'], { timeoutMs: 15_000 });
112
+ if (r.timedOut)
113
+ return fail('The Codex CLI did not answer within 15 seconds.');
114
+ if (r.code !== 0)
115
+ return fail('The Codex CLI is not signed in. Run codex login on this server.');
116
+ const model = get('LOCALDOST_CODEX_MODEL')?.trim();
117
+ return ok(`The Codex CLI is signed in${model ? `; dots use ${model}` : ''}.`);
118
+ }
119
+ const model = {
120
+ key: 'model',
121
+ label: 'Model',
122
+ methods: [
123
+ { id: 'claude-cli', label: 'Claude subscription (signed-in CLI)', description: 'Uses the Claude CLI that is signed in on this server.' },
124
+ { id: 'claude-token', label: 'Claude subscription (token)', description: 'Paste the token that claude setup-token prints.' },
125
+ { id: 'codex-cli', label: 'Codex subscription (signed-in CLI)', description: 'Uses the Codex CLI signed in with a ChatGPT login on this server.' },
126
+ { id: 'anthropic', label: 'Anthropic API key', description: 'Bills the Anthropic API per token.' },
127
+ ],
128
+ fields: [
129
+ { key: 'ANTHROPIC_API_KEY', name: 'apiKey', label: 'API key', secret: true, kind: 'secret', methods: ['anthropic'], required: true },
130
+ {
131
+ key: 'CLAUDE_CODE_OAUTH_TOKEN',
132
+ name: 'oauthToken',
133
+ label: 'Subscription token',
134
+ secret: true,
135
+ kind: 'secret',
136
+ methods: ['claude-token'],
137
+ required: true,
138
+ },
139
+ { key: 'LOCALDOST_MODEL', name: 'model', label: 'Main model', secret: false, kind: 'text', help: 'Verdicts, reviews, and chat.' },
140
+ { key: 'LOCALDOST_FAST_MODEL', name: 'fastModel', label: 'Fast model', secret: false, kind: 'text', help: 'Ticket scores and action review.' },
141
+ {
142
+ key: 'LOCALDOST_CODEX_MODEL',
143
+ name: 'codexModel',
144
+ label: 'Codex model',
145
+ secret: false,
146
+ kind: 'text',
147
+ methods: ['codex-cli'],
148
+ help: 'Unset: the Codex CLI default.',
149
+ },
150
+ { key: 'LOCALDOST_LLM', name: 'backend', label: 'Backend', secret: false, kind: 'text', hidden: true },
151
+ ],
152
+ optionKinds: ['models'],
153
+ implied: (m) => ({ LOCALDOST_LLM: m === 'anthropic' ? 'anthropic' : m === 'codex-cli' ? 'codex-cli' : 'claude-cli' }),
154
+ clears: (m) => (m === 'claude-cli' ? ['CLAUDE_CODE_OAUTH_TOKEN'] : []),
155
+ activeMethod(get) {
156
+ const pick = (get('LOCALDOST_LLM') ?? '').trim().toLowerCase();
157
+ if (pick === 'claude-cli')
158
+ return get('CLAUDE_CODE_OAUTH_TOKEN') ? 'claude-token' : 'claude-cli';
159
+ if (pick === 'codex-cli')
160
+ return 'codex-cli';
161
+ if (pick === 'mock')
162
+ return undefined;
163
+ return pick === 'anthropic' || get('ANTHROPIC_API_KEY') ? 'anthropic' : undefined;
164
+ },
165
+ validate(values, method) {
166
+ if (method === 'anthropic' && values.ANTHROPIC_API_KEY && !/^sk-ant-/.test(values.ANTHROPIC_API_KEY))
167
+ return 'Anthropic API keys start with sk-ant-.';
168
+ if (method === 'claude-token' && values.CLAUDE_CODE_OAUTH_TOKEN && !/^sk-ant-/.test(values.CLAUDE_CODE_OAUTH_TOKEN))
169
+ return 'Subscription tokens start with sk-ant-oat. Run claude setup-token to get one.';
170
+ return undefined;
171
+ },
172
+ async test(get, method) {
173
+ const m = method ?? this.activeMethod(get);
174
+ if (!m)
175
+ return fail('No model is connected. The dots use the mock model.');
176
+ if (m === 'codex-cli')
177
+ return codexLoginCheck(get);
178
+ if (m !== 'anthropic')
179
+ return claudeRoundTrip(get, m);
180
+ const key = get('ANTHROPIC_API_KEY');
181
+ if (!key)
182
+ return fail('Enter an Anthropic API key.');
183
+ return guarded('Anthropic', async () => {
184
+ const { status, models } = await anthropicModels(key);
185
+ if (status === 401 || status === 403)
186
+ return fail('Anthropic rejected the API key.');
187
+ if (status !== 200)
188
+ return fail(`Anthropic answered HTTP ${status}.`);
189
+ const ids = new Set(models.map((x) => x.id));
190
+ for (const k of ['LOCALDOST_MODEL', 'LOCALDOST_FAST_MODEL']) {
191
+ const want = get(k)?.trim();
192
+ if (want && ids.size && !ids.has(want))
193
+ return fail(`The model ${want} is not available to this key.`);
194
+ }
195
+ return ok(`The API key works. ${models.length} models available.`);
196
+ });
197
+ },
198
+ async options(kind, get) {
199
+ if (kind !== 'models')
200
+ return [];
201
+ const key = get('ANTHROPIC_API_KEY');
202
+ if (key && this.activeMethod(get) !== 'claude-cli' && this.activeMethod(get) !== 'claude-token') {
203
+ try {
204
+ const { models } = await anthropicModels(key);
205
+ if (models.length)
206
+ return models.map((m) => ({ value: m.id, label: m.display_name ?? m.id, hint: m.id }));
207
+ }
208
+ catch {
209
+ /* fall through to the defaults */
210
+ }
211
+ }
212
+ return [
213
+ { value: 'sonnet', label: 'Sonnet (latest)', hint: 'Claude CLI alias' },
214
+ { value: 'opus', label: 'Opus (latest)', hint: 'Claude CLI alias' },
215
+ { value: 'haiku', label: 'Haiku (latest)', hint: 'Claude CLI alias' },
216
+ { value: ANALYSIS_MODEL, label: ANALYSIS_MODEL, hint: 'Default main model' },
217
+ { value: FAST_MODEL, label: FAST_MODEL, hint: 'Default fast model' },
218
+ ];
219
+ },
220
+ };
221
+ // ---------- GitHub ----------
222
+ /** Token from the gh CLI, or undefined. The token never leaves the server. */
223
+ export async function ghToken() {
224
+ if (!deps.which('gh'))
225
+ return undefined;
226
+ const r = await deps.run('gh', ['auth', 'token'], { timeoutMs: 10_000 });
227
+ const tok = r.code === 0 ? r.stdout.trim() : '';
228
+ return tok || undefined;
229
+ }
230
+ /**
231
+ * With the gh-cli method nothing is stored: the token is read from gh at start and every 30 minutes,
232
+ * and held as a runtime value. An env GITHUB_TOKEN still wins.
233
+ */
234
+ export async function refreshGhToken() {
235
+ if (getMeta('github').method !== 'gh-cli')
236
+ return;
237
+ const tok = await ghToken().catch(() => undefined);
238
+ setRuntimeValue('GITHUB_TOKEN', tok ?? null);
239
+ }
240
+ let ghTimer;
241
+ export function startGhRefresh() {
242
+ if (ghTimer)
243
+ return;
244
+ void refreshGhToken();
245
+ ghTimer = setInterval(() => void refreshGhToken(), 30 * 60_000);
246
+ ghTimer.unref?.();
247
+ }
248
+ async function githubUser(token) {
249
+ const res = await fetchT(`${apiBase()}/user`, { headers: ghHeaders(token) });
250
+ if (res.status === 401)
251
+ return fail('GitHub rejected the token.');
252
+ if (!res.ok)
253
+ return fail(`GitHub answered HTTP ${res.status}.`);
254
+ const login = String((await json(res))?.login ?? '');
255
+ const scopes = res.headers.get('x-oauth-scopes');
256
+ // Classic tokens list their scopes; fine-grained tokens send no header and are checked per repo.
257
+ if (scopes !== null) {
258
+ const list = scopes.split(',').map((s) => s.trim());
259
+ if (!list.includes('repo'))
260
+ return fail(`The token is missing the repo scope (it has: ${list.filter(Boolean).join(', ') || 'none'}).`);
261
+ }
262
+ return ok(scopes === null ? `Connected as ${login}. Fine-grained token: grant it the repos the dots watch.` : `Connected as ${login}.`, login || undefined);
263
+ }
264
+ async function githubApp(get) {
265
+ const id = get('GITHUB_APP_ID');
266
+ const key = get('GITHUB_PRIVATE_KEY');
267
+ if (!id || !key)
268
+ return fail('A GitHub App needs both the App id and the private key.');
269
+ let jwt;
270
+ try {
271
+ jwt = (await (await appAuth(id, key))({ type: 'app' })).token;
272
+ }
273
+ catch {
274
+ return fail('The private key could not sign a GitHub App token.');
275
+ }
276
+ const res = await fetchT(`${apiBase()}/app`, { headers: ghHeaders(jwt) });
277
+ if (res.status === 401)
278
+ return fail('GitHub rejected the App id and private key.');
279
+ if (!res.ok)
280
+ return fail(`GitHub answered HTTP ${res.status}.`);
281
+ const app = await json(res);
282
+ const inst = await fetchT(`${apiBase()}/app/installations?per_page=100`, { headers: ghHeaders(jwt) });
283
+ const count = inst.ok ? ((await json(inst)) ?? []).length : 0;
284
+ const slug = app?.slug ?? get('GITHUB_APP_SLUG');
285
+ const name = app?.name ?? slug ?? 'GitHub App';
286
+ if (!count)
287
+ return ok(`${name} works. Install it on the repos the dots watch.`, slug);
288
+ return ok(`${name} works. Installed on ${count} account${count === 1 ? '' : 's'}.`, slug);
289
+ }
290
+ /** A token for one repo from the credentials being tested: the PAT or gh token, or an App installation token. */
291
+ async function repoToken(get, method, full) {
292
+ if (method !== 'app') {
293
+ const token = get('GITHUB_TOKEN');
294
+ if (!token)
295
+ throw new Error('No token to test with.');
296
+ return token;
297
+ }
298
+ const id = get('GITHUB_APP_ID');
299
+ const key = get('GITHUB_PRIVATE_KEY');
300
+ if (!id || !key)
301
+ throw new Error('A GitHub App needs both the App id and the private key.');
302
+ const auth = await appAuth(id, key);
303
+ const jwt = (await auth({ type: 'app' })).token;
304
+ const res = await fetchT(`${apiBase()}/repos/${full}/installation`, { headers: ghHeaders(jwt) });
305
+ if (!res.ok)
306
+ throw new Error(`The GitHub App is not installed on ${full}. An organization owner has to install it on this repo.`);
307
+ const inst = await json(res);
308
+ if (!inst?.id)
309
+ throw new Error(`The GitHub App is not installed on ${full}.`);
310
+ return (await auth({ type: 'installation', installationId: inst.id })).token;
311
+ }
312
+ /**
313
+ * The Test button of the GitHub sheet after the identity check passed (KAT-357): every repo in the workspace is read, with its
314
+ * issues endpoint, using the credentials in the form. A repo it cannot read, or a token that needs SAML SSO, fails the test
315
+ * and says which repo and why. Connect does not run this, so saving a connection never waits on a repo.
316
+ */
317
+ async function withRepoChecks(base, get, method) {
318
+ const repos = list('repos')
319
+ .map((r) => r.id)
320
+ .slice(0, 20);
321
+ if (!repos.length)
322
+ return base;
323
+ const rows = await Promise.all(repos.map(async (full) => {
324
+ try {
325
+ return await checkRepoWith(full, await repoToken(get, method, full));
326
+ }
327
+ catch (err) {
328
+ return { repo: full, ok: false, issues: null, message: err instanceof Error ? err.message : String(err) };
329
+ }
330
+ }));
331
+ const summary = accessMessage(rows);
332
+ const bad = rows.filter((r) => !r.ok);
333
+ if (!bad.length)
334
+ return ok(`${base.message} ${summary}`, base.account);
335
+ return fail(`${base.message} ${summary} ${bad
336
+ .slice(0, 3)
337
+ .map((r) => `${r.repo}: ${r.message}`)
338
+ .join(' ')}`);
339
+ }
340
+ async function githubRepos(get, q) {
341
+ const out = [];
342
+ const add = (r) => {
343
+ if (r.full_name && (!q || r.full_name.toLowerCase().includes(q.toLowerCase())))
344
+ out.push({ value: r.full_name, label: r.full_name, ...(r.private ? { hint: 'private' } : {}) });
345
+ };
346
+ const id = get('GITHUB_APP_ID');
347
+ const key = get('GITHUB_PRIVATE_KEY');
348
+ if (id && key) {
349
+ const auth = await appAuth(id, key);
350
+ const jwt = (await auth({ type: 'app' })).token;
351
+ const inst = await fetchT(`${apiBase()}/app/installations?per_page=100`, { headers: ghHeaders(jwt) });
352
+ for (const i of inst.ok ? ((await json(inst)) ?? []) : []) {
353
+ const tok = (await auth({ type: 'installation', installationId: i.id })).token;
354
+ const res = await fetchT(`${apiBase()}/installation/repositories?per_page=100`, { headers: ghHeaders(tok) });
355
+ for (const r of res.ok ? ((await json(res))?.repositories ?? []) : [])
356
+ add(r);
357
+ }
358
+ return out;
359
+ }
360
+ const token = get('GITHUB_TOKEN');
361
+ if (!token)
362
+ return out;
363
+ const res = await fetchT(`${apiBase()}/user/repos?per_page=100&sort=pushed`, { headers: ghHeaders(token) });
364
+ for (const r of res.ok ? ((await json(res)) ?? []) : [])
365
+ add(r);
366
+ return out;
367
+ }
368
+ const APP_KEYS = ['GITHUB_APP_ID', 'GITHUB_PRIVATE_KEY', 'GITHUB_APP_SLUG'];
369
+ const github = {
370
+ key: 'github',
371
+ label: 'GitHub',
372
+ methods: [
373
+ { id: 'gh-cli', label: 'GitHub CLI login', description: 'Uses the token of the gh CLI signed in on this server.' },
374
+ { id: 'app', label: 'GitHub App', description: 'localdost creates an App for you on github.com.' },
375
+ { id: 'pat', label: 'Personal access token', description: 'Paste a fine-grained or classic token.' },
376
+ ],
377
+ fields: [
378
+ { key: 'GITHUB_TOKEN', name: 'token', label: 'Token', secret: true, kind: 'secret', methods: ['pat'], required: true },
379
+ { key: 'GITHUB_APP_ID', name: 'appId', label: 'App id', secret: false, kind: 'text', methods: ['app'], required: true },
380
+ { key: 'GITHUB_PRIVATE_KEY', name: 'privateKey', label: 'Private key', secret: true, kind: 'textarea', methods: ['app'], required: true },
381
+ { key: 'GITHUB_APP_SLUG', name: 'appSlug', label: 'App slug', secret: false, kind: 'text', methods: ['app'] },
382
+ { key: 'GITHUB_WEBHOOK_SECRET', name: 'webhookSecret', label: 'Webhook secret', secret: true, kind: 'secret' },
383
+ ],
384
+ optionKinds: ['repos'],
385
+ clears: (m) => (m === 'app' ? ['GITHUB_TOKEN'] : m === 'gh-cli' ? [...APP_KEYS, 'GITHUB_TOKEN'] : APP_KEYS),
386
+ activeMethod(get) {
387
+ if (get('GITHUB_APP_ID') && get('GITHUB_PRIVATE_KEY'))
388
+ return 'app';
389
+ if (!get('GITHUB_TOKEN'))
390
+ return undefined;
391
+ return settingSource('GITHUB_TOKEN') !== 'env' && getMeta('github').method === 'gh-cli' ? 'gh-cli' : 'pat';
392
+ },
393
+ async resolve(method, values) {
394
+ if (method !== 'gh-cli')
395
+ return values;
396
+ const tok = await ghToken();
397
+ if (!tok)
398
+ throw new Error('gh is not signed in on this server. Run gh auth login there, then try again.');
399
+ return { ...values, GITHUB_TOKEN: tok };
400
+ },
401
+ validate(values, method) {
402
+ if (method === 'pat' && values.GITHUB_TOKEN && !/^(ghp_|github_pat_|gho_|ghu_)/.test(values.GITHUB_TOKEN))
403
+ return 'GitHub tokens start with ghp_ or github_pat_.';
404
+ if (values.GITHUB_APP_ID && !/^\d+$/.test(values.GITHUB_APP_ID))
405
+ return 'The App id is a number.';
406
+ return undefined;
407
+ },
408
+ async test(get, method, opts) {
409
+ const m = method ?? this.activeMethod(get);
410
+ if (!m)
411
+ return fail('GitHub is not connected. Comments and check runs go to the outbox.');
412
+ return guarded('GitHub', async () => {
413
+ let base;
414
+ if (m === 'app')
415
+ base = await githubApp(get);
416
+ else {
417
+ const token = get('GITHUB_TOKEN');
418
+ if (!token)
419
+ return fail(m === 'gh-cli' ? 'gh is not signed in on this server.' : 'Enter a token.');
420
+ base = await githubUser(token);
421
+ }
422
+ return base.ok && opts?.checkRepos ? withRepoChecks(base, get, m) : base;
423
+ });
424
+ },
425
+ options: (kind, get, q) => (kind === 'repos' ? githubRepos(get, q.q) : Promise.resolve([])),
426
+ links(get) {
427
+ const slug = get('GITHUB_APP_SLUG');
428
+ return slug ? { install: installUrl(slug) } : {};
429
+ },
430
+ async onDisconnect() {
431
+ setRuntimeValue('GITHUB_TOKEN', null);
432
+ },
433
+ };
434
+ // ---------- Linear ----------
435
+ async function linearQuery(key, query, variables) {
436
+ const res = await fetchT(liveEnv.LINEAR_API_URL?.trim() || 'https://api.linear.app/graphql', {
437
+ method: 'POST',
438
+ headers: { 'content-type': 'application/json', authorization: key },
439
+ body: JSON.stringify({ query, variables }),
440
+ });
441
+ const body = await json(res);
442
+ return { status: res.status, data: body?.data, error: body?.errors?.[0]?.message };
443
+ }
444
+ const linear = {
445
+ key: 'linear',
446
+ label: 'Linear',
447
+ methods: [{ id: 'api-key', label: 'API key', description: 'A personal API key from Linear settings.' }],
448
+ fields: [
449
+ { key: 'LINEAR_API_KEY', name: 'apiKey', label: 'API key', secret: true, kind: 'secret', required: true },
450
+ { key: 'LINEAR_WEBHOOK_SECRET', name: 'webhookSecret', label: 'Webhook secret', secret: true, kind: 'secret' },
451
+ ],
452
+ optionKinds: ['teams', 'projects'],
453
+ activeMethod: (get) => (get('LINEAR_API_KEY') ? 'api-key' : undefined),
454
+ validate: (v) => (v.LINEAR_API_KEY && !/^lin_api_/.test(v.LINEAR_API_KEY) ? 'Linear API keys start with lin_api_.' : undefined),
455
+ async test(get) {
456
+ const key = get('LINEAR_API_KEY');
457
+ if (!key)
458
+ return fail('Linear is not connected. Ticket comments go to the outbox.');
459
+ return guarded('Linear', async () => {
460
+ const r = await linearQuery(key, '{ viewer { name } organization { name } }');
461
+ if (r.status === 401 || r.status === 400 || !r.data?.viewer)
462
+ return fail(`Linear rejected the API key${r.error ? `: ${r.error}` : ''}.`);
463
+ const org = r.data.organization?.name;
464
+ return ok(`Connected as ${r.data.viewer.name ?? 'unknown'}${org ? ` in ${org}` : ''}.`, org ?? r.data.viewer.name);
465
+ });
466
+ },
467
+ async options(kind, get, q) {
468
+ const key = get('LINEAR_API_KEY');
469
+ if (!key)
470
+ return [];
471
+ if (kind === 'teams') {
472
+ const r = await linearQuery(key, '{ teams(first: 100) { nodes { id key name } } }');
473
+ return (r.data?.teams?.nodes ?? []).map((t) => ({ value: t.id, label: t.name, hint: t.key }));
474
+ }
475
+ if (kind === 'projects') {
476
+ if (q.parent) {
477
+ const r = await linearQuery(key, 'query($id: String!) { team(id: $id) { projects(first: 100) { nodes { id name } } } }', { id: q.parent });
478
+ return (r.data?.team?.projects?.nodes ?? []).map((p) => ({ value: p.id, label: p.name }));
479
+ }
480
+ const r = await linearQuery(key, '{ projects(first: 100) { nodes { id name } } }');
481
+ return (r.data?.projects?.nodes ?? []).map((p) => ({ value: p.id, label: p.name }));
482
+ }
483
+ return [];
484
+ },
485
+ };
486
+ // ---------- Jira ----------
487
+ /** "acme.atlassian.net" or a full URL -> "https://acme.atlassian.net". Undefined when not a URL. */
488
+ export function normalizeSite(v) {
489
+ const t = v.trim();
490
+ if (!t)
491
+ return undefined;
492
+ try {
493
+ return new URL(/^[a-z][a-z0-9+.-]*:\/\//i.test(t) ? t : `https://${t}`).origin;
494
+ }
495
+ catch {
496
+ return undefined;
497
+ }
498
+ }
499
+ function jiraAuth(get) {
500
+ const base = get('JIRA_BASE_URL')?.replace(/\/$/, '');
501
+ const email = get('JIRA_EMAIL');
502
+ const token = get('JIRA_API_TOKEN');
503
+ if (!base || !email || !token)
504
+ return undefined;
505
+ return { base, headers: { Authorization: `Basic ${Buffer.from(`${email}:${token}`).toString('base64')}`, Accept: 'application/json' } };
506
+ }
507
+ const jira = {
508
+ key: 'jira',
509
+ label: 'Jira',
510
+ methods: [{ id: 'api-token', label: 'API token', description: 'An Atlassian API token for the account the dots comment as.' }],
511
+ fields: [
512
+ { key: 'JIRA_BASE_URL', name: 'baseUrl', label: 'Site', secret: false, kind: 'url', required: true },
513
+ { key: 'JIRA_EMAIL', name: 'email', label: 'Email', secret: false, kind: 'email', required: true },
514
+ { key: 'JIRA_API_TOKEN', name: 'apiToken', label: 'API token', secret: true, kind: 'secret', required: true },
515
+ { key: 'JIRA_WEBHOOK_SECRET', name: 'webhookSecret', label: 'Webhook secret', secret: true, kind: 'secret' },
516
+ ],
517
+ optionKinds: ['projects'],
518
+ activeMethod: (get) => (get('JIRA_BASE_URL') && get('JIRA_EMAIL') && get('JIRA_API_TOKEN') ? 'api-token' : undefined),
519
+ validate(values) {
520
+ if (values.JIRA_BASE_URL !== undefined) {
521
+ const site = normalizeSite(values.JIRA_BASE_URL);
522
+ if (!site)
523
+ return 'Enter a site address such as acme.atlassian.net.';
524
+ if (!site.startsWith('https://'))
525
+ return 'Jira sites use https.';
526
+ values.JIRA_BASE_URL = site;
527
+ }
528
+ if (values.JIRA_EMAIL !== undefined && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(values.JIRA_EMAIL.trim()))
529
+ return 'Enter a valid email.';
530
+ return undefined;
531
+ },
532
+ async test(get) {
533
+ const a = jiraAuth(get);
534
+ if (!a)
535
+ return fail('Jira needs the site, the email, and an API token.');
536
+ return guarded('Jira', async () => {
537
+ const res = await fetchT(`${a.base}/rest/api/3/myself`, { headers: a.headers });
538
+ if (res.status === 401 || res.status === 403)
539
+ return fail('Jira rejected the email and API token.');
540
+ if (!res.ok)
541
+ return fail(`Jira answered HTTP ${res.status}.`);
542
+ const me = await json(res);
543
+ const host = new URL(a.base).host;
544
+ return ok(`Connected to ${host} as ${me?.displayName ?? 'unknown'}.`, host);
545
+ });
546
+ },
547
+ async options(kind, get) {
548
+ const a = jiraAuth(get);
549
+ if (kind !== 'projects' || !a)
550
+ return [];
551
+ const res = await fetchT(`${a.base}/rest/api/3/project/search?maxResults=100&orderBy=name`, { headers: a.headers });
552
+ const body = res.ok ? await json(res) : undefined;
553
+ return (body?.values ?? []).map((p) => ({ value: p.key, label: p.name, hint: p.key }));
554
+ },
555
+ };
556
+ // ---------- Slack ----------
557
+ /**
558
+ * Scopes and events for docs/SLACK.md: answer mentions, post notices, list channels for the picker. Interactivity
559
+ * carries Approve and Reject on a dot's decision message over Socket Mode; the Messages tab holds direct-message updates.
560
+ */
561
+ export function slackManifest(name = 'localdost') {
562
+ return {
563
+ display_information: { name, description: 'Always-on QA agents. Mention the bot to ask a dot.' },
564
+ features: { bot_user: { display_name: name, always_online: true }, app_home: { messages_tab_enabled: true, messages_tab_read_only_enabled: true } },
565
+ oauth_config: { scopes: { bot: ['app_mentions:read', 'chat:write', 'channels:read', 'groups:read'] } },
566
+ settings: {
567
+ event_subscriptions: { bot_events: ['app_mention'] },
568
+ interactivity: { is_enabled: true },
569
+ org_deploy_enabled: false,
570
+ socket_mode_enabled: true,
571
+ token_rotation_enabled: false,
572
+ },
573
+ };
574
+ }
575
+ export function slackCreateUrl(manifest = slackManifest()) {
576
+ return `https://api.slack.com/apps?new_app=1&manifest_json=${encodeURIComponent(JSON.stringify(manifest))}`;
577
+ }
578
+ const slackApi = () => (liveEnv.SLACK_API_URL ?? 'https://slack.com/api').replace(/\/$/, '');
579
+ async function slackCall(method, token, params = {}) {
580
+ const res = await fetchT(`${slackApi()}/${method}`, {
581
+ method: 'POST',
582
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/x-www-form-urlencoded' },
583
+ body: new URLSearchParams(params).toString(),
584
+ });
585
+ return ((await json(res)) ?? { ok: false, error: `HTTP ${res.status}` });
586
+ }
587
+ const SLACK_CHANNEL_PAGES = 20;
588
+ const SLACK_CHANNEL_TTL_MS = 5 * 60_000;
589
+ let slackChannelCache;
590
+ /**
591
+ * Every channel the bot can see, for the picker. The picker searches only what it loaded, and a large
592
+ * workspace has thousands of channels, so this pages through conversations.list (1,000 a page, 20 pages
593
+ * at most) instead of stopping at the first page. Channels the bot is in come first. Cached for 5 minutes
594
+ * per bot token, so typing in the picker does not hit Slack's rate limit. A page that fails rejects the whole load.
595
+ */
596
+ export async function slackChannelOptions(bot, now = Date.now()) {
597
+ const cached = slackChannelCache && slackChannelCache.bot === bot && now - slackChannelCache.at < SLACK_CHANNEL_TTL_MS;
598
+ const options = cached ? slackChannelCache.options : await listSlackChannels(bot, now);
599
+ // Channels where the bot was mentioned, which a list without groups:read leaves out (private ones).
600
+ // Read on every call, so a new mention shows at once even while the Slack list is cached.
601
+ const listed = new Set(options.map((o) => o.value));
602
+ const seen = (getMeta('slack').seenChannels ?? []).filter((c) => !listed.has(c.id));
603
+ return [...seen.map((c) => ({ value: c.id, label: c.name ? `#${c.name}` : c.id, hint: 'bot was mentioned here' })), ...options];
604
+ }
605
+ async function listSlackChannels(bot, now) {
606
+ const all = [];
607
+ let cursor = '';
608
+ for (let page = 0; page < SLACK_CHANNEL_PAGES; page++) {
609
+ const r = await slackCall('conversations.list', bot, {
610
+ types: 'public_channel,private_channel',
611
+ exclude_archived: 'true',
612
+ limit: '1000',
613
+ ...(cursor ? { cursor } : {}),
614
+ });
615
+ // A failed page on any request is an error, never a shorter list: a partial list would hide the channels
616
+ // on later pages with no explanation (KAT-236). Nothing is cached, so the next open reads every page.
617
+ if (r.ok === false)
618
+ throw new Error(`Slack answered ${r.error ?? 'an error'}`);
619
+ all.push(...(r.channels ?? []));
620
+ cursor = r.response_metadata?.next_cursor ?? '';
621
+ if (!cursor)
622
+ break;
623
+ }
624
+ const options = all
625
+ .sort((a, b) => Number(!!b.is_member) - Number(!!a.is_member) || a.name.localeCompare(b.name))
626
+ .map((c) => {
627
+ const hint = [c.is_private ? 'private' : '', c.is_member ? 'bot is in it' : ''].filter(Boolean).join(', ');
628
+ return { value: c.id, label: `#${c.name}`, ...(hint ? { hint } : {}) };
629
+ });
630
+ slackChannelCache = { bot, at: now, options };
631
+ return options;
632
+ }
633
+ /** Test hook: forget the cached channel list. */
634
+ export function resetSlackChannelCache() {
635
+ slackChannelCache = undefined;
636
+ }
637
+ const slack = {
638
+ key: 'slack',
639
+ label: 'Slack',
640
+ methods: [{ id: 'socket', label: 'Socket Mode app', description: 'A Slack app from the manifest. No public URL needed.' }],
641
+ fields: [
642
+ { key: 'SLACK_BOT_TOKEN', name: 'botToken', label: 'Bot token', secret: true, kind: 'secret', required: true },
643
+ { key: 'SLACK_APP_TOKEN', name: 'appToken', label: 'App-level token', secret: true, kind: 'secret', required: true },
644
+ { key: 'SLACK_ALLOWED_TEAM', name: 'allowedTeam', label: 'Allowed workspace ids', secret: false, kind: 'text' },
645
+ { key: 'SLACK_ALLOWED_USERS', name: 'allowedUsers', label: 'Allowed user ids', secret: false, kind: 'text' },
646
+ ],
647
+ optionKinds: ['channels'],
648
+ activeMethod: (get) => (get('SLACK_BOT_TOKEN') && get('SLACK_APP_TOKEN') ? 'socket' : undefined),
649
+ validate(v) {
650
+ if (v.SLACK_BOT_TOKEN && !/^xoxb-/.test(v.SLACK_BOT_TOKEN))
651
+ return 'Bot tokens start with xoxb-.';
652
+ if (v.SLACK_APP_TOKEN && !/^xapp-/.test(v.SLACK_APP_TOKEN))
653
+ return 'App-level tokens start with xapp-.';
654
+ return undefined;
655
+ },
656
+ async test(get) {
657
+ const bot = get('SLACK_BOT_TOKEN');
658
+ const appTok = get('SLACK_APP_TOKEN');
659
+ if (!bot || !appTok)
660
+ return fail('Slack needs the bot token and the app-level token.');
661
+ return guarded('Slack', async () => {
662
+ const who = await slackCall('auth.test', bot);
663
+ if (!who.ok)
664
+ return fail(`Slack rejected the bot token (${who.error ?? 'unknown error'}).`);
665
+ const open = await slackCall('apps.connections.open', appTok);
666
+ if (!open.ok || !open.url)
667
+ return fail(`Slack rejected the app-level token (${open.error ?? 'no socket URL'}). It needs the connections:write scope.`);
668
+ if (!(await deps.socketHello(open.url, 8000)))
669
+ return fail('Slack gave a socket URL, but the socket did not say hello. Check that Socket Mode is on.');
670
+ return ok(`Connected to ${who.team ?? 'the workspace'} as @${who.user ?? 'bot'}. Socket Mode answered.`, who.team);
671
+ });
672
+ },
673
+ async options(kind, get) {
674
+ const bot = get('SLACK_BOT_TOKEN');
675
+ if (kind !== 'channels' || !bot)
676
+ return [];
677
+ return slackChannelOptions(bot);
678
+ },
679
+ links: () => ({ createApp: slackCreateUrl() }),
680
+ };
681
+ // ---------- Voice ----------
682
+ const voice = {
683
+ key: 'voice',
684
+ label: 'Voice',
685
+ methods: [{ id: 'openai', label: 'OpenAI Realtime', description: 'Realtime voice calls with a dot.' }],
686
+ fields: [{ key: 'OPENAI_API_KEY', name: 'apiKey', label: 'API key', secret: true, kind: 'secret', required: true }],
687
+ activeMethod: (get) => (get('OPENAI_API_KEY') ? 'openai' : undefined),
688
+ validate: (v) => (v.OPENAI_API_KEY && !/^sk-/.test(v.OPENAI_API_KEY) ? 'OpenAI API keys start with sk-.' : undefined),
689
+ async test(get) {
690
+ const key = get('OPENAI_API_KEY');
691
+ if (!key)
692
+ return fail('Voice uses browser speech. Connect OpenAI for realtime voice.');
693
+ return guarded('OpenAI', async () => {
694
+ const res = await fetchT('https://api.openai.com/v1/models', { headers: { Authorization: `Bearer ${key}` } });
695
+ if (res.status === 401 || res.status === 403)
696
+ return fail('OpenAI rejected the API key.');
697
+ if (!res.ok)
698
+ return fail(`OpenAI answered HTTP ${res.status}.`);
699
+ return ok(config.token
700
+ ? 'The OpenAI key works. Calls use realtime voice.'
701
+ : 'The OpenAI key works. Realtime voice turns on once LOCALDOST_TOKEN is set; until then calls use browser speech.');
702
+ });
703
+ },
704
+ };
705
+ // ---------- AI-Vision ----------
706
+ /** http or https origin plus path, no trailing slash, no credentials. Undefined for anything else. */
707
+ function aivisionUrl(raw) {
708
+ try {
709
+ const u = new URL((raw ?? '').trim());
710
+ if ((u.protocol !== 'http:' && u.protocol !== 'https:') || u.username || u.password)
711
+ return undefined;
712
+ return `${u.origin}${u.pathname.replace(/\/+$/, '')}`;
713
+ }
714
+ catch {
715
+ return undefined;
716
+ }
717
+ }
718
+ const aivision = {
719
+ key: 'aivision',
720
+ label: 'AI-Vision',
721
+ methods: [{ id: 'server', label: 'AI-Vision server', description: 'Runs vision tests that check what a user sees.' }],
722
+ fields: [
723
+ {
724
+ key: 'AIVISION_SERVER_URL',
725
+ name: 'serverUrl',
726
+ label: 'Server address',
727
+ secret: false,
728
+ kind: 'url',
729
+ required: true,
730
+ help: 'For example http://localhost:5880.',
731
+ },
732
+ {
733
+ key: 'AIVISION_INTERNAL_TOKEN',
734
+ name: 'token',
735
+ label: 'Access token',
736
+ secret: true,
737
+ kind: 'secret',
738
+ help: 'Only when the server asks for sign-in.',
739
+ },
740
+ {
741
+ key: 'AIVISION_CHECKOUT',
742
+ name: 'checkout',
743
+ label: 'AI-Vision folder',
744
+ secret: false,
745
+ kind: 'text',
746
+ help: 'Where AI-Vision is installed on this machine. Lets dots use its tools in chat.',
747
+ },
748
+ ],
749
+ detected: async () => detectedActive(),
750
+ activeMethod: (get) => (get('AIVISION_SERVER_URL') ? 'server' : undefined),
751
+ validate(values) {
752
+ if (values.AIVISION_SERVER_URL !== undefined) {
753
+ const url = aivisionUrl(values.AIVISION_SERVER_URL);
754
+ if (!url)
755
+ return 'Enter an http or https URL without a user name or password.';
756
+ values.AIVISION_SERVER_URL = url;
757
+ }
758
+ if (values.AIVISION_CHECKOUT && !path.isAbsolute(values.AIVISION_CHECKOUT))
759
+ return 'The checkout path must be absolute.';
760
+ return undefined;
761
+ },
762
+ async test(get) {
763
+ const url = aivisionUrl(get('AIVISION_SERVER_URL'));
764
+ if (!url)
765
+ return fail('Enter the AI-Vision server address.');
766
+ const checkout = get('AIVISION_CHECKOUT')?.trim();
767
+ if (checkout && !existsSync(path.join(checkout, 'apps/playground/demo/veesan-mcp.mts')))
768
+ return fail(`${checkout} is not an AI-Vision folder.`);
769
+ // The token goes through the one gate (KAT-119). A token typed in this form is bound to the
770
+ // address under test; a saved token (an empty field) only to the origin it was saved for.
771
+ const typed = get.fromForm?.(TOKEN_KEY) ? get(TOKEN_KEY) : undefined;
772
+ const token = typed ? aivisionTokenFor(url, [{ token: typed, origin: originOf(url) }]) : aivisionTokenFor(url);
773
+ const withheld = typed ? undefined : tokenWithheldReason(url);
774
+ return guarded('the AI-Vision server', async () => {
775
+ // No redirects: the token header would follow to a host the user did not enter.
776
+ const res = await fetchT(`${url}/aivision/tests`, { headers: token ? { 'x-veesan-internal': token } : {}, redirect: 'manual' });
777
+ if (res.status >= 300 && res.status < 400)
778
+ return fail(`The AI-Vision server answered with a redirect (HTTP ${res.status}). Enter the address it redirects to.`);
779
+ if (res.status === 401 || res.status === 403)
780
+ return fail(`The AI-Vision server asked for sign-in. ${withheld ?? 'Add an access token.'}`);
781
+ if (!res.ok)
782
+ return fail(`The AI-Vision server answered HTTP ${res.status}.`);
783
+ const body = await json(res);
784
+ if (!Array.isArray(body?.tests))
785
+ return fail(`${new URL(url).origin} answered, but not like an AI-Vision server.`);
786
+ return ok(`The AI-Vision server answered with ${body.tests.length} test${body.tests.length === 1 ? '' : 's'}.`, new URL(url).host);
787
+ });
788
+ },
789
+ };
790
+ // ---------- Public URL ----------
791
+ async function reachable(url) {
792
+ const headers = config.token ? { Authorization: `Bearer ${config.token}` } : {};
793
+ let last = 'no answer';
794
+ for (let attempt = 0; attempt < 3; attempt++) {
795
+ if (attempt)
796
+ await deps.sleep(2000);
797
+ try {
798
+ const res = await fetchT(`${url.replace(/\/$/, '')}/api/setup`, { headers }, 8000);
799
+ const body = (await json(res)) ?? {};
800
+ if (res.ok && body.services)
801
+ return ok(`${new URL(url).origin} reaches this server.`, new URL(url).origin);
802
+ // Without LOCALDOST_TOKEN the API refuses a foreign Host: that answer still proves the URL reaches localdost.
803
+ if (res.status === 403 && /localhost only/.test(body.error ?? ''))
804
+ return ok(`${new URL(url).origin} reaches this server. The API stays closed to it until LOCALDOST_TOKEN is set. Webhooks need their secrets (GITHUB_WEBHOOK_SECRET, JIRA_WEBHOOK_SECRET, LINEAR_WEBHOOK_SECRET).`, new URL(url).origin);
805
+ last = `HTTP ${res.status}`;
806
+ }
807
+ catch (err) {
808
+ last = errText(err);
809
+ }
810
+ }
811
+ return fail(`${url} does not reach this server (${last}).`);
812
+ }
813
+ const publicUrl = {
814
+ key: 'publicUrl',
815
+ label: 'Public URL',
816
+ methods: [
817
+ { id: 'tunnel', label: 'Quick tunnel', description: 'Starts a free cloudflared tunnel. The address changes on every restart.' },
818
+ { id: 'url', label: 'Your own URL', description: 'The HTTPS address of a reverse proxy or a deployed server.' },
819
+ ],
820
+ fields: [{ key: 'LOCALDOST_PUBLIC_URL', name: 'url', label: 'Public URL', secret: false, kind: 'url', methods: ['url'], required: true }],
821
+ activeMethod(get) {
822
+ if (tunnelState().running && settingSource('LOCALDOST_PUBLIC_URL') !== 'env')
823
+ return 'tunnel';
824
+ return get('LOCALDOST_PUBLIC_URL') ? 'url' : undefined;
825
+ },
826
+ validate(v) {
827
+ if (v.LOCALDOST_PUBLIC_URL === undefined)
828
+ return undefined;
829
+ let u;
830
+ try {
831
+ u = new URL(v.LOCALDOST_PUBLIC_URL.trim());
832
+ }
833
+ catch {
834
+ return 'Enter a full address, for example https://qa.example.com.';
835
+ }
836
+ if (u.protocol !== 'https:' && u.hostname !== 'localhost' && u.hostname !== '127.0.0.1')
837
+ return 'Use https. Push and webhooks need it.';
838
+ v.LOCALDOST_PUBLIC_URL = `${u.origin}${u.pathname.replace(/\/+$/, '')}`;
839
+ return undefined;
840
+ },
841
+ async test(get) {
842
+ const url = get('LOCALDOST_PUBLIC_URL');
843
+ if (!url)
844
+ return fail('No public URL. Links in comments and pushes have no run page.');
845
+ return reachable(url);
846
+ },
847
+ async onDisconnect() {
848
+ await stopTunnel();
849
+ },
850
+ };
851
+ // ---------- Sandbox and push ----------
852
+ async function dockerWithRetry() {
853
+ let r = { ok: false };
854
+ for (let i = 0; i < 3; i++) {
855
+ if (i)
856
+ await deps.sleep(1000);
857
+ r = await deps.dockerPing();
858
+ if (r.ok)
859
+ return r;
860
+ }
861
+ return r;
862
+ }
863
+ const sandbox = {
864
+ key: 'sandbox',
865
+ label: 'Docker runner',
866
+ methods: [{ id: 'docker', label: 'Docker', description: 'Runs tests in containers when Docker answers.' }],
867
+ fields: [],
868
+ activeMethod: () => 'docker',
869
+ async test() {
870
+ const r = await dockerWithRetry();
871
+ return r.ok
872
+ ? ok(`${r.detail ?? 'Docker'} is reachable. Runner mode docker is available.`, r.detail)
873
+ : fail(`Docker is not reachable (${r.detail ?? 'no answer'}). Start Docker, then retry.`);
874
+ },
875
+ detected: async () => (await deps.dockerPing()).ok,
876
+ };
877
+ const vapidFile = () => existsSync(path.join(config.dataDir, 'vapid.json'));
878
+ const push = {
879
+ key: 'push',
880
+ label: 'Push',
881
+ methods: [{ id: 'web-push', label: 'Web push', description: 'Keys are made on first start.' }],
882
+ fields: [],
883
+ activeMethod: () => 'web-push',
884
+ async test(get) {
885
+ if ((get('VAPID_PUBLIC_KEY') && get('VAPID_PRIVATE_KEY')) || vapidFile())
886
+ return ok('Web push keys are ready. Turn on alerts per device in Settings.');
887
+ if (get('NTFY_TOPIC'))
888
+ return ok('ntfy is set. Web push keys are made on first start.');
889
+ return fail('Web push keys are made on first start. Restart the server once.');
890
+ },
891
+ detected: async () => vapidFile(),
892
+ };
893
+ /** Server order, same as GET /api/setup. */
894
+ export const PROVIDERS = [model, github, jira, linear, slack, push, publicUrl, sandbox, voice, aivision];
895
+ export function providerFor(key) {
896
+ return PROVIDERS.find((p) => p.key === key);
897
+ }
898
+ /** Live value of a setting, for code that cannot import config (kept for symmetry with Getter). */
899
+ export const live = (k) => setting(k);
900
+ //# sourceMappingURL=providers.js.map