@loompad/cli 0.1.0 → 1.1.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 (687) hide show
  1. package/ARCHITECTURE.md +96 -11
  2. package/CHANGELOG.md +1042 -0
  3. package/README.md +1473 -44
  4. package/THIRD_PARTY_NOTICES.md +275 -0
  5. package/dist/adapters/antigravity-cli.d.ts +62 -0
  6. package/dist/adapters/antigravity-cli.js +258 -0
  7. package/dist/adapters/antigravity-cli.js.map +1 -0
  8. package/dist/adapters/base.d.ts +61 -9
  9. package/dist/adapters/base.js +266 -15
  10. package/dist/adapters/base.js.map +1 -1
  11. package/dist/adapters/bridges/antigravity.d.ts +9 -12
  12. package/dist/adapters/bridges/antigravity.js +9 -12
  13. package/dist/adapters/bridges/antigravity.js.map +1 -1
  14. package/dist/adapters/echo.d.ts +1 -0
  15. package/dist/adapters/echo.js +59 -3
  16. package/dist/adapters/echo.js.map +1 -1
  17. package/dist/adapters/grok.d.ts +7 -0
  18. package/dist/adapters/grok.js +20 -10
  19. package/dist/adapters/grok.js.map +1 -1
  20. package/dist/adapters/index.d.ts +5 -1
  21. package/dist/adapters/index.js +53 -7
  22. package/dist/adapters/index.js.map +1 -1
  23. package/dist/adapters/model.d.ts +137 -0
  24. package/dist/adapters/model.js +527 -0
  25. package/dist/adapters/model.js.map +1 -0
  26. package/dist/adapters/opencode.d.ts +101 -1
  27. package/dist/adapters/opencode.js +874 -98
  28. package/dist/adapters/opencode.js.map +1 -1
  29. package/dist/cli/doctor.d.ts +32 -0
  30. package/dist/cli/doctor.js +89 -4
  31. package/dist/cli/doctor.js.map +1 -1
  32. package/dist/cli/index.js +2651 -87
  33. package/dist/cli/index.js.map +1 -1
  34. package/dist/cli/tui-model.js +3 -1
  35. package/dist/cli/tui-model.js.map +1 -1
  36. package/dist/cli/tui.js +44 -1
  37. package/dist/cli/tui.js.map +1 -1
  38. package/dist/cli/ui.d.ts +2 -0
  39. package/dist/cli/ui.js +13 -0
  40. package/dist/cli/ui.js.map +1 -1
  41. package/dist/core/ades.d.ts +32 -16
  42. package/dist/core/ades.js +57 -20
  43. package/dist/core/ades.js.map +1 -1
  44. package/dist/core/agent-state.d.ts +14 -0
  45. package/dist/core/agent-state.js +32 -0
  46. package/dist/core/agent-state.js.map +1 -0
  47. package/dist/core/approvals.d.ts +33 -0
  48. package/dist/core/approvals.js +29 -0
  49. package/dist/core/approvals.js.map +1 -0
  50. package/dist/core/backup.d.ts +19 -0
  51. package/dist/core/backup.js +86 -0
  52. package/dist/core/backup.js.map +1 -0
  53. package/dist/core/baton.d.ts +2 -2
  54. package/dist/core/baton.js.map +1 -1
  55. package/dist/core/brain-extract.d.ts +17 -0
  56. package/dist/core/brain-extract.js +28 -2
  57. package/dist/core/brain-extract.js.map +1 -1
  58. package/dist/core/brain-index.d.ts +71 -0
  59. package/dist/core/brain-index.js +204 -5
  60. package/dist/core/brain-index.js.map +1 -1
  61. package/dist/core/brain.d.ts +58 -2
  62. package/dist/core/brain.js +79 -1
  63. package/dist/core/brain.js.map +1 -1
  64. package/dist/core/chat-import.d.ts +71 -0
  65. package/dist/core/chat-import.js +419 -0
  66. package/dist/core/chat-import.js.map +1 -0
  67. package/dist/core/checkpoint.d.ts +107 -0
  68. package/dist/core/checkpoint.js +259 -0
  69. package/dist/core/checkpoint.js.map +1 -0
  70. package/dist/core/claude-cli.js +1 -1
  71. package/dist/core/claude-cli.js.map +1 -1
  72. package/dist/core/continuity/artifacts.d.ts +14 -0
  73. package/dist/core/continuity/artifacts.js +118 -0
  74. package/dist/core/continuity/artifacts.js.map +1 -0
  75. package/dist/core/continuity/capabilities.d.ts +65 -0
  76. package/dist/core/continuity/capabilities.js +129 -0
  77. package/dist/core/continuity/capabilities.js.map +1 -0
  78. package/dist/core/continuity/contracts.d.ts +352 -0
  79. package/dist/core/continuity/contracts.js +117 -0
  80. package/dist/core/continuity/contracts.js.map +1 -0
  81. package/dist/core/continuity/engine.d.ts +55 -0
  82. package/dist/core/continuity/engine.js +504 -0
  83. package/dist/core/continuity/engine.js.map +1 -0
  84. package/dist/core/continuity/store.d.ts +73 -0
  85. package/dist/core/continuity/store.js +438 -0
  86. package/dist/core/continuity/store.js.map +1 -0
  87. package/dist/core/conversations.d.ts +19 -0
  88. package/dist/core/conversations.js +87 -0
  89. package/dist/core/conversations.js.map +1 -0
  90. package/dist/core/crew-coordination.d.ts +6 -0
  91. package/dist/core/crew-coordination.js +24 -0
  92. package/dist/core/crew-coordination.js.map +1 -0
  93. package/dist/core/crew-policy.d.ts +18 -0
  94. package/dist/core/crew-policy.js +40 -0
  95. package/dist/core/crew-policy.js.map +1 -0
  96. package/dist/core/crew-protocol.d.ts +64 -0
  97. package/dist/core/crew-protocol.js +146 -0
  98. package/dist/core/crew-protocol.js.map +1 -0
  99. package/dist/core/crew-requests.d.ts +14 -0
  100. package/dist/core/crew-requests.js +22 -0
  101. package/dist/core/crew-requests.js.map +1 -0
  102. package/dist/core/crew.d.ts +395 -0
  103. package/dist/core/crew.js +1857 -0
  104. package/dist/core/crew.js.map +1 -0
  105. package/dist/core/digest.d.ts +40 -0
  106. package/dist/core/digest.js +94 -0
  107. package/dist/core/digest.js.map +1 -0
  108. package/dist/core/distill.js +3 -5
  109. package/dist/core/distill.js.map +1 -1
  110. package/dist/core/eventlog.d.ts +27 -25
  111. package/dist/core/eventlog.js +97 -150
  112. package/dist/core/eventlog.js.map +1 -1
  113. package/dist/core/events/contracts.d.ts +51 -0
  114. package/dist/core/events/contracts.js +2 -0
  115. package/dist/core/events/contracts.js.map +1 -0
  116. package/dist/core/events/jsonl-store.d.ts +23 -0
  117. package/dist/core/events/jsonl-store.js +90 -0
  118. package/dist/core/events/jsonl-store.js.map +1 -0
  119. package/dist/core/events/sqlite-store.d.ts +37 -0
  120. package/dist/core/events/sqlite-store.js +215 -0
  121. package/dist/core/events/sqlite-store.js.map +1 -0
  122. package/dist/core/forecast.d.ts +44 -0
  123. package/dist/core/forecast.js +46 -0
  124. package/dist/core/forecast.js.map +1 -0
  125. package/dist/core/free-pool.d.ts +65 -0
  126. package/dist/core/free-pool.js +171 -0
  127. package/dist/core/free-pool.js.map +1 -0
  128. package/dist/core/git.d.ts +30 -0
  129. package/dist/core/git.js +50 -2
  130. package/dist/core/git.js.map +1 -1
  131. package/dist/core/github-events.d.ts +53 -0
  132. package/dist/core/github-events.js +227 -0
  133. package/dist/core/github-events.js.map +1 -0
  134. package/dist/core/goal-lanes.d.ts +53 -0
  135. package/dist/core/goal-lanes.js +99 -0
  136. package/dist/core/goal-lanes.js.map +1 -0
  137. package/dist/core/hosted.d.ts +27 -0
  138. package/dist/core/hosted.js +50 -0
  139. package/dist/core/hosted.js.map +1 -0
  140. package/dist/core/http-server.d.ts +5 -0
  141. package/dist/core/http-server.js +8 -0
  142. package/dist/core/http-server.js.map +1 -0
  143. package/dist/core/invite-link.d.ts +31 -0
  144. package/dist/core/invite-link.js +45 -0
  145. package/dist/core/invite-link.js.map +1 -0
  146. package/dist/core/loops.d.ts +37 -0
  147. package/dist/core/loops.js +81 -0
  148. package/dist/core/loops.js.map +1 -0
  149. package/dist/core/mcp-catalog.d.ts +182 -0
  150. package/dist/core/mcp-catalog.js +431 -0
  151. package/dist/core/mcp-catalog.js.map +1 -0
  152. package/dist/core/mcp.d.ts +87 -0
  153. package/dist/core/mcp.js +181 -0
  154. package/dist/core/mcp.js.map +1 -0
  155. package/dist/core/memory.d.ts +1 -0
  156. package/dist/core/memory.js +5 -2
  157. package/dist/core/memory.js.map +1 -1
  158. package/dist/core/model-tools.d.ts +97 -0
  159. package/dist/core/model-tools.js +388 -0
  160. package/dist/core/model-tools.js.map +1 -0
  161. package/dist/core/notify.js +19 -1
  162. package/dist/core/notify.js.map +1 -1
  163. package/dist/core/orchestra.d.ts +635 -0
  164. package/dist/core/orchestra.js +2120 -0
  165. package/dist/core/orchestra.js.map +1 -0
  166. package/dist/core/permissions.d.ts +56 -0
  167. package/dist/core/permissions.js +122 -0
  168. package/dist/core/permissions.js.map +1 -0
  169. package/dist/core/preview-proxy.d.ts +70 -0
  170. package/dist/core/preview-proxy.js +563 -0
  171. package/dist/core/preview-proxy.js.map +1 -0
  172. package/dist/core/preview-shot.d.ts +46 -0
  173. package/dist/core/preview-shot.js +109 -0
  174. package/dist/core/preview-shot.js.map +1 -0
  175. package/dist/core/process.d.ts +36 -0
  176. package/dist/core/process.js +168 -0
  177. package/dist/core/process.js.map +1 -0
  178. package/dist/core/prompt-queue.d.ts +136 -0
  179. package/dist/core/prompt-queue.js +269 -0
  180. package/dist/core/prompt-queue.js.map +1 -0
  181. package/dist/core/prompts.d.ts +53 -0
  182. package/dist/core/prompts.js +127 -0
  183. package/dist/core/prompts.js.map +1 -0
  184. package/dist/core/proof.d.ts +82 -0
  185. package/dist/core/proof.js +216 -0
  186. package/dist/core/proof.js.map +1 -0
  187. package/dist/core/provider-text.d.ts +23 -0
  188. package/dist/core/provider-text.js +66 -0
  189. package/dist/core/provider-text.js.map +1 -0
  190. package/dist/core/providers.d.ts +152 -0
  191. package/dist/core/providers.js +343 -0
  192. package/dist/core/providers.js.map +1 -0
  193. package/dist/core/quota.d.ts +33 -0
  194. package/dist/core/quota.js +74 -0
  195. package/dist/core/quota.js.map +1 -0
  196. package/dist/core/recipes.d.ts +50 -0
  197. package/dist/core/recipes.js +99 -0
  198. package/dist/core/recipes.js.map +1 -0
  199. package/dist/core/registry.d.ts +54 -0
  200. package/dist/core/registry.js +62 -5
  201. package/dist/core/registry.js.map +1 -1
  202. package/dist/core/relay-client.d.ts +67 -0
  203. package/dist/core/relay-client.js +184 -0
  204. package/dist/core/relay-client.js.map +1 -0
  205. package/dist/core/relay-protocol.d.ts +140 -0
  206. package/dist/core/relay-protocol.js +189 -0
  207. package/dist/core/relay-protocol.js.map +1 -0
  208. package/dist/core/replay.d.ts +18 -0
  209. package/dist/core/replay.js +191 -0
  210. package/dist/core/replay.js.map +1 -0
  211. package/dist/core/review-triage.d.ts +41 -0
  212. package/dist/core/review-triage.js +124 -0
  213. package/dist/core/review-triage.js.map +1 -0
  214. package/dist/core/router.js +2 -2
  215. package/dist/core/router.js.map +1 -1
  216. package/dist/core/routes.d.ts +39 -3
  217. package/dist/core/routes.js +137 -4
  218. package/dist/core/routes.js.map +1 -1
  219. package/dist/core/run-command.d.ts +14 -0
  220. package/dist/core/run-command.js +45 -0
  221. package/dist/core/run-command.js.map +1 -0
  222. package/dist/core/runner-setup.d.ts +36 -0
  223. package/dist/core/runner-setup.js +114 -0
  224. package/dist/core/runner-setup.js.map +1 -0
  225. package/dist/core/search.js +0 -0
  226. package/dist/core/search.js.map +1 -1
  227. package/dist/core/semantic.d.ts +92 -0
  228. package/dist/core/semantic.js +227 -0
  229. package/dist/core/semantic.js.map +1 -0
  230. package/dist/core/servers.d.ts +115 -0
  231. package/dist/core/servers.js +305 -0
  232. package/dist/core/servers.js.map +1 -0
  233. package/dist/core/setup.js +64 -6
  234. package/dist/core/setup.js.map +1 -1
  235. package/dist/core/shield.d.ts +17 -0
  236. package/dist/core/shield.js +81 -0
  237. package/dist/core/shield.js.map +1 -0
  238. package/dist/core/shift.d.ts +69 -0
  239. package/dist/core/shift.js +120 -0
  240. package/dist/core/shift.js.map +1 -0
  241. package/dist/core/skill-install.d.ts +125 -0
  242. package/dist/core/skill-install.js +328 -0
  243. package/dist/core/skill-install.js.map +1 -0
  244. package/dist/core/skills.d.ts +116 -0
  245. package/dist/core/skills.js +223 -0
  246. package/dist/core/skills.js.map +1 -0
  247. package/dist/core/step-conditions.d.ts +65 -0
  248. package/dist/core/step-conditions.js +102 -0
  249. package/dist/core/step-conditions.js.map +1 -0
  250. package/dist/core/subagents.d.ts +45 -0
  251. package/dist/core/subagents.js +90 -0
  252. package/dist/core/subagents.js.map +1 -0
  253. package/dist/core/team-canon.d.ts +42 -0
  254. package/dist/core/team-canon.js +121 -0
  255. package/dist/core/team-canon.js.map +1 -0
  256. package/dist/core/team-crypto.d.ts +97 -0
  257. package/dist/core/team-crypto.js +175 -0
  258. package/dist/core/team-crypto.js.map +1 -0
  259. package/dist/core/team-hub.d.ts +514 -0
  260. package/dist/core/team-hub.js +964 -0
  261. package/dist/core/team-hub.js.map +1 -0
  262. package/dist/core/team-landing.d.ts +239 -0
  263. package/dist/core/team-landing.js +504 -0
  264. package/dist/core/team-landing.js.map +1 -0
  265. package/dist/core/team-leases.d.ts +44 -0
  266. package/dist/core/team-leases.js +145 -0
  267. package/dist/core/team-leases.js.map +1 -0
  268. package/dist/core/team-memory.d.ts +42 -0
  269. package/dist/core/team-memory.js +84 -0
  270. package/dist/core/team-memory.js.map +1 -0
  271. package/dist/core/team-policy.d.ts +85 -0
  272. package/dist/core/team-policy.js +191 -0
  273. package/dist/core/team-policy.js.map +1 -0
  274. package/dist/core/thread-md.d.ts +6 -0
  275. package/dist/core/thread-md.js +42 -0
  276. package/dist/core/thread-md.js.map +1 -0
  277. package/dist/core/turn-stats.d.ts +61 -0
  278. package/dist/core/turn-stats.js +124 -0
  279. package/dist/core/turn-stats.js.map +1 -0
  280. package/dist/core/updater.d.ts +73 -0
  281. package/dist/core/updater.js +153 -0
  282. package/dist/core/updater.js.map +1 -0
  283. package/dist/core/usage.d.ts +75 -0
  284. package/dist/core/usage.js +163 -0
  285. package/dist/core/usage.js.map +1 -0
  286. package/dist/core/windows-jobs.d.ts +15 -0
  287. package/dist/core/windows-jobs.js +170 -0
  288. package/dist/core/windows-jobs.js.map +1 -0
  289. package/dist/core/worktree-merge.d.ts +57 -0
  290. package/dist/core/worktree-merge.js +123 -0
  291. package/dist/core/worktree-merge.js.map +1 -0
  292. package/dist/core/worktree.d.ts +5 -0
  293. package/dist/core/worktree.js +45 -5
  294. package/dist/core/worktree.js.map +1 -1
  295. package/dist/core/worktrees.d.ts +6 -0
  296. package/dist/core/worktrees.js +21 -0
  297. package/dist/core/worktrees.js.map +1 -0
  298. package/dist/daemon/app-page.d.ts +0 -17
  299. package/dist/daemon/app-page.js +10 -6346
  300. package/dist/daemon/app-page.js.map +1 -1
  301. package/dist/daemon/auth.d.ts +24 -3
  302. package/dist/daemon/auth.js +66 -7
  303. package/dist/daemon/auth.js.map +1 -1
  304. package/dist/daemon/board.d.ts +7 -0
  305. package/dist/daemon/board.js +12 -1
  306. package/dist/daemon/board.js.map +1 -1
  307. package/dist/daemon/brand-icons.d.ts +6 -1
  308. package/dist/daemon/brand-icons.js +11 -3
  309. package/dist/daemon/brand-icons.js.map +1 -1
  310. package/dist/daemon/client.d.ts +665 -1
  311. package/dist/daemon/client.js +381 -3
  312. package/dist/daemon/client.js.map +1 -1
  313. package/dist/daemon/delivery.d.ts +34 -0
  314. package/dist/daemon/delivery.js +63 -0
  315. package/dist/daemon/delivery.js.map +1 -0
  316. package/dist/daemon/deploys.d.ts +62 -0
  317. package/dist/daemon/deploys.js +159 -0
  318. package/dist/daemon/deploys.js.map +1 -0
  319. package/dist/daemon/landing.d.ts +192 -0
  320. package/dist/daemon/landing.js +992 -0
  321. package/dist/daemon/landing.js.map +1 -0
  322. package/dist/daemon/onboard.d.ts +150 -0
  323. package/dist/daemon/onboard.js +390 -0
  324. package/dist/daemon/onboard.js.map +1 -0
  325. package/dist/daemon/proof.d.ts +70 -0
  326. package/dist/daemon/proof.js +172 -0
  327. package/dist/daemon/proof.js.map +1 -0
  328. package/dist/daemon/push.d.ts +19 -1
  329. package/dist/daemon/push.js +90 -3
  330. package/dist/daemon/push.js.map +1 -1
  331. package/dist/daemon/relay.d.ts +82 -0
  332. package/dist/daemon/relay.js +351 -0
  333. package/dist/daemon/relay.js.map +1 -0
  334. package/dist/daemon/routes/agent-discovery.d.ts +4 -0
  335. package/dist/daemon/routes/agent-discovery.js +29 -0
  336. package/dist/daemon/routes/agent-discovery.js.map +1 -0
  337. package/dist/daemon/routes/agent-settings.d.ts +4 -0
  338. package/dist/daemon/routes/agent-settings.js +94 -0
  339. package/dist/daemon/routes/agent-settings.js.map +1 -0
  340. package/dist/daemon/routes/agents.d.ts +4 -0
  341. package/dist/daemon/routes/agents.js +105 -0
  342. package/dist/daemon/routes/agents.js.map +1 -0
  343. package/dist/daemon/routes/alerts.d.ts +4 -0
  344. package/dist/daemon/routes/alerts.js +137 -0
  345. package/dist/daemon/routes/alerts.js.map +1 -0
  346. package/dist/daemon/routes/approvals.d.ts +4 -0
  347. package/dist/daemon/routes/approvals.js +40 -0
  348. package/dist/daemon/routes/approvals.js.map +1 -0
  349. package/dist/daemon/routes/assets.d.ts +3 -0
  350. package/dist/daemon/routes/assets.js +64 -0
  351. package/dist/daemon/routes/assets.js.map +1 -0
  352. package/dist/daemon/routes/board.d.ts +4 -0
  353. package/dist/daemon/routes/board.js +147 -0
  354. package/dist/daemon/routes/board.js.map +1 -0
  355. package/dist/daemon/routes/brain.d.ts +4 -0
  356. package/dist/daemon/routes/brain.js +270 -0
  357. package/dist/daemon/routes/brain.js.map +1 -0
  358. package/dist/daemon/routes/chats.d.ts +4 -0
  359. package/dist/daemon/routes/chats.js +249 -0
  360. package/dist/daemon/routes/chats.js.map +1 -0
  361. package/dist/daemon/routes/clients.d.ts +4 -0
  362. package/dist/daemon/routes/clients.js +49 -0
  363. package/dist/daemon/routes/clients.js.map +1 -0
  364. package/dist/daemon/routes/cloud.d.ts +4 -0
  365. package/dist/daemon/routes/cloud.js +46 -0
  366. package/dist/daemon/routes/cloud.js.map +1 -0
  367. package/dist/daemon/routes/config.d.ts +4 -0
  368. package/dist/daemon/routes/config.js +35 -0
  369. package/dist/daemon/routes/config.js.map +1 -0
  370. package/dist/daemon/routes/context.d.ts +51 -0
  371. package/dist/daemon/routes/context.js +2 -0
  372. package/dist/daemon/routes/context.js.map +1 -0
  373. package/dist/daemon/routes/crews.d.ts +4 -0
  374. package/dist/daemon/routes/crews.js +149 -0
  375. package/dist/daemon/routes/crews.js.map +1 -0
  376. package/dist/daemon/routes/files.d.ts +3 -0
  377. package/dist/daemon/routes/files.js +253 -0
  378. package/dist/daemon/routes/files.js.map +1 -0
  379. package/dist/daemon/routes/git.d.ts +4 -0
  380. package/dist/daemon/routes/git.js +96 -0
  381. package/dist/daemon/routes/git.js.map +1 -0
  382. package/dist/daemon/routes/history.d.ts +4 -0
  383. package/dist/daemon/routes/history.js +101 -0
  384. package/dist/daemon/routes/history.js.map +1 -0
  385. package/dist/daemon/routes/integrations-project.d.ts +3 -0
  386. package/dist/daemon/routes/integrations-project.js +103 -0
  387. package/dist/daemon/routes/integrations-project.js.map +1 -0
  388. package/dist/daemon/routes/integrations.d.ts +3 -0
  389. package/dist/daemon/routes/integrations.js +111 -0
  390. package/dist/daemon/routes/integrations.js.map +1 -0
  391. package/dist/daemon/routes/logs.d.ts +3 -0
  392. package/dist/daemon/routes/logs.js +40 -0
  393. package/dist/daemon/routes/logs.js.map +1 -0
  394. package/dist/daemon/routes/messages.d.ts +4 -0
  395. package/dist/daemon/routes/messages.js +60 -0
  396. package/dist/daemon/routes/messages.js.map +1 -0
  397. package/dist/daemon/routes/observability.d.ts +4 -0
  398. package/dist/daemon/routes/observability.js +247 -0
  399. package/dist/daemon/routes/observability.js.map +1 -0
  400. package/dist/daemon/routes/onboard.d.ts +12 -0
  401. package/dist/daemon/routes/onboard.js +67 -0
  402. package/dist/daemon/routes/onboard.js.map +1 -0
  403. package/dist/daemon/routes/orchestra.d.ts +4 -0
  404. package/dist/daemon/routes/orchestra.js +110 -0
  405. package/dist/daemon/routes/orchestra.js.map +1 -0
  406. package/dist/daemon/routes/pairing.d.ts +4 -0
  407. package/dist/daemon/routes/pairing.js +155 -0
  408. package/dist/daemon/routes/pairing.js.map +1 -0
  409. package/dist/daemon/routes/preview.d.ts +24 -0
  410. package/dist/daemon/routes/preview.js +122 -0
  411. package/dist/daemon/routes/preview.js.map +1 -0
  412. package/dist/daemon/routes/project-actions.d.ts +4 -0
  413. package/dist/daemon/routes/project-actions.js +53 -0
  414. package/dist/daemon/routes/project-actions.js.map +1 -0
  415. package/dist/daemon/routes/project-team.d.ts +4 -0
  416. package/dist/daemon/routes/project-team.js +201 -0
  417. package/dist/daemon/routes/project-team.js.map +1 -0
  418. package/dist/daemon/routes/projects.d.ts +14 -0
  419. package/dist/daemon/routes/projects.js +138 -0
  420. package/dist/daemon/routes/projects.js.map +1 -0
  421. package/dist/daemon/routes/prompts.d.ts +4 -0
  422. package/dist/daemon/routes/prompts.js +44 -0
  423. package/dist/daemon/routes/prompts.js.map +1 -0
  424. package/dist/daemon/routes/proof.d.ts +4 -0
  425. package/dist/daemon/routes/proof.js +22 -0
  426. package/dist/daemon/routes/proof.js.map +1 -0
  427. package/dist/daemon/routes/providers.d.ts +3 -0
  428. package/dist/daemon/routes/providers.js +60 -0
  429. package/dist/daemon/routes/providers.js.map +1 -0
  430. package/dist/daemon/routes/public.d.ts +4 -0
  431. package/dist/daemon/routes/public.js +64 -0
  432. package/dist/daemon/routes/public.js.map +1 -0
  433. package/dist/daemon/routes/queue.d.ts +4 -0
  434. package/dist/daemon/routes/queue.js +140 -0
  435. package/dist/daemon/routes/queue.js.map +1 -0
  436. package/dist/daemon/routes/routing.d.ts +4 -0
  437. package/dist/daemon/routes/routing.js +61 -0
  438. package/dist/daemon/routes/routing.js.map +1 -0
  439. package/dist/daemon/routes/runtime-handler.d.ts +2 -0
  440. package/dist/daemon/routes/runtime-handler.js +63 -0
  441. package/dist/daemon/routes/runtime-handler.js.map +1 -0
  442. package/dist/daemon/routes/search.d.ts +4 -0
  443. package/dist/daemon/routes/search.js +17 -0
  444. package/dist/daemon/routes/search.js.map +1 -0
  445. package/dist/daemon/routes/servers.d.ts +4 -0
  446. package/dist/daemon/routes/servers.js +133 -0
  447. package/dist/daemon/routes/servers.js.map +1 -0
  448. package/dist/daemon/routes/setup.d.ts +3 -0
  449. package/dist/daemon/routes/setup.js +50 -0
  450. package/dist/daemon/routes/setup.js.map +1 -0
  451. package/dist/daemon/routes/shift.d.ts +4 -0
  452. package/dist/daemon/routes/shift.js +30 -0
  453. package/dist/daemon/routes/shift.js.map +1 -0
  454. package/dist/daemon/routes/specs.d.ts +4 -0
  455. package/dist/daemon/routes/specs.js +57 -0
  456. package/dist/daemon/routes/specs.js.map +1 -0
  457. package/dist/daemon/routes/task-delivery.d.ts +4 -0
  458. package/dist/daemon/routes/task-delivery.js +38 -0
  459. package/dist/daemon/routes/task-delivery.js.map +1 -0
  460. package/dist/daemon/routes/team.d.ts +4 -0
  461. package/dist/daemon/routes/team.js +193 -0
  462. package/dist/daemon/routes/team.js.map +1 -0
  463. package/dist/daemon/routes/terminals.d.ts +4 -0
  464. package/dist/daemon/routes/terminals.js +87 -0
  465. package/dist/daemon/routes/terminals.js.map +1 -0
  466. package/dist/daemon/routes/tools.d.ts +4 -0
  467. package/dist/daemon/routes/tools.js +180 -0
  468. package/dist/daemon/routes/tools.js.map +1 -0
  469. package/dist/daemon/routes/updates.d.ts +4 -0
  470. package/dist/daemon/routes/updates.js +89 -0
  471. package/dist/daemon/routes/updates.js.map +1 -0
  472. package/dist/daemon/routes/voice.d.ts +4 -0
  473. package/dist/daemon/routes/voice.js +53 -0
  474. package/dist/daemon/routes/voice.js.map +1 -0
  475. package/dist/daemon/runner.d.ts +186 -0
  476. package/dist/daemon/runner.js +612 -0
  477. package/dist/daemon/runner.js.map +1 -0
  478. package/dist/daemon/runtime/accounting.d.ts +130 -0
  479. package/dist/daemon/runtime/accounting.js +303 -0
  480. package/dist/daemon/runtime/accounting.js.map +1 -0
  481. package/dist/daemon/runtime/agents.d.ts +16 -0
  482. package/dist/daemon/runtime/agents.js +71 -0
  483. package/dist/daemon/runtime/agents.js.map +1 -0
  484. package/dist/daemon/runtime/briefings.d.ts +134 -0
  485. package/dist/daemon/runtime/briefings.js +329 -0
  486. package/dist/daemon/runtime/briefings.js.map +1 -0
  487. package/dist/daemon/runtime/native-usage.d.ts +21 -0
  488. package/dist/daemon/runtime/native-usage.js +71 -0
  489. package/dist/daemon/runtime/native-usage.js.map +1 -0
  490. package/dist/daemon/runtime/queue.d.ts +94 -0
  491. package/dist/daemon/runtime/queue.js +222 -0
  492. package/dist/daemon/runtime/queue.js.map +1 -0
  493. package/dist/daemon/runtime/relay.d.ts +93 -0
  494. package/dist/daemon/runtime/relay.js +240 -0
  495. package/dist/daemon/runtime/relay.js.map +1 -0
  496. package/dist/daemon/runtime/turns.d.ts +202 -0
  497. package/dist/daemon/runtime/turns.js +663 -0
  498. package/dist/daemon/runtime/turns.js.map +1 -0
  499. package/dist/daemon/runtime-support.d.ts +76 -0
  500. package/dist/daemon/runtime-support.js +134 -0
  501. package/dist/daemon/runtime-support.js.map +1 -0
  502. package/dist/daemon/runtime.d.ts +739 -70
  503. package/dist/daemon/runtime.js +2751 -470
  504. package/dist/daemon/runtime.js.map +1 -1
  505. package/dist/daemon/server.d.ts +82 -55
  506. package/dist/daemon/server.js +674 -1435
  507. package/dist/daemon/server.js.map +1 -1
  508. package/dist/daemon/shift.d.ts +70 -0
  509. package/dist/daemon/shift.js +170 -0
  510. package/dist/daemon/shift.js.map +1 -0
  511. package/dist/daemon/specs.d.ts +92 -0
  512. package/dist/daemon/specs.js +285 -0
  513. package/dist/daemon/specs.js.map +1 -0
  514. package/dist/daemon/system.d.ts +208 -0
  515. package/dist/daemon/system.js +557 -0
  516. package/dist/daemon/system.js.map +1 -0
  517. package/dist/daemon/tasks.js +1 -1
  518. package/dist/daemon/team-brain.d.ts +136 -0
  519. package/dist/daemon/team-brain.js +659 -0
  520. package/dist/daemon/team-brain.js.map +1 -0
  521. package/dist/daemon/team-coordinator.d.ts +78 -0
  522. package/dist/daemon/team-coordinator.js +408 -0
  523. package/dist/daemon/team-coordinator.js.map +1 -0
  524. package/dist/daemon/team.d.ts +339 -0
  525. package/dist/daemon/team.js +1433 -0
  526. package/dist/daemon/team.js.map +1 -0
  527. package/dist/daemon/terminals.d.ts +22 -3
  528. package/dist/daemon/terminals.js +236 -16
  529. package/dist/daemon/terminals.js.map +1 -1
  530. package/dist/hub/client.d.ts +120 -0
  531. package/dist/hub/client.js +228 -0
  532. package/dist/hub/client.js.map +1 -0
  533. package/dist/hub/server.d.ts +32 -0
  534. package/dist/hub/server.js +180 -0
  535. package/dist/hub/server.js.map +1 -0
  536. package/dist/hub/supabase-client.d.ts +220 -0
  537. package/dist/hub/supabase-client.js +843 -0
  538. package/dist/hub/supabase-client.js.map +1 -0
  539. package/dist/observability/ask.d.ts +91 -0
  540. package/dist/observability/ask.js +179 -0
  541. package/dist/observability/ask.js.map +1 -0
  542. package/dist/observability/clickhouse.d.ts +33 -0
  543. package/dist/observability/clickhouse.js +48 -0
  544. package/dist/observability/clickhouse.js.map +1 -0
  545. package/dist/observability/decisions.d.ts +176 -0
  546. package/dist/observability/decisions.js +377 -0
  547. package/dist/observability/decisions.js.map +1 -0
  548. package/dist/observability/index.d.ts +89 -0
  549. package/dist/observability/index.js +348 -0
  550. package/dist/observability/index.js.map +1 -0
  551. package/dist/observability/insights.d.ts +151 -0
  552. package/dist/observability/insights.js +319 -0
  553. package/dist/observability/insights.js.map +1 -0
  554. package/dist/observability/logs-query.d.ts +82 -0
  555. package/dist/observability/logs-query.js +102 -0
  556. package/dist/observability/logs-query.js.map +1 -0
  557. package/dist/observability/logs.d.ts +72 -0
  558. package/dist/observability/logs.js +295 -0
  559. package/dist/observability/logs.js.map +1 -0
  560. package/dist/observability/metrics.d.ts +86 -0
  561. package/dist/observability/metrics.js +303 -0
  562. package/dist/observability/metrics.js.map +1 -0
  563. package/dist/observability/otlp.d.ts +127 -0
  564. package/dist/observability/otlp.js +242 -0
  565. package/dist/observability/otlp.js.map +1 -0
  566. package/dist/observability/snapshots.d.ts +43 -0
  567. package/dist/observability/snapshots.js +129 -0
  568. package/dist/observability/snapshots.js.map +1 -0
  569. package/dist/observability/triage.d.ts +49 -0
  570. package/dist/observability/triage.js +284 -0
  571. package/dist/observability/triage.js.map +1 -0
  572. package/dist/providers/adapter.d.ts +50 -0
  573. package/dist/providers/adapter.js +38 -0
  574. package/dist/providers/adapter.js.map +1 -0
  575. package/dist/providers/agent.d.ts +110 -0
  576. package/dist/providers/agent.js +487 -0
  577. package/dist/providers/agent.js.map +1 -0
  578. package/dist/providers/approvals.d.ts +24 -0
  579. package/dist/providers/approvals.js +78 -0
  580. package/dist/providers/approvals.js.map +1 -0
  581. package/dist/providers/attachments.d.ts +20 -0
  582. package/dist/providers/attachments.js +51 -0
  583. package/dist/providers/attachments.js.map +1 -0
  584. package/dist/providers/claude/adapter.d.ts +99 -0
  585. package/dist/providers/claude/adapter.js +790 -0
  586. package/dist/providers/claude/adapter.js.map +1 -0
  587. package/dist/providers/codex/adapter.d.ts +113 -0
  588. package/dist/providers/codex/adapter.js +881 -0
  589. package/dist/providers/codex/adapter.js.map +1 -0
  590. package/dist/providers/codex/instructions.d.ts +11 -0
  591. package/dist/providers/codex/instructions.js +154 -0
  592. package/dist/providers/codex/instructions.js.map +1 -0
  593. package/dist/providers/codex/rpc.d.ts +36 -0
  594. package/dist/providers/codex/rpc.js +104 -0
  595. package/dist/providers/codex/rpc.js.map +1 -0
  596. package/dist/providers/contracts.d.ts +339 -0
  597. package/dist/providers/contracts.js +19 -0
  598. package/dist/providers/contracts.js.map +1 -0
  599. package/dist/providers/directory.d.ts +70 -0
  600. package/dist/providers/directory.js +95 -0
  601. package/dist/providers/directory.js.map +1 -0
  602. package/dist/providers/errors.d.ts +47 -0
  603. package/dist/providers/errors.js +24 -0
  604. package/dist/providers/errors.js.map +1 -0
  605. package/dist/providers/index.d.ts +18 -0
  606. package/dist/providers/index.js +19 -0
  607. package/dist/providers/index.js.map +1 -0
  608. package/dist/providers/ingestion.d.ts +80 -0
  609. package/dist/providers/ingestion.js +330 -0
  610. package/dist/providers/ingestion.js.map +1 -0
  611. package/dist/providers/live.d.ts +22 -0
  612. package/dist/providers/live.js +56 -0
  613. package/dist/providers/live.js.map +1 -0
  614. package/dist/providers/process.d.ts +29 -0
  615. package/dist/providers/process.js +71 -0
  616. package/dist/providers/process.js.map +1 -0
  617. package/dist/providers/reaper.d.ts +33 -0
  618. package/dist/providers/reaper.js +65 -0
  619. package/dist/providers/reaper.js.map +1 -0
  620. package/dist/providers/service.d.ts +87 -0
  621. package/dist/providers/service.js +256 -0
  622. package/dist/providers/service.js.map +1 -0
  623. package/dist/sdk.d.ts +1 -1
  624. package/dist/sdk.js +1 -1
  625. package/dist/sdk.js.map +1 -1
  626. package/dist/types.d.ts +385 -6
  627. package/dist/types.js +1 -0
  628. package/dist/types.js.map +1 -1
  629. package/dist/version.d.ts +7 -0
  630. package/dist/version.js +16 -0
  631. package/dist/version.js.map +1 -0
  632. package/dist/web/app.css +4643 -0
  633. package/dist/web/app.js +22640 -0
  634. package/dist/web/app.js.map +7 -0
  635. package/dist/web/shell.html +39 -0
  636. package/docs/README.md +21 -0
  637. package/docs/SETUP.md +10 -0
  638. package/docs/adapters.md +21 -8
  639. package/docs/brain-continuity.md +186 -0
  640. package/docs/cloud.md +108 -0
  641. package/docs/crews.md +62 -0
  642. package/docs/design-system.md +31 -2
  643. package/docs/integration-notes.md +128 -20
  644. package/docs/loompad.md +105 -0
  645. package/docs/observability.md +220 -0
  646. package/docs/play-store.md +123 -0
  647. package/docs/proposals/agent-teams.md +249 -0
  648. package/docs/proposals/brain-continuity-implementation.md +468 -0
  649. package/docs/proposals/brain-session-continuity.md +623 -0
  650. package/docs/proposals/t3code-port.md +81 -0
  651. package/docs/proposals/t3code-reference.md +95 -0
  652. package/docs/refactoring/AGENT-TEAMS-PROGRESS.md +88 -0
  653. package/docs/refactoring/BOUNDARIES.md +120 -0
  654. package/docs/refactoring/BRAIN-AUDIT.md +176 -0
  655. package/docs/refactoring/BRAIN-NOTES.md +390 -0
  656. package/docs/refactoring/BRAIN-TODO.md +214 -0
  657. package/docs/refactoring/NOTES.md +129 -0
  658. package/docs/refactoring/T3-PORT-NOTES.md +165 -0
  659. package/docs/refactoring/T3-PORT-TODO.md +123 -0
  660. package/docs/refactoring/TODO.md +46 -0
  661. package/docs/refactoring/brain-benchmark-2026-09-28.json +48 -0
  662. package/docs/refactoring/brain-benchmark-audit-2026-09-28.json +48 -0
  663. package/docs/release-notes/v0.2.0.md +35 -0
  664. package/docs/release-notes/v0.2.1.md +59 -0
  665. package/docs/release-notes/v0.2.3.md +77 -0
  666. package/docs/release-notes/v0.2.4.md +128 -0
  667. package/docs/release-notes/v0.2.5.md +153 -0
  668. package/docs/release-notes/v0.2.6.md +62 -0
  669. package/docs/release-notes/v1.0.0.md +120 -0
  670. package/docs/release-notes/v1.0.1.md +77 -0
  671. package/docs/release-notes/v1.1.0.md +71 -0
  672. package/docs/release-notes/v1.1.1.md +38 -0
  673. package/docs/teams-architecture.md +697 -0
  674. package/docs/teams.md +171 -0
  675. package/docs/windows.md +85 -0
  676. package/package.json +22 -9
  677. package/dist/adapters/claude-code.d.ts +0 -26
  678. package/dist/adapters/claude-code.js +0 -209
  679. package/dist/adapters/claude-code.js.map +0 -1
  680. package/dist/adapters/codex.d.ts +0 -51
  681. package/dist/adapters/codex.js +0 -291
  682. package/dist/adapters/codex.js.map +0 -1
  683. package/docs/img/board-linear.png +0 -0
  684. package/docs/img/board-projects.png +0 -0
  685. package/docs/img/brain.png +0 -0
  686. package/docs/img/settings.png +0 -0
  687. package/docs/img/workspace.png +0 -0
