@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,499 @@
1
+ import type { AccessEntry, EntityListItem, PermissionLevel, Principal } from "../contracts";
2
+ import { arg, command, confirmFlag, flag, paginationFlags } from "./commands";
3
+ import type { CloudCliContext, CloudCliTableColumn } from "./index";
4
+
5
+ type GrantablePermission = Exclude<PermissionLevel, "none">;
6
+ type AccessPermission = GrantablePermission;
7
+
8
+ type PaginationResponse = {
9
+ has_next?: boolean;
10
+ hasNext?: boolean;
11
+ };
12
+
13
+ type EntitiesResponse = {
14
+ items: EntityListItem[];
15
+ pagination?: PaginationResponse;
16
+ };
17
+
18
+ export type AccessResource = {
19
+ id: string;
20
+ label: string;
21
+ };
22
+
23
+ export type AccessCommandResourceResolver<TResource extends AccessResource> = (ctx: CloudCliContext, args: string[]) => Promise<TResource>;
24
+
25
+ export type AccessCommandAdapter<TResource extends AccessResource> = {
26
+ resourceLabel: string;
27
+ resourceArgLabel?: string;
28
+ resourceArgDescription?: string;
29
+ resolveResource: AccessCommandResourceResolver<TResource>;
30
+ list: (ctx: CloudCliContext, resource: TResource) => Promise<AccessEntry[]>;
31
+ grant: (ctx: CloudCliContext, resource: TResource, principal: Principal, permission: AccessPermission) => Promise<AccessEntry>;
32
+ update: (ctx: CloudCliContext, resource: TResource, accessId: string, permission: AccessPermission) => Promise<void>;
33
+ revoke: (ctx: CloudCliContext, resource: TResource, accessId: string) => Promise<void>;
34
+ allowedPermissions?: readonly AccessPermission[];
35
+ allowPublic?: boolean;
36
+ allowAuthenticated?: boolean;
37
+ allowServiceAccounts?: boolean;
38
+ examples?: {
39
+ list?: readonly string[];
40
+ grant?: readonly string[];
41
+ set?: readonly string[];
42
+ revoke?: readonly string[];
43
+ searchPrincipals?: readonly string[];
44
+ };
45
+ };
46
+
47
+ type PrincipalFlags = {
48
+ user?: string;
49
+ group?: string;
50
+ serviceAccount?: string;
51
+ authenticated?: boolean;
52
+ public?: boolean;
53
+ };
54
+
55
+ const DEFAULT_ALLOWED_PERMISSIONS = ["read", "write", "admin"] as const satisfies readonly GrantablePermission[];
56
+ const PRINCIPAL_KINDS = ["user", "group", "service_account"] as const;
57
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
58
+ type PrincipalKind = (typeof PRINCIPAL_KINDS)[number];
59
+
60
+ const isUuid = (value: string): boolean => UUID_RE.test(value);
61
+
62
+ const queryString = (values: Record<string, string | number | boolean | undefined>): string => {
63
+ const params = new URLSearchParams();
64
+ for (const [key, value] of Object.entries(values)) {
65
+ if (value !== undefined) params.set(key, String(value));
66
+ }
67
+ const rendered = params.toString();
68
+ return rendered ? `?${rendered}` : "";
69
+ };
70
+
71
+ const normalizeAllowedPermissions = (allowed: readonly AccessPermission[] | undefined): readonly AccessPermission[] =>
72
+ allowed && allowed.length > 0 ? allowed : DEFAULT_ALLOWED_PERMISSIONS;
73
+
74
+ const permissionRank = (permission: PermissionLevel): number => {
75
+ switch (permission) {
76
+ case "none":
77
+ return 0;
78
+ case "read":
79
+ return 1;
80
+ case "write":
81
+ return 2;
82
+ case "admin":
83
+ return 3;
84
+ }
85
+ };
86
+
87
+ const assertAllowedPermission = (permission: AccessPermission, allowed: readonly AccessPermission[]) => {
88
+ if (!allowed.includes(permission)) throw new Error(`Permission must be one of: ${allowed.join(", ")}.`);
89
+ };
90
+
91
+ const principalFlagCount = (flags: PrincipalFlags): number =>
92
+ [flags.user, flags.group, flags.serviceAccount, flags.authenticated, flags.public].filter(Boolean).length;
93
+
94
+ const principalKey = (principal: Principal): string => {
95
+ switch (principal.type) {
96
+ case "user":
97
+ return `user:${principal.userId}`;
98
+ case "group":
99
+ return `group:${principal.groupId}`;
100
+ case "service_account":
101
+ return `service_account:${principal.serviceAccountId}`;
102
+ case "authenticated":
103
+ return "authenticated";
104
+ case "public":
105
+ return "public";
106
+ }
107
+ };
108
+
109
+ const entryDisplayName = (entry: AccessEntry): string => {
110
+ if (entry.displayName) return entry.displayName;
111
+ switch (entry.principal.type) {
112
+ case "user":
113
+ return entry.principal.userId;
114
+ case "group":
115
+ return entry.principal.groupId;
116
+ case "service_account":
117
+ return entry.principal.serviceAccountId;
118
+ case "authenticated":
119
+ return "All users (incl. guests)";
120
+ case "public":
121
+ return "Public";
122
+ }
123
+ };
124
+
125
+ const formatEntityCandidate = (item: EntityListItem): string => {
126
+ if (item.kind === "user") return `${item.user.displayName} (${item.user.uid}${item.user.mail ? `, ${item.user.mail}` : ""})`;
127
+ if (item.kind === "group") return `${item.group.name} (${item.group.id})`;
128
+ return `${item.serviceAccount.name} (${item.serviceAccount.id})`;
129
+ };
130
+
131
+ const exactEntityMatches = (items: EntityListItem[], kind: (typeof PRINCIPAL_KINDS)[number], ref: string): EntityListItem[] =>
132
+ items.filter((item) => {
133
+ if (item.kind !== kind) return false;
134
+ if (kind === "user" && item.kind === "user") {
135
+ return item.user.id === ref || item.user.uid === ref || item.user.mail === ref || item.user.displayName === ref;
136
+ }
137
+ if (kind === "group" && item.kind === "group") return item.group.id === ref || item.group.name === ref;
138
+ if (kind === "service_account" && item.kind === "service_account") {
139
+ return item.serviceAccount.id === ref || item.serviceAccount.name === ref;
140
+ }
141
+ return false;
142
+ });
143
+
144
+ export const listAccessPrincipalEntities = async (
145
+ ctx: CloudCliContext,
146
+ options: {
147
+ search?: string;
148
+ kinds?: readonly (typeof PRINCIPAL_KINDS)[number][];
149
+ page?: number;
150
+ perPage?: number;
151
+ },
152
+ ): Promise<EntitiesResponse> =>
153
+ ctx.readJson<EntitiesResponse>(
154
+ await ctx.fetch(
155
+ `/api/accounts/entities${queryString({
156
+ page: options.page ?? 1,
157
+ per_page: options.perPage ?? 20,
158
+ search: options.search,
159
+ kinds: (options.kinds ?? PRINCIPAL_KINDS).join(","),
160
+ })}`,
161
+ ),
162
+ );
163
+
164
+ const resolveEntityPrincipal = async (ctx: CloudCliContext, kind: PrincipalKind, ref: string): Promise<Principal> => {
165
+ if (isUuid(ref)) {
166
+ if (kind === "user") return { type: "user", userId: ref };
167
+ if (kind === "group") return { type: "group", groupId: ref };
168
+ return { type: "service_account", serviceAccountId: ref };
169
+ }
170
+
171
+ const exact: EntityListItem[] = [];
172
+ const seen: EntityListItem[] = [];
173
+ let page = 1;
174
+
175
+ for (;;) {
176
+ const payload = await listAccessPrincipalEntities(ctx, {
177
+ search: ref,
178
+ kinds: [kind],
179
+ page,
180
+ perPage: 100,
181
+ });
182
+ const items = payload.items.filter((item) => item.kind === kind);
183
+ seen.push(...items);
184
+ exact.push(...exactEntityMatches(items, kind, ref));
185
+ if (!(payload.pagination?.has_next ?? payload.pagination?.hasNext)) break;
186
+ page += 1;
187
+ }
188
+
189
+ if (exact.length === 1) {
190
+ const item = exact[0]!;
191
+ if (item.kind === "user") return { type: "user", userId: item.user.id };
192
+ if (item.kind === "group") return { type: "group", groupId: item.group.id };
193
+ return { type: "service_account", serviceAccountId: item.serviceAccount.id };
194
+ }
195
+
196
+ if (exact.length > 1)
197
+ throw new Error(`${kind.replace("_", " ")} "${ref}" is ambiguous. Use one of: ${exact.map(formatEntityCandidate).join(", ")}`);
198
+
199
+ const candidates = seen.slice(0, 5).map(formatEntityCandidate).join(", ");
200
+ throw new Error(
201
+ candidates
202
+ ? `${kind.replace("_", " ")} "${ref}" was not found by exact id/name. Similar matches: ${candidates}`
203
+ : `${kind.replace("_", " ")} "${ref}" was not found.`,
204
+ );
205
+ };
206
+
207
+ export const resolveAccessPrincipal = async (
208
+ ctx: CloudCliContext,
209
+ flags: PrincipalFlags,
210
+ options: { allowPublic?: boolean; allowAuthenticated?: boolean; allowServiceAccounts?: boolean } = {},
211
+ ): Promise<Principal> => {
212
+ const count = principalFlagCount(flags);
213
+ if (count !== 1) {
214
+ const allowedFlags = [
215
+ "--user",
216
+ "--group",
217
+ ...(options.allowAuthenticated === false ? [] : ["--authenticated"]),
218
+ ...(options.allowPublic === true ? ["--public"] : []),
219
+ ...(options.allowServiceAccounts === true ? ["--service-account"] : []),
220
+ ];
221
+ throw new Error(`Pass exactly one principal flag: ${allowedFlags.join(", ")}.`);
222
+ }
223
+ if (flags.public && options.allowPublic !== true) throw new Error("This resource does not allow public access grants.");
224
+ if (flags.authenticated && options.allowAuthenticated === false) {
225
+ throw new Error("This resource does not allow authenticated-audience grants.");
226
+ }
227
+ if (flags.serviceAccount && options.allowServiceAccounts !== true) {
228
+ throw new Error("Service-account grants are hidden by default. Enable allowServiceAccounts for this access command.");
229
+ }
230
+ if (flags.authenticated) return { type: "authenticated" };
231
+ if (flags.public) return { type: "public" };
232
+ if (flags.user) return resolveEntityPrincipal(ctx, "user", flags.user);
233
+ if (flags.group) return resolveEntityPrincipal(ctx, "group", flags.group);
234
+ return resolveEntityPrincipal(ctx, "service_account", flags.serviceAccount!);
235
+ };
236
+
237
+ const accessRows = (entries: AccessEntry[], options: { includeServiceAccounts?: boolean } = {}) =>
238
+ entries
239
+ .filter((entry) => options.includeServiceAccounts || entry.principal.type !== "service_account")
240
+ .sort((a, b) => {
241
+ const rank = permissionRank(b.permission) - permissionRank(a.permission);
242
+ if (rank !== 0) return rank;
243
+ return entryDisplayName(a).localeCompare(entryDisplayName(b));
244
+ })
245
+ .map((entry) => ({
246
+ accessId: entry.id,
247
+ principal: entryDisplayName(entry),
248
+ type: entry.principal.type,
249
+ permission: entry.permission,
250
+ createdAt: entry.createdAt,
251
+ }));
252
+
253
+ const printStructured = (ctx: CloudCliContext, value: unknown): boolean => {
254
+ if (ctx.options.output === "json") ctx.json(value);
255
+ else if (ctx.options.output === "jsonl") ctx.jsonLine(value);
256
+ else return false;
257
+ return true;
258
+ };
259
+
260
+ export const printAccessEntries = (
261
+ ctx: CloudCliContext,
262
+ entries: AccessEntry[],
263
+ options: { includeServiceAccounts?: boolean; jsonValue?: unknown } = {},
264
+ ) => {
265
+ if (printStructured(ctx, options.jsonValue ?? entries)) return;
266
+ const rows = accessRows(entries, options);
267
+ if (rows.length === 0) {
268
+ ctx.print("No direct grants.");
269
+ return;
270
+ }
271
+ ctx.table(rows, [
272
+ { key: "principal", label: "PRINCIPAL" },
273
+ { key: "type", label: "TYPE" },
274
+ { key: "permission", label: "PERMISSION" },
275
+ { key: "accessId", label: "ACCESS ID" },
276
+ ]);
277
+ };
278
+
279
+ const printPrincipalEntities = (ctx: CloudCliContext, payload: EntitiesResponse) => {
280
+ if (printStructured(ctx, payload)) return;
281
+ const rows = payload.items.map((item) => {
282
+ if (item.kind === "user") {
283
+ return {
284
+ kind: "user",
285
+ id: item.user.id,
286
+ name: item.user.displayName,
287
+ handle: item.user.uid,
288
+ detail: item.user.mail ?? "",
289
+ };
290
+ }
291
+ if (item.kind === "group") {
292
+ return {
293
+ kind: "group",
294
+ id: item.group.id,
295
+ name: item.group.name,
296
+ handle: item.group.provider,
297
+ detail: item.group.description ?? "",
298
+ };
299
+ }
300
+ return {
301
+ kind: "service_account",
302
+ id: item.serviceAccount.id,
303
+ name: item.serviceAccount.name,
304
+ handle: item.serviceAccount.kind,
305
+ detail: item.serviceAccount.appId ?? "",
306
+ };
307
+ });
308
+ ctx.table(rows, [
309
+ { key: "kind", label: "KIND" },
310
+ { key: "name", label: "NAME" },
311
+ { key: "handle", label: "HANDLE" },
312
+ { key: "id", label: "ID" },
313
+ ] as CloudCliTableColumn<(typeof rows)[number]>[]);
314
+ };
315
+
316
+ const principalFlags = (options: {
317
+ includePublicFlag: boolean;
318
+ includeAuthenticatedFlag: boolean;
319
+ includeServiceAccountFlag: boolean;
320
+ }) => ({
321
+ user: flag.string({ description: "User id, uid, email, or exact display name" }),
322
+ group: flag.string({ description: "Group id or exact name" }),
323
+ ...(options.includeServiceAccountFlag
324
+ ? { serviceAccount: flag.string({ name: "service-account", description: "Service account id or exact name" }) }
325
+ : {}),
326
+ ...(options.includeAuthenticatedFlag ? { authenticated: flag.boolean({ description: "Signed-in users, including guests" }) } : {}),
327
+ ...(options.includePublicFlag ? { public: flag.boolean({ description: "Anyone with the link, including anonymous users" }) } : {}),
328
+ });
329
+
330
+ const accessIdFlag = {
331
+ accessId: flag.string({ name: "access-id", description: "Access entry id from `access list`" }),
332
+ };
333
+
334
+ export const createAccessCommands = <TResource extends AccessResource>(adapter: AccessCommandAdapter<TResource>) => {
335
+ const allowed = normalizeAllowedPermissions(adapter.allowedPermissions);
336
+ const searchableKinds = adapter.allowServiceAccounts ? PRINCIPAL_KINDS : (["user", "group"] as const);
337
+ const principalFlagOptions = {
338
+ includePublicFlag: adapter.allowPublic === true,
339
+ includeAuthenticatedFlag: adapter.allowAuthenticated !== false,
340
+ includeServiceAccountFlag: adapter.allowServiceAccounts === true,
341
+ };
342
+ const resolve = (ctx: CloudCliContext, args: string[]) => adapter.resolveResource(ctx, args);
343
+ const resourceArgs = {
344
+ args: arg.rest({
345
+ valueLabel: adapter.resourceArgLabel ?? adapter.resourceLabel,
346
+ description: adapter.resourceArgDescription ?? `Optional ${adapter.resourceLabel} reference consumed by the app.`,
347
+ }),
348
+ };
349
+
350
+ const list = command("access list", {
351
+ summary: `List direct ${adapter.resourceLabel} grants`,
352
+ description:
353
+ "Shows the same direct access entries as the Cloud PermissionEditor. Inherited/effective access is intentionally not expanded here.",
354
+ args: resourceArgs,
355
+ flags: {
356
+ includeServiceAccounts: flag.boolean({
357
+ name: "include-service-accounts",
358
+ description: "Include resource-bound service account grants that the UI normally hides.",
359
+ }),
360
+ },
361
+ examples: adapter.examples?.list,
362
+ async run({ ctx, args, flags }) {
363
+ const resource = await resolve(ctx, args.args);
364
+ const entries = await adapter.list(ctx, resource);
365
+ printAccessEntries(ctx, entries, {
366
+ includeServiceAccounts: flags.includeServiceAccounts,
367
+ jsonValue: { resource, entries },
368
+ });
369
+ },
370
+ });
371
+
372
+ const grant = command("access grant", {
373
+ summary: `Grant direct ${adapter.resourceLabel} access`,
374
+ description: "Creates a new direct grant. If the principal already has a direct grant, use `access set` to update it idempotently.",
375
+ args: resourceArgs,
376
+ flags: {
377
+ ...principalFlags(principalFlagOptions),
378
+ permission: flag.enum(allowed, { required: true, description: `Permission to grant. Allowed: ${allowed.join(", ")}` }),
379
+ },
380
+ examples: adapter.examples?.grant,
381
+ async run({ ctx, args, flags }) {
382
+ const resource = await resolve(ctx, args.args);
383
+ const permission = flags.permission as AccessPermission;
384
+ assertAllowedPermission(permission, allowed);
385
+ const principal = await resolveAccessPrincipal(ctx, flags as PrincipalFlags, adapter);
386
+ const entry = await adapter.grant(ctx, resource, principal, permission);
387
+ if (!printStructured(ctx, { resource, entry }))
388
+ ctx.print(`Granted ${permission} on ${resource.label} to ${entryDisplayName(entry)}.`);
389
+ },
390
+ });
391
+
392
+ const set = command("access set", {
393
+ summary: `Create or update direct ${adapter.resourceLabel} access`,
394
+ description:
395
+ "Idempotent agent-friendly command: with --access-id it patches that entry; otherwise it resolves the principal, updates an existing direct grant, or creates one.",
396
+ args: resourceArgs,
397
+ flags: {
398
+ ...principalFlags(principalFlagOptions),
399
+ ...accessIdFlag,
400
+ permission: flag.enum(allowed, { required: true, description: `Permission to set. Allowed: ${allowed.join(", ")}` }),
401
+ },
402
+ examples: adapter.examples?.set,
403
+ async run({ ctx, args, flags }) {
404
+ const resource = await resolve(ctx, args.args);
405
+ const permission = flags.permission as AccessPermission;
406
+ assertAllowedPermission(permission, allowed);
407
+
408
+ if (flags.accessId) {
409
+ await adapter.update(ctx, resource, flags.accessId, permission);
410
+ if (!printStructured(ctx, { resource, accessId: flags.accessId, permission, action: "updated" })) {
411
+ ctx.print(`Updated ${flags.accessId} to ${permission} on ${resource.label}.`);
412
+ }
413
+ return;
414
+ }
415
+
416
+ const principal = await resolveAccessPrincipal(ctx, flags as PrincipalFlags, adapter);
417
+ const entries = await adapter.list(ctx, resource);
418
+ const existing = entries.find((entry) => principalKey(entry.principal) === principalKey(principal));
419
+ if (existing) {
420
+ await adapter.update(ctx, resource, existing.id, permission);
421
+ if (!printStructured(ctx, { resource, accessId: existing.id, permission, action: "updated" })) {
422
+ ctx.print(`Updated ${entryDisplayName(existing)} to ${permission} on ${resource.label}.`);
423
+ }
424
+ return;
425
+ }
426
+ const entry = await adapter.grant(ctx, resource, principal, permission);
427
+ if (!printStructured(ctx, { resource, entry, action: "created" })) {
428
+ ctx.print(`Granted ${permission} on ${resource.label} to ${entryDisplayName(entry)}.`);
429
+ }
430
+ },
431
+ });
432
+
433
+ const revoke = command("access revoke", {
434
+ summary: `Revoke direct ${adapter.resourceLabel} access`,
435
+ description:
436
+ "Deletes one direct grant. Pass --access-id from `access list`, or pass exactly one principal flag to resolve the matching direct grant.",
437
+ args: resourceArgs,
438
+ flags: {
439
+ ...principalFlags(principalFlagOptions),
440
+ ...accessIdFlag,
441
+ yes: confirmFlag("Confirm access revocation"),
442
+ },
443
+ examples: adapter.examples?.revoke,
444
+ async run({ ctx, args, flags }) {
445
+ if (!flags.yes) throw new Error("Refusing to revoke access without --yes.");
446
+ const resource = await resolve(ctx, args.args);
447
+ let accessId = flags.accessId;
448
+ let label = accessId;
449
+
450
+ if (!accessId) {
451
+ const principal = await resolveAccessPrincipal(ctx, flags as PrincipalFlags, adapter);
452
+ const entries = await adapter.list(ctx, resource);
453
+ const entry = entries.find((candidate) => principalKey(candidate.principal) === principalKey(principal));
454
+ if (!entry) throw new Error("No direct grant for that principal.");
455
+ accessId = entry.id;
456
+ label = entryDisplayName(entry);
457
+ } else if (principalFlagCount(flags as PrincipalFlags) > 0) {
458
+ throw new Error("Pass either --access-id or one principal flag, not both.");
459
+ }
460
+
461
+ await adapter.revoke(ctx, resource, accessId);
462
+ if (!printStructured(ctx, { resource, accessId, action: "revoked" })) {
463
+ ctx.print(`Revoked access for ${label} on ${resource.label}.`);
464
+ }
465
+ },
466
+ });
467
+
468
+ const searchPrincipals = command("access search-principals", {
469
+ summary: "Search principals for access grants",
470
+ description: "Uses the same `/api/accounts/entities` principal search endpoint as the Cloud PermissionEditor.",
471
+ args: {
472
+ query: arg.required({ description: "Search text; exact names are safest for grant/set commands." }),
473
+ },
474
+ flags: {
475
+ kind: flag.stringList({
476
+ separator: ",",
477
+ default: searchableKinds,
478
+ description: `Comma-separated principal kinds. Allowed: ${searchableKinds.join(", ")}`,
479
+ }),
480
+ ...paginationFlags({ defaultPerPage: 20, maxPerPage: 100 }),
481
+ },
482
+ examples: adapter.examples?.searchPrincipals ?? [`cld <app> access search-principals val --kind user,group`],
483
+ async run({ ctx, args, flags }) {
484
+ const kinds = flags.kind.filter((kind): kind is (typeof PRINCIPAL_KINDS)[number] =>
485
+ (searchableKinds as readonly string[]).includes(kind),
486
+ );
487
+ if (kinds.length !== flags.kind.length) throw new Error(`--kind must contain only: ${searchableKinds.join(", ")}.`);
488
+ const payload = await listAccessPrincipalEntities(ctx, {
489
+ search: args.query,
490
+ kinds,
491
+ page: flags.page,
492
+ perPage: flags.perPage,
493
+ });
494
+ printPrincipalEntities(ctx, payload);
495
+ },
496
+ });
497
+
498
+ return [list, grant, set, revoke, searchPrincipals];
499
+ };