@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,382 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { arg, type CliInputFlagValue, type CloudCliContext, command, confirmFlag, defineCliCommands, flag, readCliInput } from "./index";
3
+
4
+ type User = {
5
+ id: string;
6
+ uid: string;
7
+ provider: "ipa" | "local";
8
+ profile: "user" | "guest";
9
+ roles: string[];
10
+ givenname: string;
11
+ sn: string;
12
+ displayName: string;
13
+ mail: string | null;
14
+ memberofGroup: string[];
15
+ manages: string[];
16
+ accountExpires: string | null;
17
+ lastLoginLocal: string | null;
18
+ ipa: null | {
19
+ phone: string | null;
20
+ address: {
21
+ street: string | null;
22
+ postalCode: string | null;
23
+ city: string | null;
24
+ state: string | null;
25
+ };
26
+ passwordExpires: string | null;
27
+ lastLoginIpa: string | null;
28
+ sshPublicKeys: string[];
29
+ sshFingerprints: string[];
30
+ };
31
+ };
32
+
33
+ type ApiKey = {
34
+ id: string;
35
+ name: string;
36
+ status: "active" | "revoked";
37
+ tokenPrefix: string;
38
+ expiresAt: string | null;
39
+ lastUsedAt: string | null;
40
+ createdAt: string;
41
+ };
42
+
43
+ type AccountActivity = {
44
+ id: number;
45
+ createdAt: string;
46
+ action: string;
47
+ label: string;
48
+ outcome: "allowed" | "denied" | "failed";
49
+ };
50
+
51
+ type ProfileUpdateFlags = {
52
+ givenName?: string;
53
+ lastName?: string;
54
+ displayName?: string;
55
+ phone?: string;
56
+ street?: string;
57
+ postalCode?: string;
58
+ city?: string;
59
+ state?: string;
60
+ };
61
+
62
+ const apiPath = (path = "") => `/api/me${path === "/" ? "" : path}`;
63
+
64
+ const readApi = async <T>(ctx: CloudCliContext, path: string, init?: RequestInit): Promise<T> =>
65
+ ctx.readJson<T>(await ctx.fetch(apiPath(path), init));
66
+
67
+ const jsonRequest = (method: string, value?: unknown): RequestInit => ({
68
+ method,
69
+ headers: value === undefined ? undefined : { "Content-Type": "application/json" },
70
+ body: value === undefined ? undefined : JSON.stringify(value),
71
+ });
72
+
73
+ const printJsonOrTable = <TRow extends Record<string, unknown>>(
74
+ ctx: CloudCliContext,
75
+ value: unknown,
76
+ rows: TRow[],
77
+ columns: Parameters<CloudCliContext["table"]>[1],
78
+ ) => {
79
+ if (ctx.options.output === "json") ctx.json(value);
80
+ else ctx.table(rows, columns);
81
+ };
82
+
83
+ const parseExpiry = (value: string | undefined): string | null => {
84
+ if (!value) return null;
85
+ const relative = value.match(/^(\d+)([dwmqy])$/i);
86
+ if (relative) {
87
+ const amount = Number.parseInt(relative[1]!, 10);
88
+ const unit = relative[2]!.toLowerCase();
89
+ const days = unit === "d" ? amount : unit === "w" ? amount * 7 : unit === "m" ? amount * 30 : unit === "q" ? amount * 90 : amount * 365;
90
+ return new Date(Date.now() + days * 24 * 60 * 60 * 1000).toISOString();
91
+ }
92
+ const date = new Date(value);
93
+ if (Number.isNaN(date.getTime())) throw new Error('--expires must be an ISO timestamp or a duration like "90d".');
94
+ return date.toISOString();
95
+ };
96
+
97
+ const userRows = (user: User) => [
98
+ { key: "uid", value: user.uid },
99
+ { key: "name", value: user.displayName },
100
+ { key: "mail", value: user.mail ?? "" },
101
+ { key: "provider", value: user.provider },
102
+ { key: "profile", value: user.profile },
103
+ { key: "roles", value: user.roles.join(", ") },
104
+ ];
105
+
106
+ const profileRows = (user: User) => [
107
+ ...userRows(user),
108
+ { key: "given name", value: user.givenname },
109
+ { key: "last name", value: user.sn },
110
+ { key: "phone", value: user.ipa?.phone ?? "" },
111
+ { key: "street", value: user.ipa?.address.street ?? "" },
112
+ { key: "postal code", value: user.ipa?.address.postalCode ?? "" },
113
+ { key: "city", value: user.ipa?.address.city ?? "" },
114
+ { key: "state", value: user.ipa?.address.state ?? "" },
115
+ { key: "groups", value: user.memberofGroup.join(", ") },
116
+ { key: "manages", value: user.manages.join(", ") },
117
+ ];
118
+
119
+ const apiKeyRows = (keys: ApiKey[]) =>
120
+ keys.map((key) => ({
121
+ id: key.id,
122
+ name: key.name,
123
+ prefix: key.tokenPrefix,
124
+ expires: key.expiresAt ?? "never",
125
+ lastUsed: key.lastUsedAt ?? "never",
126
+ created: key.createdAt,
127
+ }));
128
+
129
+ const activityRows = (items: AccountActivity[]) =>
130
+ items.map((item) => ({
131
+ id: item.id,
132
+ time: item.createdAt,
133
+ outcome: item.outcome,
134
+ action: item.action,
135
+ label: item.label,
136
+ }));
137
+
138
+ const buildProfileUpdate = (flags: ProfileUpdateFlags) => {
139
+ const data: {
140
+ givenname?: string;
141
+ sn?: string;
142
+ displayName?: string;
143
+ ipa?: {
144
+ phone?: string;
145
+ address?: {
146
+ street?: string;
147
+ postalCode?: string;
148
+ city?: string;
149
+ state?: string;
150
+ };
151
+ sshPublicKeys?: string[];
152
+ };
153
+ } = {};
154
+
155
+ if (flags.givenName !== undefined) data.givenname = flags.givenName;
156
+ if (flags.lastName !== undefined) data.sn = flags.lastName;
157
+ if (flags.displayName !== undefined) data.displayName = flags.displayName;
158
+
159
+ if ([flags.phone, flags.street, flags.postalCode, flags.city, flags.state].some((value) => value !== undefined)) {
160
+ data.ipa = {};
161
+ if (flags.phone !== undefined) data.ipa.phone = flags.phone;
162
+ if ([flags.street, flags.postalCode, flags.city, flags.state].some((value) => value !== undefined)) {
163
+ data.ipa.address = {};
164
+ if (flags.street !== undefined) data.ipa.address.street = flags.street;
165
+ if (flags.postalCode !== undefined) data.ipa.address.postalCode = flags.postalCode;
166
+ if (flags.city !== undefined) data.ipa.address.city = flags.city;
167
+ if (flags.state !== undefined) data.ipa.address.state = flags.state;
168
+ }
169
+ }
170
+
171
+ if (Object.keys(data).length === 0) throw new Error("No profile fields provided.");
172
+ return data;
173
+ };
174
+
175
+ const getCurrentUser = (ctx: CloudCliContext): Promise<User> => readApi<User>(ctx, "/");
176
+
177
+ const updateProfile = async (ctx: CloudCliContext, data: unknown) => {
178
+ const result = await readApi<{ message: string }>(ctx, "/", jsonRequest("PATCH", data));
179
+ if (ctx.options.output === "json") ctx.json(result);
180
+ else ctx.print(result.message);
181
+ };
182
+
183
+ const resolveApiKey = async (ctx: CloudCliContext, ref: string): Promise<ApiKey> => {
184
+ const { items } = await readApi<{ items: ApiKey[] }>(ctx, "/api-keys");
185
+ const matches = items.filter((key) => key.id === ref || key.tokenPrefix === ref || key.tokenPrefix.startsWith(ref) || key.name === ref);
186
+ if (matches.length === 0) throw new Error(`API key not found: ${ref}`);
187
+ if (matches.length > 1) throw new Error(`API key reference is ambiguous: ${ref}`);
188
+ return matches[0]!;
189
+ };
190
+
191
+ const requireIpaUser = (user: User): NonNullable<User["ipa"]> => {
192
+ if (!user.ipa) throw new Error("SSH keys and address fields are only available for IPA-backed accounts.");
193
+ return user.ipa;
194
+ };
195
+
196
+ const readPublicKey = async (file: string | undefined, valueParts: readonly string[]): Promise<string> => {
197
+ if (file && valueParts.length > 0) throw new Error("Pass either a public key argument or --file, not both.");
198
+ const key = file ? await readFile(file, "utf8") : valueParts.join(" ");
199
+ const trimmed = key.trim();
200
+ if (!trimmed) throw new Error("Missing SSH public key.");
201
+ return trimmed;
202
+ };
203
+
204
+ const removeSshKey = (user: User, ref: string): string[] => {
205
+ const ipa = requireIpaUser(user);
206
+ const matches = ipa.sshPublicKeys
207
+ .map((key, index) => ({ index, key, fingerprint: ipa.sshFingerprints[index] ?? "" }))
208
+ .filter((item) => item.key === ref || item.key.startsWith(ref) || item.fingerprint.startsWith(ref));
209
+ if (matches.length === 0) throw new Error(`SSH key not found: ${ref}`);
210
+ if (matches.length > 1) {
211
+ const candidates = matches.map((item) => `${item.fingerprint || "no fingerprint"} ${item.key.slice(0, 48)}`).join(", ");
212
+ throw new Error(`SSH key reference is ambiguous: ${ref}. Candidates: ${candidates}`);
213
+ }
214
+ const index = matches[0]!.index;
215
+ return ipa.sshPublicKeys.filter((_, keyIndex) => keyIndex !== index);
216
+ };
217
+
218
+ const readRequiredSecret = async (input: CliInputFlagValue, label: string): Promise<string> => {
219
+ const value = await readCliInput(input, { label, required: true, trimFinalNewline: true });
220
+ if (!value) throw new Error(`Missing ${label}.`);
221
+ return value;
222
+ };
223
+
224
+ export default defineCliCommands({
225
+ name: "account",
226
+ summary: "Manage the authenticated account, profile, personal API keys, and SSH keys.",
227
+ commands: [
228
+ command("whoami", {
229
+ summary: "Show the authenticated account",
230
+ run: async ({ ctx }) => {
231
+ const user = await getCurrentUser(ctx);
232
+ printJsonOrTable(ctx, user, userRows(user), [{ key: "key" }, { key: "value" }]);
233
+ },
234
+ }),
235
+ command("profile show", {
236
+ summary: "Show account profile fields",
237
+ run: async ({ ctx }) => {
238
+ const user = await getCurrentUser(ctx);
239
+ printJsonOrTable(ctx, user, profileRows(user), [{ key: "key" }, { key: "value" }]);
240
+ },
241
+ }),
242
+ command("profile set", {
243
+ summary: "Update account profile fields",
244
+ flags: {
245
+ givenName: flag.string({ name: "given-name", aliases: ["givenname"], description: "Given name" }),
246
+ lastName: flag.string({ name: "last-name", aliases: ["sn"], description: "Last name" }),
247
+ displayName: flag.string({ name: "display-name", aliases: ["displayName"], description: "Display name" }),
248
+ phone: flag.string({ description: "Phone number" }),
249
+ street: flag.string({ description: "Street address" }),
250
+ postalCode: flag.string({ name: "postal-code", aliases: ["postalCode"], description: "Postal code" }),
251
+ city: flag.string({ description: "City" }),
252
+ state: flag.string({ description: "State" }),
253
+ },
254
+ run: async ({ ctx, flags }) => {
255
+ await updateProfile(ctx, buildProfileUpdate(flags));
256
+ },
257
+ }),
258
+ command("activity", {
259
+ summary: "List recent account activity",
260
+ flags: {
261
+ days: flag.int({ default: 30, min: 1, max: 3650, description: "Number of days to include" }),
262
+ },
263
+ run: async ({ ctx, flags }) => {
264
+ const result = await readApi<{ items: AccountActivity[] }>(ctx, `/activity?days=${encodeURIComponent(String(flags.days ?? 30))}`);
265
+ printJsonOrTable(ctx, result, activityRows(result.items), [
266
+ { key: "time" },
267
+ { key: "outcome" },
268
+ { key: "action" },
269
+ { key: "label" },
270
+ ]);
271
+ },
272
+ }),
273
+ command("api-keys list", {
274
+ summary: "List personal API keys",
275
+ run: async ({ ctx }) => {
276
+ const result = await readApi<{ items: ApiKey[] }>(ctx, "/api-keys");
277
+ printJsonOrTable(ctx, result, apiKeyRows(result.items), [
278
+ { key: "name" },
279
+ { key: "prefix" },
280
+ { key: "expires" },
281
+ { key: "lastUsed" },
282
+ { key: "id" },
283
+ ]);
284
+ },
285
+ }),
286
+ command("api-keys create", {
287
+ summary: "Create a personal API key",
288
+ args: { name: arg.required({ valueLabel: "name", description: "API key name" }) },
289
+ flags: {
290
+ expires: flag.string({ description: "ISO timestamp or duration like 90d" }),
291
+ },
292
+ run: async ({ ctx, args, flags }) => {
293
+ const result = await readApi<{ credential: ApiKey; token: string }>(
294
+ ctx,
295
+ "/api-keys",
296
+ jsonRequest("POST", { name: args.name, expiresAt: parseExpiry(flags.expires) }),
297
+ );
298
+ if (ctx.options.output === "json") ctx.json(result);
299
+ else ctx.print(`Token: ${result.token}\nPrefix: ${result.credential.tokenPrefix}\nStore this token now. It cannot be shown again.`);
300
+ },
301
+ }),
302
+ command("api-keys revoke", {
303
+ summary: "Revoke a personal API key",
304
+ args: { ref: arg.required({ valueLabel: "id|prefix|name", description: "API key reference" }) },
305
+ flags: { yes: confirmFlag("Confirm API key revocation") },
306
+ run: async ({ ctx, args, flags }) => {
307
+ if (!flags.yes) throw new Error("Refusing to revoke without --yes.");
308
+ const key = await resolveApiKey(ctx, args.ref);
309
+ const result = await readApi<{ message: string }>(ctx, `/api-keys/${encodeURIComponent(key.id)}`, jsonRequest("DELETE"));
310
+ if (ctx.options.output === "json") ctx.json({ ...result, credential: key });
311
+ else ctx.print(result.message);
312
+ },
313
+ }),
314
+ command("ssh-keys list", {
315
+ summary: "List SSH public keys",
316
+ run: async ({ ctx }) => {
317
+ const user = await getCurrentUser(ctx);
318
+ const ipa = requireIpaUser(user);
319
+ const items = ipa.sshPublicKeys.map((key, index) => ({ fingerprint: ipa.sshFingerprints[index] ?? "", key }));
320
+ printJsonOrTable(ctx, { items }, items, [{ key: "fingerprint" }, { key: "key" }]);
321
+ },
322
+ }),
323
+ command("ssh-keys add", {
324
+ summary: "Add an SSH public key",
325
+ args: { publicKey: arg.rest({ valueLabel: "public-key", description: "SSH public key", required: false }) },
326
+ flags: { file: flag.string({ aliases: ["f"], description: "Read SSH public key from file" }) },
327
+ run: async ({ ctx, args, flags }) => {
328
+ const user = await getCurrentUser(ctx);
329
+ const ipa = requireIpaUser(user);
330
+ const key = await readPublicKey(flags.file, args.publicKey);
331
+ if (ipa.sshPublicKeys.includes(key)) throw new Error("SSH public key already exists.");
332
+ await updateProfile(ctx, { ipa: { sshPublicKeys: [...ipa.sshPublicKeys, key] } });
333
+ },
334
+ }),
335
+ command("ssh-keys remove", {
336
+ summary: "Remove an SSH public key",
337
+ args: { ref: arg.required({ valueLabel: "fingerprint|key-prefix", description: "SSH key fingerprint or key prefix" }) },
338
+ run: async ({ ctx, args }) => {
339
+ const user = await getCurrentUser(ctx);
340
+ await updateProfile(ctx, { ipa: { sshPublicKeys: removeSshKey(user, args.ref) } });
341
+ },
342
+ }),
343
+ command("password change", {
344
+ summary: "Change the account password",
345
+ flags: {
346
+ currentPassword: flag.input({
347
+ name: "current-password",
348
+ fileName: "current-password-file",
349
+ stdinName: false,
350
+ required: true,
351
+ description: "Current password or file",
352
+ }),
353
+ newPassword: flag.input({
354
+ name: "new-password",
355
+ fileName: "new-password-file",
356
+ stdinName: false,
357
+ required: true,
358
+ description: "New password or file",
359
+ }),
360
+ },
361
+ run: async ({ ctx, flags }) => {
362
+ const currentPassword = await readRequiredSecret(flags.currentPassword, "current password");
363
+ const newPassword = await readRequiredSecret(flags.newPassword, "new password");
364
+ const result = await readApi<{ message: string }>(
365
+ ctx,
366
+ "/password",
367
+ jsonRequest("POST", { currentPassword, newPassword, confirmPassword: newPassword }),
368
+ );
369
+ if (ctx.options.output === "json") ctx.json(result);
370
+ else ctx.print(result.message);
371
+ },
372
+ }),
373
+ command("extend", {
374
+ summary: "Request account extension",
375
+ run: async ({ ctx }) => {
376
+ const result = await readApi<{ message: string; newExpiry?: string }>(ctx, "/account-extension", jsonRequest("POST"));
377
+ if (ctx.options.output === "json") ctx.json(result);
378
+ else ctx.print(result.newExpiry ? `${result.message} New expiry: ${result.newExpiry}` : result.message);
379
+ },
380
+ }),
381
+ ],
382
+ });
@@ -0,0 +1,45 @@
1
+ import { z } from "zod";
2
+ import { cliText, command, confirmFlag, flag, printStructured, readCliInput } from "../index";
3
+ import { apiGet } from "./shared";
4
+
5
+ const path = "/api/admin/core/settings";
6
+ const Configuration = z.object({ requestsEnabled: z.boolean(), actionNotice: z.string() }).strict();
7
+
8
+ export const accountAdministrationCommands = [
9
+ command("accounts administration get", {
10
+ summary: "Export account-request policy and the optional account/group follow-up template",
11
+ async run({ ctx }) {
12
+ const config = Configuration.parse(await apiGet(ctx, `${path}/account-administration`));
13
+ if (!printStructured(ctx, config)) ctx.print(JSON.stringify(config, null, 2));
14
+ },
15
+ }),
16
+ command("accounts administration set", {
17
+ summary: "Configure account requests and the optional Liquid-Markdown follow-up template",
18
+ flags: {
19
+ config: flag.input({ required: true, description: "JSON with requestsEnabled and actionNotice: --config, --config-file or --stdin" }),
20
+ yes: confirmFlag("Confirm changes to account requests and administrative follow-up notices"),
21
+ },
22
+ async run({ ctx, flags }) {
23
+ if (!flags.yes)
24
+ throw new Error(
25
+ cliText(ctx, {
26
+ en: "Account administration changes require --yes.",
27
+ de: "Änderungen an der Account-Verwaltung erfordern --yes.",
28
+ }),
29
+ );
30
+ const input = await readCliInput(flags.config, { required: true, label: "Account administration configuration" });
31
+ const config = Configuration.parse(JSON.parse(input ?? ""));
32
+ await ctx.readJson(
33
+ await ctx.fetch(path, {
34
+ method: "PUT",
35
+ headers: { "content-type": "application/json" },
36
+ body: JSON.stringify({
37
+ updates: { "user.account_requests.enabled": config.requestsEnabled, "user.action_notice": config.actionNotice },
38
+ }),
39
+ }),
40
+ );
41
+ if (!printStructured(ctx, { saved: true }))
42
+ ctx.print(cliText(ctx, { en: "Account administration saved.", de: "Account-Verwaltung gespeichert." }));
43
+ },
44
+ }),
45
+ ];
@@ -0,0 +1,49 @@
1
+ import { AccountCategoryPolicySchema } from "../../contracts/account-categories";
2
+ import { cliText, command, confirmFlag, flag, printStructured, readCliInput } from "../index";
3
+ import { apiGet } from "./shared";
4
+
5
+ const path = "/api/admin/core/settings";
6
+ export const accountCategoryCommands = [
7
+ command("accounts config get", {
8
+ summary: "Export account types, login visibility and the local Login label",
9
+ async run({ ctx }) {
10
+ const policy = AccountCategoryPolicySchema.parse(await apiGet(ctx, `${path}/account-categories`));
11
+ if (!printStructured(ctx, policy)) ctx.print(JSON.stringify(policy, null, 2));
12
+ },
13
+ }),
14
+ command("accounts config set", {
15
+ summary: "Replace account category policy; disabled categories lose user-bound access",
16
+ flags: {
17
+ config: flag.input({ required: true, description: "Complete configuration JSON: --config, --config-file or --stdin" }),
18
+ yes: confirmFlag("Confirm access changes, including your own account category"),
19
+ },
20
+ async run({ ctx, flags }) {
21
+ if (!flags.yes)
22
+ throw new Error(
23
+ cliText(ctx, {
24
+ en: "Account access changes require --yes. Keep an allowed admin or emergency token available.",
25
+ de: "Zugriffsänderungen erfordern --yes. Halte einen erlaubten Admin-Zugang oder Notfall-Token bereit.",
26
+ }),
27
+ );
28
+ const input = await readCliInput(flags.config, { required: true, label: "Account category configuration" });
29
+ const policy = AccountCategoryPolicySchema.parse(JSON.parse(input ?? ""));
30
+ const updates = Object.fromEntries(
31
+ Object.entries(policy).flatMap(([category, fields]) =>
32
+ Object.entries(fields).map(([field, value]) => [`user.category.${category}.${field}`, value]),
33
+ ),
34
+ );
35
+ const response = await ctx.fetch(path, {
36
+ method: "PUT",
37
+ headers: { "content-type": "application/json" },
38
+ body: JSON.stringify({ updates }),
39
+ });
40
+ if (!response.ok) {
41
+ await ctx.readJson(response);
42
+ throw new Error(`Account configuration failed (${response.status})`);
43
+ }
44
+ // Do not re-fetch after disabling the caller's own category: its next request is denied.
45
+ if (!printStructured(ctx, { saved: true }))
46
+ ctx.print(cliText(ctx, { en: "Account configuration saved.", de: "Account-Konfiguration gespeichert." }));
47
+ },
48
+ }),
49
+ ];
@@ -0,0 +1,118 @@
1
+ import { arg, command, flag } from "../index";
2
+ import { apiGet, printJsonOrTable } from "./shared";
3
+ import { AI_USAGE_RANGES, AI_USAGE_REASONS } from "../../shared/ai-usage";
4
+ import type { AiUsageReport, AiUsageRun } from "../../ai/usage";
5
+ const filters = {
6
+ range: flag.enum(AI_USAGE_RANGES, { default: "30d", description: "Response/run period" }),
7
+ until: flag.string({ description: "Fixed ISO end time; reuse report.query.until across pages" }),
8
+ userId: flag.string({ name: "user", description: "User UUID or unassigned" }),
9
+ modelProfileId: flag.string({ name: "model", description: "Model profile ID" }),
10
+ providerModel: flag.string({ name: "provider-model", description: "Actual provider model" }),
11
+ appId: flag.string({ name: "app", description: "Source application ID" }),
12
+ kind: flag.enum(["chat", "background", "tool"] as const, { description: "Run kind (runs only)" }),
13
+ status: flag.string({ description: "Run status, e.g. failed (runs only)" }),
14
+ task: flag.string({ description: "Exact task or tool name (runs only)" }),
15
+ errorCode: flag.string({ name: "error-code", description: "Stored error code (runs only)" }),
16
+ search: flag.string({ description: "Search task and error text (runs/facets only)" }),
17
+ rating: flag.enum(["up", "down"] as const, { description: "Rating (feedback only)" }),
18
+ reason: flag.enum(AI_USAGE_REASONS, { description: "Feedback reason (feedback only)" }),
19
+ sort: flag.enum(["runs", "tokens", "credits", "errors", "negative", "negativeRate"] as const, {
20
+ default: "runs",
21
+ description: "Comparison sort order",
22
+ }),
23
+ page: flag.int({ default: 1, min: 1 }),
24
+ perPage: flag.int({ name: "per-page", default: 50, min: 1, max: 100 }),
25
+ };
26
+ // HTTP validation is authoritative, also for dynamically discovered CLI modules.
27
+ const params = (values: Record<string, string | number | undefined>) => {
28
+ const q = new URLSearchParams();
29
+ for (const [key, value] of Object.entries(values)) if (value !== undefined) q.set(key, String(value));
30
+ return q;
31
+ };
32
+ export const aiUsageCommands = [
33
+ ...(["report", "users", "models", "tasks", "apps", "launches", "capabilities", "feedback", "runs"] as const).map((section) =>
34
+ command(`ai usage ${section}`, {
35
+ summary:
36
+ section === "report"
37
+ ? "Summarize AI usage and coverage; use --json for the complete report"
38
+ : `List AI usage ${section}; supports --json and pagination`,
39
+ flags: filters,
40
+ run: async ({ ctx, flags }) => {
41
+ const report = await apiGet<AiUsageReport>(ctx, `/api/admin/core/ai-usage/report?${params(flags)}`);
42
+ if (section === "report" && ctx.options.output === "jsonl") return ctx.jsonLine(report);
43
+ if (section === "report")
44
+ return printJsonOrTable(
45
+ ctx,
46
+ report,
47
+ [report.overview],
48
+ [{ key: "runs" }, { key: "tokens" }, { key: "credits" }, { key: "failed" }, { key: "positive" }, { key: "negative" }],
49
+ );
50
+ const page = report[section];
51
+ if (ctx.options.output === "jsonl") {
52
+ for (const item of page.items) ctx.jsonLine(item);
53
+ return;
54
+ }
55
+ if (ctx.options.output === "json") return ctx.json({ ...page, query: report.query, since: report.since, until: report.until });
56
+ if (section === "runs")
57
+ ctx.table(report.runs.items, [
58
+ { key: "id" },
59
+ { key: "kind" },
60
+ { key: "task" },
61
+ { key: "status" },
62
+ { key: "userLabel" },
63
+ { key: "modelProfileId" },
64
+ { key: "error" },
65
+ ]);
66
+ else if (section === "feedback")
67
+ ctx.table(report.feedback.items, [
68
+ { key: "id" },
69
+ { key: "userLabel" },
70
+ { key: "modelProfileId" },
71
+ { key: "rating" },
72
+ { key: "comment" },
73
+ ]);
74
+ else if (section === "launches") ctx.table(report.launches.items, [{ key: "appId" }, { key: "chats" }, { key: "users" }]);
75
+ else
76
+ ctx.table(report[section].items, [
77
+ { key: "id" },
78
+ { key: "label" },
79
+ { key: "providerModel" },
80
+ { key: "runs" },
81
+ { key: "tokens" },
82
+ { key: "failed" },
83
+ { key: "positive" },
84
+ { key: "negative" },
85
+ { key: "rated" },
86
+ ]);
87
+ ctx.print(`Page ${page.page}; ${page.total} total. Snapshot until ${report.until}`);
88
+ },
89
+ }),
90
+ ),
91
+ command("ai usage get", {
92
+ summary: "Read one AI run, including its complete stored error and references",
93
+ args: { kind: arg.required(), id: arg.required() },
94
+ run: async ({ ctx, args }) => {
95
+ const result = await apiGet<AiUsageRun>(
96
+ ctx,
97
+ `/api/admin/core/ai-usage/runs/${encodeURIComponent(args.kind)}/${encodeURIComponent(args.id)}`,
98
+ );
99
+ ctx.json(result);
100
+ },
101
+ }),
102
+ command("ai usage facets", {
103
+ summary: "Find user IDs, model profiles, provider models, apps or tasks for filtering",
104
+ flags: {
105
+ field: flag.enum(["userId", "modelProfileId", "providerModel", "appId", "task"] as const, { required: true }),
106
+ search: flag.string(),
107
+ range: filters.range,
108
+ },
109
+ run: async ({ ctx, flags }) => {
110
+ const result = await apiGet<{ items: { id: string; label: string }[] }>(ctx, `/api/admin/core/ai-usage/facets?${params(flags)}`);
111
+ if (ctx.options.output === "jsonl") {
112
+ for (const item of result.items) ctx.jsonLine(item);
113
+ return;
114
+ }
115
+ printJsonOrTable(ctx, result, result.items, [{ key: "id" }, { key: "label" }]);
116
+ },
117
+ }),
118
+ ];
@@ -0,0 +1,49 @@
1
+ import { z } from "zod";
2
+ import { cliText, command, confirmFlag, flag, printStructured, readCliInput } from "../index";
3
+ import { apiGet } from "./shared";
4
+
5
+ const path = "/api/admin/core/settings";
6
+ const Configuration = z.object({ enabled: z.boolean(), origin: z.string(), adminPairing: z.boolean() }).strict();
7
+
8
+ export const appSignInCommands = [
9
+ command("app-sign-in config get", {
10
+ summary: "Export app sign-in activation, trusted origin, and administrator-assisted pairing policy",
11
+ async run({ ctx }) {
12
+ const config = Configuration.parse(await apiGet(ctx, `${path}/app-sign-in`));
13
+ if (!printStructured(ctx, config)) ctx.print(JSON.stringify(config, null, 2));
14
+ },
15
+ }),
16
+ command("app-sign-in config set", {
17
+ summary: "Save app sign-in settings; incomplete setup keeps pairing and sign-in unavailable",
18
+ flags: {
19
+ config: flag.input({ required: true, description: "JSON with enabled, origin and adminPairing: --config, --config-file or --stdin" }),
20
+ yes: confirmFlag("Confirm app sign-in configuration and trusted website changes"),
21
+ },
22
+ async run({ ctx, flags }) {
23
+ if (!flags.yes)
24
+ throw new Error(cliText(ctx, { en: "App sign-in changes require --yes.", de: "Änderungen an der App-Anmeldung erfordern --yes." }));
25
+ const input = await readCliInput(flags.config, { required: true, label: "App sign-in configuration" });
26
+ const config = Configuration.parse(JSON.parse(input ?? ""));
27
+ await ctx.readJson(
28
+ await ctx.fetch(path, {
29
+ method: "PUT",
30
+ headers: { "content-type": "application/json" },
31
+ body: JSON.stringify({
32
+ updates: {
33
+ "user.app_approval.enabled": config.enabled,
34
+ "user.app_approval.origin": config.origin,
35
+ "user.app_approval.admin_pairing": config.adminPairing,
36
+ },
37
+ }),
38
+ }),
39
+ );
40
+ if (!printStructured(ctx, { saved: true }))
41
+ ctx.print(
42
+ cliText(ctx, {
43
+ en: "App sign-in settings saved. Check the saved configuration status in Administration → Sign-in. This does not verify the PWA.",
44
+ de: "App-Anmeldung gespeichert. Prüfe den Konfigurationsstatus unter Administration → Anmeldung. Die PWA wird damit nicht geprüft.",
45
+ }),
46
+ );
47
+ },
48
+ }),
49
+ ];