@@ -0,0 +1,319 @@
1
+ /**
2
+ * Observatory insights, read back from the backend's ClickHouse store: the spans
3
+ * behind the Span Replay viewer and the Trace Waterfall, the per-agent burn-rate
4
+ * series, and a deterministic 0–100 Agent Health Score. All of it is derived from
5
+ * the same real gen_ai spans Loom exports — nothing here is synthetic.
6
+ *
7
+ * The scoring (`healthScore`) is a pure function so it is unit-tested without a
8
+ * live ClickHouse, and it is the same math the UI badges render.
9
+ */
10
+ import { SERVICE_NAME, SPAN_TABLE, chLiteral, chQuery } from "./clickhouse.js";
11
+ const SELECT = `
12
+ toString(trace_id) AS traceId, toString(span_id) AS spanId,
13
+ toUnixTimestamp64Milli(timestamp) AS ts, name,
14
+ round(duration_nano / 1e6) AS ms, status_code AS code, status_message AS msg,
15
+ attributes_string['gen_ai.agent.id'] AS agent,
16
+ attributes_string['gen_ai.system'] AS ade,
17
+ attributes_string['gen_ai.request.model'] AS model,
18
+ attributes_string['loom.handoff.from'] AS handoffFrom,
19
+ attributes_string['loom.handoff.to'] AS handoffTo,
20
+ toFloat64(attributes_number['gen_ai.usage.cost_usd']) AS cost,
21
+ toUInt32(attributes_number['gen_ai.usage.input_tokens']) AS tin,
22
+ toUInt32(attributes_number['gen_ai.usage.output_tokens']) AS tout`;
23
+ const SERVICE = `\`resource_string_service$$name\` = '${chLiteral(SERVICE_NAME)}'`;
24
+ function rowToSpan(r) {
25
+ return {
26
+ traceId: String(r.traceId ?? ""),
27
+ spanId: String(r.spanId ?? ""),
28
+ ts: Number(r.ts ?? 0),
29
+ name: String(r.name ?? ""),
30
+ ms: Number(r.ms ?? 0),
31
+ code: Number(r.code ?? 0),
32
+ msg: String(r.msg ?? ""),
33
+ agent: String(r.agent ?? ""),
34
+ ade: String(r.ade ?? ""),
35
+ model: String(r.model ?? ""),
36
+ tin: Number(r.tin ?? 0),
37
+ tout: Number(r.tout ?? 0),
38
+ cost: Number(r.cost ?? 0),
39
+ handoffFrom: String(r.handoffFrom ?? ""),
40
+ handoffTo: String(r.handoffTo ?? ""),
41
+ };
42
+ }
43
+ /** Recent spans for a project (optionally one agent), newest first. */
44
+ export async function fetchSpans(project, opts = {}) {
45
+ const proj = chLiteral(project);
46
+ const limit = Math.min(500, Math.max(1, opts.limit ?? 200));
47
+ const agentFilter = opts.agent ? `AND attributes_string['gen_ai.agent.id'] = '${chLiteral(opts.agent)}'` : "";
48
+ const sql = `SELECT ${SELECT} FROM ${SPAN_TABLE}
49
+ WHERE ${SERVICE} AND attributes_string['loom.project'] = '${proj}' ${agentFilter}
50
+ ORDER BY timestamp DESC LIMIT ${limit}`;
51
+ return (await chQuery(sql)).map(rowToSpan);
52
+ }
53
+ /** How many error spans an agent has emitted since `sinceMs` — the self-heal recheck signal. */
54
+ export async function recentAgentErrors(project, agent, sinceMs) {
55
+ const proj = chLiteral(project);
56
+ const a = chLiteral(agent);
57
+ const sinceSec = Math.floor(Math.max(0, sinceMs) / 1000);
58
+ const sql = `SELECT count() AS n FROM ${SPAN_TABLE}
59
+ WHERE ${SERVICE} AND attributes_string['loom.project'] = '${proj}'
60
+ AND attributes_string['gen_ai.agent.id'] = '${a}'
61
+ AND status_code = 2
62
+ AND timestamp >= toDateTime(${sinceSec})`;
63
+ const rows = await chQuery(sql);
64
+ return Number(rows[0]?.n ?? 0);
65
+ }
66
+ /** Every span in one trace, oldest first — the waterfall's rows. */
67
+ export async function traceSpans(traceId) {
68
+ const t = chLiteral(traceId);
69
+ if (!t)
70
+ return [];
71
+ const sql = `SELECT ${SELECT} FROM ${SPAN_TABLE}
72
+ WHERE ${SERVICE} AND trace_id = '${t}' ORDER BY timestamp ASC LIMIT 300`;
73
+ return (await chQuery(sql)).map(rowToSpan);
74
+ }
75
+ /**
76
+ * Fallback: derive InsightSpans from the local event log — the same data the
77
+ * backend gets — so the Observatory's replay/health/waterfall still work when
78
+ * ClickHouse is down or the agent hasn't exported anything yet.
79
+ */
80
+ export function insightSpansFromLog(events, agent) {
81
+ const out = [];
82
+ for (const e of events) {
83
+ const p = (e.payload ?? {});
84
+ const mine = e.agentId === agent || p.to === agent || p.from === agent;
85
+ if (agent && !mine)
86
+ continue;
87
+ const common = { traceId: "", spanId: String(e.id), ts: e.ts, ade: "", model: String(p.model ?? ""), handoffFrom: "", handoffTo: "" };
88
+ if (e.kind === "run_complete") {
89
+ out.push({ ...common, name: "gen_ai.agent.turn", ms: Number(p.durationMs ?? 0), code: p.error ? 2 : 1, msg: String(p.error ?? ""),
90
+ agent: e.agentId ?? "", tin: Number(p.inputTokens ?? 0), tout: Number(p.outputTokens ?? 0), cost: Number(p.costUsd ?? 0) });
91
+ }
92
+ else if (e.kind === "error") {
93
+ out.push({ ...common, name: "loom.error", ms: 0, code: 2, msg: String(p.message ?? "error"), agent: e.agentId ?? "", tin: 0, tout: 0, cost: 0 });
94
+ }
95
+ else if (e.kind === "handoff") {
96
+ out.push({ ...common, name: "loom.baton.handoff", ms: 0, code: 1, msg: `${p.from ?? "?"} -> ${p.to ?? "?"}`,
97
+ agent: e.agentId ?? "", tin: 0, tout: 0, cost: 0, handoffFrom: String(p.from ?? ""), handoffTo: String(p.to ?? "") });
98
+ }
99
+ }
100
+ return out.sort((a, b) => b.ts - a.ts);
101
+ }
102
+ /** Per-agent cost over time, bucketed — the burn-rate sparkline's data + a linear projection. */
103
+ export async function burnSeries(project, opts = {}) {
104
+ const proj = chLiteral(project);
105
+ const hours = Math.min(720, Math.max(1, opts.hours ?? 24));
106
+ const nBuckets = Math.min(60, Math.max(2, opts.buckets ?? 12));
107
+ const stepSec = Math.max(60, Math.round((hours * 3600) / nBuckets));
108
+ const sql = `SELECT
109
+ toUnixTimestamp(toStartOfInterval(timestamp, INTERVAL ${stepSec} SECOND)) AS bucket,
110
+ attributes_string['gen_ai.agent.id'] AS agent,
111
+ sum(toFloat64(attributes_number['gen_ai.usage.cost_usd'])) AS cost
112
+ FROM ${SPAN_TABLE}
113
+ WHERE ${SERVICE} AND attributes_string['loom.project'] = '${proj}'
114
+ AND name = 'gen_ai.agent.turn'
115
+ AND timestamp >= now() - INTERVAL ${hours} HOUR
116
+ GROUP BY bucket, agent ORDER BY bucket ASC`;
117
+ const rows = await chQuery(sql);
118
+ const map = new Map();
119
+ for (const r of rows) {
120
+ const t = Number(r.bucket ?? 0) * 1000;
121
+ const agent = String(r.agent ?? "unknown");
122
+ const cost = Number(r.cost ?? 0);
123
+ const b = map.get(t) ?? { t, byAgent: {}, total: 0 };
124
+ b.byAgent[agent] = (b.byAgent[agent] ?? 0) + cost;
125
+ b.total += cost;
126
+ map.set(t, b);
127
+ }
128
+ const buckets = [...map.values()].sort((a, b) => a.t - b.t);
129
+ const totalUsd = buckets.reduce((a, b) => a + b.total, 0);
130
+ const ratePerHour = totalUsd / hours;
131
+ return { hours, buckets, totalUsd, ratePerHour, projected24h: ratePerHour * 24 };
132
+ }
133
+ /* ------------------------------------------------------------------------- *
134
+ * Metrics read-back
135
+ *
136
+ * Loom exports loom.turns, loom.handoffs, loom.cost.usd, loom.agents.active,
137
+ * gen_ai.client.token.usage and a gen_ai.client.operation.duration histogram
138
+ * (observability/metrics.ts). Reading them back closes the loop: the same
139
+ * numbers the Observatory shows can be checked against what the backend stored.
140
+ *
141
+ * The backend splits a metric across two tables, confirmed by DESCRIBE on the
142
+ * live stack:
143
+ * distributed_time_series_v4 — one row per (fingerprint, hour) carrying the
144
+ * metadata and label maps: metric_name, type, unit, temporality, attrs
145
+ * (metric attributes), resource_attrs, labels (a JSON string).
146
+ * distributed_samples_v4 — the actual points: metric_name, fingerprint,
147
+ * unix_milli, value.
148
+ * `fingerprint` is the join key: it identifies one label set, i.e. one series.
149
+ * ------------------------------------------------------------------------- */
150
+ /**
151
+ * The metric tables the collector writes into. Defaults are that layout;
152
+ * both are overridable for a backend that stores its metrics elsewhere.
153
+ */
154
+ export const METRIC_SAMPLES_TABLE = process.env.LOOM_METRIC_SAMPLES_TABLE || "signoz_metrics.distributed_samples_v4";
155
+ export const METRIC_SERIES_TABLE = process.env.LOOM_METRIC_SERIES_TABLE || "signoz_metrics.distributed_time_series_v4";
156
+ /**
157
+ * A histogram does not exist under its own name in ClickHouse — the OTLP
158
+ * exporter fans it out into suffixed sums/gauges. Asking for
159
+ * "gen_ai.client.operation.duration" therefore has to expand to the real names,
160
+ * or the query silently returns nothing.
161
+ *
162
+ * `.bucket` is deliberately excluded: it is one series per histogram boundary
163
+ * (le="0.005", le="0.01", …), which is a dozen lines of noise on a chart and
164
+ * never what a caller asking for "the duration metric" means. A caller that
165
+ * genuinely wants buckets can name `...duration.bucket` explicitly, which the
166
+ * exact-name path below still honours.
167
+ */
168
+ const HISTOGRAM_SUFFIXES = ["sum", "count", "min", "max"];
169
+ /** Expand each requested name to itself plus its histogram parts, deduped. */
170
+ export function expandMetricNames(names) {
171
+ const out = new Set();
172
+ for (const raw of names) {
173
+ const n = chLiteral(String(raw ?? "").trim());
174
+ if (!n)
175
+ continue;
176
+ out.add(n);
177
+ // Suffixing a non-histogram name is harmless — nothing matches it.
178
+ if (!HISTOGRAM_SUFFIXES.some((s) => n.endsWith(`.${s}`)) && !n.endsWith(".bucket")) {
179
+ for (const s of HISTOGRAM_SUFFIXES)
180
+ out.add(`${n}.${s}`);
181
+ }
182
+ }
183
+ return [...out];
184
+ }
185
+ /** Drop the backend's internal label keys (`__name__`, `__temporality__`, …). */
186
+ function cleanLabels(v) {
187
+ const out = {};
188
+ if (v && typeof v === "object") {
189
+ for (const [k, val] of Object.entries(v)) {
190
+ if (k.startsWith("__"))
191
+ continue;
192
+ out[k] = String(val ?? "");
193
+ }
194
+ }
195
+ return out;
196
+ }
197
+ /**
198
+ * Build the SQL for a metric series query — split out so the join, the project
199
+ * filter and the bucketing are testable without a live ClickHouse.
200
+ *
201
+ * Note what the inner subquery does *not* do: filter time_series_v4 by
202
+ * unix_milli. That column is floored to the hour there, so a naive
203
+ * `>= sinceMs` would drop the metadata row for a series whose hour started
204
+ * before the window and take the whole series with it. The metric_name +
205
+ * project filters already narrow it to a handful of fingerprints, so the time
206
+ * filter belongs on the samples side only, where it is exact.
207
+ *
208
+ * The GROUP BY inside the subquery collapses the one-row-per-hour duplication;
209
+ * without it the join would multiply every sample by the number of hours the
210
+ * series has existed.
211
+ */
212
+ export function buildMetricQuery(names, opts) {
213
+ const proj = chLiteral(opts.project ?? "");
214
+ const step = Math.max(1000, Math.round(opts.stepMs ?? 60_000));
215
+ const since = Math.max(0, Math.round(opts.sinceMs ?? Date.now() - 6 * 3600_000));
216
+ const list = expandMetricNames(names)
217
+ .map((n) => `'${n}'`)
218
+ .join(", ");
219
+ return `SELECT
220
+ any(s.s_metric) AS metric, any(s.s_type) AS type, any(s.s_unit) AS unit,
221
+ any(s.s_temporality) AS temporality, any(s.s_attrs) AS labels,
222
+ toString(sm.fingerprint) AS fingerprint,
223
+ intDiv(sm.unix_milli, ${step}) * ${step} AS t,
224
+ sum(sm.value) AS vsum, avg(sm.value) AS vavg, max(sm.value) AS vmax, count() AS n
225
+ FROM ${METRIC_SAMPLES_TABLE} AS sm
226
+ INNER JOIN (
227
+ SELECT fingerprint,
228
+ any(metric_name) AS s_metric, any(type) AS s_type, any(unit) AS s_unit,
229
+ any(temporality) AS s_temporality, any(attrs) AS s_attrs
230
+ FROM ${METRIC_SERIES_TABLE}
231
+ WHERE metric_name IN (${list})
232
+ AND resource_attrs['service.name'] = '${chLiteral(SERVICE_NAME)}'
233
+ AND attrs['loom.project'] = '${proj}'
234
+ GROUP BY fingerprint
235
+ ) AS s ON s.fingerprint = sm.fingerprint
236
+ WHERE sm.metric_name IN (${list}) AND sm.unix_milli >= ${since}
237
+ GROUP BY fingerprint, t
238
+ ORDER BY metric ASC, fingerprint ASC, t ASC`;
239
+ }
240
+ /** Fold the flat (series, bucket) rows into one entry per series, points ordered. */
241
+ export function rowsToSeries(rows) {
242
+ const byFp = new Map();
243
+ for (const r of rows) {
244
+ const fp = String(r.fingerprint ?? "");
245
+ const type = String(r.type ?? "");
246
+ let s = byFp.get(fp);
247
+ if (!s) {
248
+ s = {
249
+ metric: String(r.metric ?? ""),
250
+ type,
251
+ unit: String(r.unit ?? ""),
252
+ temporality: String(r.temporality ?? ""),
253
+ labels: cleanLabels(r.labels),
254
+ fingerprint: fp,
255
+ prefer: type === "Gauge" ? "avg" : "sum",
256
+ points: [],
257
+ };
258
+ byFp.set(fp, s);
259
+ }
260
+ s.points.push({
261
+ t: Number(r.t ?? 0),
262
+ sum: Number(r.vsum ?? 0),
263
+ avg: Number(r.vavg ?? 0),
264
+ max: Number(r.vmax ?? 0),
265
+ n: Number(r.n ?? 0),
266
+ });
267
+ }
268
+ for (const s of byFp.values())
269
+ s.points.sort((a, b) => a.t - b.t);
270
+ return [...byFp.values()].sort((a, b) => a.metric.localeCompare(b.metric) || a.fingerprint.localeCompare(b.fingerprint));
271
+ }
272
+ /**
273
+ * Read named metrics back for one project, one entry per distinct label set.
274
+ * Throws if ClickHouse is unreachable — like logs, there is no local substitute
275
+ * for a metric the backend never received, and the route reports that honestly.
276
+ */
277
+ export async function fetchMetricSeries(names, opts) {
278
+ if (!expandMetricNames(names).length)
279
+ return [];
280
+ return rowsToSeries(await chQuery(buildMetricQuery(names, opts)));
281
+ }
282
+ /** The metrics Loom actually emits — the default set when a caller names none. */
283
+ export const LOOM_METRIC_NAMES = [
284
+ "loom.turns",
285
+ "loom.handoffs",
286
+ "loom.cost.usd",
287
+ "loom.agents.active",
288
+ "gen_ai.client.token.usage",
289
+ "gen_ai.client.operation.duration",
290
+ ];
291
+ const isErr = (s) => s.code === 2 || s.name === "loom.error" || s.name === "loom.route.failed";
292
+ /**
293
+ * A deterministic 0–100 health score from an agent's own spans. Four penalty
294
+ * buckets subtract from 100:
295
+ * errorRate (≤40) — share of spans that errored
296
+ * latency (≤25) — share of turns slower than 30s
297
+ * tokenBloat(≤20) — average input tokens above an 80k comfort line
298
+ * recency (≤15) — how recently the last error fired (fades over 30 min)
299
+ * Pure: same input, same score — this is what the UI badge shows.
300
+ */
301
+ export function healthScore(spans, now = Date.now()) {
302
+ const turns = spans.filter((s) => s.name === "gen_ai.agent.turn");
303
+ const errs = spans.filter(isErr).sort((a, b) => b.ts - a.ts);
304
+ const nTurns = turns.length;
305
+ const errorRate = spans.length ? Math.round((errs.length / spans.length) * 40) : 0;
306
+ const slow = turns.filter((t) => t.ms > 30_000).length;
307
+ const latency = nTurns ? Math.round(Math.min(1, slow / nTurns) * 25) : 0;
308
+ const avgIn = nTurns ? turns.reduce((a, t) => a + t.tin, 0) / nTurns : 0;
309
+ const tokenBloat = Math.round(Math.min(1, Math.max(0, (avgIn - 80_000) / 120_000)) * 20);
310
+ let recency = 0;
311
+ if (errs[0]) {
312
+ const ageMin = (now - errs[0].ts) / 60_000;
313
+ recency = Math.round(Math.max(0, 1 - ageMin / 30) * 15);
314
+ }
315
+ const score = Math.max(0, Math.min(100, 100 - errorRate - latency - tokenBloat - recency));
316
+ const grade = score >= 80 ? "healthy" : score >= 50 ? "degraded" : "unhealthy";
317
+ return { score, grade, turns: nTurns, errorCount: errs.length, buckets: { errorRate, latency, tokenBloat, recency } };
318
+ }
319
+ //# sourceMappingURL=insights.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insights.js","sourceRoot":"","sources":["../../src/observability/insights.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Reading Loom's own logs back out of the telemetry backend.
3
+ *
4
+ * Loom already *emits* structured logs over OTLP (see observability/logs.ts).
5
+ * This is the other half: the query that lets the Observatory show an agent what
6
+ * it actually said, correlated to the span it said it in.
7
+ *
8
+ * Two things make this different from the span read-back in insights.ts:
9
+ *
10
+ * 1. There is NO local fallback. Spans have one — `insightSpansFromLog` derives
11
+ * equivalent spans from the event log, because a span is a summary of an
12
+ * event Loom already has on disk. A log line is not: severity, body and the
13
+ * trace/span correlation only exist once the log record has been built and
14
+ * shipped. Reconstructing something log-shaped from the event log would be
15
+ * inventing data, so when ClickHouse is unreachable the caller reports
16
+ * `from: "unavailable"` and the UI says so plainly.
17
+ *
18
+ * 2. The identity filter is doubled up. `resources_string['service.name']`
19
+ * pins us to Loom (rather than any other service shipping to the same
20
+ * backend), and `attributes_string['loom.project']` pins us to one project.
21
+ * Confirmed against the live table: Loom sets loom.project as a *record*
22
+ * attribute, not a resource attribute, so it lands in attributes_string —
23
+ * one daemon's logs would otherwise leak into another project's view.
24
+ */
25
+ /**
26
+ * The log store. Columns confirmed with DESCRIBE against a live 25.12 instance.
27
+ * As with the span table, this is the layout the collector writes into and is
28
+ * overridable for a backend that stores its logs elsewhere.
29
+ */
30
+ export declare const LOG_TABLE: string;
31
+ /**
32
+ * A log line, normalised for the UI.
33
+ *
34
+ * `ts` is milliseconds (the column is UInt64 *nanoseconds*, hence the intDiv).
35
+ * `traceId`/`spanId` are already lowercase hex Strings in v2 — no unhex/hex
36
+ * dance like the trace tables need — and are empty strings when the record was
37
+ * emitted outside a span, which is normal for status lines.
38
+ */
39
+ export type InsightLog = {
40
+ ts: number;
41
+ severity: string;
42
+ /** OTel severity_number (1–24). Kept so the UI can sort/threshold without parsing text. */
43
+ severityNumber: number;
44
+ body: string;
45
+ traceId: string;
46
+ spanId: string;
47
+ agent: string;
48
+ /** loom.event.kind — which event produced the line (run_complete, status, message, ...). */
49
+ kind: string;
50
+ /** loom.chat — the conversation the line belongs to. */
51
+ chat: string;
52
+ };
53
+ export type FetchLogsOpts = {
54
+ project: string;
55
+ agent?: string;
56
+ /** One or more severity_text values, comma-separated and case-insensitive ("error,warn"). */
57
+ severity?: string;
58
+ /** Pin to a single trace — the log side of the Trace Waterfall. */
59
+ traceId?: string;
60
+ /** Case-insensitive substring match on the body. */
61
+ search?: string;
62
+ limit?: number;
63
+ };
64
+ /**
65
+ * Build the SQL for a log query. Split out from the fetch so the WHERE clause —
66
+ * where a missing project filter would be a real leak — is unit-testable without
67
+ * a live ClickHouse.
68
+ *
69
+ * Every interpolated value goes through `chLiteral`, which strips anything
70
+ * outside `[\w.\-:/ ]`. That is deliberately blunt: it also removes `%` and `_`,
71
+ * so a search term can never turn into a LIKE wildcard, and quotes can never
72
+ * escape the literal. The cost is that punctuation in a search term is dropped
73
+ * rather than matched, which for substring search over log bodies is a fine
74
+ * trade.
75
+ */
76
+ export declare function buildLogsQuery(opts: FetchLogsOpts): string;
77
+ /**
78
+ * Recent log lines for one project, newest first. Throws if ClickHouse is
79
+ * unreachable — the caller turns that into `from: "unavailable"` rather than
80
+ * substituting anything made up.
81
+ */
82
+ export declare function fetchLogs(opts: FetchLogsOpts): Promise<InsightLog[]>;
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Reading Loom's own logs back out of the telemetry backend.
3
+ *
4
+ * Loom already *emits* structured logs over OTLP (see observability/logs.ts).
5
+ * This is the other half: the query that lets the Observatory show an agent what
6
+ * it actually said, correlated to the span it said it in.
7
+ *
8
+ * Two things make this different from the span read-back in insights.ts:
9
+ *
10
+ * 1. There is NO local fallback. Spans have one — `insightSpansFromLog` derives
11
+ * equivalent spans from the event log, because a span is a summary of an
12
+ * event Loom already has on disk. A log line is not: severity, body and the
13
+ * trace/span correlation only exist once the log record has been built and
14
+ * shipped. Reconstructing something log-shaped from the event log would be
15
+ * inventing data, so when ClickHouse is unreachable the caller reports
16
+ * `from: "unavailable"` and the UI says so plainly.
17
+ *
18
+ * 2. The identity filter is doubled up. `resources_string['service.name']`
19
+ * pins us to Loom (rather than any other service shipping to the same
20
+ * backend), and `attributes_string['loom.project']` pins us to one project.
21
+ * Confirmed against the live table: Loom sets loom.project as a *record*
22
+ * attribute, not a resource attribute, so it lands in attributes_string —
23
+ * one daemon's logs would otherwise leak into another project's view.
24
+ */
25
+ import { SERVICE_NAME, chLiteral, chQuery } from "./clickhouse.js";
26
+ /**
27
+ * The log store. Columns confirmed with DESCRIBE against a live 25.12 instance.
28
+ * As with the span table, this is the layout the collector writes into and is
29
+ * overridable for a backend that stores its logs elsewhere.
30
+ */
31
+ export const LOG_TABLE = process.env.LOOM_LOG_TABLE || "signoz_logs.distributed_logs_v2";
32
+ const SELECT = `
33
+ intDiv(timestamp, 1000000) AS ts,
34
+ severity_text AS severity,
35
+ toUInt16(severity_number) AS severityNumber,
36
+ body,
37
+ trace_id AS traceId,
38
+ span_id AS spanId,
39
+ attributes_string['gen_ai.agent.id'] AS agent,
40
+ attributes_string['loom.event.kind'] AS kind,
41
+ attributes_string['loom.chat'] AS chat`;
42
+ /** Same shape as insights.ts's SERVICE guard, but logs keep resource attrs in a Map. */
43
+ const SERVICE = `resources_string['service.name'] = '${chLiteral(SERVICE_NAME)}'`;
44
+ function rowToLog(r) {
45
+ return {
46
+ ts: Number(r.ts ?? 0),
47
+ severity: String(r.severity ?? ""),
48
+ severityNumber: Number(r.severityNumber ?? 0),
49
+ body: String(r.body ?? ""),
50
+ traceId: String(r.traceId ?? ""),
51
+ spanId: String(r.spanId ?? ""),
52
+ agent: String(r.agent ?? ""),
53
+ kind: String(r.kind ?? ""),
54
+ chat: String(r.chat ?? ""),
55
+ };
56
+ }
57
+ /**
58
+ * Build the SQL for a log query. Split out from the fetch so the WHERE clause —
59
+ * where a missing project filter would be a real leak — is unit-testable without
60
+ * a live ClickHouse.
61
+ *
62
+ * Every interpolated value goes through `chLiteral`, which strips anything
63
+ * outside `[\w.\-:/ ]`. That is deliberately blunt: it also removes `%` and `_`,
64
+ * so a search term can never turn into a LIKE wildcard, and quotes can never
65
+ * escape the literal. The cost is that punctuation in a search term is dropped
66
+ * rather than matched, which for substring search over log bodies is a fine
67
+ * trade.
68
+ */
69
+ export function buildLogsQuery(opts) {
70
+ const proj = chLiteral(opts.project ?? "");
71
+ const limit = Math.min(1000, Math.max(1, opts.limit ?? 200));
72
+ const where = [SERVICE, `attributes_string['loom.project'] = '${proj}'`];
73
+ if (opts.agent)
74
+ where.push(`attributes_string['gen_ai.agent.id'] = '${chLiteral(opts.agent)}'`);
75
+ if (opts.traceId)
76
+ where.push(`trace_id = '${chLiteral(opts.traceId)}'`);
77
+ // severity_text is LowCardinality(String) and Loom writes it upper-case, but
78
+ // callers type "error". Compare upper-cased on both sides so either works.
79
+ const sevs = (opts.severity ?? "")
80
+ .split(",")
81
+ .map((s) => chLiteral(s.trim()).toUpperCase())
82
+ .filter(Boolean);
83
+ if (sevs.length)
84
+ where.push(`upper(severity_text) IN (${sevs.map((s) => `'${s}'`).join(", ")})`);
85
+ // positionCaseInsensitive rather than ILIKE: no wildcard semantics to smuggle
86
+ // in, and it reads as "contains" which is what the search box promises.
87
+ const q = chLiteral((opts.search ?? "").trim());
88
+ if (q)
89
+ where.push(`positionCaseInsensitive(body, '${q}') > 0`);
90
+ return `SELECT ${SELECT} FROM ${LOG_TABLE}
91
+ WHERE ${where.join("\n AND ")}
92
+ ORDER BY timestamp DESC LIMIT ${limit}`;
93
+ }
94
+ /**
95
+ * Recent log lines for one project, newest first. Throws if ClickHouse is
96
+ * unreachable — the caller turns that into `from: "unavailable"` rather than
97
+ * substituting anything made up.
98
+ */
99
+ export async function fetchLogs(opts) {
100
+ return (await chQuery(buildLogsQuery(opts))).map(rowToLog);
101
+ }
102
+ //# sourceMappingURL=logs-query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs-query.js","sourceRoot":"","sources":["../../src/observability/logs-query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Loom → OpenTelemetry logs (OTLP/HTTP JSON, `/v1/logs`).
3
+ *
4
+ * Loom already has a log: the LoomEvent stream is the source of truth for the
5
+ * whole product. This ships it. Every agent message, tool call, file edit,
6
+ * decision, route step, budget pause and error becomes one OTLP log record with
7
+ * the same `service.name` as the spans, and — when the event happened inside a
8
+ * turn — the same `traceId`/`spanId`.
9
+ *
10
+ * That last part is the whole point. Without trace correlation this is just a
11
+ * second copy of the event log in a different database. With it, a slow turn
12
+ * in the trace view gets a "related logs" tab showing what the agent actually
13
+ * said and did while it was slow, and a log line has a link back to the span
14
+ * that produced it. Traces tell you a turn took 40s; logs tell you why.
15
+ *
16
+ * Same contract as the other two exporters: buffered, best-effort, never throws
17
+ * into the agent loop. Off with LOOM_OTEL_LOGS=0 (or any consent opt-out).
18
+ */
19
+ import type { LoomEvent } from "../types.js";
20
+ import { type AttrValue, type TelemetryConfig } from "./otlp.js";
21
+ /**
22
+ * OTLP SeverityNumber. The spec's named levels; we use four of them.
23
+ *
24
+ * Mapped honestly, which mostly means resisting the urge to inflate. An agent
25
+ * saying something is INFO, not DEBUG — it is the primary content of the
26
+ * product. A turn that failed is ERROR. Something a human needs to look at but
27
+ * that isn't a failure (blocked on input, over budget, a suggested handoff) is
28
+ * WARN. Adapter lifecycle chatter is DEBUG. Nothing is FATAL: Loom survives
29
+ * every event it logs, and a severity nobody can act on is noise with a red
30
+ * icon.
31
+ */
32
+ export declare const SEVERITY: {
33
+ readonly DEBUG: 5;
34
+ readonly INFO: 9;
35
+ readonly WARN: 13;
36
+ readonly ERROR: 17;
37
+ };
38
+ export type LogRecordInput = {
39
+ timeUnixNano: bigint;
40
+ severityNumber: number;
41
+ body: string;
42
+ attributes: Record<string, AttrValue>;
43
+ traceId?: string;
44
+ spanId?: string;
45
+ };
46
+ /**
47
+ * A LoomEvent → the log record it should produce, or null for kinds that carry
48
+ * nothing a human would read.
49
+ *
50
+ * Pure, and exported so the mapping (and especially the severity mapping) is
51
+ * testable without a collector — same arrangement as `eventToSpan`.
52
+ */
53
+ export declare function eventToLogRecord(event: LoomEvent, ctx?: {
54
+ project?: string;
55
+ }): LogRecordInput | null;
56
+ /** Cut an over-long body and say by how much, rather than lying about length. */
57
+ export declare function truncate(body: string, max?: number): string;
58
+ /** Buffered OTLP log exporter. Mirrors LoomTelemetry's batching exactly. */
59
+ export declare class LoomLogs {
60
+ private readonly cfg;
61
+ private buffer;
62
+ private timer;
63
+ private readonly logsUrl;
64
+ private readonly resource;
65
+ constructor(cfg: TelemetryConfig);
66
+ get enabled(): boolean;
67
+ /** Buffer one record. No-op when logs are disabled. */
68
+ log(input: LogRecordInput): void;
69
+ private ensureTimer;
70
+ private drain;
71
+ flush(): void;
72
+ }