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,894 @@
1
+ // Validation for composed chat views (KAT-366, docs/CHAT-UI.md "Composed views"). The model composes a view from our
2
+ // own components: layout nodes (column, row, tabs, section), short text, and the answer blocks. This file is the one
3
+ // registry of those components and the checks every spec goes through. The server runs it before it binds a view to
4
+ // tool results, and the client runs it again before it renders, with the same rules as parseChatBlock:
5
+ //
6
+ // - A component or a prop that is not in the registry is dropped and counted. There is no HTML, no CSS, no class name,
7
+ // no color (only a tone from an enum, which the client maps to theme tokens), and no action: a button comes from a
8
+ // block, and the client wires it to the same routes as any block.
9
+ // - Depth, node, child, and step counts are capped. Strings are trimmed and capped, and a string that holds an HTML
10
+ // tag is dropped. Links must be http or https.
11
+ // - A dataset whose pipeline has one bad step is dropped whole, and so is every node that reads it, because a pipeline
12
+ // with a skipped step would show wrong numbers.
13
+ //
14
+ // Pure and dependency free, so the client imports the same file (`@view-spec`).
15
+ import { clean, isObj, num, oneOf, safeHttpUrl, str } from './chat-parse-util.js';
16
+ export const MAX_VIEW_DEPTH = 4;
17
+ export const MAX_VIEW_NODES = 40;
18
+ export const MAX_VIEW_CHILDREN = 12;
19
+ export const MAX_VIEW_TABS = 6;
20
+ export const MAX_VIEW_DATASETS = 8;
21
+ export const MAX_VIEW_STEPS = 8;
22
+ export const MAX_VIEW_VARS = 12;
23
+ export const MAX_VIEW_TILES = 6;
24
+ export const MAX_VIEW_COLUMNS = 6;
25
+ export const MAX_VIEW_SERIES = 4;
26
+ export const MAX_VIEW_CONDITIONS = 6;
27
+ export const MAX_VIEW_AGGS = 6;
28
+ export const MAX_VIEW_NOTES = 12;
29
+ /** Rows of one source table the server sends to the client, and cells in all of them. */
30
+ export const MAX_SOURCE_ROWS = 2000;
31
+ export const MAX_SOURCE_CELLS = 12_000;
32
+ export const MAX_SOURCE_COLUMNS = 12;
33
+ /** Characters of a text cell that go to the client. */
34
+ export const MAX_CELL_TEXT = 120;
35
+ const CAP = { title: 80, label: 60, text: 600, finding: 240, tileValue: 60, tileSub: 120, unit: 12, cell: 120 };
36
+ export const VIEW_LAYOUT_TYPES = ['column', 'row', 'section', 'tabs', 'text'];
37
+ export const VIEW_RECORD_TYPES = [
38
+ 'runs',
39
+ 'pulls',
40
+ 'approvals',
41
+ 'defects',
42
+ 'probes',
43
+ 'memory',
44
+ 'ticket_review',
45
+ 'test_cases',
46
+ 'cards',
47
+ 'release_call',
48
+ ];
49
+ /** Every component a view may hold: the 14 answer blocks (all but `view`) and the layout nodes. */
50
+ export const VIEW_NODE_TYPES = [...VIEW_LAYOUT_TYPES, ...VIEW_RECORD_TYPES, 'triage', 'table', 'stats', 'chart'];
51
+ export const VIEW_FORMATS = ['text', 'number', 'percent', 'duration', 'hour', 'weekday', 'day', 'spec'];
52
+ export const VIEW_BUCKETS = ['hour', 'hour_of_day', 'day', 'weekday', 'week', 'month'];
53
+ const COMPARES = ['eq', 'ne', 'gt', 'gte', 'lt', 'lte', 'in', 'contains'];
54
+ const AGG_FNS = ['count', 'sum', 'avg', 'min', 'max', 'distinct'];
55
+ const EXPR_FNS = ['ratio', 'percent', 'change', 'diff'];
56
+ const SCALAR_FNS = ['count', 'sum', 'avg', 'min', 'max', 'cell'];
57
+ const CHART_TYPES = ['bar', 'stacked_bar', 'line'];
58
+ const TRIAGE_WINDOWS = ['last_merge', 'today', 'recent'];
59
+ const TONES = ['ok', 'attention', 'bad'];
60
+ const title = { kind: 'string', max: CAP.title };
61
+ const limit = (max) => ({ kind: 'int', min: 1, max });
62
+ /** One entry per component. Names, types, and allowed values of every prop a node may carry; nothing else passes. */
63
+ export const VIEW_COMPONENTS = {
64
+ column: { summary: 'Stacks its children.', props: { children: { kind: 'nodes', required: true } } },
65
+ row: { summary: 'Puts its children side by side when there is room, else stacks them.', props: { children: { kind: 'nodes', required: true } } },
66
+ section: { summary: 'A heading over its children.', props: { title: { ...title, required: true }, children: { kind: 'nodes', required: true } } },
67
+ tabs: { summary: 'One tab shows at a time.', props: { tabs: { kind: 'tabs', required: true } } },
68
+ text: {
69
+ summary: 'A short line of prose.',
70
+ props: { text: { kind: 'string', max: CAP.text, required: true }, tone: { kind: 'enum', values: ['muted'] }, href: { kind: 'url' } },
71
+ },
72
+ runs: { summary: 'Test runs, from a list_runs or runs_in_progress result.', props: recordProps() },
73
+ pulls: { summary: 'Open pull requests, from an open_prs result.', props: recordProps() },
74
+ approvals: { summary: 'Drafts that wait for approval, from a pending_approvals result.', props: recordProps() },
75
+ defects: { summary: 'Defects, from a recent_defects result.', props: recordProps() },
76
+ probes: { summary: 'Probe status, from a probe_status result.', props: recordProps() },
77
+ memory: { summary: 'What the dot remembers, from a get_memory result.', props: recordProps() },
78
+ ticket_review: { summary: 'A ticket review, from a list_tickets_reviewed or get_ticket result.', props: recordProps() },
79
+ test_cases: { summary: 'Test cases, from a list_cases result.', props: recordProps() },
80
+ cards: { summary: 'The card of a ticket, from a get_ticket result.', props: recordProps() },
81
+ release_call: { summary: 'The release call of a lead, from a release_call result.', props: recordProps() },
82
+ triage: {
83
+ summary: 'Failed and flaky tests of recent runs, grouped by cause, built from the stored runs.',
84
+ props: { window: { kind: 'enum', values: TRIAGE_WINDOWS }, title },
85
+ },
86
+ table: {
87
+ summary: 'A table of a dataset, or of a result that is already a table.',
88
+ props: { title, data: { kind: 'dataset' }, from: { kind: 'result' }, columns: { kind: 'columns' }, limit: limit(50) },
89
+ },
90
+ stats: {
91
+ summary: 'Big-number tiles. Each value is text, and {name} marks take values from vars.',
92
+ props: { title, tiles: { kind: 'tiles' }, from: { kind: 'result' } },
93
+ },
94
+ chart: {
95
+ summary: 'A bar, stacked bar, or line chart of a dataset, or of a result that is already a chart.',
96
+ props: {
97
+ title,
98
+ from: { kind: 'result' },
99
+ data: { kind: 'dataset' },
100
+ chartType: { kind: 'enum', values: CHART_TYPES },
101
+ x: { kind: 'field' },
102
+ xFormat: { kind: 'enum', values: VIEW_FORMATS },
103
+ series: { kind: 'series' },
104
+ unit: { kind: 'string', max: CAP.unit },
105
+ finding: { kind: 'string', max: CAP.finding },
106
+ limit: limit(31),
107
+ },
108
+ },
109
+ };
110
+ function recordProps() {
111
+ return {
112
+ from: { kind: 'result', required: true },
113
+ nth: { kind: 'int', min: 0, max: 9 },
114
+ title,
115
+ limit: limit(50),
116
+ };
117
+ }
118
+ /** The component names, for tests and for the tool description. */
119
+ export const VIEW_COMPONENT_NAMES = Object.keys(VIEW_COMPONENTS);
120
+ // ---------- Names, fields, strings ----------
121
+ const RESULT_ID = /^r\d{1,3}$/;
122
+ const DATASET_NAME = /^[a-z][A-Za-z0-9_]{0,23}$/;
123
+ const FIELD = /^[A-Za-z_][A-Za-z0-9_]{0,39}(?:\.[A-Za-z_][A-Za-z0-9_]{0,39}){0,2}$/;
124
+ const BAD_SEGMENT = /(?:^|\.)(?:__proto__|constructor|prototype)(?:\.|$)/;
125
+ /** Names an object already has from its prototype. A dataset or var with one of them would shadow a built-in, so none is allowed. */
126
+ const RESERVED_NAMES = new Set([
127
+ 'constructor',
128
+ 'prototype',
129
+ 'toString',
130
+ 'valueOf',
131
+ 'hasOwnProperty',
132
+ 'isPrototypeOf',
133
+ 'propertyIsEnumerable',
134
+ 'toLocaleString',
135
+ 'toJSON',
136
+ ]);
137
+ // A `<` that opens a tag, a closing tag, a comment, or a processing mark. The `>` is not needed: `<img src=x onerror=alert(1)` with
138
+ // no closing bracket is still the start of a tag, and a prose line has no reason to put a letter right after a `<`.
139
+ const MARKUP = /<\/?[a-zA-Z]|<[!?]/;
140
+ const PLACEHOLDER = /\{([a-z][A-Za-z0-9_]{0,23})\}/g;
141
+ /** A look-back window, which the model sets itself in the tool call, so it may say it. */
142
+ const WINDOW = /\b(?:last|past|previous)\s+\d{1,3}\s+(?:hour|day|week|month)s?\b/gi;
143
+ /** A word that is a number: digits with separators, an optional sign, and a percent sign or a short unit after them. */
144
+ const TYPED_NUMBER = /^[+-]?\d[\d,.:/-]*(?:%|[a-zA-Z]{0,7})$/;
145
+ export const isResultId = (v) => typeof v === 'string' && RESULT_ID.test(v);
146
+ function fieldName(v) {
147
+ return typeof v === 'string' && v.length <= 82 && FIELD.test(v) && !BAD_SEGMENT.test(v) ? v : undefined;
148
+ }
149
+ /** The names a string asks the vars to fill: "Peak {peak}" asks for peak. */
150
+ export function placeholdersIn(s) {
151
+ return [...s.matchAll(PLACEHOLDER)].map((m) => m[1]);
152
+ }
153
+ function note(ctx, text) {
154
+ if (ctx.notes.length < MAX_VIEW_NOTES)
155
+ ctx.notes.push(text);
156
+ }
157
+ /**
158
+ * The first number in a text that is typed out by hand: a word made of digits, with a sign, separators, a percent sign, or a short
159
+ * unit (`1234`, `99.9%`, `1,234`, `12ms`, `#58`). A {name} mark is a number the view computed, so it is not counted, and neither is a
160
+ * window the model asked the tool for ("the last 14 days"). The check looks at digits only: a number spelled out in words is not caught, and neither is a claim with no number in it.
161
+ */
162
+ export function typedNumber(s) {
163
+ for (const raw of s.replace(PLACEHOLDER, ' ').replace(WINDOW, ' ').split(/\s+/)) {
164
+ const word = raw.replace(/^[("'*_~#<>=[]+|[)"'*_~\],.:;!?]+$/g, '');
165
+ if (word && TYPED_NUMBER.test(word))
166
+ return word;
167
+ }
168
+ return undefined;
169
+ }
170
+ /**
171
+ * A string prop: trimmed and capped. One that holds an HTML tag is dropped, so the page never gets markup from a view. With
172
+ * `figures: false` (prose, tile values, findings) one that holds a number typed by hand is dropped too: the numbers on screen come
173
+ * from tool results, through vars, and never from the model's own text.
174
+ */
175
+ function text(ctx, path, v, max, opts = {}) {
176
+ if (v === undefined)
177
+ return undefined;
178
+ const s = str(v, max);
179
+ if (s === undefined) {
180
+ note(ctx, `${path} is not a text`);
181
+ return undefined;
182
+ }
183
+ if (MARKUP.test(s)) {
184
+ note(ctx, `${path} holds markup, which a view never carries`);
185
+ return undefined;
186
+ }
187
+ if (opts.figures === false) {
188
+ const typed = typedNumber(s);
189
+ if (typed) {
190
+ note(ctx, `${path} holds the number ${typed}, which comes from no tool result. Put it in vars and write {name} instead`);
191
+ return undefined;
192
+ }
193
+ }
194
+ for (const name of placeholdersIn(s))
195
+ if (!ctx.vars.has(name))
196
+ note(ctx, `${path} uses {${name}}, which is not in vars`);
197
+ return s;
198
+ }
199
+ function int(v, min, max) {
200
+ const n = num(v);
201
+ return n !== undefined && Number.isInteger(n) && n >= min && n <= max ? n : undefined;
202
+ }
203
+ // ---------- Datasets: conditions, steps, scalars ----------
204
+ function parseCondition(o) {
205
+ if (!isObj(o))
206
+ return null;
207
+ const field = fieldName(o.field);
208
+ const is = oneOf(o.is, COMPARES);
209
+ if (!field || !is)
210
+ return null;
211
+ const v = o.value;
212
+ if (is === 'in') {
213
+ if (!Array.isArray(v) || !v.length || v.length > 20)
214
+ return null;
215
+ const list = v.filter((x) => (typeof x === 'string' && x.length <= CAP.cell) || (typeof x === 'number' && Number.isFinite(x)));
216
+ return list.length === v.length ? { field, is, value: list } : null;
217
+ }
218
+ if (is === 'contains')
219
+ return typeof v === 'string' && v && v.length <= CAP.cell ? { field, is, value: v } : null;
220
+ if (typeof v === 'string' && v.length <= CAP.cell)
221
+ return { field, is, value: v };
222
+ if (typeof v === 'number' && Number.isFinite(v))
223
+ return { field, is, value: v };
224
+ if (typeof v === 'boolean')
225
+ return { field, is, value: v };
226
+ return null;
227
+ }
228
+ function parseConditions(v, max = MAX_VIEW_CONDITIONS) {
229
+ if (!Array.isArray(v) || !v.length || v.length > max)
230
+ return null;
231
+ const out = v.map(parseCondition);
232
+ return out.every((c) => c !== null) ? out : null;
233
+ }
234
+ function parseExpr(o) {
235
+ if (!isObj(o))
236
+ return null;
237
+ const of = fieldName(o.of);
238
+ if (!of)
239
+ return null;
240
+ if (o.fn === 'bucket') {
241
+ const by = oneOf(o.by, VIEW_BUCKETS);
242
+ return by ? { fn: 'bucket', of, by } : null;
243
+ }
244
+ const fn = oneOf(o.fn, EXPR_FNS);
245
+ if (!fn)
246
+ return null;
247
+ const over = typeof o.over === 'number' && Number.isFinite(o.over) ? o.over : fieldName(o.over);
248
+ return over === undefined ? null : { fn, of, over };
249
+ }
250
+ function parseAgg(o) {
251
+ if (!isObj(o))
252
+ return null;
253
+ const as = typeof o.as === 'string' && /^[A-Za-z_][A-Za-z0-9_]{0,39}$/.test(o.as) && !BAD_SEGMENT.test(o.as) ? o.as : undefined;
254
+ const fn = oneOf(o.fn, AGG_FNS);
255
+ if (!as || !fn)
256
+ return null;
257
+ const of = o.of === undefined ? undefined : fieldName(o.of);
258
+ if ((o.of !== undefined && !of) || (fn !== 'count' && !of))
259
+ return null;
260
+ const where = o.where === undefined ? undefined : parseConditions(o.where, 4);
261
+ if (o.where !== undefined && !where)
262
+ return null;
263
+ return clean({ as, fn, of, where: where ?? undefined });
264
+ }
265
+ function parseStep(o) {
266
+ if (!isObj(o))
267
+ return null;
268
+ switch (o.op) {
269
+ case 'filter': {
270
+ const where = parseConditions(o.where);
271
+ return where ? { op: 'filter', where } : null;
272
+ }
273
+ case 'derive': {
274
+ const as = typeof o.as === 'string' && /^[A-Za-z_][A-Za-z0-9_]{0,39}$/.test(o.as) && !BAD_SEGMENT.test(o.as) ? o.as : undefined;
275
+ const expr = parseExpr(o.expr);
276
+ return as && expr ? { op: 'derive', as, expr } : null;
277
+ }
278
+ case 'group': {
279
+ const by = Array.isArray(o.by) ? o.by.map(fieldName) : [];
280
+ if (!by.length || by.length > 3 || !by.every((b) => Boolean(b)))
281
+ return null;
282
+ if (!Array.isArray(o.agg) || !o.agg.length || o.agg.length > MAX_VIEW_AGGS)
283
+ return null;
284
+ const agg = o.agg.map(parseAgg);
285
+ if (!agg.every((a) => a !== null))
286
+ return null;
287
+ const names = [...by, ...agg.map((a) => a.as)];
288
+ if (new Set(names).size !== names.length)
289
+ return null;
290
+ const fill = o.fill === undefined ? undefined : oneOf(o.fill, ['hour_of_day', 'weekday']);
291
+ if (o.fill !== undefined && !fill)
292
+ return null;
293
+ return clean({ op: 'group', by, agg, fill });
294
+ }
295
+ case 'sort': {
296
+ const by = fieldName(o.by);
297
+ const dir = o.dir === undefined ? undefined : oneOf(o.dir, ['asc', 'desc']);
298
+ return by && (o.dir === undefined || dir) ? clean({ op: 'sort', by, dir }) : null;
299
+ }
300
+ case 'limit': {
301
+ const n = int(o.n, 1, 500);
302
+ return n ? { op: 'limit', n } : null;
303
+ }
304
+ case 'pick': {
305
+ if (!Array.isArray(o.fields) || !o.fields.length || o.fields.length > 12)
306
+ return null;
307
+ const fields = o.fields.map(fieldName);
308
+ return fields.every((f) => Boolean(f)) ? { op: 'pick', fields } : null;
309
+ }
310
+ default:
311
+ return null;
312
+ }
313
+ }
314
+ function parseDatasets(raw, ctx) {
315
+ if (raw === undefined)
316
+ return undefined;
317
+ if (!isObj(raw)) {
318
+ note(ctx, 'datasets is not an object');
319
+ return undefined;
320
+ }
321
+ const out = {};
322
+ for (const [name, d] of Object.entries(raw).slice(0, MAX_VIEW_DATASETS)) {
323
+ const bad = (why) => note(ctx, `dataset ${name} dropped: ${why}`);
324
+ if (!DATASET_NAME.test(name) || RESULT_ID.test(name) || RESERVED_NAMES.has(name)) {
325
+ bad('a dataset name starts with a lowercase letter and is not like r1');
326
+ continue;
327
+ }
328
+ if (!isObj(d)) {
329
+ bad('it is not an object');
330
+ continue;
331
+ }
332
+ // Each dataset reads a tool result or an earlier dataset, so a loop is not possible.
333
+ const from = typeof d.from === 'string' ? d.from : '';
334
+ const fromResult = RESULT_ID.test(from);
335
+ if (!fromResult && !Object.hasOwn(out, from)) {
336
+ bad(`from "${from.slice(0, 24)}" is not a result id or an earlier dataset`);
337
+ continue;
338
+ }
339
+ if (fromResult && ctx.bound && !ctx.sources.has(from)) {
340
+ bad(`no rows of ${from} came with the view`);
341
+ continue;
342
+ }
343
+ const stepsRaw = d.steps === undefined ? [] : d.steps;
344
+ if (!Array.isArray(stepsRaw) || stepsRaw.length > MAX_VIEW_STEPS) {
345
+ bad(`steps must be a list of at most ${MAX_VIEW_STEPS}`);
346
+ continue;
347
+ }
348
+ const steps = stepsRaw.map(parseStep);
349
+ const badAt = steps.findIndex((s) => s === null);
350
+ // A step that fails the check drops the dataset: a pipeline with a skipped step would show wrong numbers.
351
+ if (badAt >= 0) {
352
+ bad(`step ${badAt + 1} is not valid`);
353
+ continue;
354
+ }
355
+ out[name] = { from, ...(steps.length ? { steps: steps } : {}) };
356
+ ctx.datasets.add(name);
357
+ }
358
+ return Object.keys(out).length ? out : undefined;
359
+ }
360
+ function parseVars(raw, ctx) {
361
+ if (raw === undefined)
362
+ return undefined;
363
+ if (!isObj(raw)) {
364
+ note(ctx, 'vars is not an object');
365
+ return undefined;
366
+ }
367
+ const out = {};
368
+ for (const [name, v] of Object.entries(raw).slice(0, MAX_VIEW_VARS)) {
369
+ const bad = (why) => note(ctx, `var ${name} dropped: ${why}`);
370
+ if (!DATASET_NAME.test(name) || RESERVED_NAMES.has(name)) {
371
+ bad('a var name starts with a lowercase letter');
372
+ continue;
373
+ }
374
+ if (!isObj(v)) {
375
+ bad('it is not an object');
376
+ continue;
377
+ }
378
+ const of = typeof v.of === 'string' ? v.of : '';
379
+ const fn = oneOf(v.fn, SCALAR_FNS);
380
+ const field = v.field === undefined ? undefined : fieldName(v.field);
381
+ const format = v.format === undefined ? undefined : oneOf(v.format, VIEW_FORMATS);
382
+ const row = v.row === undefined ? undefined : int(v.row, 0, 499);
383
+ if (!ctx.datasets.has(of))
384
+ bad(`dataset "${of.slice(0, 24)}" is not defined`);
385
+ else if (!fn)
386
+ bad('fn is not one of count, sum, avg, min, max, cell');
387
+ else if ((fn !== 'count' && !field) || (v.field !== undefined && !field))
388
+ bad('field is missing or not a field name');
389
+ else if ((v.format !== undefined && !format) || (v.row !== undefined && row === undefined))
390
+ bad('format or row is not valid');
391
+ else {
392
+ out[name] = clean({ of, fn, field, row, format });
393
+ ctx.vars.add(name);
394
+ }
395
+ }
396
+ return Object.keys(out).length ? out : undefined;
397
+ }
398
+ // ---------- Nodes ----------
399
+ const ALLOWED_KEYS = (type, ctx) => new Set(['type', ...Object.keys(VIEW_COMPONENTS[type].props), ...(ctx.bound && isBlockNode(type) ? ['block'] : [])]);
400
+ const isBlockNode = (type) => VIEW_RECORD_TYPES.includes(type) || ['triage', 'table', 'stats', 'chart'].includes(type);
401
+ /** Notes every prop of a node that the registry does not know, so the model hears what was dropped. */
402
+ function noteUnknown(o, type, path, ctx) {
403
+ const allowed = ALLOWED_KEYS(type, ctx);
404
+ for (const k of Object.keys(o))
405
+ if (!allowed.has(k))
406
+ note(ctx, `${path}: ${k} is not a prop of ${type}, dropped`);
407
+ }
408
+ function parseChildren(raw, depth, path, ctx) {
409
+ if (!Array.isArray(raw))
410
+ return [];
411
+ if (raw.length > MAX_VIEW_CHILDREN)
412
+ note(ctx, `${path} holds at most ${MAX_VIEW_CHILDREN} children, the rest are dropped`);
413
+ const out = [];
414
+ raw.slice(0, MAX_VIEW_CHILDREN).forEach((c, i) => {
415
+ const n = parseNode(c, depth, `${path}[${i}]`, ctx);
416
+ if (n)
417
+ out.push(n);
418
+ });
419
+ return out;
420
+ }
421
+ function tiles(raw, path, ctx) {
422
+ if (!Array.isArray(raw))
423
+ return [];
424
+ const out = [];
425
+ for (const [i, t] of raw.slice(0, MAX_VIEW_TILES).entries()) {
426
+ if (!isObj(t))
427
+ continue;
428
+ const label = text(ctx, `${path}.tiles[${i}].label`, t.label, CAP.label);
429
+ const value = text(ctx, `${path}.tiles[${i}].value`, typeof t.value === 'number' && Number.isFinite(t.value) ? String(t.value) : t.value, CAP.tileValue, {
430
+ figures: false,
431
+ });
432
+ if (!label || !value) {
433
+ note(ctx, `${path}.tiles[${i}] needs a label and a value`);
434
+ continue;
435
+ }
436
+ // A tile shows a number the view computed. A value with no {name} in it is something the model wrote, so the tile goes.
437
+ if (!placeholdersIn(value).length) {
438
+ note(ctx, `${path}.tiles[${i}].value must be a {name} from vars: a tile never shows a figure the model wrote`);
439
+ continue;
440
+ }
441
+ out.push(clean({ label, value, sub: text(ctx, `${path}.tiles[${i}].sub`, t.sub, CAP.tileSub, { figures: false }), tone: oneOf(t.tone, TONES) }));
442
+ }
443
+ if (raw.length > MAX_VIEW_TILES)
444
+ note(ctx, `${path}.tiles holds at most ${MAX_VIEW_TILES} tiles`);
445
+ return out;
446
+ }
447
+ function columns(raw, path, ctx) {
448
+ if (!Array.isArray(raw))
449
+ return undefined;
450
+ const out = [];
451
+ for (const [i, c] of raw.slice(0, MAX_VIEW_COLUMNS).entries()) {
452
+ const field = isObj(c) ? fieldName(c.field) : undefined;
453
+ if (!isObj(c) || !field) {
454
+ note(ctx, `${path}.columns[${i}] needs a field`);
455
+ continue;
456
+ }
457
+ out.push(clean({ field, label: text(ctx, `${path}.columns[${i}].label`, c.label, CAP.label), format: oneOf(c.format, VIEW_FORMATS) }));
458
+ }
459
+ return out.length ? out : undefined;
460
+ }
461
+ function series(raw, path, ctx) {
462
+ if (!Array.isArray(raw))
463
+ return [];
464
+ const out = [];
465
+ for (const [i, s] of raw.slice(0, MAX_VIEW_SERIES).entries()) {
466
+ const field = isObj(s) ? fieldName(s.field) : undefined;
467
+ if (!isObj(s) || !field) {
468
+ note(ctx, `${path}.series[${i}] needs a field`);
469
+ continue;
470
+ }
471
+ out.push(clean({ field, name: text(ctx, `${path}.series[${i}].name`, s.name, CAP.label) }));
472
+ }
473
+ return out;
474
+ }
475
+ /** In a bound view a block node carries the block the server built; it must be a valid block of the node's kind. */
476
+ function boundBlock(o, kind, path, ctx) {
477
+ const b = ctx.parseBlock?.(o.block) ?? null;
478
+ if (!b || b.kind !== kind) {
479
+ note(ctx, `${path}: the ${kind} block is missing or not valid`);
480
+ return null;
481
+ }
482
+ return b;
483
+ }
484
+ function resultRef(ctx, path, v) {
485
+ if (v === undefined)
486
+ return undefined;
487
+ if (!isResultId(v)) {
488
+ note(ctx, `${path}.from must be a result id such as r1`);
489
+ return undefined;
490
+ }
491
+ return v;
492
+ }
493
+ function datasetRef(ctx, path, v) {
494
+ if (v === undefined)
495
+ return undefined;
496
+ if (typeof v !== 'string' || !ctx.datasets.has(v)) {
497
+ note(ctx, `${path}.data names "${String(v).slice(0, 24)}", which is not a dataset of this view`);
498
+ return undefined;
499
+ }
500
+ return v;
501
+ }
502
+ function parseNode(raw, depth, path, ctx) {
503
+ if (!isObj(raw)) {
504
+ note(ctx, `${path} is not an object`);
505
+ return null;
506
+ }
507
+ const type = oneOf(raw.type, VIEW_NODE_TYPES);
508
+ if (!type) {
509
+ note(ctx, `${path}: "${String(raw.type ?? '').slice(0, 24)}" is not a component, dropped`);
510
+ return null;
511
+ }
512
+ if (depth > MAX_VIEW_DEPTH) {
513
+ note(ctx, `${path} is nested deeper than ${MAX_VIEW_DEPTH} levels, dropped`);
514
+ return null;
515
+ }
516
+ if (ctx.nodes >= MAX_VIEW_NODES) {
517
+ if (!ctx.nodeLimitNoted)
518
+ note(ctx, `a view holds at most ${MAX_VIEW_NODES} nodes, the rest are dropped`);
519
+ ctx.nodeLimitNoted = true;
520
+ return null;
521
+ }
522
+ ctx.nodes++;
523
+ noteUnknown(raw, type, path, ctx);
524
+ switch (type) {
525
+ case 'column':
526
+ case 'row': {
527
+ const children = parseChildren(raw.children, depth + 1, `${path}.children`, ctx);
528
+ return children.length || ctx.bound ? { type, children } : (note(ctx, `${path}: a ${type} with no valid child is dropped`), null);
529
+ }
530
+ case 'section': {
531
+ const t = text(ctx, `${path}.title`, raw.title, CAP.title);
532
+ const children = parseChildren(raw.children, depth + 1, `${path}.children`, ctx);
533
+ if (!t || !children.length)
534
+ return (note(ctx, `${path}: a section needs a title and a valid child`), null);
535
+ return { type, title: t, children };
536
+ }
537
+ case 'tabs': {
538
+ const out = [];
539
+ const list = Array.isArray(raw.tabs) ? raw.tabs : [];
540
+ if (list.length > MAX_VIEW_TABS)
541
+ note(ctx, `${path}.tabs holds at most ${MAX_VIEW_TABS} tabs`);
542
+ for (const [i, t] of list.slice(0, MAX_VIEW_TABS).entries()) {
543
+ const label = isObj(t) ? text(ctx, `${path}.tabs[${i}].label`, t.label, CAP.label) : undefined;
544
+ const children = isObj(t) ? parseChildren(t.children, depth + 1, `${path}.tabs[${i}].children`, ctx) : [];
545
+ if (label && children.length)
546
+ out.push({ label, children });
547
+ else
548
+ note(ctx, `${path}.tabs[${i}] needs a label and a valid child`);
549
+ }
550
+ return out.length ? { type, tabs: out } : (note(ctx, `${path}: tabs with no valid tab is dropped`), null);
551
+ }
552
+ case 'text': {
553
+ const t = text(ctx, `${path}.text`, raw.text, CAP.text, { figures: false });
554
+ if (!t)
555
+ return null;
556
+ const href = raw.href === undefined ? undefined : safeHttpUrl(raw.href);
557
+ if (raw.href !== undefined && !href)
558
+ note(ctx, `${path}.href is not an http or https link, dropped`);
559
+ return clean({ type, text: t, tone: oneOf(raw.tone, ['muted']), href });
560
+ }
561
+ case 'triage': {
562
+ const block = ctx.bound ? boundBlock(raw, 'triage', path, ctx) : undefined;
563
+ if (ctx.bound && !block)
564
+ return null;
565
+ return clean({ type, window: oneOf(raw.window, TRIAGE_WINDOWS), title: text(ctx, `${path}.title`, raw.title, CAP.title), block: block ?? undefined });
566
+ }
567
+ case 'table': {
568
+ const from = resultRef(ctx, path, raw.from);
569
+ const data = datasetRef(ctx, path, raw.data);
570
+ if ((from === undefined) === (data === undefined))
571
+ return (note(ctx, `${path}: a table reads one of data or from`), null);
572
+ const block = ctx.bound && from ? boundBlock(raw, 'table', path, ctx) : undefined;
573
+ if (ctx.bound && from && !block)
574
+ return null;
575
+ return clean({
576
+ type,
577
+ title: text(ctx, `${path}.title`, raw.title, CAP.title),
578
+ data,
579
+ from,
580
+ columns: data ? columns(raw.columns, path, ctx) : undefined,
581
+ limit: int(raw.limit, 1, 50),
582
+ block: block ?? undefined,
583
+ });
584
+ }
585
+ case 'stats': {
586
+ const from = resultRef(ctx, path, raw.from);
587
+ const list = from ? [] : tiles(raw.tiles, path, ctx);
588
+ if (!from && !list.length)
589
+ return (note(ctx, `${path}: stats needs tiles or a from`), null);
590
+ const block = ctx.bound && from ? boundBlock(raw, 'stats', path, ctx) : undefined;
591
+ if (ctx.bound && from && !block)
592
+ return null;
593
+ return clean({ type, title: text(ctx, `${path}.title`, raw.title, CAP.title), from, tiles: list.length ? list : undefined, block: block ?? undefined });
594
+ }
595
+ case 'chart': {
596
+ const from = resultRef(ctx, path, raw.from);
597
+ const title = text(ctx, `${path}.title`, raw.title, CAP.title);
598
+ if (from) {
599
+ const block = ctx.bound ? boundBlock(raw, 'chart', path, ctx) : undefined;
600
+ if (ctx.bound && !block)
601
+ return null;
602
+ return clean({ type, title, from, block: block ?? undefined });
603
+ }
604
+ const data = datasetRef(ctx, path, raw.data);
605
+ const chartType = oneOf(raw.chartType, CHART_TYPES);
606
+ const x = fieldName(raw.x);
607
+ const list = series(raw.series, path, ctx);
608
+ if (!data || !chartType || !x || !list.length)
609
+ return (note(ctx, `${path}: a chart needs data, chartType, x, and series, or a from`), null);
610
+ return clean({
611
+ type,
612
+ title,
613
+ data,
614
+ chartType,
615
+ x,
616
+ xFormat: oneOf(raw.xFormat, VIEW_FORMATS),
617
+ series: list,
618
+ unit: text(ctx, `${path}.unit`, raw.unit, CAP.unit),
619
+ finding: text(ctx, `${path}.finding`, typeof raw.finding === 'string' ? raw.finding.replace(/\s+/g, ' ') : raw.finding, CAP.finding, {
620
+ figures: false,
621
+ }),
622
+ limit: int(raw.limit, 1, 31),
623
+ });
624
+ }
625
+ default: {
626
+ // The record blocks: the server builds the block from the result named by `from`.
627
+ const from = resultRef(ctx, path, raw.from);
628
+ if (!from)
629
+ return (note(ctx, `${path}: ${type} needs a from, the id of a tool result`), null);
630
+ const block = ctx.bound ? boundBlock(raw, type, path, ctx) : undefined;
631
+ if (ctx.bound && !block)
632
+ return null;
633
+ return clean({
634
+ type: type,
635
+ from,
636
+ nth: int(raw.nth, 0, 9),
637
+ title: text(ctx, `${path}.title`, raw.title, CAP.title),
638
+ limit: int(raw.limit, 1, 50),
639
+ block: block ?? undefined,
640
+ });
641
+ }
642
+ }
643
+ }
644
+ // ---------- Sources (set by the server) ----------
645
+ function cellOf(v) {
646
+ if (typeof v === 'string')
647
+ return v.length > CAP.cell ? `${v.slice(0, CAP.cell - 1)}…` : v;
648
+ if (typeof v === 'number')
649
+ return Number.isFinite(v) ? v : null;
650
+ return typeof v === 'boolean' ? v : null;
651
+ }
652
+ function parseSources(raw, ctx) {
653
+ if (!isObj(raw))
654
+ return undefined;
655
+ const out = {};
656
+ let cells = 0;
657
+ for (const [id, t] of Object.entries(raw)) {
658
+ if (!RESULT_ID.test(id) || !isObj(t) || !Array.isArray(t.columns) || !Array.isArray(t.rows))
659
+ continue;
660
+ const cols = t.columns.map((c) => fieldName(c));
661
+ if (!cols.length || cols.length > MAX_SOURCE_COLUMNS || !cols.every((c) => Boolean(c)))
662
+ continue;
663
+ const rows = [];
664
+ for (const r of t.rows.slice(0, MAX_SOURCE_ROWS)) {
665
+ if (!Array.isArray(r) || cells + cols.length > MAX_SOURCE_CELLS)
666
+ break;
667
+ rows.push(cols.map((_, i) => cellOf(r[i])));
668
+ cells += cols.length;
669
+ }
670
+ if (rows.length < t.rows.length)
671
+ note(ctx, `${id}: only ${rows.length} of ${t.rows.length} rows came with the view`);
672
+ const more = int(t.more, 1, 1_000_000_000);
673
+ out[id] = { columns: cols, rows, ...(more ? { more } : {}) };
674
+ ctx.sources.add(id);
675
+ }
676
+ return Object.keys(out).length ? out : undefined;
677
+ }
678
+ /** Checks a whole view. Invalid nodes, props, and datasets are dropped and noted; a view with no valid node is refused. */
679
+ export function parseViewTree(raw, opts = {}) {
680
+ const ctx = {
681
+ bound: opts.bound === true,
682
+ notes: [],
683
+ nodes: 0,
684
+ nodeLimitNoted: false,
685
+ datasets: new Set(),
686
+ vars: new Set(),
687
+ sources: new Set(),
688
+ ...(opts.parseBlock ? { parseBlock: opts.parseBlock } : {}),
689
+ };
690
+ if (!isObj(raw))
691
+ return { ok: false, reason: 'the view is not an object', notes: ctx.notes };
692
+ if (raw.root === undefined)
693
+ return { ok: false, reason: 'the view has no root', notes: ctx.notes };
694
+ const known = new Set(['v', 'title', 'datasets', 'vars', 'root', ...(ctx.bound ? ['sources', 'total', 'tzOffsetMin'] : [])]);
695
+ for (const k of Object.keys(raw))
696
+ if (!known.has(k))
697
+ note(ctx, `${k} is not a prop of a view, dropped`);
698
+ const sources = ctx.bound ? parseSources(raw.sources, ctx) : undefined;
699
+ const datasets = parseDatasets(raw.datasets, ctx);
700
+ // Vars read datasets, and a text may name a var, so the vars come before the nodes.
701
+ const vars = parseVars(raw.vars, ctx);
702
+ const node = parseNode(raw.root, 1, 'root', ctx);
703
+ if (!node)
704
+ return { ok: false, reason: 'the view has no valid node', notes: ctx.notes };
705
+ const root = { type: 'column', children: node.type === 'column' ? node.children : [node] };
706
+ const total = ctx.bound ? int(raw.total, 0, MAX_VIEW_CHILDREN) : undefined;
707
+ const tz = ctx.bound ? int(raw.tzOffsetMin, -840, 840) : undefined;
708
+ const view = clean({
709
+ v: 1,
710
+ title: text(ctx, 'title', raw.title, CAP.title),
711
+ sources,
712
+ datasets,
713
+ vars,
714
+ tzOffsetMin: tz,
715
+ root,
716
+ total,
717
+ });
718
+ return { ok: true, view, notes: ctx.notes, nodes: ctx.nodes };
719
+ }
720
+ /**
721
+ * The title, datasets, and vars of a view on their own. The server reads them while the model is still writing the nodes, so it can
722
+ * send the shell of the view and then each node as it closes. The same checks as parseViewTree, so a head that passes here passes there.
723
+ */
724
+ export function parseViewHead(raw) {
725
+ const ctx = { bound: false, notes: [], nodes: 0, nodeLimitNoted: false, datasets: new Set(), vars: new Set(), sources: new Set() };
726
+ const o = isObj(raw) ? raw : {};
727
+ const datasets = parseDatasets(o.datasets, ctx);
728
+ const vars = parseVars(o.vars, ctx);
729
+ return clean({ title: text(ctx, 'title', o.title, CAP.title), datasets, vars, notes: ctx.notes });
730
+ }
731
+ /** One node on its own, for a streamed `view_node` event. The datasets and vars of the view it joins say which names are known. */
732
+ export function parseViewNode(raw, view, opts = {}) {
733
+ const ctx = {
734
+ bound: opts.bound === true,
735
+ notes: [],
736
+ nodes: 0,
737
+ nodeLimitNoted: false,
738
+ datasets: new Set(Object.keys(view.datasets ?? {})),
739
+ vars: new Set(Object.keys(view.vars ?? {})),
740
+ sources: new Set(),
741
+ ...(opts.parseBlock ? { parseBlock: opts.parseBlock } : {}),
742
+ };
743
+ // A node of the root is at depth 2: the root column is depth 1.
744
+ return parseNode(raw, 2, 'node', ctx);
745
+ }
746
+ // ---------- Fallback, and walking a view ----------
747
+ /**
748
+ * Every object in a raw tree that looks like a node (it has a string `type`), in document order. Used when a spec fails the
749
+ * check: the blocks inside it still show (docs/CHAT-UI.md, Composed views: Fallback). A spec fails often because it nests too deep,
750
+ * so this reads deeper than the check allows: 16 levels of objects, and 80 nodes.
751
+ */
752
+ export function rawNodes(raw, max = 80) {
753
+ const out = [];
754
+ const walk = (v, depth) => {
755
+ if (out.length >= max || depth > 16)
756
+ return;
757
+ if (Array.isArray(v)) {
758
+ // A list is not a level: the nodes in it sit at the depth of the object that holds the list.
759
+ for (const x of v)
760
+ walk(x, depth);
761
+ return;
762
+ }
763
+ if (!isObj(v))
764
+ return;
765
+ if (typeof v.type === 'string')
766
+ out.push(v);
767
+ for (const k of ['root', 'children', 'tabs'])
768
+ if (k in v)
769
+ walk(v[k], depth + 1);
770
+ };
771
+ walk(raw, 0);
772
+ return out;
773
+ }
774
+ /** The nodes of a view in document order, nested ones included. */
775
+ export function viewNodes(node) {
776
+ const out = [node];
777
+ if ('children' in node)
778
+ for (const c of node.children)
779
+ out.push(...viewNodes(c));
780
+ if (node.type === 'tabs')
781
+ for (const t of node.tabs)
782
+ for (const c of t.children)
783
+ out.push(...viewNodes(c));
784
+ return out;
785
+ }
786
+ /** The blocks a bound view embeds. */
787
+ export function viewBlocks(view) {
788
+ const out = [];
789
+ for (const n of viewNodes(view.root))
790
+ if ('block' in n && n.block)
791
+ out.push(n.block);
792
+ return out;
793
+ }
794
+ /** What a view is built of, for the chat eval and for logs: the kinds of its nodes, in document order. */
795
+ export function viewKinds(view) {
796
+ return viewNodes(view.root)
797
+ .map((n) => n.type)
798
+ .filter((t) => t !== 'column');
799
+ }
800
+ /** The fields a view's datasets, vars, and nodes name, so the server can send only those columns of a result. */
801
+ export function fieldsUsed(spec) {
802
+ const out = new Set();
803
+ const cond = (c) => out.add(c.field);
804
+ for (const d of Object.values(spec.datasets ?? {})) {
805
+ for (const s of d.steps ?? []) {
806
+ if (s.op === 'filter')
807
+ s.where.forEach(cond);
808
+ else if (s.op === 'derive') {
809
+ out.add(s.expr.of);
810
+ if (s.expr.fn !== 'bucket' && typeof s.expr.over === 'string')
811
+ out.add(s.expr.over);
812
+ }
813
+ else if (s.op === 'group') {
814
+ s.by.forEach((b) => out.add(b));
815
+ for (const a of s.agg) {
816
+ if (a.of)
817
+ out.add(a.of);
818
+ a.where?.forEach(cond);
819
+ }
820
+ }
821
+ else if (s.op === 'sort')
822
+ out.add(s.by);
823
+ else if (s.op === 'pick')
824
+ s.fields.forEach((f) => out.add(f));
825
+ }
826
+ }
827
+ for (const v of Object.values(spec.vars ?? {}))
828
+ if (v.field)
829
+ out.add(v.field);
830
+ if (spec.root)
831
+ for (const n of viewNodes(spec.root)) {
832
+ if (n.type === 'chart') {
833
+ if (n.x)
834
+ out.add(n.x);
835
+ n.series?.forEach((s) => out.add(s.field));
836
+ }
837
+ if (n.type === 'table')
838
+ n.columns?.forEach((c) => out.add(c.field));
839
+ }
840
+ return out;
841
+ }
842
+ // ---------- What the model is told ----------
843
+ const EXAMPLE = {
844
+ title: 'Flaky tests by hour of day',
845
+ datasets: {
846
+ byHour: {
847
+ from: 'r2',
848
+ steps: [
849
+ { op: 'derive', as: 'hour', expr: { fn: 'bucket', of: 'at', by: 'hour_of_day' } },
850
+ { op: 'group', by: ['hour'], agg: [{ as: 'flaky', fn: 'count' }], fill: 'hour_of_day' },
851
+ ],
852
+ },
853
+ peak: { from: 'byHour', steps: [{ op: 'sort', by: 'flaky', dir: 'desc' }] },
854
+ },
855
+ vars: { peakHour: { of: 'peak', fn: 'cell', field: 'hour', row: 0, format: 'hour' }, peakCount: { of: 'peak', fn: 'cell', field: 'flaky', row: 0 } },
856
+ root: {
857
+ type: 'column',
858
+ children: [
859
+ { type: 'stats', tiles: [{ label: 'Busiest hour', value: '{peakHour}', sub: '{peakCount} flaky results', tone: 'attention' }] },
860
+ {
861
+ type: 'chart',
862
+ data: 'byHour',
863
+ chartType: 'bar',
864
+ x: 'hour',
865
+ xFormat: 'hour',
866
+ series: [{ field: 'flaky', name: 'Flaky results' }],
867
+ finding: 'Flaky results cluster at **{peakHour}**.',
868
+ },
869
+ ],
870
+ },
871
+ };
872
+ /** The description of compose_view: the format in the words the model needs, one registry entry per component. */
873
+ export function viewSpecGuide() {
874
+ const props = (type) => Object.entries(VIEW_COMPONENTS[type].props)
875
+ .map(([k, p]) => `${k}${p.required ? '' : '?'}`)
876
+ .join(', ');
877
+ const kinds = (types) => types.map((t) => `${t} {${props(t)}}`).join('; ');
878
+ return [
879
+ 'Compose one view that arranges several blocks, or numbers a lookup does not give, from our own components. Use it only when no single block answers the question; a question one tool answers gets that tool and no view.',
880
+ 'The input is JSON: { title?, datasets?, vars?, root }. root is a column of nodes, nested at most 4 levels, at most 40 nodes. There is no HTML, CSS, color, or action: buttons come from the blocks, and only the actions those blocks already have exist.',
881
+ 'Data comes only from tool results of this turn. Each lookup result carries a resultId such as "r1". Filter in the tool call (days, branch, status), never in the view; the view arranges and computes over what came back. Set context to true on a list lookup whose rows you only arrange here, so it does not also show alone.',
882
+ `Layout and text: ${kinds(['column', 'row', 'section', 'tabs', 'text'])}. A tab is { label, children }.`,
883
+ `Blocks localdost builds from a result id: ${kinds(VIEW_RECORD_TYPES)}; ${kinds(['triage'])}. A result with no row for that block gives no block.`,
884
+ `Blocks built from your data: ${kinds(['stats', 'chart', 'table'])}. stats, chart, and table also take from: "<resultId>" for a result that is already tiles, a chart, or a table (pass_rate, flaky_by_spec). A tile is { label, value, sub?, tone? ok|attention|bad }, a column is { field, label?, format? }, a series is { field, name? }, chartType is bar, stacked_bar, or line.`,
885
+ 'datasets: { name: { from: "<resultId>" or an earlier dataset, steps: [...] } }. Steps run in order:',
886
+ '{op:"filter", where:[{field, is: eq|ne|gt|gte|lt|lte|in|contains, value}]}; {op:"derive", as, expr:{fn:"bucket", of, by: hour|hour_of_day|day|weekday|week|month} or {fn: ratio|percent|change|diff, of, over}} (over is a field or a number; percent is of/over*100, change is (of/over-1)*100); {op:"group", by:[fields], agg:[{as, fn: count|sum|avg|min|max|distinct, of?, where?}], fill?: hour_of_day|weekday}; {op:"sort", by, dir?: asc|desc}; {op:"limit", n}; {op:"pick", fields}.',
887
+ 'vars: { name: { of: dataset, fn: count|sum|avg|min|max|cell, field?, row?, format? } }. {name} in a text, a tile value or sub, or a finding takes the value. formats: text, number, percent, duration (ms), hour, weekday, day, spec (a test file path without .spec.ts).',
888
+ 'Never type a number. Every figure on screen comes from a tool result through vars: a tile value is always a {name}, and a text, a tile sub, or a finding that holds a number you typed is dropped. A look-back window such as "the last 7 days" may be typed, and so may a title or a label.',
889
+ 'A result that says `more` holds only part of the data: the view computes over the rows it has and shows a notice. Narrow the filter in the tool call (fewer days, one branch, one spec) so the view counts everything, or say in your sentence that the numbers cover part of the data.',
890
+ 'A step or a field that is not valid drops the whole dataset and every node that reads it, and the answer says what was dropped. Write one or two sentences of judgement after the view, and do not repeat its numbers.',
891
+ `Example: ${JSON.stringify(EXAMPLE)}`,
892
+ ].join('\n');
893
+ }
894
+ //# sourceMappingURL=view-spec.js.map