@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,222 @@
1
+ /**
2
+ * Health webhook configuration and delivery testing.
3
+ */
4
+ import { arg, type CloudCliTableColumn, command, confirmFlag, flag } from "../index";
5
+ import { apiGet, apiJson, cleanObject, printJsonOrTable, readJsonInput, truncate } from "./shared";
6
+
7
+ export type HealthWebhook = {
8
+ id: string;
9
+ name: string;
10
+ url: string;
11
+ method: "GET" | "POST";
12
+ enabled: boolean;
13
+ scopeKind: "all" | "include" | "exclude";
14
+ scopeAppIds: string[];
15
+ sendOn: ("ok" | "warn" | "error" | "recovery" | "every_check")[];
16
+ minStatus: "ok" | "warn" | "error";
17
+ repeatIntervalMs: number;
18
+ timeoutMs: number;
19
+ lastStatus: "ok" | "warn" | "error" | null;
20
+ lastSentAt: string | null;
21
+ lastSuccessAt: string | null;
22
+ lastErrorAt: string | null;
23
+ lastError: string | null;
24
+ deliveryCount: number;
25
+ failureCount: number;
26
+ };
27
+
28
+ export const webhookInputFromFlags = (flags: {
29
+ name?: string;
30
+ url?: string;
31
+ method?: "GET" | "POST";
32
+ enabled?: boolean;
33
+ disabled?: boolean;
34
+ scope?: "all" | "include" | "exclude";
35
+ apps?: string;
36
+ sendOn?: string;
37
+ minStatus?: "ok" | "warn" | "error";
38
+ repeatIntervalMs?: number;
39
+ timeoutMs?: number;
40
+ }) => ({
41
+ name: flags.name,
42
+ url: flags.url,
43
+ method: flags.method,
44
+ enabled: flags.disabled ? false : flags.enabled ? true : undefined,
45
+ scopeKind: flags.scope,
46
+ scopeAppIds: flags.apps
47
+ ?.split(",")
48
+ .map((item) => item.trim())
49
+ .filter(Boolean),
50
+ sendOn: flags.sendOn
51
+ ?.split(",")
52
+ .map((item) => item.trim())
53
+ .filter(Boolean),
54
+ minStatus: flags.minStatus,
55
+ repeatIntervalMs: flags.repeatIntervalMs,
56
+ timeoutMs: flags.timeoutMs,
57
+ });
58
+
59
+ export const defaultWebhookInput = (flags: ReturnType<typeof webhookInputFromFlags>) => ({
60
+ name: flags.name,
61
+ url: flags.url,
62
+ method: flags.method ?? "POST",
63
+ enabled: flags.enabled ?? true,
64
+ scopeKind: flags.scopeKind ?? "all",
65
+ scopeAppIds: flags.scopeAppIds ?? [],
66
+ sendOn: flags.sendOn ?? ["error", "recovery"],
67
+ minStatus: flags.minStatus ?? "error",
68
+ repeatIntervalMs: flags.repeatIntervalMs ?? 1_800_000,
69
+ timeoutMs: flags.timeoutMs ?? 5000,
70
+ });
71
+
72
+ export const webhookRows = (items: HealthWebhook[]) =>
73
+ items.map((webhook) => ({
74
+ enabled: webhook.enabled,
75
+ name: webhook.name,
76
+ method: webhook.method,
77
+ status: webhook.lastStatus ?? "",
78
+ failures: webhook.failureCount,
79
+ scope: webhook.scopeKind,
80
+ sendOn: webhook.sendOn.join(","),
81
+ url: truncate(webhook.url, 72),
82
+ id: webhook.id,
83
+ }));
84
+
85
+ export const webhookColumns = [
86
+ { key: "enabled" },
87
+ { key: "name" },
88
+ { key: "method" },
89
+ { key: "status" },
90
+ { key: "failures" },
91
+ { key: "scope" },
92
+ { key: "sendOn" },
93
+ { key: "url" },
94
+ { key: "id" },
95
+ ] satisfies CloudCliTableColumn<ReturnType<typeof webhookRows>[number]>[];
96
+
97
+ export const webhookCommands = [
98
+ command("webhooks list", {
99
+ summary: "List gateway health webhooks",
100
+ run: async ({ ctx }) => {
101
+ const result = await apiGet<HealthWebhook[]>(ctx, "/api/gateway/health/webhooks");
102
+ printJsonOrTable(ctx, result, webhookRows(result), webhookColumns);
103
+ },
104
+ }),
105
+ command("webhooks get", {
106
+ summary: "Show one gateway health webhook",
107
+ args: { id: arg.required({ valueLabel: "id" }) },
108
+ run: async ({ ctx, args }) => {
109
+ const result = await apiGet<HealthWebhook[]>(ctx, "/api/gateway/health/webhooks");
110
+ const webhook = result.find((item) => item.id === args.id);
111
+ if (!webhook) throw new Error("Health webhook not found.");
112
+ printJsonOrTable(ctx, webhook, webhookRows([webhook]), webhookColumns);
113
+ },
114
+ }),
115
+ command("webhooks apply", {
116
+ summary: "Create or replace a gateway health webhook from JSON",
117
+ args: { id: arg.optional({ valueLabel: "id" }) },
118
+ flags: {
119
+ body: flag.input({
120
+ name: "body",
121
+ fileName: "body-file",
122
+ fileAliases: ["f"],
123
+ required: true,
124
+ description: "Webhook JSON body",
125
+ }),
126
+ },
127
+ run: async ({ ctx, args, flags }) => {
128
+ const payload = await readJsonInput<unknown>(flags.body, "webhook");
129
+ const path = args.id ? `/api/gateway/health/webhooks/${encodeURIComponent(args.id)}` : "/api/gateway/health/webhooks";
130
+ const result = await apiJson<HealthWebhook>(ctx, args.id ? "PUT" : "POST", path, payload);
131
+ if (ctx.options.output === "json") ctx.json(result);
132
+ else ctx.print(`${args.id ? "Updated" : "Created"} webhook ${result.name}.`);
133
+ },
134
+ }),
135
+ command("webhooks create", {
136
+ summary: "Create a gateway health webhook from flags",
137
+ flags: {
138
+ name: flag.string({ required: true, description: "Webhook name" }),
139
+ url: flag.string({ required: true, description: "Webhook URL" }),
140
+ method: flag.enum(["GET", "POST"], { default: "POST", description: "HTTP method" }),
141
+ enabled: flag.boolean({ default: true, description: "Enable webhook" }),
142
+ disabled: flag.boolean({ description: "Create disabled" }),
143
+ scope: flag.enum(["all", "include", "exclude"], { default: "all", description: "App scope mode" }),
144
+ apps: flag.string({ description: "Comma-separated app ids for include/exclude scope" }),
145
+ sendOn: flag.string({ name: "send-on", description: "Comma-separated events: ok,warn,error,recovery,every_check" }),
146
+ minStatus: flag.enum(["ok", "warn", "error"], { name: "min-status", default: "error", description: "Minimum status" }),
147
+ repeatIntervalMs: flag.int({ name: "repeat-interval-ms", description: "Repeat interval in milliseconds" }),
148
+ timeoutMs: flag.int({ name: "timeout-ms", description: "Request timeout in milliseconds" }),
149
+ },
150
+ run: async ({ ctx, flags }) => {
151
+ const input = defaultWebhookInput(webhookInputFromFlags(flags));
152
+ const result = await apiJson<HealthWebhook>(ctx, "POST", "/api/gateway/health/webhooks", input);
153
+ if (ctx.options.output === "json") ctx.json(result);
154
+ else ctx.print(`Created webhook ${result.name}.`);
155
+ },
156
+ }),
157
+ command("webhooks update", {
158
+ summary: "Partially update a gateway health webhook from flags",
159
+ args: { id: arg.required({ valueLabel: "id" }) },
160
+ flags: {
161
+ name: flag.string({ description: "Webhook name" }),
162
+ url: flag.string({ description: "Webhook URL" }),
163
+ method: flag.enum(["GET", "POST"], { description: "HTTP method" }),
164
+ enabled: flag.boolean({ description: "Enable webhook" }),
165
+ disabled: flag.boolean({ description: "Disable webhook" }),
166
+ scope: flag.enum(["all", "include", "exclude"], { description: "App scope mode" }),
167
+ apps: flag.string({ description: "Comma-separated app ids for include/exclude scope" }),
168
+ sendOn: flag.string({ name: "send-on", description: "Comma-separated events: ok,warn,error,recovery,every_check" }),
169
+ minStatus: flag.enum(["ok", "warn", "error"], { name: "min-status", description: "Minimum status" }),
170
+ repeatIntervalMs: flag.int({ name: "repeat-interval-ms", description: "Repeat interval in milliseconds" }),
171
+ timeoutMs: flag.int({ name: "timeout-ms", description: "Request timeout in milliseconds" }),
172
+ },
173
+ run: async ({ ctx, args, flags }) => {
174
+ const items = await apiGet<HealthWebhook[]>(ctx, "/api/gateway/health/webhooks");
175
+ const current = items.find((item) => item.id === args.id);
176
+ if (!current) throw new Error("Health webhook not found.");
177
+ const update = cleanObject(webhookInputFromFlags(flags));
178
+ const input = {
179
+ name: current.name,
180
+ url: current.url,
181
+ method: current.method,
182
+ enabled: current.enabled,
183
+ scopeKind: current.scopeKind,
184
+ scopeAppIds: current.scopeAppIds,
185
+ sendOn: current.sendOn,
186
+ minStatus: current.minStatus,
187
+ repeatIntervalMs: current.repeatIntervalMs,
188
+ timeoutMs: current.timeoutMs,
189
+ ...update,
190
+ };
191
+ const result = await apiJson<HealthWebhook>(ctx, "PUT", `/api/gateway/health/webhooks/${encodeURIComponent(args.id)}`, input);
192
+ if (ctx.options.output === "json") ctx.json(result);
193
+ else ctx.print(`Updated webhook ${result.name}.`);
194
+ },
195
+ }),
196
+ command("webhooks test", {
197
+ summary: "Submit a gateway health webhook test delivery",
198
+ args: { id: arg.required({ valueLabel: "id" }) },
199
+ flags: { yes: confirmFlag("Confirm sending a webhook test delivery") },
200
+ run: async ({ ctx, args, flags }) => {
201
+ if (!flags.yes) throw new Error("Refusing to test a webhook without --yes.");
202
+ const result = await apiJson<{ message: string; jobId: string }>(
203
+ ctx,
204
+ "POST",
205
+ `/api/gateway/health/webhooks/${encodeURIComponent(args.id)}/test`,
206
+ );
207
+ if (ctx.options.output === "json") ctx.json(result);
208
+ else ctx.print(`${result.message}: ${result.jobId}`);
209
+ },
210
+ }),
211
+ command("webhooks delete", {
212
+ summary: "Delete a gateway health webhook",
213
+ args: { id: arg.required({ valueLabel: "id" }) },
214
+ flags: { yes: confirmFlag("Confirm webhook deletion") },
215
+ run: async ({ ctx, args, flags }) => {
216
+ if (!flags.yes) throw new Error("Refusing to delete a webhook without --yes.");
217
+ const result = await apiJson<{ message: string }>(ctx, "DELETE", `/api/gateway/health/webhooks/${encodeURIComponent(args.id)}`);
218
+ if (ctx.options.output === "json") ctx.json(result);
219
+ else ctx.print(result.message);
220
+ },
221
+ }),
222
+ ];
@@ -0,0 +1,367 @@
1
+ /**
2
+ * Workflow runs from the command line.
3
+ *
4
+ * Everything the admin page shows, reachable from a script: whether anything
5
+ * is broken, which runs failed, why a run started, and which effects escaped
6
+ * without reporting back. Mutations require an explicit `--yes` decision.
7
+ */
8
+ import { arg, command, confirmFlag, flag } from "../index";
9
+ import { apiGet, apiJson, formatMs, printJsonOrTable, queryString, readJsonInput, truncate } from "./shared";
10
+
11
+ type RunState = "queued" | "running" | "waiting" | "succeeded" | "failed" | "canceled" | "needs_attention";
12
+
13
+ export type WorkflowHealthRow = {
14
+ appId: string;
15
+ runs: Record<RunState, number>;
16
+ strandedEffects: number;
17
+ undispatchedEvents: number;
18
+ oldestUndispatchedMs: number | null;
19
+ worstStartLagMs: number | null;
20
+ };
21
+
22
+ export type WorkflowRunRow = {
23
+ id: string;
24
+ appId: string;
25
+ workflowName: string;
26
+ revision: number;
27
+ mode: string;
28
+ state: RunState;
29
+ attempt: number;
30
+ eventType: string | null;
31
+ parentRunId: string | null;
32
+ startLagMs: number | null;
33
+ durationMs: number | null;
34
+ createdAt: string;
35
+ };
36
+
37
+ export type WorkflowStepRow = {
38
+ stepKey: string;
39
+ kind: string;
40
+ action: string | null;
41
+ state: string;
42
+ attempt: number;
43
+ effectKey: string | null;
44
+ effectState: string | null;
45
+ durationMs: number | null;
46
+ };
47
+
48
+ export type WorkflowRunDetailRow = WorkflowRunRow & {
49
+ scopeId: string;
50
+ occurredAt: string;
51
+ finishedAt: string | null;
52
+ inputs: Record<string, unknown>;
53
+ result: unknown;
54
+ error: unknown;
55
+ effectsUsed: Record<string, number>;
56
+ effectBudget: Record<string, number>;
57
+ eventData: Record<string, unknown> | null;
58
+ steps: WorkflowStepRow[];
59
+ children: Record<RunState, number>;
60
+ };
61
+
62
+ export type StrandedEffectRow = {
63
+ runId: string;
64
+ appId: string;
65
+ workflowName: string;
66
+ stepKey: string;
67
+ action: string | null;
68
+ effectState: string;
69
+ ageMs: number;
70
+ };
71
+
72
+ export type UndispatchedEventRow = {
73
+ id: string;
74
+ appId: string;
75
+ type: string;
76
+ occurredAt: string;
77
+ attempts: number;
78
+ lastError: string | null;
79
+ };
80
+
81
+ const WINDOW_VALUES = ["1h", "24h", "7d", "30d"] as const;
82
+ const STATE_VALUES = ["all", "queued", "running", "waiting", "succeeded", "failed", "canceled", "needs_attention"] as const;
83
+ const MODE_VALUES = ["all", "execute", "dryRun"] as const;
84
+
85
+ const windowFlag = () => flag.enum(WINDOW_VALUES, { default: "24h", description: "Lookback window" });
86
+
87
+ /** A budget reads as `emails 3/10`, which is the only form that shows headroom. */
88
+ const budgetSummary = (used: Record<string, number>, budget: Record<string, number>): string => {
89
+ const dimensions = [...new Set([...Object.keys(budget), ...Object.keys(used)])];
90
+ if (dimensions.length === 0) return "-";
91
+ return dimensions.map((dimension) => `${dimension} ${used[dimension] ?? 0}/${budget[dimension] ?? "∞"}`).join(", ");
92
+ };
93
+
94
+ export const workflowCommands = [
95
+ command("workflows health", {
96
+ summary: "Show per-app workflow health",
97
+ description:
98
+ "One row per app. `stranded` counts effects that left the process and never reported back — a replay refuses to repeat those, so each is a run that cannot continue on its own. `undispatched` counts events that never turned into runs, which is what a workflow that silently stopped looks like.",
99
+ examples: ["cld admin workflows health", "cld admin workflows health --window 7d --json"],
100
+ flags: { window: windowFlag() },
101
+ run: async ({ ctx, flags }) => {
102
+ const raw = await apiGet<{ items: WorkflowHealthRow[] }>(ctx, `/api/gateway/workflows${queryString({ window: flags.window })}`);
103
+ printJsonOrTable(
104
+ ctx,
105
+ raw,
106
+ raw.items.map((row) => ({
107
+ app: row.appId,
108
+ active: row.runs.queued + row.runs.running + row.runs.waiting,
109
+ succeeded: row.runs.succeeded,
110
+ failed: row.runs.failed,
111
+ attention: row.runs.needs_attention,
112
+ stranded: row.strandedEffects,
113
+ undispatched: row.undispatchedEvents,
114
+ worstLag: formatMs(row.worstStartLagMs),
115
+ })),
116
+ [
117
+ { key: "app", label: "App" },
118
+ { key: "active", label: "Active" },
119
+ { key: "succeeded", label: "Succeeded" },
120
+ { key: "failed", label: "Failed" },
121
+ { key: "attention", label: "Attention" },
122
+ { key: "stranded", label: "Stranded" },
123
+ { key: "undispatched", label: "Undispatched" },
124
+ { key: "worstLag", label: "Worst lag" },
125
+ ],
126
+ );
127
+ },
128
+ }),
129
+
130
+ command("workflows runs", {
131
+ summary: "List workflow runs, newest first",
132
+ description:
133
+ "Child runs of a fan-out are hidden unless `--children` is passed; a bulk operation over ten thousand records would otherwise bury everything else. `lag` is the gap between the occurrence that caused a run and the run actually starting — the drift that says a workflow is falling behind.",
134
+ examples: [
135
+ "cld admin workflows runs --state failed",
136
+ "cld admin workflows runs --app mail --window 7d --json",
137
+ "cld admin workflows runs --state needs_attention",
138
+ ],
139
+ flags: {
140
+ app: flag.string({ description: "Restrict to one app" }),
141
+ workflow: flag.string({ description: "Restrict to one workflow id" }),
142
+ parent: flag.string({ description: "Restrict to direct children of one run" }),
143
+ state: flag.enum(STATE_VALUES, { default: "all", description: "Run state" }),
144
+ mode: flag.enum(MODE_VALUES, { default: "all", description: "Execute or dry run" }),
145
+ children: flag.boolean({ description: "Include child runs of a fan-out" }),
146
+ window: windowFlag(),
147
+ page: flag.int({ default: 1, description: "Page number" }),
148
+ limit: flag.int({ default: 50, description: "Rows per page" }),
149
+ },
150
+ run: async ({ ctx, flags }) => {
151
+ const raw = await apiGet<{ items: WorkflowRunRow[] }>(
152
+ ctx,
153
+ `/api/gateway/workflows/runs${queryString({
154
+ app: flags.app,
155
+ workflow: flags.workflow,
156
+ parent: flags.parent,
157
+ state: flags.state,
158
+ mode: flags.mode,
159
+ children: flags.children ? "true" : undefined,
160
+ window: flags.window,
161
+ page: flags.page,
162
+ per_page: flags.limit,
163
+ })}`,
164
+ );
165
+ printJsonOrTable(
166
+ ctx,
167
+ raw,
168
+ raw.items.map((run) => ({
169
+ id: run.id,
170
+ app: run.appId,
171
+ workflow: truncate(`${run.workflowName} r${run.revision}`, 34),
172
+ cause: run.eventType ?? "direct",
173
+ state: run.state,
174
+ attempts: run.attempt,
175
+ lag: formatMs(run.startLagMs),
176
+ duration: formatMs(run.durationMs),
177
+ })),
178
+ [
179
+ { key: "id", label: "Run" },
180
+ { key: "app", label: "App" },
181
+ { key: "workflow", label: "Workflow" },
182
+ { key: "cause", label: "Cause" },
183
+ { key: "state", label: "State" },
184
+ { key: "attempts", label: "Attempts" },
185
+ { key: "lag", label: "Lag" },
186
+ { key: "duration", label: "Duration" },
187
+ ],
188
+ );
189
+ },
190
+ }),
191
+
192
+ command("workflows show", {
193
+ summary: "Show one run with its steps, cause and effects",
194
+ description: "The table lists steps; `--json` additionally carries the inputs, the event payload, the result and the child-run counts.",
195
+ examples: ["cld admin workflows show <run-id>", "cld admin workflows show <run-id> --json"],
196
+ args: { run: arg.required({ description: "Run id" }) },
197
+ run: async ({ ctx, args }) => {
198
+ const raw = await apiGet<WorkflowRunDetailRow>(ctx, `/api/gateway/workflows/runs/${encodeURIComponent(args.run)}`);
199
+ // The header lines are for humans; --json already carries all of it.
200
+ if (ctx.options.output !== "json") {
201
+ ctx.print(`${raw.workflowName} r${raw.revision} · ${raw.state} · ${raw.appId}`);
202
+ ctx.print(
203
+ `cause ${raw.eventType ?? "direct invocation"} · attempt ${raw.attempt} · lag ${formatMs(raw.startLagMs)} · ${formatMs(raw.durationMs)}`,
204
+ );
205
+ ctx.print(`effects ${budgetSummary(raw.effectsUsed, raw.effectBudget)}`);
206
+ const children = Object.entries(raw.children).filter(([, count]) => count > 0);
207
+ if (children.length > 0) ctx.print(`children ${children.map(([state, count]) => `${count} ${state}`).join(", ")}`);
208
+ }
209
+ printJsonOrTable(
210
+ ctx,
211
+ raw,
212
+ raw.steps.map((step) => ({
213
+ step: truncate(step.stepKey, 30),
214
+ action: step.action ?? step.kind,
215
+ state: step.state,
216
+ effect: step.effectState ?? "-",
217
+ attempts: step.attempt + 1,
218
+ duration: formatMs(step.durationMs),
219
+ })),
220
+ [
221
+ { key: "step", label: "Step" },
222
+ { key: "action", label: "Action" },
223
+ { key: "state", label: "State" },
224
+ { key: "effect", label: "Effect" },
225
+ { key: "attempts", label: "Attempts" },
226
+ { key: "duration", label: "Duration" },
227
+ ],
228
+ );
229
+ },
230
+ }),
231
+
232
+ command("workflows cancel", {
233
+ summary: "Cancel a queued, running or waiting workflow run",
234
+ description:
235
+ "Requests cooperative cancellation. A queued run stops immediately; running or waiting work stops at its next heartbeat. Completed external effects are not undone.",
236
+ examples: ["cld admin workflows cancel <run-id> --yes", "cld admin workflows cancel <run-id> --yes --json"],
237
+ args: { run: arg.required({ description: "Run id" }) },
238
+ flags: { yes: confirmFlag("Confirm workflow run cancellation") },
239
+ run: async ({ ctx, args, flags }) => {
240
+ if (!flags.yes) throw new Error("Refusing to cancel a workflow run without --yes.");
241
+ const raw = await apiJson<{ canceled: true }>(ctx, "POST", `/api/gateway/workflows/runs/${encodeURIComponent(args.run)}/cancel`);
242
+ if (ctx.options.output === "json") ctx.json(raw);
243
+ else ctx.print(`Cancellation requested for ${args.run}.`);
244
+ },
245
+ }),
246
+
247
+ command("workflows effects", {
248
+ summary: "List effects that escaped without reporting back",
249
+ description:
250
+ "Each row is a step that told an external system to do something and never learned whether it landed. A replay will not repeat them — repeating is how the same message goes out twice — so a human decides. This is the queue to work through after an incident.",
251
+ examples: ["cld admin workflows effects", "cld admin workflows effects --app mail --json"],
252
+ flags: {
253
+ app: flag.string({ description: "Restrict to one app" }),
254
+ page: flag.int({ default: 1, description: "Page number" }),
255
+ limit: flag.int({ default: 100, description: "Rows per page" }),
256
+ },
257
+ run: async ({ ctx, flags }) => {
258
+ const raw = await apiGet<{ items: StrandedEffectRow[] }>(
259
+ ctx,
260
+ `/api/gateway/workflows/effects${queryString({ app: flags.app, page: flags.page, limit: flags.limit })}`,
261
+ );
262
+ printJsonOrTable(
263
+ ctx,
264
+ raw,
265
+ raw.items.map((effect) => ({
266
+ run: effect.runId,
267
+ app: effect.appId,
268
+ workflow: truncate(effect.workflowName, 28),
269
+ step: truncate(effect.stepKey, 26),
270
+ action: effect.action ?? "-",
271
+ effect: effect.effectState,
272
+ age: formatMs(effect.ageMs),
273
+ })),
274
+ [
275
+ { key: "run", label: "Run" },
276
+ { key: "app", label: "App" },
277
+ { key: "workflow", label: "Workflow" },
278
+ { key: "step", label: "Step" },
279
+ { key: "action", label: "Action" },
280
+ { key: "effect", label: "State" },
281
+ { key: "age", label: "Age" },
282
+ ],
283
+ );
284
+ },
285
+ }),
286
+
287
+ command("workflows resolve", {
288
+ summary: "Resolve a workflow effect that needs attention",
289
+ description:
290
+ "Confirm whether an ambiguous external effect succeeded or failed. Success records the supplied output and resumes the pinned plan; failure settles the step and run. This never repeats the effect.",
291
+ examples: [
292
+ 'cld admin workflows resolve <run-id> <step-key> --decision succeeded --result \'{"id":"m-1"}\' --yes',
293
+ "cld admin workflows resolve <run-id> <step-key> --decision failed --message 'provider rejected it' --yes",
294
+ ],
295
+ args: {
296
+ run: arg.required({ description: "Run id" }),
297
+ step: arg.required({ description: "Step key" }),
298
+ },
299
+ flags: {
300
+ decision: flag.enum(["succeeded", "failed"] as const, { required: true, description: "Confirmed effect outcome" }),
301
+ result: flag.input({ description: "JSON output for a succeeded effect, or @file/-" }),
302
+ message: flag.string({ description: "Failure explanation" }),
303
+ code: flag.string({ description: "Stable failure code" }),
304
+ yes: confirmFlag("Confirm the effect resolution"),
305
+ },
306
+ run: async ({ ctx, args, flags }) => {
307
+ if (!flags.yes) throw new Error("Refusing to resolve a workflow effect without --yes.");
308
+ const resolution =
309
+ flags.decision === "succeeded"
310
+ ? {
311
+ state: "succeeded" as const,
312
+ ...(flags.result ? { output: await readJsonInput<unknown>(flags.result, "effect result") } : {}),
313
+ }
314
+ : {
315
+ state: "failed" as const,
316
+ message: flags.message?.trim() || "effect confirmed failed by operator",
317
+ ...(flags.code ? { code: flags.code } : {}),
318
+ };
319
+ const raw = await apiJson<{ resolved: true }>(
320
+ ctx,
321
+ "POST",
322
+ `/api/gateway/workflows/runs/${encodeURIComponent(args.run)}/attention/${encodeURIComponent(args.step)}`,
323
+ resolution,
324
+ );
325
+ if (ctx.options.output === "json") ctx.json(raw);
326
+ else ctx.print(`Resolved ${args.run} ${args.step} as ${flags.decision}.`);
327
+ },
328
+ }),
329
+
330
+ command("workflows events", {
331
+ summary: "List events that never turned into runs",
332
+ description:
333
+ "An event that matched no activation, or whose dispatch failed. This is what a workflow that silently stopped firing looks like — the occurrence happened, nothing ran, and nothing errored where anyone would see it.",
334
+ examples: ["cld admin workflows events", "cld admin workflows events --app grids --json"],
335
+ flags: {
336
+ app: flag.string({ description: "Restrict to one app" }),
337
+ page: flag.int({ default: 1, description: "Page number" }),
338
+ limit: flag.int({ default: 100, description: "Rows per page" }),
339
+ },
340
+ run: async ({ ctx, flags }) => {
341
+ const raw = await apiGet<{ items: UndispatchedEventRow[] }>(
342
+ ctx,
343
+ `/api/gateway/workflows/events${queryString({ app: flags.app, page: flags.page, limit: flags.limit })}`,
344
+ );
345
+ printJsonOrTable(
346
+ ctx,
347
+ raw,
348
+ raw.items.map((event) => ({
349
+ id: event.id,
350
+ app: event.appId,
351
+ type: event.type,
352
+ occurred: event.occurredAt,
353
+ attempts: event.attempts,
354
+ error: truncate(event.lastError ?? "-", 44),
355
+ })),
356
+ [
357
+ { key: "id", label: "Event" },
358
+ { key: "app", label: "App" },
359
+ { key: "type", label: "Type" },
360
+ { key: "occurred", label: "Occurred" },
361
+ { key: "attempts", label: "Attempts" },
362
+ { key: "error", label: "Last error" },
363
+ ],
364
+ );
365
+ },
366
+ }),
367
+ ];
@@ -0,0 +1,40 @@
1
+ import { type CloudCliContext, command, defineCliCommands, flag } from "./index";
2
+
3
+ type VisibleApp = {
4
+ id: string;
5
+ name: string;
6
+ description: string;
7
+ icon: string;
8
+ href: string;
9
+ };
10
+
11
+ const listApps = async (ctx: CloudCliContext, search: string | undefined) => {
12
+ const query = search ? `?${new URLSearchParams({ search }).toString()}` : "";
13
+ return ctx.readJson<{ items: VisibleApp[] }>(await ctx.fetch(`/api/apps${query}`));
14
+ };
15
+
16
+ export default defineCliCommands({
17
+ name: "apps",
18
+ summary: "List Cloud apps available to the current user.",
19
+ commands: [
20
+ command("list", {
21
+ summary: "List available Cloud apps",
22
+ flags: {
23
+ search: flag.string({ aliases: ["q"], description: "Filter by app name, id, or description" }),
24
+ },
25
+ run: async ({ ctx, flags }) => {
26
+ const result = await listApps(ctx, flags.search);
27
+ if (ctx.options.output === "json") {
28
+ ctx.json(result);
29
+ return;
30
+ }
31
+ ctx.table(result.items, [
32
+ { key: "id", label: "ID" },
33
+ { key: "name", label: "NAME" },
34
+ { key: "description", label: "DESCRIPTION" },
35
+ { key: "href", label: "URL" },
36
+ ]);
37
+ },
38
+ }),
39
+ ],
40
+ });