@k2b/cloud 0.6.0-rc.0

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 (540) hide show
  1. package/README.md +98 -0
  2. package/package.json +128 -0
  3. package/public/logo.svg +1 -0
  4. package/scripts/app-favicon.test.ts +49 -0
  5. package/scripts/app-favicon.ts +51 -0
  6. package/scripts/build.ts +205 -0
  7. package/scripts/preload.ts +164 -0
  8. package/scripts/sync-recovery-smoke.ts +200 -0
  9. package/src/_internal/app-favicon.ts +2 -0
  10. package/src/_internal/app-presentation.ts +61 -0
  11. package/src/_internal/app-workspace-state.ts +24 -0
  12. package/src/_internal/bounded-json.ts +47 -0
  13. package/src/_internal/build-metadata.ts +9 -0
  14. package/src/_internal/capabilities.ts +1118 -0
  15. package/src/_internal/define-app.ts +801 -0
  16. package/src/_internal/heartbeat.ts +167 -0
  17. package/src/_internal/help-catalog.ts +241 -0
  18. package/src/_internal/help.ts +95 -0
  19. package/src/_internal/nats-connection.ts +34 -0
  20. package/src/_internal/page-responses.ts +40 -0
  21. package/src/_internal/process-sync.ts +117 -0
  22. package/src/_internal/readiness.ts +3 -0
  23. package/src/_internal/registry-validation.ts +136 -0
  24. package/src/_internal/registry-watch.ts +52 -0
  25. package/src/_internal/registry.ts +338 -0
  26. package/src/_internal/runtime-compatibility.ts +64 -0
  27. package/src/_internal/runtime-context.ts +84 -0
  28. package/src/_internal/runtime-watcher.ts +78 -0
  29. package/src/_internal/static-assets.ts +86 -0
  30. package/src/_internal/status-preserving-ssr.ts +49 -0
  31. package/src/access/PermissionEditor.tsx +486 -0
  32. package/src/access/ResourceApiKeys.tsx +271 -0
  33. package/src/access/messages.ts +121 -0
  34. package/src/access/ui.ts +16 -0
  35. package/src/account/Avatar.tsx +28 -0
  36. package/src/account/EntitySearch.tsx +363 -0
  37. package/src/account/avatar-upload-dialog.tsx +197 -0
  38. package/src/account/avatar-upload.ts +149 -0
  39. package/src/account/ui.ts +3 -0
  40. package/src/ai/admin.ts +47 -0
  41. package/src/ai/approval-routes.ts +130 -0
  42. package/src/ai/approvals.ts +139 -0
  43. package/src/ai/assistant-models.ts +61 -0
  44. package/src/ai/attachments.ts +40 -0
  45. package/src/ai/browser.ts +92 -0
  46. package/src/ai/capabilities.ts +714 -0
  47. package/src/ai/capability-execution.ts +151 -0
  48. package/src/ai/chat/blocks.render.test.tsx +1108 -0
  49. package/src/ai/chat/blocks.tsx +730 -0
  50. package/src/ai/chat/builtin-tools.tsx +428 -0
  51. package/src/ai/chat/capability-table.tsx +87 -0
  52. package/src/ai/chat/composer-adapter.ts +169 -0
  53. package/src/ai/chat/file-tools.tsx +81 -0
  54. package/src/ai/chat/message-actions.tsx +370 -0
  55. package/src/ai/chat/message-utils.ts +479 -0
  56. package/src/ai/chat/messages.ts +43 -0
  57. package/src/ai/chat/presentation.tsx +395 -0
  58. package/src/ai/chat/primitives.tsx +3 -0
  59. package/src/ai/chat/tool-disclosure.tsx +41 -0
  60. package/src/ai/chat/turn-navigator-utils.ts +28 -0
  61. package/src/ai/chat/turn-navigator.tsx +164 -0
  62. package/src/ai/chat/user-message.tsx +149 -0
  63. package/src/ai/chat/visual-tools.tsx +435 -0
  64. package/src/ai/chat/web-tools.tsx +202 -0
  65. package/src/ai/chat-task-contracts.ts +113 -0
  66. package/src/ai/chat-tasks.ts +952 -0
  67. package/src/ai/client/controller.ts +1211 -0
  68. package/src/ai/client/file-source.ts +95 -0
  69. package/src/ai/client/live-connection.ts +140 -0
  70. package/src/ai/client/projection.ts +178 -0
  71. package/src/ai/client/transport.ts +111 -0
  72. package/src/ai/compaction.ts +182 -0
  73. package/src/ai/credentials.ts +124 -0
  74. package/src/ai/default-tool-contracts.ts +108 -0
  75. package/src/ai/default-tools.ts +127 -0
  76. package/src/ai/enrich.ts +280 -0
  77. package/src/ai/executor.ts +1624 -0
  78. package/src/ai/fetch-file-tool.ts +313 -0
  79. package/src/ai/file-context.ts +92 -0
  80. package/src/ai/file-media-type.ts +28 -0
  81. package/src/ai/file-mount.ts +16 -0
  82. package/src/ai/file-tools.ts +566 -0
  83. package/src/ai/files-store.ts +390 -0
  84. package/src/ai/firecrawl-tools.ts +305 -0
  85. package/src/ai/grids-skill.ts +126 -0
  86. package/src/ai/http.ts +265 -0
  87. package/src/ai/index.ts +337 -0
  88. package/src/ai/kit-skill.ts +22 -0
  89. package/src/ai/limits.ts +5 -0
  90. package/src/ai/live-events.ts +289 -0
  91. package/src/ai/live-messages.ts +45 -0
  92. package/src/ai/live-outbox.ts +102 -0
  93. package/src/ai/live-routes.ts +412 -0
  94. package/src/ai/live.ts +2 -0
  95. package/src/ai/maintenance.ts +302 -0
  96. package/src/ai/markdown-pdf-tool.ts +95 -0
  97. package/src/ai/memories.ts +605 -0
  98. package/src/ai/memory-learning-runs.ts +222 -0
  99. package/src/ai/memory-learning.ts +619 -0
  100. package/src/ai/memory-tool.ts +120 -0
  101. package/src/ai/memory-workflow-evidence.ts +158 -0
  102. package/src/ai/migrate.ts +2082 -0
  103. package/src/ai/model-access-migrate.ts +30 -0
  104. package/src/ai/model-access.ts +191 -0
  105. package/src/ai/personal-agent.ts +6 -0
  106. package/src/ai/prefs.ts +72 -0
  107. package/src/ai/project-tool.ts +94 -0
  108. package/src/ai/projects-routes.ts +277 -0
  109. package/src/ai/projects.ts +902 -0
  110. package/src/ai/protocol.ts +279 -0
  111. package/src/ai/provider.ts +73 -0
  112. package/src/ai/public-projection.ts +25 -0
  113. package/src/ai/resource-markers.ts +31 -0
  114. package/src/ai/resource-refs.ts +70 -0
  115. package/src/ai/routes.ts +1131 -0
  116. package/src/ai/runtime-tools.ts +39 -0
  117. package/src/ai/runtime.ts +544 -0
  118. package/src/ai/settings.ts +529 -0
  119. package/src/ai/short-id.ts +45 -0
  120. package/src/ai/skill-catalog.ts +73 -0
  121. package/src/ai/skill-format.ts +145 -0
  122. package/src/ai/skill-seeds.ts +430 -0
  123. package/src/ai/skill-tool.ts +81 -0
  124. package/src/ai/skills-routes.ts +143 -0
  125. package/src/ai/skills.ts +934 -0
  126. package/src/ai/solid.ts +27 -0
  127. package/src/ai/store.ts +3113 -0
  128. package/src/ai/stream.ts +308 -0
  129. package/src/ai/structured-runs.ts +66 -0
  130. package/src/ai/structured.ts +186 -0
  131. package/src/ai/system-prompt.ts +170 -0
  132. package/src/ai/task-prompt.ts +22 -0
  133. package/src/ai/timeline.ts +148 -0
  134. package/src/ai/tool-audit.ts +177 -0
  135. package/src/ai/tool-result-budget.ts +16 -0
  136. package/src/ai/tools.ts +155 -0
  137. package/src/ai/types.ts +967 -0
  138. package/src/ai/ui.tsx +39 -0
  139. package/src/ai/usage-migrate.ts +81 -0
  140. package/src/ai/usage.ts +315 -0
  141. package/src/ai/validate.ts +54 -0
  142. package/src/ai/vision-tool.ts +79 -0
  143. package/src/api/accounts-entities.ts +174 -0
  144. package/src/api/admin-ai-projects.ts +74 -0
  145. package/src/api/admin-ai-skills.ts +76 -0
  146. package/src/api/admin-ai-usage.ts +42 -0
  147. package/src/api/admin-core-settings.ts +508 -0
  148. package/src/api/admin-identity.ts +148 -0
  149. package/src/api/admin-lifecycle.ts +206 -0
  150. package/src/api/admin-linux-identities.ts +66 -0
  151. package/src/api/announcements.ts +131 -0
  152. package/src/api/app-approval.ts +129 -0
  153. package/src/api/apps.ts +51 -0
  154. package/src/api/auth/schemas.ts +54 -0
  155. package/src/api/auth.ts +370 -0
  156. package/src/api/capabilities.ts +658 -0
  157. package/src/api/help-messages.ts +19 -0
  158. package/src/api/help.ts +78 -0
  159. package/src/api/index.ts +108 -0
  160. package/src/api/mcp.ts +744 -0
  161. package/src/api/me-rail.ts +45 -0
  162. package/src/api/me.ts +753 -0
  163. package/src/api/search/schemas.ts +79 -0
  164. package/src/api/search.bench.ts +185 -0
  165. package/src/api/search.ts +407 -0
  166. package/src/api/sync-ops.ts +79 -0
  167. package/src/api/widgets.ts +143 -0
  168. package/src/browser/CloudResourceSearch.behavior.test.tsx +74 -0
  169. package/src/browser/CloudResourceSearch.tsx +791 -0
  170. package/src/browser/app-approval-vault.ts +305 -0
  171. package/src/browser/app-approval.ts +234 -0
  172. package/src/browser/live-websocket.ts +268 -0
  173. package/src/browser/locale-preference.ts +25 -0
  174. package/src/browser/notification-target.ts +27 -0
  175. package/src/browser/notification-timeout.ts +14 -0
  176. package/src/browser/notifications.ts +181 -0
  177. package/src/browser/resource-clipboard.ts +70 -0
  178. package/src/browser/resource-picker.tsx +39 -0
  179. package/src/browser/resource-search-messages.ts +55 -0
  180. package/src/browser/resource-search.ts +27 -0
  181. package/src/capabilities/client.ts +149 -0
  182. package/src/capabilities/response.ts +39 -0
  183. package/src/capabilities/server.ts +215 -0
  184. package/src/capabilities/signals.ts +4 -0
  185. package/src/capabilities/testing.ts +12 -0
  186. package/src/capabilities/types.ts +32 -0
  187. package/src/cli/access.ts +499 -0
  188. package/src/cli/account.ts +382 -0
  189. package/src/cli/admin/account-administration.ts +45 -0
  190. package/src/cli/admin/account-categories.ts +49 -0
  191. package/src/cli/admin/ai-usage.ts +118 -0
  192. package/src/cli/admin/app-sign-in.ts +49 -0
  193. package/src/cli/admin/data.ts +343 -0
  194. package/src/cli/admin/documentation.ts +34 -0
  195. package/src/cli/admin/gateway.ts +155 -0
  196. package/src/cli/admin/index.ts +61 -0
  197. package/src/cli/admin/instance.ts +250 -0
  198. package/src/cli/admin/jobs.ts +223 -0
  199. package/src/cli/admin/legal.ts +122 -0
  200. package/src/cli/admin/linux.ts +53 -0
  201. package/src/cli/admin/logs.ts +324 -0
  202. package/src/cli/admin/metrics.ts +142 -0
  203. package/src/cli/admin/nats.ts +167 -0
  204. package/src/cli/admin/notifications.ts +516 -0
  205. package/src/cli/admin/shared.ts +113 -0
  206. package/src/cli/admin/sync.ts +188 -0
  207. package/src/cli/admin/telemetry.ts +314 -0
  208. package/src/cli/admin/webhooks.ts +222 -0
  209. package/src/cli/admin/workflows.ts +367 -0
  210. package/src/cli/apps.ts +40 -0
  211. package/src/cli/capabilities.ts +239 -0
  212. package/src/cli/commands.ts +604 -0
  213. package/src/cli/index.ts +61 -0
  214. package/src/cli/locale.ts +31 -0
  215. package/src/cli/output.ts +58 -0
  216. package/src/clients/core.ts +20 -0
  217. package/src/config/env.ts +54 -0
  218. package/src/config/index.ts +6 -0
  219. package/src/contracts/account-categories.ts +62 -0
  220. package/src/contracts/announcements.ts +121 -0
  221. package/src/contracts/app-approval.ts +197 -0
  222. package/src/contracts/app.ts +162 -0
  223. package/src/contracts/capabilities.ts +484 -0
  224. package/src/contracts/index.ts +14 -0
  225. package/src/contracts/notification-live.ts +66 -0
  226. package/src/contracts/notification-types.ts +235 -0
  227. package/src/contracts/posix.ts +69 -0
  228. package/src/contracts/profile.ts +85 -0
  229. package/src/contracts/rail-preferences.ts +53 -0
  230. package/src/contracts/registry.ts +110 -0
  231. package/src/contracts/resource-clipboard.ts +33 -0
  232. package/src/contracts/settings-types.ts +98 -0
  233. package/src/contracts/shared.ts +408 -0
  234. package/src/contracts/user-notifications.ts +101 -0
  235. package/src/contracts/widgets.ts +183 -0
  236. package/src/desktop/index.ts +704 -0
  237. package/src/desktop/solid.tsx +938 -0
  238. package/src/index.ts +58 -0
  239. package/src/server/actor.ts +41 -0
  240. package/src/server/api/index.ts +2 -0
  241. package/src/server/api/respond.ts +96 -0
  242. package/src/server/api-client.ts +54 -0
  243. package/src/server/app-context.ts +39 -0
  244. package/src/server/help.ts +187 -0
  245. package/src/server/index.ts +89 -0
  246. package/src/server/locale.ts +55 -0
  247. package/src/server/middleware/auth.ts +386 -0
  248. package/src/server/middleware/index.ts +28 -0
  249. package/src/server/middleware/invocation.ts +55 -0
  250. package/src/server/middleware/middleware.ts +65 -0
  251. package/src/server/middleware/openapi.ts +126 -0
  252. package/src/server/middleware/rate-limit.ts +125 -0
  253. package/src/server/middleware/request-logger.ts +41 -0
  254. package/src/server/middleware/route-template.ts +46 -0
  255. package/src/server/middleware/runtime.ts +22 -0
  256. package/src/server/middleware/settings.ts +55 -0
  257. package/src/server/middleware/validator.ts +49 -0
  258. package/src/server/middleware/workload.ts +22 -0
  259. package/src/server/ratelimit.ts +151 -0
  260. package/src/server/request-cookies.ts +18 -0
  261. package/src/server/services/access.ts +644 -0
  262. package/src/server/services/freeipa/client.ts +137 -0
  263. package/src/server/services/freeipa/index.ts +9 -0
  264. package/src/server/services/freeipa/session.ts +123 -0
  265. package/src/server/services/freeipa/test-certificates.ts +44 -0
  266. package/src/server/services/freeipa/tls.ts +44 -0
  267. package/src/server/services/freeipa/transport.ts +116 -0
  268. package/src/server/services/freeipa/util.ts +59 -0
  269. package/src/server/services/geo.ts +198 -0
  270. package/src/server/services/index.ts +48 -0
  271. package/src/server/services/pagination.ts +22 -0
  272. package/src/server/services/services.ts +13 -0
  273. package/src/server/time.ts +33 -0
  274. package/src/services/account-category-policy.ts +51 -0
  275. package/src/services/account-lifecycle/audit.ts +41 -0
  276. package/src/services/account-lifecycle/index.ts +940 -0
  277. package/src/services/account-lifecycle/ipa-backfill.ts +152 -0
  278. package/src/services/account-lifecycle/notification-sender.ts +13 -0
  279. package/src/services/account-lifecycle/scheduler.ts +506 -0
  280. package/src/services/account-model.ts +22 -0
  281. package/src/services/accounts/app.ts +1671 -0
  282. package/src/services/accounts/authz.ts +44 -0
  283. package/src/services/accounts/avatar.ts +120 -0
  284. package/src/services/accounts/base-group.ts +11 -0
  285. package/src/services/accounts/base-user.ts +46 -0
  286. package/src/services/accounts/duplicate-emails.ts +82 -0
  287. package/src/services/accounts/entities.ts +622 -0
  288. package/src/services/accounts/group-sql.ts +106 -0
  289. package/src/services/accounts/groups.ts +272 -0
  290. package/src/services/accounts/index.ts +14 -0
  291. package/src/services/accounts/ipa-data.ts +66 -0
  292. package/src/services/accounts/lifecycle.ts +2 -0
  293. package/src/services/accounts/local-groups.ts +499 -0
  294. package/src/services/accounts/model.ts +129 -0
  295. package/src/services/accounts/notification-sender.ts +31 -0
  296. package/src/services/accounts/posix.ts +386 -0
  297. package/src/services/accounts/request-policy.ts +11 -0
  298. package/src/services/accounts/switching.ts +126 -0
  299. package/src/services/accounts/users.ts +745 -0
  300. package/src/services/announcements/index.ts +224 -0
  301. package/src/services/app-approval.ts +498 -0
  302. package/src/services/audit/index.ts +438 -0
  303. package/src/services/auth-flows/index.ts +15 -0
  304. package/src/services/auth-flows/ipa.ts +197 -0
  305. package/src/services/auth-flows/magic-link.ts +185 -0
  306. package/src/services/auth-flows/notification-sender.ts +10 -0
  307. package/src/services/auth-flows/password-reset.ts +268 -0
  308. package/src/services/auth-flows/proxy-return.ts +49 -0
  309. package/src/services/document-extraction.ts +148 -0
  310. package/src/services/freeipa-config.ts +179 -0
  311. package/src/services/gateway.ts +186 -0
  312. package/src/services/identity/constants.ts +18 -0
  313. package/src/services/identity/index.ts +52 -0
  314. package/src/services/identity/invocation-actor.ts +120 -0
  315. package/src/services/identity/invocation-authority.ts +53 -0
  316. package/src/services/identity/invocation-operations.ts +15 -0
  317. package/src/services/identity/invocation-token.ts +276 -0
  318. package/src/services/identity/key-config.ts +41 -0
  319. package/src/services/identity/key-ring.ts +530 -0
  320. package/src/services/identity/metrics.ts +29 -0
  321. package/src/services/identity/routes.ts +18 -0
  322. package/src/services/identity/runtime-config.ts +88 -0
  323. package/src/services/identity/session-token.ts +152 -0
  324. package/src/services/identity/signer-refresh.ts +44 -0
  325. package/src/services/identity/workload-auth.ts +64 -0
  326. package/src/services/index.ts +187 -0
  327. package/src/services/ipa/auth.ts +216 -0
  328. package/src/services/ipa/connection.ts +57 -0
  329. package/src/services/ipa/effective-groups.ts +70 -0
  330. package/src/services/ipa/groups.ts +722 -0
  331. package/src/services/ipa/guard.ts +17 -0
  332. package/src/services/ipa/index.ts +17 -0
  333. package/src/services/ipa/posix.ts +19 -0
  334. package/src/services/ipa/profile.ts +132 -0
  335. package/src/services/ipa/runtime.ts +28 -0
  336. package/src/services/ipa/search.ts +154 -0
  337. package/src/services/ipa/service-account.ts +15 -0
  338. package/src/services/ipa/sync-planning.ts +100 -0
  339. package/src/services/ipa/sync.ts +862 -0
  340. package/src/services/ipa/users.ts +806 -0
  341. package/src/services/legal-consent.ts +76 -0
  342. package/src/services/logging/index.ts +477 -0
  343. package/src/services/logging/redaction.ts +20 -0
  344. package/src/services/logging/trace.ts +1231 -0
  345. package/src/services/mandates/index.ts +855 -0
  346. package/src/services/mandates/policy.ts +85 -0
  347. package/src/services/network-security.ts +31 -0
  348. package/src/services/notifications/batches.ts +722 -0
  349. package/src/services/notifications/browser.ts +252 -0
  350. package/src/services/notifications/catalog.ts +113 -0
  351. package/src/services/notifications/channels.ts +104 -0
  352. package/src/services/notifications/dispatcher.ts +139 -0
  353. package/src/services/notifications/email.ts +118 -0
  354. package/src/services/notifications/index.ts +633 -0
  355. package/src/services/notifications/live.ts +50 -0
  356. package/src/services/notifications/observability.ts +407 -0
  357. package/src/services/notifications/platform.ts +421 -0
  358. package/src/services/notifications/runtime.ts +120 -0
  359. package/src/services/notifications/user.ts +248 -0
  360. package/src/services/notifications/web-push-transport.ts +135 -0
  361. package/src/services/oauth-tokens.ts +209 -0
  362. package/src/services/outbox.ts +187 -0
  363. package/src/services/pdf/gotenberg.ts +290 -0
  364. package/src/services/pdf/index.ts +43 -0
  365. package/src/services/pdf/markdown.ts +209 -0
  366. package/src/services/pdf/template-preview.ts +122 -0
  367. package/src/services/postgres.ts +76 -0
  368. package/src/services/providers/index.ts +27 -0
  369. package/src/services/providers/local/auth.ts +51 -0
  370. package/src/services/providers/local/index.ts +4 -0
  371. package/src/services/providers/local/users.ts +263 -0
  372. package/src/services/rail-preferences.ts +27 -0
  373. package/src/services/runtime-lifecycle.ts +191 -0
  374. package/src/services/secrets.ts +10 -0
  375. package/src/services/service-account-credentials.ts +891 -0
  376. package/src/services/service-accounts.ts +184 -0
  377. package/src/services/session/index.ts +236 -0
  378. package/src/services/session/test-fixture.ts +18 -0
  379. package/src/services/session/user.ts +144 -0
  380. package/src/services/settings/api.ts +61 -0
  381. package/src/services/settings/app.ts +86 -0
  382. package/src/services/settings/core-settings.ts +796 -0
  383. package/src/services/settings/crypto.ts +69 -0
  384. package/src/services/settings/defaults.ts +374 -0
  385. package/src/services/settings/index.ts +215 -0
  386. package/src/services/settings/namespace.ts +9 -0
  387. package/src/services/settings/snapshot.ts +49 -0
  388. package/src/services/settings/store.ts +241 -0
  389. package/src/services/settings/templates.ts +4 -0
  390. package/src/services/sync-ops.ts +403 -0
  391. package/src/services/topic-cursor.ts +22 -0
  392. package/src/services/weather/forecast.ts +323 -0
  393. package/src/services/weather/geo.ts +119 -0
  394. package/src/services/weather/index.ts +67 -0
  395. package/src/services/weather/location.ts +24 -0
  396. package/src/services/weather/locations.ts +133 -0
  397. package/src/services/weather/migrate.ts +45 -0
  398. package/src/services/weather/settings.ts +66 -0
  399. package/src/services/weather/short-id.ts +57 -0
  400. package/src/services/weather/types.ts +61 -0
  401. package/src/services/weather/ui.ts +50 -0
  402. package/src/services/webauthn.ts +385 -0
  403. package/src/shared/account-action-notice.ts +70 -0
  404. package/src/shared/account-display.ts +15 -0
  405. package/src/shared/account-session.ts +15 -0
  406. package/src/shared/ai-platform-prompt.ts +134 -0
  407. package/src/shared/ai-usage.ts +49 -0
  408. package/src/shared/app-presentation.ts +48 -0
  409. package/src/shared/app-url.ts +12 -0
  410. package/src/shared/branding.ts +14 -0
  411. package/src/shared/capability-messages.ts +70 -0
  412. package/src/shared/email-html.ts +54 -0
  413. package/src/shared/format.ts +91 -0
  414. package/src/shared/help.ts +68 -0
  415. package/src/shared/icons.ts +400 -0
  416. package/src/shared/index.ts +54 -0
  417. package/src/shared/locale.ts +48 -0
  418. package/src/shared/login-method.ts +44 -0
  419. package/src/shared/markdown/client.ts +130 -0
  420. package/src/shared/markdown/extensions/code.ts +105 -0
  421. package/src/shared/markdown/extensions/guided-help.ts +100 -0
  422. package/src/shared/markdown/extensions/images.ts +79 -0
  423. package/src/shared/markdown/extensions/info-blocks.ts +97 -0
  424. package/src/shared/markdown/extensions/katex.ts +120 -0
  425. package/src/shared/markdown/extensions/links.ts +43 -0
  426. package/src/shared/markdown/extensions/mark.ts +48 -0
  427. package/src/shared/markdown/extensions/sub-sup.ts +60 -0
  428. package/src/shared/markdown/extensions/tables.ts +109 -0
  429. package/src/shared/markdown/extensions/task-list.ts +53 -0
  430. package/src/shared/markdown/formula.ts +1187 -0
  431. package/src/shared/markdown/index.ts +193 -0
  432. package/src/shared/markdown/shared.ts +36 -0
  433. package/src/shared/mock-cover.ts +130 -0
  434. package/src/shared/network-address.ts +106 -0
  435. package/src/shared/redirect.ts +56 -0
  436. package/src/shared/template-rendering.ts +140 -0
  437. package/src/shared/theme.ts +68 -0
  438. package/src/shared/time.ts +13 -0
  439. package/src/ssr/AdminLayout.tsx +53 -0
  440. package/src/ssr/AdminSidebar.tsx +50 -0
  441. package/src/ssr/AppLaunchpad.island.tsx +236 -0
  442. package/src/ssr/AppWorkspaceController.island.tsx +21 -0
  443. package/src/ssr/BrowserNotifications.island.tsx +135 -0
  444. package/src/ssr/GlobalAnnouncements.island.tsx +142 -0
  445. package/src/ssr/GlobalSearchDialog.behavior.test.tsx +96 -0
  446. package/src/ssr/GlobalSearchDialog.tsx +35 -0
  447. package/src/ssr/GlobalSearchHelpDialog.tsx +104 -0
  448. package/src/ssr/GlobalSearchTrigger.island.tsx +55 -0
  449. package/src/ssr/HotkeysHelpRail.island.tsx +55 -0
  450. package/src/ssr/Layout.render.test.tsx +148 -0
  451. package/src/ssr/Layout.tsx +292 -0
  452. package/src/ssr/LayoutBreadcrumbs.island.tsx +44 -0
  453. package/src/ssr/LayoutFooter.tsx +22 -0
  454. package/src/ssr/LayoutHeader.tsx +81 -0
  455. package/src/ssr/LayoutHelp.tsx +869 -0
  456. package/src/ssr/LayoutPreferences.island.tsx +36 -0
  457. package/src/ssr/LayoutRail.tsx +58 -0
  458. package/src/ssr/MinimalLayout.tsx +46 -0
  459. package/src/ssr/PageError.tsx +29 -0
  460. package/src/ssr/ProfilePreferences.island.tsx +92 -0
  461. package/src/ssr/RailApps.island.tsx +61 -0
  462. package/src/ssr/RailEditor.tsx +293 -0
  463. package/src/ssr/RegisteredHelpDocuments.island.tsx +3 -0
  464. package/src/ssr/TimezoneCookie.island.tsx +23 -0
  465. package/src/ssr/admin-active-link.ts +47 -0
  466. package/src/ssr/admin-navigation.ts +78 -0
  467. package/src/ssr/app-appearance.ts +23 -0
  468. package/src/ssr/app-navigation.ts +41 -0
  469. package/src/ssr/help-messages.ts +104 -0
  470. package/src/ssr/index.ts +14 -0
  471. package/src/ssr/islands/SearchBar.island.tsx +80 -0
  472. package/src/ssr/islands/index.ts +16 -0
  473. package/src/ssr/layout-context.ts +17 -0
  474. package/src/ssr/layout-help-markdown.ts +9 -0
  475. package/src/ssr/layout-help-navigation.ts +24 -0
  476. package/src/ssr/layout-help-url.ts +5 -0
  477. package/src/ssr/layout-runtime.ts +22 -0
  478. package/src/ssr/page-error-messages.ts +25 -0
  479. package/src/ssr/platform-messages.ts +135 -0
  480. package/src/ssr/preference-controller.ts +44 -0
  481. package/src/ssr/profile-preferences-messages.ts +29 -0
  482. package/src/ssr/rail-context.ts +21 -0
  483. package/src/ssr/rail-messages.ts +66 -0
  484. package/src/ssr/rail-navigation.ts +60 -0
  485. package/src/ssr/runtime.ts +31 -0
  486. package/src/ssr/url-filter.ts +127 -0
  487. package/src/styles/base-popover.css +36 -0
  488. package/src/styles/effects.css +851 -0
  489. package/src/styles/global.css +268 -0
  490. package/src/styles/input.css +58 -0
  491. package/src/styles/tokens.css +230 -0
  492. package/src/styles/utilities-buttons.css +405 -0
  493. package/src/styles/utilities-data.css +33 -0
  494. package/src/styles/utilities-feedback.css +232 -0
  495. package/src/styles/utilities-layout.css +603 -0
  496. package/src/styles/utilities-markdown-editor.css +525 -0
  497. package/src/styles/utilities-markdown-table.css +234 -0
  498. package/src/styles/utilities-navigation.css +1054 -0
  499. package/src/types/ambient.d.ts +24 -0
  500. package/src/workflows/ai/index.ts +17 -0
  501. package/src/workflows/ai/runtime.ts +286 -0
  502. package/src/workflows/ai/store.ts +314 -0
  503. package/src/workflows/ai/types.ts +111 -0
  504. package/src/workflows/ai-actions.ts +269 -0
  505. package/src/workflows/authoring.ts +88 -0
  506. package/src/workflows/builtins.ts +193 -0
  507. package/src/workflows/contracts.ts +280 -0
  508. package/src/workflows/definition.ts +334 -0
  509. package/src/workflows/editor.ts +113 -0
  510. package/src/workflows/index.ts +71 -0
  511. package/src/workflows/language/binder.ts +45 -0
  512. package/src/workflows/language/canonical.ts +29 -0
  513. package/src/workflows/language/compiler.ts +396 -0
  514. package/src/workflows/language/expressions.ts +34 -0
  515. package/src/workflows/language/index.ts +20 -0
  516. package/src/workflows/language/references.ts +55 -0
  517. package/src/workflows/language/schema.ts +134 -0
  518. package/src/workflows/language/strict-yaml.ts +131 -0
  519. package/src/workflows/manifest.ts +24 -0
  520. package/src/workflows/module.ts +12 -0
  521. package/src/workflows/runtime/coordinator.ts +115 -0
  522. package/src/workflows/runtime/executor.ts +1003 -0
  523. package/src/workflows/runtime/index.ts +60 -0
  524. package/src/workflows/runtime/instant.ts +8 -0
  525. package/src/workflows/runtime/ports.ts +213 -0
  526. package/src/workflows/runtime/schedule.ts +203 -0
  527. package/src/workflows/runtime/trigger.ts +37 -0
  528. package/src/workflows/runtime/wake.ts +13 -0
  529. package/src/workflows/store/actions.ts +438 -0
  530. package/src/workflows/store/budget.ts +145 -0
  531. package/src/workflows/store/definitions.ts +345 -0
  532. package/src/workflows/store/events.ts +383 -0
  533. package/src/workflows/store/index.ts +107 -0
  534. package/src/workflows/store/observability.ts +594 -0
  535. package/src/workflows/store/runs.ts +975 -0
  536. package/src/workflows/store/transaction.ts +23 -0
  537. package/src/workflows/store/worker.ts +439 -0
  538. package/src/workflows/testing/conformance.ts +72 -0
  539. package/src/workflows/testing/index.ts +11 -0
  540. package/src/workflows/testing/process-fixtures.ts +275 -0
@@ -0,0 +1,188 @@
1
+ /** Admin access to application-owned Sync diagnostics and recovery. */
2
+ import type { SyncDeadLetterEntry, SyncDeadLetterKind, SyncDeadLetterStoreView, SyncScheduleView } from "../../services/sync-ops";
3
+ import { arg, command, confirmFlag, flag, type CloudCliContext } from "../index";
4
+ import { apiGet, apiJson, printJsonOrTable, queryString } from "./shared";
5
+
6
+ export type SyncOverview = {
7
+ sampledAt: string;
8
+ apps: { appId: string; appName: string; status: string; error: string | null; health: { state: string; connection: string } | null }[];
9
+ resources: { appId: string; appName: string; kind: string; id: string; state: string; deadLetters: number | null; error?: string }[];
10
+ deadLetters: (SyncDeadLetterEntry & { appId: string; store: string; kind: SyncDeadLetterKind })[];
11
+ truncatedStores: string[];
12
+ schedules: (SyncScheduleView & { appId: string; appName: string })[];
13
+ };
14
+ const filters = {
15
+ app: flag.string({ description: "App ID" }),
16
+ resource: flag.string({ description: "Resource ID filter" }),
17
+ problems: flag.boolean({ description: "Only resources and apps needing attention" }),
18
+ };
19
+ const storeArgs = { app: arg.required(), kind: arg.required({ description: "queue, job, or topic" }), store: arg.required() };
20
+ const entryArgs = { ...storeArgs, message: arg.required() };
21
+ const storePath = (args: { app: string; kind: string; store: string }) => {
22
+ if (!["queue", "job", "topic"].includes(args.kind)) throw new Error("kind must be queue, job, or topic.");
23
+ return `/api/gateway/sync/dead-letters/${encodeURIComponent(args.app)}/${args.kind}/${encodeURIComponent(args.store)}`;
24
+ };
25
+ const scheduleArgs = { app: arg.required(), scheduler: arg.required(), id: arg.required() };
26
+ const schedulePath = (args: { app: string; scheduler: string; id: string }) =>
27
+ `/api/gateway/sync/schedules/${encodeURIComponent(args.app)}/${encodeURIComponent(args.scheduler)}/${encodeURIComponent(args.id)}`;
28
+ const outputRows = <T extends Record<string, unknown>>(
29
+ ctx: CloudCliContext,
30
+ raw: unknown,
31
+ rows: T[],
32
+ keys: (keyof T & string)[],
33
+ metadata: Record<string, unknown>,
34
+ ) => {
35
+ if (ctx.options.output === "jsonl") {
36
+ ctx.jsonLine({ type: "snapshot", ...metadata });
37
+ for (const row of rows) ctx.jsonLine({ type: "entry", ...row });
38
+ } else
39
+ printJsonOrTable(
40
+ ctx,
41
+ raw,
42
+ rows,
43
+ keys.map((key) => ({ key })),
44
+ );
45
+ };
46
+
47
+ export const syncCommands = [
48
+ command("sync status", {
49
+ summary: "Read a current Sync snapshot across registered apps",
50
+ flags: filters,
51
+ run: async ({ ctx, flags }) => {
52
+ const result = await apiGet<SyncOverview>(ctx, `/api/gateway/sync${queryString(flags)}`);
53
+ outputRows(
54
+ ctx,
55
+ result,
56
+ result.apps.map((app) => ({
57
+ app: app.appId,
58
+ status: app.status,
59
+ runtime: app.health?.state ?? "unknown",
60
+ connection: app.health?.connection ?? "unknown",
61
+ error: app.error,
62
+ })),
63
+ ["app", "status", "runtime", "connection", "error"],
64
+ { sampledAt: result.sampledAt, apps: result.apps, truncatedStores: result.truncatedStores },
65
+ );
66
+ },
67
+ }),
68
+ command("sync resources list", {
69
+ summary: "List Sync resource declarations and failures",
70
+ flags: filters,
71
+ run: async ({ ctx, flags }) => {
72
+ const result = await apiGet<SyncOverview>(ctx, `/api/gateway/sync${queryString(flags)}`);
73
+ outputRows(
74
+ ctx,
75
+ { sampledAt: result.sampledAt, apps: result.apps, items: result.resources },
76
+ result.resources,
77
+ ["appId", "kind", "id", "state", "deadLetters", "error"],
78
+ { sampledAt: result.sampledAt, apps: result.apps },
79
+ );
80
+ },
81
+ }),
82
+ command("sync dead-letters list", {
83
+ summary: "Page through one store, oldest retained failures first",
84
+ args: storeArgs,
85
+ flags: {
86
+ cursor: flag.string({ description: "Opaque nextCursor from the previous page" }),
87
+ limit: flag.int({ default: 20, min: 1, max: 100 }),
88
+ },
89
+ run: async ({ ctx, args, flags }) => {
90
+ const result = await apiGet<{ store: SyncDeadLetterStoreView; nextCursor: string | null; sampledAt: string }>(
91
+ ctx,
92
+ `${storePath(args)}${queryString(flags)}`,
93
+ );
94
+ outputRows(ctx, result, result.store.entries, ["messageId", "streamSequence", "tenantId", "attempts", "failedAt", "reason"], {
95
+ sampledAt: result.sampledAt,
96
+ store: result.store.name,
97
+ truncated: result.store.truncated,
98
+ nextCursor: result.nextCursor,
99
+ });
100
+ if (ctx.options.output === "text" && result.nextCursor) ctx.print(`Next cursor: ${result.nextCursor}`);
101
+ },
102
+ }),
103
+ command("sync dead-letters get", {
104
+ summary: "Inspect a failure and its bounded payload preview",
105
+ args: entryArgs,
106
+ flags: { sequence: flag.int({ min: 1, description: "streamSequence from the queue/job list entry" }) },
107
+ run: async ({ ctx, args, flags }) => {
108
+ const result = await apiGet<{ entry: SyncDeadLetterEntry; sampledAt: string }>(
109
+ ctx,
110
+ `${storePath(args)}/${encodeURIComponent(args.message)}${queryString(flags)}`,
111
+ );
112
+ if (ctx.options.output === "jsonl") ctx.jsonLine(result);
113
+ else ctx.json(result);
114
+ },
115
+ }),
116
+ command("sync dead-letters requeue", {
117
+ summary: "Requeue a queue/job failure with a new idempotency key",
118
+ args: entryArgs,
119
+ flags: { yes: confirmFlag() },
120
+ run: async ({ ctx, args, flags }) => {
121
+ if (!flags.yes) throw new Error("Requeue requires --yes.");
122
+ if (args.kind === "topic") throw new Error("Topic failures require sync dead-letters replay with consumer and tenant.");
123
+ ctx.json(await apiJson(ctx, "POST", `${storePath(args)}/requeue`, { messageId: args.message }));
124
+ },
125
+ }),
126
+ command("sync dead-letters replay", {
127
+ summary: "Replay a topic failure through its original consumer",
128
+ args: { app: arg.required(), store: arg.required(), message: arg.required() },
129
+ flags: { consumer: flag.string({ required: true }), tenant: flag.string({ required: true }), yes: confirmFlag() },
130
+ run: async ({ ctx, args, flags }) => {
131
+ if (!flags.yes) throw new Error("Replay requires --yes.");
132
+ ctx.json(
133
+ await apiJson(ctx, "POST", `${storePath({ ...args, kind: "topic" })}/replay`, {
134
+ messageId: args.message,
135
+ consumer: flags.consumer,
136
+ tenantId: flags.tenant,
137
+ }),
138
+ );
139
+ },
140
+ }),
141
+ command("sync dead-letters delete", {
142
+ summary: "Permanently remove a dead letter",
143
+ args: entryArgs,
144
+ flags: { yes: confirmFlag() },
145
+ run: async ({ ctx, args, flags }) => {
146
+ if (!flags.yes) throw new Error("Deletion requires --yes.");
147
+ ctx.json(await apiJson(ctx, "DELETE", `${storePath(args)}/${encodeURIComponent(args.message)}`));
148
+ },
149
+ }),
150
+ command("sync schedules list", {
151
+ summary: "List schedules, handler availability and last completion",
152
+ flags: filters,
153
+ run: async ({ ctx, flags }) => {
154
+ const result = await apiGet<SyncOverview>(ctx, `/api/gateway/sync${queryString(flags)}`);
155
+ outputRows(
156
+ ctx,
157
+ { sampledAt: result.sampledAt, apps: result.apps, items: result.schedules },
158
+ result.schedules,
159
+ ["appId", "schedulerId", "id", "nextRunAt", "handlerAvailable", "lastCompletedAt", "lastRunId", "lastError"],
160
+ { sampledAt: result.sampledAt, apps: result.apps },
161
+ );
162
+ },
163
+ }),
164
+ command("sync schedules run", {
165
+ summary: "Accept a manual run; use runs get to inspect completion",
166
+ args: scheduleArgs,
167
+ flags: {
168
+ requestId: flag.string({
169
+ name: "request-id",
170
+ required: true,
171
+ description: "Stable idempotency ID; reuse after an uncertain response",
172
+ }),
173
+ yes: confirmFlag(),
174
+ },
175
+ run: async ({ ctx, args, flags }) => {
176
+ if (!flags.yes) throw new Error("Running a schedule requires --yes.");
177
+ ctx.json(await apiJson(ctx, "POST", `${schedulePath(args)}/run-now`, { requestId: flags.requestId }));
178
+ },
179
+ }),
180
+ command("sync schedules runs get", {
181
+ summary: "Read one run result; incomplete means still pending",
182
+ args: { ...scheduleArgs, run: arg.required() },
183
+ flags: { timeoutMs: flag.int({ name: "timeout-ms", default: 0, min: 0, max: 30000 }) },
184
+ run: async ({ ctx, args, flags }) => {
185
+ ctx.json(await apiGet(ctx, `${schedulePath(args)}/runs/${encodeURIComponent(args.run)}${queryString(flags)}`));
186
+ },
187
+ }),
188
+ ];
@@ -0,0 +1,314 @@
1
+ /**
2
+ * HTTP request telemetry: aggregate health, per-route rankings, and drilldown
3
+ * into individual requests.
4
+ */
5
+ import { arg, command, flag, paginationFlags } from "../index";
6
+ import { getLogs } from "./logs";
7
+ import { apiGet, formatMs, pageQuery, printJsonOrTable, queryString, safeCollect } from "./shared";
8
+
9
+ export type TelemetryEvent = {
10
+ id: number;
11
+ appId: string;
12
+ routePrefix: string;
13
+ method: string;
14
+ status: number;
15
+ durationMs: number;
16
+ errorKind: string | null;
17
+ occurredAt: string;
18
+ };
19
+
20
+ const telemetryLegacyCommands = [
21
+ command("telemetry summary", {
22
+ summary: "Show gateway telemetry summary",
23
+ flags: { hours: flag.int({ default: 24, min: 1, max: 24 * 31, description: "Lookback window in hours" }) },
24
+ run: async ({ ctx, flags }) => {
25
+ const result = await apiGet<Record<string, number | null>>(
26
+ ctx,
27
+ `/api/gateway/telemetry/summary${queryString({ hours: flags.hours })}`,
28
+ );
29
+ const rows = [result as Record<string, unknown>];
30
+ printJsonOrTable(ctx, result, rows, [
31
+ { key: "requests" },
32
+ { key: "errors" },
33
+ { key: "slowRequests" },
34
+ { key: "avgDurationMs", value: (row) => formatMs(row.avgDurationMs as number | null) },
35
+ { key: "p95DurationMs", value: (row) => formatMs(row.p95DurationMs as number | null) },
36
+ ]);
37
+ },
38
+ }),
39
+ command("telemetry events", {
40
+ summary: "List request telemetry events",
41
+ flags: {
42
+ search: flag.string({ aliases: ["q"], description: "Search app, route, method, or error" }),
43
+ app: flag.string({ description: "App id filter" }),
44
+ route: flag.string({ description: "Route prefix filter" }),
45
+ hours: flag.int({ default: 24, min: 1, max: 24 * 31, description: "Lookback window in hours" }),
46
+ slow: flag.boolean({ description: "Only slow requests" }),
47
+ errors: flag.boolean({ description: "Only error requests" }),
48
+ ...paginationFlags({ defaultPerPage: 100, maxPerPage: 200 }),
49
+ },
50
+ run: async ({ ctx, flags }) => {
51
+ const result = await apiGet<{ items: TelemetryEvent[]; total: number }>(
52
+ ctx,
53
+ `/api/gateway/telemetry/events${queryString({
54
+ search: flags.search,
55
+ app: flags.app,
56
+ route: flags.route,
57
+ hours: flags.hours,
58
+ slow: flags.slow ? "1" : undefined,
59
+ errors: flags.errors ? "1" : undefined,
60
+ ...pageQuery(flags),
61
+ })}`,
62
+ );
63
+ const rows = result.items.map((event) => ({
64
+ time: event.occurredAt,
65
+ app: event.appId,
66
+ route: event.routePrefix,
67
+ method: event.method,
68
+ status: event.status,
69
+ duration: formatMs(event.durationMs),
70
+ error: event.errorKind ?? "",
71
+ }));
72
+ printJsonOrTable(ctx, result, rows, [
73
+ { key: "time" },
74
+ { key: "app" },
75
+ { key: "route" },
76
+ { key: "method" },
77
+ { key: "status" },
78
+ { key: "duration" },
79
+ { key: "error" },
80
+ ]);
81
+ },
82
+ }),
83
+ command("telemetry apps", {
84
+ summary: "List apps with telemetry in the lookback window",
85
+ flags: { hours: flag.int({ default: 24, min: 1, max: 24 * 31, description: "Lookback window in hours" }) },
86
+ run: async ({ ctx, flags }) => {
87
+ const result = await apiGet<{ items: string[] }>(ctx, `/api/gateway/telemetry/apps${queryString({ hours: flags.hours })}`);
88
+ printJsonOrTable(
89
+ ctx,
90
+ result,
91
+ result.items.map((app) => ({ app })),
92
+ [{ key: "app" }],
93
+ );
94
+ },
95
+ }),
96
+ ];
97
+
98
+ // ─── Route analysis ──────────────────────────────────────────────────────────
99
+ // Aggregate-first: `routes` answers "what is broken" or "what is busy" in a
100
+ // single call, which is the question worth asking before paging through
101
+ // individual requests. Backed by minute rollups, so a 30d window is cheap.
102
+
103
+ export type TelemetryRouteRow = {
104
+ appId: string;
105
+ route: string;
106
+ requests: number;
107
+ errors: number;
108
+ slowRequests: number;
109
+ avgDurationMs: number | null;
110
+ maxDurationMs: number | null;
111
+ };
112
+
113
+ export type TelemetryOverview = {
114
+ requests: number;
115
+ serverErrors: number;
116
+ clientErrors: number;
117
+ rateLimited: number;
118
+ slowRequests: number;
119
+ avgDurationMs: number | null;
120
+ maxDurationMs: number | null;
121
+ };
122
+
123
+ export const TELEMETRY_RANGES = ["1h", "6h", "24h", "7d", "30d"] as const;
124
+ export const TELEMETRY_SORTS = ["errorRate", "errors", "requests", "slow", "duration"] as const;
125
+
126
+ export const errorRate = (errors: number, requests: number): string =>
127
+ requests === 0 ? "-" : `${((errors / requests) * 100).toFixed(1)}%`;
128
+
129
+ export const routeRows = (items: TelemetryRouteRow[]) =>
130
+ items.map((row) => ({
131
+ route: row.route,
132
+ app: row.appId,
133
+ requests: row.requests,
134
+ errors: row.errors,
135
+ errorRate: errorRate(row.errors, row.requests),
136
+ slow: row.slowRequests,
137
+ avgMs: formatMs(row.avgDurationMs),
138
+ maxMs: formatMs(row.maxDurationMs),
139
+ }));
140
+
141
+ export const rangeFlag = () => flag.enum(TELEMETRY_RANGES, { default: "24h", description: "Time window: 1h, 6h, 24h, 7d, or 30d" });
142
+
143
+ export const telemetryAnalysisCommands = [
144
+ command("telemetry overview", {
145
+ summary: "Show request volume split by error class",
146
+ description:
147
+ "Rollup-backed counts for the selected window. Server errors (5xx), client errors (4xx) and rate limits (429) are counted separately, because a rate-limited caller and a broken endpoint need different responses.",
148
+ examples: ["cld admin telemetry overview --range 24h --json", "cld admin telemetry overview --range 7d --app grids"],
149
+ flags: {
150
+ range: rangeFlag(),
151
+ app: flag.string({ description: "Restrict to one app id" }),
152
+ route: flag.string({ description: "Restrict to one route template" }),
153
+ },
154
+ run: async ({ ctx, flags }) => {
155
+ const raw = await apiGet<TelemetryOverview>(
156
+ ctx,
157
+ `/api/gateway/telemetry/overview${queryString({ range: flags.range, app: flags.app, route: flags.route })}`,
158
+ );
159
+ printJsonOrTable(
160
+ ctx,
161
+ raw,
162
+ [
163
+ {
164
+ requests: raw.requests,
165
+ serverErrors: raw.serverErrors,
166
+ clientErrors: raw.clientErrors,
167
+ rateLimited: raw.rateLimited,
168
+ slow: raw.slowRequests,
169
+ avgMs: formatMs(raw.avgDurationMs),
170
+ maxMs: formatMs(raw.maxDurationMs),
171
+ },
172
+ ],
173
+ [
174
+ { key: "requests", label: "Requests" },
175
+ { key: "serverErrors", label: "5xx" },
176
+ { key: "clientErrors", label: "4xx" },
177
+ { key: "rateLimited", label: "429" },
178
+ { key: "slow", label: "Slow" },
179
+ { key: "avgMs", label: "Avg" },
180
+ { key: "maxMs", label: "Max" },
181
+ ],
182
+ );
183
+ },
184
+ }),
185
+
186
+ command("telemetry routes", {
187
+ summary: "Rank route templates by errors, popularity, or latency",
188
+ description:
189
+ "The primary troubleshooting view. Routes are real route templates (`/api/mail/mailboxes/:id`), not registry prefixes, so a failing endpoint is identifiable. Sort by errorRate to find what is broken, by requests to find what is popular. errorRate ignores routes under 20 requests so a single failure cannot top the list.",
190
+ examples: [
191
+ "cld admin telemetry routes --sort errorRate --range 24h --json",
192
+ "cld admin telemetry routes --sort requests --range 7d",
193
+ "cld admin telemetry routes --errors --app mail",
194
+ ],
195
+ flags: {
196
+ range: rangeFlag(),
197
+ app: flag.string({ description: "Restrict to one app id" }),
198
+ sort: flag.enum(TELEMETRY_SORTS, { default: "errorRate", description: "Ranking order" }),
199
+ errors: flag.boolean({ description: "Only routes that produced errors" }),
200
+ slow: flag.boolean({ description: "Only routes that produced slow requests" }),
201
+ limit: flag.int({ default: 25, min: 1, max: 100, description: "Maximum routes returned" }),
202
+ },
203
+ run: async ({ ctx, flags }) => {
204
+ const raw = await apiGet<{ items: TelemetryRouteRow[] }>(
205
+ ctx,
206
+ `/api/gateway/telemetry/routes${queryString({
207
+ range: flags.range,
208
+ app: flags.app,
209
+ sort: flags.sort,
210
+ errors: flags.errors ? "1" : undefined,
211
+ slow: flags.slow ? "1" : undefined,
212
+ limit: flags.limit,
213
+ })}`,
214
+ );
215
+ printJsonOrTable(ctx, raw, routeRows(raw.items), [
216
+ { key: "route", label: "Route" },
217
+ { key: "app", label: "App" },
218
+ { key: "requests", label: "Requests" },
219
+ { key: "errors", label: "Errors" },
220
+ { key: "errorRate", label: "Rate" },
221
+ { key: "slow", label: "Slow" },
222
+ { key: "avgMs", label: "Avg" },
223
+ { key: "maxMs", label: "Max" },
224
+ ]);
225
+ },
226
+ }),
227
+
228
+ command("telemetry timeseries", {
229
+ summary: "Show requests and errors bucketed over time",
230
+ description:
231
+ "Bucket width follows the range so every window returns a readable number of points. Use it to place when a change started.",
232
+ examples: ["cld admin telemetry timeseries --range 24h --json", "cld admin telemetry timeseries --range 7d --app grids"],
233
+ flags: {
234
+ range: rangeFlag(),
235
+ app: flag.string({ description: "Restrict to one app id" }),
236
+ route: flag.string({ description: "Restrict to one route template" }),
237
+ },
238
+ run: async ({ ctx, flags }) => {
239
+ const raw = await apiGet<{ items: { at: string; requests: number; errors: number }[] }>(
240
+ ctx,
241
+ `/api/gateway/telemetry/timeseries${queryString({ range: flags.range, app: flags.app, route: flags.route })}`,
242
+ );
243
+ printJsonOrTable(ctx, raw, raw.items, [
244
+ { key: "at", label: "Bucket" },
245
+ { key: "requests", label: "Requests" },
246
+ { key: "errors", label: "Errors" },
247
+ ]);
248
+ },
249
+ }),
250
+
251
+ command("telemetry explain", {
252
+ summary: "Collect one route with its requests and related logs",
253
+ description:
254
+ "The counterpart to `logs explain`: takes a route template and returns its error breakdown, recent individual requests, and log entries from the owning app in one bundle. Sections that fail are reported as {ok:false,error} instead of aborting the command.",
255
+ examples: [
256
+ 'cld admin telemetry explain "/api/mail/mailboxes/:id" --json',
257
+ 'cld admin telemetry explain "/app/grids" --range 6h --app grids',
258
+ ],
259
+ args: { route: arg.required({ valueLabel: "route" }) },
260
+ flags: {
261
+ range: rangeFlag(),
262
+ app: flag.string({ description: "App id owning the route; narrows the log lookup" }),
263
+ limit: flag.int({ default: 20, min: 1, max: 100, description: "Requests and log rows per section" }),
264
+ },
265
+ run: async ({ ctx, args, flags }) => {
266
+ const scope = { range: flags.range, app: flags.app, route: args.route };
267
+ const [overview, events, logs] = await Promise.all([
268
+ safeCollect("overview", () => apiGet<TelemetryOverview>(ctx, `/api/gateway/telemetry/overview${queryString(scope)}`)),
269
+ safeCollect("requests", () =>
270
+ apiGet<{ items: Record<string, unknown>[] }>(
271
+ ctx,
272
+ `/api/gateway/telemetry/route-events${queryString({ ...scope, limit: flags.limit })}`,
273
+ ),
274
+ ),
275
+ // Reuses the logs helper so the query shape cannot drift from `logs list`.
276
+ safeCollect("logs", () =>
277
+ getLogs(ctx, { source: flags.app, level: "error", sinceHours: rangeHours(flags.range ?? "24h"), perPage: flags.limit }),
278
+ ),
279
+ ]);
280
+
281
+ const bundle = { route: args.route, range: flags.range, app: flags.app ?? null, overview, requests: events, logs };
282
+ if (ctx.options.output === "json") {
283
+ ctx.json(bundle);
284
+ return;
285
+ }
286
+ ctx.print(`route: ${args.route} (${flags.range})`);
287
+ ctx.print(
288
+ overview.ok
289
+ ? `requests: ${overview.data.requests}, 5xx: ${overview.data.serverErrors}, 4xx: ${overview.data.clientErrors}, 429: ${overview.data.rateLimited}, slow: ${overview.data.slowRequests}`
290
+ : `overview: unavailable (${overview.error})`,
291
+ );
292
+ ctx.print(events.ok ? `recent requests: ${events.data.items.length}` : `recent requests: unavailable (${events.error})`);
293
+ ctx.print(logs.ok ? `related error logs: ${logs.data.entries.length}` : `related error logs: unavailable (${logs.error})`);
294
+ },
295
+ }),
296
+ ];
297
+
298
+ export const telemetryCommands = [...telemetryLegacyCommands, ...telemetryAnalysisCommands];
299
+
300
+ /**
301
+ * Maps `diagnose --since` (free-form hours) onto the nearest supported
302
+ * telemetry range, so one lookback flag drives every section of the bundle.
303
+ */
304
+ export const diagnoseRange = (hours: number): string => {
305
+ if (hours <= 1) return "1h";
306
+ if (hours <= 6) return "6h";
307
+ if (hours <= 24) return "24h";
308
+ if (hours <= 24 * 7) return "7d";
309
+ return "30d";
310
+ };
311
+
312
+ /** Range identifiers back to hours, for helpers that take a lookback window. */
313
+ export const rangeHours = (range: string): number =>
314
+ range === "1h" ? 1 : range === "6h" ? 6 : range === "7d" ? 24 * 7 : range === "30d" ? 24 * 30 : 24;