@k2b/cloud 0.6.0 → 0.8.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 (349) hide show
  1. package/README.md +2 -2
  2. package/package.json +22 -11
  3. package/scripts/README.md +10 -0
  4. package/scripts/browser-performance.ts +14 -0
  5. package/scripts/build-pdf-renderer.ts +39 -0
  6. package/scripts/build.ts +20 -35
  7. package/scripts/preload.ts +16 -12
  8. package/scripts/sync-recovery-smoke.ts +22 -6
  9. package/src/_internal/app-presentation.ts +14 -2
  10. package/src/_internal/build-metadata.ts +8 -1
  11. package/src/_internal/capabilities.ts +131 -7
  12. package/src/_internal/capability-streams.ts +81 -0
  13. package/src/_internal/define-app.ts +80 -37
  14. package/src/_internal/heartbeat.ts +4 -0
  15. package/src/_internal/help-catalog.ts +27 -172
  16. package/src/_internal/help.ts +13 -76
  17. package/src/_internal/page-responses.ts +2 -0
  18. package/src/_internal/postgres-application-name.ts +30 -0
  19. package/src/_internal/process-identity.ts +15 -0
  20. package/src/_internal/process-sync.ts +1 -1
  21. package/src/_internal/readiness.ts +4 -1
  22. package/src/_internal/registry-validation.ts +29 -25
  23. package/src/_internal/registry.ts +2 -53
  24. package/src/_internal/runtime-context.ts +5 -16
  25. package/src/_internal/server-timing.ts +13 -0
  26. package/src/_internal/status-preserving-ssr.ts +18 -6
  27. package/src/_internal/web-vitals-asset.ts +10 -0
  28. package/src/access/PermissionEditor.tsx +18 -151
  29. package/src/access/PrincipalPicker.tsx +110 -0
  30. package/src/access/ResourceApiKeys.tsx +1 -1
  31. package/src/access/ui.ts +1 -0
  32. package/src/ai/admin.ts +14 -13
  33. package/src/ai/assistant-models.ts +12 -1
  34. package/src/ai/audio-format.ts +34 -0
  35. package/src/ai/audio-tool.ts +90 -0
  36. package/src/ai/browser-code-contracts.ts +201 -0
  37. package/src/ai/browser.ts +4 -0
  38. package/src/ai/capabilities.ts +55 -36
  39. package/src/ai/capability-execution.ts +47 -12
  40. package/src/ai/chat/blocks.tsx +229 -90
  41. package/src/ai/chat/builtin-tools.tsx +2 -4
  42. package/src/ai/chat/capability-result.ts +15 -0
  43. package/src/ai/chat/capability-table.tsx +2 -10
  44. package/src/ai/chat/composer-adapter.ts +83 -3
  45. package/src/ai/chat/message-actions.tsx +8 -7
  46. package/src/ai/chat/message-utils.ts +25 -1
  47. package/src/ai/chat/messages.ts +2 -0
  48. package/src/ai/chat/presentation.tsx +31 -47
  49. package/src/ai/chat/primitives.tsx +43 -1
  50. package/src/ai/chat/tool-disclosure.tsx +21 -2
  51. package/src/ai/chat/tool-groups.ts +58 -0
  52. package/src/ai/chat-quotas.ts +25 -0
  53. package/src/ai/chat-task-contracts.ts +14 -10
  54. package/src/ai/chat-tasks.ts +297 -43
  55. package/src/ai/client/controller.ts +165 -39
  56. package/src/ai/client/file-source.ts +12 -6
  57. package/src/ai/client/live-connection.ts +1 -0
  58. package/src/ai/client/projection.ts +29 -11
  59. package/src/ai/client/transport.ts +6 -0
  60. package/src/ai/code-capability-routes.ts +105 -0
  61. package/src/ai/code-capability-transport.ts +39 -0
  62. package/src/ai/code-execution.ts +53 -0
  63. package/src/ai/code-mode-skill.ts +118 -0
  64. package/src/ai/code-runtime-tools.ts +179 -0
  65. package/src/ai/code-source-contracts.ts +270 -0
  66. package/src/ai/code-source-tools.ts +188 -0
  67. package/src/ai/compaction.ts +27 -6
  68. package/src/ai/data-analysis-skill.ts +10 -0
  69. package/src/ai/default-tools.ts +99 -3
  70. package/src/ai/dictation-runtime.ts +171 -0
  71. package/src/ai/dictations.ts +188 -0
  72. package/src/ai/draft-content.ts +49 -0
  73. package/src/ai/enrich.ts +6 -0
  74. package/src/ai/executor.ts +189 -33
  75. package/src/ai/fetch-file-tool.ts +2 -2
  76. package/src/ai/file-content-version.ts +27 -0
  77. package/src/ai/file-context.ts +2 -1
  78. package/src/ai/file-media-type.ts +12 -0
  79. package/src/ai/file-reference-contracts.ts +15 -0
  80. package/src/ai/file-tools.ts +8 -1
  81. package/src/ai/files-store.ts +212 -71
  82. package/src/ai/fixtures/vision-encrypted.pdf +0 -0
  83. package/src/ai/grids-skill.ts +42 -10
  84. package/src/ai/http.ts +26 -8
  85. package/src/ai/index.ts +26 -3
  86. package/src/ai/inference-calls.ts +197 -0
  87. package/src/ai/live-events.ts +5 -1
  88. package/src/ai/live.ts +1 -1
  89. package/src/ai/markdown-pdf-tool.ts +2 -2
  90. package/src/ai/memories.ts +30 -27
  91. package/src/ai/memory-learning-runs.ts +1 -1
  92. package/src/ai/memory-learning.ts +64 -32
  93. package/src/ai/memory-tool.ts +1 -5
  94. package/src/ai/memory-workflow-evidence.ts +9 -4
  95. package/src/ai/message-queue.ts +178 -0
  96. package/src/ai/migrate.ts +189 -11
  97. package/src/ai/model-pricing.ts +43 -0
  98. package/src/ai/pdf-render-worker.ts +75 -0
  99. package/src/ai/pdf-render.fixture.ts +28 -0
  100. package/src/ai/pdf-render.ts +77 -0
  101. package/src/ai/projects-routes.ts +18 -43
  102. package/src/ai/projects.ts +33 -14
  103. package/src/ai/protocol.ts +3 -0
  104. package/src/ai/provider.ts +1 -8
  105. package/src/ai/quota-provider.ts +192 -0
  106. package/src/ai/quota-report.ts +152 -0
  107. package/src/ai/quotas-migrate.ts +45 -0
  108. package/src/ai/quotas.ts +168 -0
  109. package/src/ai/routes.ts +241 -11
  110. package/src/ai/run-timeout.ts +12 -0
  111. package/src/ai/runtime-tools.ts +7 -5
  112. package/src/ai/runtime.ts +74 -17
  113. package/src/ai/settings.ts +36 -8
  114. package/src/ai/short-id.ts +4 -5
  115. package/src/ai/skill-catalog.ts +0 -10
  116. package/src/ai/skill-search.ts +58 -0
  117. package/src/ai/skill-seeds.ts +114 -20
  118. package/src/ai/skill-tool.ts +21 -5
  119. package/src/ai/skills-routes.ts +49 -4
  120. package/src/ai/skills.ts +358 -163
  121. package/src/ai/store.ts +416 -201
  122. package/src/ai/stream.ts +5 -0
  123. package/src/ai/structured-runs.ts +4 -3
  124. package/src/ai/structured.ts +12 -1
  125. package/src/ai/system-prompt.ts +14 -2
  126. package/src/ai/task-contracts.ts +84 -0
  127. package/src/ai/task-execution.ts +92 -0
  128. package/src/ai/timeline.ts +2 -5
  129. package/src/ai/todo-contracts.ts +32 -0
  130. package/src/ai/todo-tool.ts +19 -0
  131. package/src/ai/tool-audit.ts +30 -40
  132. package/src/ai/tools.ts +6 -0
  133. package/src/ai/transcription.ts +202 -0
  134. package/src/ai/turn-timing.ts +114 -0
  135. package/src/ai/types.ts +58 -10
  136. package/src/ai/ui.tsx +3 -0
  137. package/src/ai/usage.ts +118 -118
  138. package/src/ai/vision-tool.ts +60 -10
  139. package/src/api/admin-ai-projects.ts +2 -2
  140. package/src/api/admin-ai-quotas.ts +80 -0
  141. package/src/api/admin-ai-skills.ts +48 -5
  142. package/src/api/admin-ai-usage.ts +2 -2
  143. package/src/api/admin-core-settings.ts +25 -0
  144. package/src/api/admin-identity.ts +91 -51
  145. package/src/api/admin-linux-identities.ts +10 -4
  146. package/src/api/admin-rail.ts +58 -0
  147. package/src/api/announcements.ts +14 -0
  148. package/src/api/app-approval.ts +2 -2
  149. package/src/api/auth.ts +1 -1
  150. package/src/api/capabilities.ts +324 -43
  151. package/src/api/capability-streams.ts +262 -0
  152. package/src/api/help.ts +8 -44
  153. package/src/api/index.ts +8 -2
  154. package/src/api/mcp.ts +45 -34
  155. package/src/api/me-web-vitals.ts +35 -0
  156. package/src/api/me.ts +2 -0
  157. package/src/api/search/schemas.ts +26 -15
  158. package/src/api/search.bench.ts +1 -1
  159. package/src/api/search.ts +54 -17
  160. package/src/browser/CloudResourceSearch.tsx +640 -702
  161. package/src/browser/app-approval-vault.ts +19 -7
  162. package/src/browser/command-bridge.ts +109 -0
  163. package/src/browser/command-shortcuts.ts +76 -0
  164. package/src/browser/commands.ts +67 -0
  165. package/src/browser/navigation-search.ts +48 -0
  166. package/src/browser/notifications.ts +1 -1
  167. package/src/browser/resource-picker.tsx +5 -18
  168. package/src/browser/resource-search-dialog.ts +9 -0
  169. package/src/browser/resource-search-input.ts +46 -0
  170. package/src/browser/resource-search-messages.ts +76 -40
  171. package/src/browser/resource-search.ts +7 -0
  172. package/src/browser/search-bridge.ts +102 -0
  173. package/src/browser/search-commands.ts +59 -0
  174. package/src/browser/search.ts +13 -0
  175. package/src/browser/spotlight-position.ts +208 -0
  176. package/src/browser/testing.ts +6 -0
  177. package/src/browser/web-vitals.ts +25 -0
  178. package/src/capabilities/claims.ts +179 -0
  179. package/src/capabilities/client.ts +34 -0
  180. package/src/capabilities/command-link.ts +16 -0
  181. package/src/capabilities/executions.ts +298 -0
  182. package/src/capabilities/migrate.ts +81 -0
  183. package/src/capabilities/server.ts +116 -35
  184. package/src/capabilities/stream-body.ts +16 -0
  185. package/src/capabilities/streams.ts +28 -0
  186. package/src/cli/admin/ai-quotas.ts +161 -0
  187. package/src/cli/admin/ai-skills.ts +64 -0
  188. package/src/cli/admin/ai-usage.ts +53 -30
  189. package/src/cli/admin/app-credentials.ts +77 -0
  190. package/src/cli/admin/data.ts +17 -0
  191. package/src/cli/admin/index.ts +10 -1
  192. package/src/cli/admin/instance.ts +2 -2
  193. package/src/cli/admin/linux.ts +4 -2
  194. package/src/cli/admin/sync.ts +1 -1
  195. package/src/cli/capabilities.ts +42 -0
  196. package/src/cli/capability-streams.ts +25 -0
  197. package/src/cli/index.ts +3 -2
  198. package/src/config/define-env.ts +97 -0
  199. package/src/config/env.ts +147 -51
  200. package/src/config/index.ts +3 -1
  201. package/src/contracts/app.ts +23 -3
  202. package/src/contracts/capabilities.ts +75 -5
  203. package/src/contracts/capability-streams.ts +46 -0
  204. package/src/contracts/commands.ts +49 -0
  205. package/src/contracts/index.ts +5 -2
  206. package/src/contracts/rail-admin.ts +38 -0
  207. package/src/contracts/rail-preferences.ts +16 -0
  208. package/src/contracts/registry.ts +5 -27
  209. package/src/contracts/settings-types.ts +1 -1
  210. package/src/contracts/shared.ts +18 -5
  211. package/src/contracts/web-vitals.ts +27 -0
  212. package/src/desktop/index.ts +1 -0
  213. package/src/desktop/solid.tsx +1 -1
  214. package/src/index.ts +8 -6
  215. package/src/server/index.ts +3 -0
  216. package/src/server/middleware/auth.ts +3 -2
  217. package/src/server/middleware/route-template.ts +9 -3
  218. package/src/server/middleware/runtime.ts +2 -1
  219. package/src/server/middleware/settings.ts +17 -11
  220. package/src/server/ratelimit.ts +1 -1
  221. package/src/server/services/access-revision.ts +10 -0
  222. package/src/server/services/access.ts +3 -1
  223. package/src/server/services/index.ts +1 -0
  224. package/src/services/account-category-policy.ts +9 -0
  225. package/src/services/account-lifecycle/audit.ts +1 -1
  226. package/src/services/accounts/app.ts +12 -2
  227. package/src/services/accounts/email-write.ts +23 -0
  228. package/src/services/accounts/groups.ts +15 -4
  229. package/src/services/accounts/identities.ts +249 -0
  230. package/src/services/accounts/identity-reconciliation.ts +87 -0
  231. package/src/services/accounts/ipa-data.ts +2 -2
  232. package/src/services/accounts/local-groups.ts +2 -2
  233. package/src/services/accounts/notification-sender.ts +12 -2
  234. package/src/services/accounts/posix.ts +45 -29
  235. package/src/services/accounts/users.ts +2 -2
  236. package/src/services/announcements/index.ts +69 -8
  237. package/src/services/app-approval.ts +11 -10
  238. package/src/services/audit/index.ts +1 -1
  239. package/src/services/cache-fill.ts +35 -0
  240. package/src/services/help/index.ts +109 -0
  241. package/src/services/help/maintenance.ts +25 -0
  242. package/src/services/help/store.ts +180 -0
  243. package/src/services/help/types.ts +46 -0
  244. package/src/services/identity/invocation-actor.ts +2 -2
  245. package/src/services/identity/key-config.ts +8 -5
  246. package/src/services/identity/key-ring.ts +1 -1
  247. package/src/services/identity/runtime-config.ts +6 -5
  248. package/src/services/index.ts +15 -0
  249. package/src/services/ipa/posix.ts +1 -1
  250. package/src/services/ipa/sync.ts +1 -1
  251. package/src/services/ipa/users.ts +268 -221
  252. package/src/services/legal-consent.ts +1 -1
  253. package/src/services/logging/index.ts +15 -13
  254. package/src/services/logging/trace.ts +2 -1
  255. package/src/services/logging/web-vitals.ts +81 -0
  256. package/src/services/mandates/index.ts +21 -4
  257. package/src/services/mandates/policy.ts +165 -2
  258. package/src/services/notifications/batches.ts +125 -57
  259. package/src/services/notifications/browser.ts +12 -0
  260. package/src/services/notifications/index.ts +0 -2
  261. package/src/services/notifications/platform.ts +0 -4
  262. package/src/services/oauth-tokens.ts +3 -3
  263. package/src/services/pdf/gotenberg.ts +131 -72
  264. package/src/services/pdf/index.ts +11 -8
  265. package/src/services/providers/local/users.ts +25 -16
  266. package/src/services/public-http.ts +101 -0
  267. package/src/services/rail-shortcuts.ts +95 -0
  268. package/src/services/rail-snapshot.ts +53 -0
  269. package/src/services/request-cache-redis.ts +29 -0
  270. package/src/services/session/index.ts +15 -2
  271. package/src/services/session/user.ts +62 -37
  272. package/src/services/settings/app.ts +5 -1
  273. package/src/services/settings/core-settings.ts +26 -35
  274. package/src/services/settings/defaults.ts +5 -0
  275. package/src/services/settings/index.ts +3 -3
  276. package/src/services/settings/store.ts +58 -84
  277. package/src/services/webauthn.ts +1 -1
  278. package/src/shared/ai-costs.ts +42 -0
  279. package/src/shared/ai-platform-prompt.ts +1 -1
  280. package/src/shared/ai-quotas.ts +136 -0
  281. package/src/shared/ai-usage.ts +6 -16
  282. package/src/shared/app-presentation.ts +21 -15
  283. package/src/shared/capability-messages.ts +14 -0
  284. package/src/shared/help.ts +6 -42
  285. package/src/shared/index.ts +3 -0
  286. package/src/shared/markdown/extensions/info-blocks.ts +1 -1
  287. package/src/ssr/AdminLayout.tsx +7 -5
  288. package/src/ssr/AdminSidebar.tsx +30 -16
  289. package/src/ssr/AppLaunchpad.island.tsx +33 -136
  290. package/src/ssr/AppLaunchpadPanel.tsx +181 -0
  291. package/src/ssr/BrowserPushRegistration.island.tsx +12 -0
  292. package/src/ssr/GlobalSearchDialog.tsx +167 -20
  293. package/src/ssr/GlobalSearchTrigger.island.tsx +33 -22
  294. package/src/ssr/Layout.tsx +17 -6
  295. package/src/ssr/LayoutBreadcrumbs.island.tsx +3 -5
  296. package/src/ssr/LayoutFooter.tsx +1 -1
  297. package/src/ssr/LayoutHeader.tsx +46 -14
  298. package/src/ssr/LayoutHelp.tsx +22 -23
  299. package/src/ssr/{HotkeysHelpRail.island.tsx → LayoutHelpTrigger.island.tsx} +18 -12
  300. package/src/ssr/LayoutRail.tsx +17 -9
  301. package/src/ssr/MinimalLayout.tsx +1 -1
  302. package/src/ssr/MobileNavigation.tsx +71 -0
  303. package/src/ssr/MobileProfileActions.tsx +49 -0
  304. package/src/ssr/ProfilePreferences.island.tsx +3 -36
  305. package/src/ssr/RailApps.island.tsx +2 -2
  306. package/src/ssr/RailEditor.tsx +17 -2
  307. package/src/ssr/WorkspaceNavigation.island.tsx +7 -0
  308. package/src/ssr/WorkspaceNavigationProvider.tsx +16 -0
  309. package/src/ssr/admin-navigation.ts +11 -1
  310. package/src/ssr/help.ts +29 -0
  311. package/src/ssr/islands/SearchBar.tsx +67 -0
  312. package/src/ssr/islands/index.ts +3 -1
  313. package/src/ssr/layout-context.ts +2 -2
  314. package/src/ssr/layout-help-search.ts +15 -0
  315. package/src/ssr/mobile-menu-history.ts +70 -0
  316. package/src/ssr/platform-messages.ts +16 -8
  317. package/src/ssr/profile-actions.ts +42 -0
  318. package/src/ssr/rail-context.ts +8 -4
  319. package/src/ssr/rail-messages.ts +2 -0
  320. package/src/ssr/rail-navigation.ts +3 -3
  321. package/src/ssr/workspace-navigation.ts +75 -0
  322. package/src/styles/effects.css +6 -6
  323. package/src/styles/global.css +54 -0
  324. package/src/styles/input.css +43 -41
  325. package/src/styles/resource-search.css +505 -0
  326. package/src/styles/utilities-feedback.css +13 -0
  327. package/src/styles/utilities-layout.css +1 -5
  328. package/src/styles/utilities-navigation.css +3 -39
  329. package/src/types/ambient.d.ts +5 -0
  330. package/src/workflows/ai/index.ts +2 -2
  331. package/src/workflows/ai/runtime.ts +19 -90
  332. package/src/workflows/ai/store.ts +2 -0
  333. package/src/workflows/ai/types.ts +6 -82
  334. package/src/workflows/ai-actions.ts +16 -13
  335. package/src/workflows/definition.ts +10 -5
  336. package/src/workflows/store/actions.ts +44 -20
  337. package/src/workflows/store/index.ts +4 -2
  338. package/src/workflows/store/runs.ts +36 -0
  339. package/src/workflows/store/worker-pool.ts +55 -0
  340. package/src/workflows/store/worker-runtime.ts +90 -0
  341. package/src/ai/kit-skill.ts +0 -22
  342. package/src/ai/usage-migrate.ts +0 -81
  343. package/src/browser/notification-target.ts +0 -27
  344. package/src/contracts/notification-live.ts +0 -66
  345. package/src/server/services/freeipa/test-certificates.ts +0 -44
  346. package/src/services/notifications/live.ts +0 -50
  347. package/src/services/session/test-fixture.ts +0 -18
  348. package/src/ssr/BrowserNotifications.island.tsx +0 -135
  349. package/src/ssr/islands/SearchBar.island.tsx +0 -80
@@ -9,21 +9,22 @@ const mergedTranslation = (catalog: AppPresentationCatalog, requestedLocale: str
9
9
  return canonical ? [[canonical, translation] as const] : [];
10
10
  }),
11
11
  );
12
- const overlays = localeFallbackChain(requestedLocale, baseLocale).filter((locale) => locale !== baseLocale).reverse();
13
- return overlays.reduce<AppPresentationTranslation>(
14
- (current, locale) => {
15
- const next = byLocale.get(locale);
16
- if (!next) return current;
17
- return {
18
- ...current,
19
- ...next,
20
- adminGroups: { ...current.adminGroups, ...next.adminGroups },
21
- adminLinks: { ...current.adminLinks, ...next.adminLinks },
22
- legalLinks: { ...current.legalLinks, ...next.legalLinks },
23
- };
24
- },
25
- {},
26
- );
12
+ const overlays = localeFallbackChain(requestedLocale, baseLocale)
13
+ .filter((locale) => locale !== baseLocale)
14
+ .reverse();
15
+ return overlays.reduce<AppPresentationTranslation>((current, locale) => {
16
+ const next = byLocale.get(locale);
17
+ if (!next) return current;
18
+ return {
19
+ ...current,
20
+ ...next,
21
+ adminGroups: { ...current.adminGroups, ...next.adminGroups },
22
+ adminLinks: { ...current.adminLinks, ...next.adminLinks },
23
+ legalLinks: { ...current.legalLinks, ...next.legalLinks },
24
+ searchLinks: { ...current.searchLinks, ...next.searchLinks },
25
+ searchLinkDescriptions: { ...current.searchLinkDescriptions, ...next.searchLinkDescriptions },
26
+ };
27
+ }, {});
27
28
  };
28
29
 
29
30
  /** Resolve only human presentation; stable app identity, routes, icons, and authorization stay untouched. */
@@ -40,6 +41,11 @@ export const resolveAppPresentation = <T extends AppMeta>(app: T, requestedLocal
40
41
  label: (group.id && translation.adminGroups?.[group.id]) || group.label,
41
42
  links: group.links.map((link) => ({ ...link, label: translation.adminLinks?.[link.href] ?? link.label })),
42
43
  })),
44
+ searchLinks: app.searchLinks?.map((link) => ({
45
+ ...link,
46
+ label: translation.searchLinks?.[link.href] ?? link.label,
47
+ description: translation.searchLinkDescriptions?.[link.href] ?? link.description,
48
+ })),
43
49
  legalLinks: app.legalLinks?.map((link) => ({ ...link, label: translation.legalLinks?.[link.href] ?? link.label })),
44
50
  };
45
51
  };
@@ -11,10 +11,17 @@ const catalog = i18n.define({
11
11
  catalogLimit: ({ max }: { max: number }) => `Capability catalog limit must be between 1 and ${max}`,
12
12
  cloudUnavailable: "Cloud is unavailable",
13
13
  deadlineExceeded: "The capability deadline was exceeded",
14
+ idempotencyConflict: "This Idempotency-Key was already used with different input",
15
+ idempotencyInProgress:
16
+ "An identical call with this Idempotency-Key is still running; verify the outcome with a Query before retrying",
14
17
  idempotencyInvalid: "Idempotency-Key is invalid",
15
18
  idempotencyNotAllowed: "This Action does not support idempotent retries; omit Idempotency-Key",
16
19
  idempotencyOnlyActions: "Idempotency-Key is only valid for Actions that require it",
17
20
  idempotencyRequired: "This Action requires an Idempotency-Key",
21
+ idempotencyResultNotRetained:
22
+ "This Action already succeeded, but its result was too large to retain; read the current state with a Query",
23
+ idempotencyUncertain:
24
+ "An earlier call with this Idempotency-Key ended with an unknown outcome; verify the current state with a Query",
18
25
  inputNotSerializable: "Capability input must be JSON-serializable",
19
26
  inputSchemaMismatch: "Capability input did not match the registered schema",
20
27
  invalidCapabilityError: ({ appId }: { appId: string }) => `App ${appId} returned an invalid capability error`,
@@ -39,10 +46,17 @@ const catalog = i18n.define({
39
46
  catalogLimit: ({ max }) => `Das Limit des Capability-Katalogs muss zwischen 1 und ${max} liegen`,
40
47
  cloudUnavailable: "Cloud ist nicht verfügbar",
41
48
  deadlineExceeded: "Das Zeitlimit der Capability wurde überschritten",
49
+ idempotencyConflict: "Dieser Idempotency-Key wurde bereits mit anderen Eingaben verwendet",
50
+ idempotencyInProgress:
51
+ "Ein identischer Aufruf mit diesem Idempotency-Key läuft noch; prüfe das Ergebnis mit einer Query, bevor du erneut aufrufst",
42
52
  idempotencyInvalid: "Der Idempotency-Key ist ungültig",
43
53
  idempotencyNotAllowed: "Diese Action unterstützt keine idempotenten Wiederholungen; Idempotency-Key weglassen",
44
54
  idempotencyOnlyActions: "Ein Idempotency-Key ist nur für Actions gültig, die ihn voraussetzen",
45
55
  idempotencyRequired: "Diese Action benötigt einen Idempotency-Key",
56
+ idempotencyResultNotRetained:
57
+ "Diese Action war bereits erfolgreich, ihr Ergebnis war jedoch zu groß zum Aufbewahren; lies den aktuellen Stand mit einer Query",
58
+ idempotencyUncertain:
59
+ "Ein früherer Aufruf mit diesem Idempotency-Key endete mit unbekanntem Ergebnis; prüfe den aktuellen Stand mit einer Query",
46
60
  inputNotSerializable: "Die Capability-Eingabe muss als JSON serialisierbar sein",
47
61
  inputSchemaMismatch: "Die Capability-Eingabe entspricht nicht dem registrierten Schema",
48
62
  invalidCapabilityError: ({ appId }) => `App ${appId} hat einen ungültigen Capability-Fehler zurückgegeben`,
@@ -1,7 +1,7 @@
1
- import { canonicalLocale, localeFallbackChain } from "./locale";
1
+ import { localeFallbackChain } from "./locale";
2
2
 
3
3
  export type HelpDocumentManifest = {
4
- /** Resolved content locale. Present on request-scoped manifests. */
4
+ /** Resolved content locale on central Help manifests. */
5
5
  locale?: string;
6
6
  id: string;
7
7
  title: string;
@@ -13,56 +13,20 @@ export type HelpDocumentManifest = {
13
13
  url: string;
14
14
  };
15
15
 
16
- export type HelpManifest = {
17
- manifestHash: string;
18
- pageBase: string;
19
- /** Base language that owns the complete logical article set. Absent on legacy registrations. */
20
- baseLocale?: string;
21
- /** Localized metadata variants keyed by canonical BCP 47 locale. */
22
- documentsByLocale?: Readonly<Record<string, readonly HelpDocumentManifest[]>>;
23
- documents: readonly HelpDocumentManifest[];
24
- };
25
-
26
16
  export type HelpSearchPayload = {
27
- /** Resolved request locale. Optional only for rolling compatibility with older Cloud hosts. */
28
- locale?: string;
17
+ /** Resolved request locale. */
18
+ locale: string;
29
19
  ids: string[];
30
20
  };
31
21
 
32
22
  export type HelpDocumentPayload = {
33
- /** Resolved request locale. Optional only for rolling compatibility with older Cloud hosts. */
34
- locale?: string;
23
+ /** Resolved request locale. */
24
+ locale: string;
35
25
  id: string;
36
26
  title: string;
37
27
  markdown: string;
38
28
  html: string;
39
29
  };
40
30
 
41
- export type ResolvedHelpManifest = Omit<HelpManifest, "documentsByLocale" | "documents"> & {
42
- locale: string;
43
- documents: readonly HelpDocumentManifest[];
44
- };
45
-
46
31
  /** Exact locale, then BCP 47 ancestors, then the corpus base locale. */
47
32
  export const helpLocaleChain = localeFallbackChain;
48
-
49
- /** Resolve localized Help metadata per article while preserving the base article set and order. */
50
- export const resolveHelpManifest = (manifest: HelpManifest, requestedLocale: string): ResolvedHelpManifest => {
51
- const baseLocale = canonicalLocale(manifest.baseLocale ?? "en") ?? "en";
52
- const variants = manifest.documentsByLocale ?? {};
53
- const chain = helpLocaleChain(requestedLocale, baseLocale);
54
- const selectedLocale = chain.find((locale) => locale === baseLocale || variants[locale] !== undefined) ?? baseLocale;
55
- const overlays = [...chain.slice(0, chain.indexOf(baseLocale)), baseLocale].reverse();
56
- const byId = new Map(manifest.documents.map((document) => [document.id, document]));
57
- for (const locale of overlays) {
58
- if (locale === baseLocale) continue;
59
- for (const document of variants[locale] ?? []) byId.set(document.id, { ...byId.get(document.id), ...document });
60
- }
61
- return {
62
- manifestHash: manifest.manifestHash,
63
- pageBase: manifest.pageBase,
64
- baseLocale,
65
- locale: selectedLocale,
66
- documents: manifest.documents.map((document) => ({ ...(byId.get(document.id) ?? document), locale: selectedLocale })),
67
- };
68
- };
@@ -11,8 +11,11 @@ export {
11
11
  } from "./account-action-notice";
12
12
  export * from "./account-display";
13
13
  export * from "./account-session";
14
+ export * from "./ai-costs";
14
15
  export type { AiPromptContextInput, AiToolPromptHint } from "./ai-platform-prompt";
15
16
  export { AI_PLATFORM_PROMPT_TEMPLATE, aiPromptContext, renderAiPlatformPrompt } from "./ai-platform-prompt";
17
+ export type { AiChatQuotaSnapshot } from "./ai-quotas";
18
+ export * from "./ai-quotas";
16
19
  export {
17
20
  AI_USAGE_RANGES,
18
21
  AI_USAGE_REASONS,
@@ -13,8 +13,8 @@
13
13
  * Supported types: note, info, success, warning, danger
14
14
  */
15
15
 
16
- import type { MarkedExtension, Tokens } from "marked";
17
16
  import { NOTICE_CARD_CLASSES, NOTICE_CARD_ICONS, type NoticeTone } from "@k2b/ui";
17
+ import type { MarkedExtension, Tokens } from "marked";
18
18
  import { escapeHtml } from "../shared";
19
19
 
20
20
  type BlockType = "note" | "info" | "success" | "warning" | "danger";
@@ -1,6 +1,6 @@
1
1
  import { AppWorkspace } from "@k2b/ui";
2
2
  import type { JSX } from "solid-js/jsx-runtime";
3
- import type { RailPreferences } from "../contracts/rail-preferences";
3
+ import type { RailSnapshot } from "../contracts/rail-preferences";
4
4
  import { getLocale } from "../server/locale";
5
5
  import type { LayoutAnnouncementsState } from "../server/middleware/settings";
6
6
  import AdminSidebar from "./AdminSidebar";
@@ -10,7 +10,7 @@ import { getLocalizedRuntimeContext, type RuntimeContext } from "./runtime";
10
10
 
11
11
  type Breadcrumb = { title: string; href?: string };
12
12
  type AdminLayoutContext = {
13
- get(key: "railPreferences"): RailPreferences | undefined;
13
+ get(key: "railPreferences"): RailSnapshot | undefined;
14
14
  get(key: "user"): any;
15
15
  get(key: "page"): any;
16
16
  get(key: "runtime"): RuntimeContext;
@@ -25,7 +25,9 @@ type Props = {
25
25
  /** Disable when a bounded child such as SettingsPage owns scrolling. */
26
26
  scroll?: boolean;
27
27
  };
28
- export default function AdminLayout({ children, c, title, scroll = true }: Props) {
28
+ export default function AdminLayout(props: Props) {
29
+ // Keep children lazy so Layout installs the request locale before rendering them.
30
+ const { c, title, scroll = true } = props;
29
31
  const locale = getLocale(c);
30
32
  const t = platformMessages.resolve([locale]).t;
31
33
  const url = new URL(c.req.raw.url);
@@ -40,11 +42,11 @@ export default function AdminLayout({ children, c, title, scroll = true }: Props
40
42
  }
41
43
  return (
42
44
  <Layout c={c} fullWidth fullPage title={breadcrumbs}>
43
- <AppWorkspace class="min-h-0 flex-1" resizable={false}>
45
+ <AppWorkspace mobileSurface="flush" class="min-h-0 flex-1" resizable={false}>
44
46
  <AdminSidebar currentPath={currentPath} apps={runtime.apps} />
45
47
  <AppWorkspace.Content>
46
48
  <AppWorkspace.Main scroll={scroll} class={scroll ? "p-[var(--ui-space-shell)]" : undefined}>
47
- {children}
49
+ {props.children}
48
50
  </AppWorkspace.Main>
49
51
  </AppWorkspace.Content>
50
52
  </AppWorkspace>
@@ -1,8 +1,9 @@
1
1
  import { AppWorkspace, useLocale } from "@k2b/ui";
2
2
  import { activeAdminHref } from "./admin-active-link";
3
3
  import { type AdminLink, buildAdminGroups } from "./admin-navigation";
4
- import type { RuntimeContext } from "./runtime";
5
4
  import { platformMessages } from "./platform-messages";
5
+ import type { RuntimeContext } from "./runtime";
6
+ import WorkspaceNavigation from "./WorkspaceNavigation.island";
6
7
 
7
8
  const AdminNavigation = (props: { currentPath: string; groups: ReturnType<typeof buildAdminGroups> }) => {
8
9
  const activeHref = activeAdminHref(
@@ -31,20 +32,33 @@ export default function AdminSidebar({ currentPath, apps }: { currentPath: strin
31
32
  const groups = () => buildAdminGroups(apps, locale());
32
33
 
33
34
  return (
34
- <AppWorkspace.Sidebar resizable={false}>
35
- <AppWorkspace.SidebarMobileTrigger label={t().admin} />
36
-
37
- <AppWorkspace.SidebarMobile>
38
- <AppWorkspace.SidebarMobileBody scrollPreserveKey="admin-sidebar-mobile">
39
- <AdminNavigation currentPath={currentPath} groups={groups()} />
40
- </AppWorkspace.SidebarMobileBody>
41
- </AppWorkspace.SidebarMobile>
42
-
43
- <AppWorkspace.SidebarDesktop>
44
- <AppWorkspace.SidebarBody scrollPreserveKey="admin-sidebar">
45
- <AdminNavigation currentPath={currentPath} groups={groups()} />
46
- </AppWorkspace.SidebarBody>
47
- </AppWorkspace.SidebarDesktop>
48
- </AppWorkspace.Sidebar>
35
+ <>
36
+ <WorkspaceNavigation
37
+ label={t().admin}
38
+ items={groups().map((group) => ({
39
+ id: group.label,
40
+ label: group.label,
41
+ children: group.links.map((link) => ({
42
+ id: link.href,
43
+ label: link.label,
44
+ href: link.href,
45
+ icon: `ti ${link.icon}`,
46
+ active:
47
+ link.href ===
48
+ activeAdminHref(
49
+ currentPath,
50
+ groups().flatMap((entry) => entry.links.map((entry) => entry.href)),
51
+ ),
52
+ })),
53
+ }))}
54
+ />
55
+ <AppWorkspace.Sidebar resizable={false}>
56
+ <AppWorkspace.SidebarDesktop>
57
+ <AppWorkspace.SidebarBody scrollPreserveKey="admin-sidebar">
58
+ <AdminNavigation currentPath={currentPath} groups={groups()} />
59
+ </AppWorkspace.SidebarBody>
60
+ </AppWorkspace.SidebarDesktop>
61
+ </AppWorkspace.Sidebar>
62
+ </>
49
63
  );
50
64
  }
@@ -1,42 +1,11 @@
1
- import { dialogCore, IconButton, ScrollArea, Tooltip, useLocale } from "@k2b/ui";
2
- import { createEffect, For, Show } from "solid-js";
3
- import { platformMessages } from "./platform-messages";
4
- import { openRailEditor } from "./RailEditor";
5
- import { readRailContext } from "./rail-context";
6
- import { railMessages } from "./rail-messages";
7
- import { projectRailNavigation } from "./rail-navigation";
8
-
9
- export type AppLaunchpadApp = {
10
- id: string;
11
- iconClass: string;
12
- label: string;
13
- href: string;
14
- description?: string;
15
- accent?: string;
16
- };
17
-
18
- export type AppLaunchpadLegalLink = {
19
- label: string;
20
- href: string;
21
- icon?: string;
22
- };
23
-
24
- type AppLaunchpadContext = {
25
- apps: AppLaunchpadApp[];
26
- legalLinks: AppLaunchpadLegalLink[];
27
- };
1
+ import { type AppLaunchpadApp, type AppLaunchpadContext, type AppLaunchpadLegalLink, AppLaunchpadPanel } from "./AppLaunchpadPanel";
2
+ import { openCloudMobileMenu } from "./MobileNavigation";
28
3
 
29
- type AppIconPaletteEntry = { from: string };
4
+ export type { AppLaunchpadApp, AppLaunchpadLegalLink } from "./AppLaunchpadPanel";
30
5
 
31
- const appIconPalette: readonly [AppIconPaletteEntry, ...AppIconPaletteEntry[]] = [
32
- { from: "#2563eb" },
33
- { from: "#059669" },
34
- { from: "#7c3aed" },
35
- { from: "#d97706" },
36
- { from: "#e11d48" },
37
- { from: "#0891b2" },
38
- { from: "#52525b" },
39
- ];
6
+ import { dialogCore, IconButton, Tooltip, useLocale } from "@k2b/ui";
7
+ import { createEffect } from "solid-js";
8
+ import { platformMessages } from "./platform-messages";
40
9
 
41
10
  declare global {
42
11
  interface Window {
@@ -47,17 +16,6 @@ declare global {
47
16
  }
48
17
  }
49
18
 
50
- const paletteForId = (id: string) => {
51
- let hash = 0;
52
- for (let i = 0; i < id.length; i++) hash = (hash + id.charCodeAt(i)) % appIconPalette.length;
53
- return appIconPalette[hash] ?? appIconPalette[0];
54
- };
55
-
56
- const appIconStyle = (app: AppLaunchpadApp) => {
57
- const tone = /^#[0-9a-f]{6}$/i.test(app.accent ?? "") ? app.accent! : paletteForId(app.id).from;
58
- return `--app-icon-color:${tone}`;
59
- };
60
-
61
19
  const readEmbeddedContext = (): AppLaunchpadContext | undefined => {
62
20
  if (typeof document === "undefined") return undefined;
63
21
  const element = document.getElementById("cloud-app-launchpad-data");
@@ -69,6 +27,7 @@ const readEmbeddedContext = (): AppLaunchpadContext | undefined => {
69
27
  if (!Array.isArray(parsed.apps)) return undefined;
70
28
  return {
71
29
  apps: parsed.apps,
30
+ profile: parsed.profile?.name && (parsed.profile.theme === "dark" || parsed.profile.theme === "light") ? parsed.profile : undefined,
72
31
  legalLinks: Array.isArray(parsed.legalLinks) ? parsed.legalLinks : [],
73
32
  };
74
33
  } catch {
@@ -76,99 +35,28 @@ const readEmbeddedContext = (): AppLaunchpadContext | undefined => {
76
35
  }
77
36
  };
78
37
 
79
- const AppLaunchpadPanel = (props: AppLaunchpadContext & { close: () => void }) => {
80
- const locale = useLocale();
81
- const t = () => railMessages.resolve([locale()]).t;
82
- const rail = readRailContext();
83
- const shortcuts = () => (rail ? projectRailNavigation(rail.apps, rail.settings, locale()).shortcuts : []);
84
- return (
85
- <ScrollArea class="launchpad-panel mx-auto max-h-[min(86vh,var(--ui-dialog-available-height))] w-[var(--ui-dialog-available-width)] max-w-[var(--ui-dialog-available-width)] overscroll-contain p-4 text-primary sm:w-fit sm:p-6 md:p-7 dark:text-white">
86
- <Show when={rail}>
87
- <div class="mb-2 flex justify-end">
88
- <IconButton
89
- variant="ghost"
90
- size="sm"
91
- label={t().customize}
92
- tooltip={t().customize}
93
- tooltipDelay={0}
94
- onClick={() => {
95
- props.close();
96
- openRailEditor(locale());
97
- }}
98
- >
99
- <i class="ti ti-adjustments-horizontal" aria-hidden="true" />
100
- </IconButton>
101
- </div>
102
- </Show>
103
- <Show when={shortcuts().length > 0}>
104
- <section class="mb-5 flex flex-col gap-3" aria-label={t().shortcuts}>
105
- <h3 class="text-center text-sm font-medium">{t().shortcuts}</h3>
106
- <div class="flex flex-wrap justify-center gap-2">
107
- <For each={shortcuts()}>
108
- {(shortcut) => (
109
- <a
110
- href={shortcut.href}
111
- class="inline-flex items-center gap-2 rounded-lg border border-[var(--ui-border)] px-3 py-2 text-sm"
112
- >
113
- <i class={shortcut.iconClass} aria-hidden="true" />
114
- {shortcut.label}
115
- </a>
116
- )}
117
- </For>
118
- </div>
119
- </section>
120
- </Show>
121
- <div class="flex flex-wrap justify-center gap-x-4 gap-y-4 sm:gap-x-7 sm:gap-y-6">
122
- <For each={props.apps}>
123
- {(app) => (
124
- <a
125
- href={app.href}
126
- class="group flex w-[4.75rem] min-w-0 flex-col items-center gap-1.5 rounded-2xl p-1 text-center outline-none focus-visible:ring-2 focus-visible:ring-white/60 sm:w-[6.25rem] sm:gap-2 sm:p-2"
127
- >
128
- <span
129
- class="app-icon grid h-12 w-12 place-items-center rounded-[0.95rem] text-[1.25rem] sm:h-16 sm:w-16 sm:rounded-[1.25rem] sm:text-[1.7rem]"
130
- style={appIconStyle(app)}
131
- >
132
- <i class={app.iconClass} />
133
- </span>
134
- <span class="max-w-full truncate text-[11px] font-medium text-primary sm:text-xs dark:text-white">{app.label}</span>
135
- </a>
136
- )}
137
- </For>
138
- </div>
139
- <Show when={props.legalLinks.length > 0}>
140
- <div class="mt-7 flex flex-wrap justify-center text-[11px] text-dimmed dark:text-white/56">
141
- <For each={props.legalLinks}>
142
- {(link) => (
143
- <a
144
- href={link.href}
145
- class="inline-flex items-center gap-1.5 rounded-md px-2 py-1 transition-colors hover:text-primary dark:hover:text-white"
146
- >
147
- <i class={link.icon ?? "ti ti-file-text"} />
148
- {link.label}
149
- </a>
150
- )}
151
- </For>
152
- </div>
153
- </Show>
154
- </ScrollArea>
155
- );
156
- };
157
-
158
- export function setAppLaunchpadContext(apps: AppLaunchpadApp[], legalLinks: AppLaunchpadLegalLink[] = []) {
38
+ export function setAppLaunchpadContext(
39
+ apps: AppLaunchpadApp[],
40
+ legalLinks: AppLaunchpadLegalLink[] = [],
41
+ profile?: AppLaunchpadContext["profile"],
42
+ ) {
159
43
  if (typeof window === "undefined") return;
160
- window.__cloudAppLaunchpad = { apps, legalLinks };
44
+ window.__cloudAppLaunchpad = { apps, legalLinks, profile };
161
45
  window.cloud ??= {};
162
46
  window.cloud.openAppLaunchpad = () => {
163
47
  openAppLaunchpad();
164
48
  };
165
49
  }
166
50
 
167
- export function openAppLaunchpad(apps?: AppLaunchpadApp[], legalLinks?: AppLaunchpadLegalLink[]) {
51
+ export function openAppLaunchpad(apps?: AppLaunchpadApp[], legalLinks?: AppLaunchpadLegalLink[], profile?: AppLaunchpadContext["profile"]) {
168
52
  if (typeof window === "undefined") return;
169
- const context = apps ? { apps, legalLinks: legalLinks ?? [] } : (window.__cloudAppLaunchpad ?? readEmbeddedContext());
170
- if (!context || context.apps.length === 0) return;
53
+ const context = apps ? { apps, legalLinks: legalLinks ?? [], profile } : (window.__cloudAppLaunchpad ?? readEmbeddedContext());
54
+ if (!context) return;
171
55
  window.__cloudAppLaunchpad = context;
56
+ if (window.matchMedia("(max-width: 1023px)").matches) {
57
+ void openCloudMobileMenu(context);
58
+ return;
59
+ }
172
60
  void dialogCore.open<void>((close) => <AppLaunchpadPanel apps={context.apps} legalLinks={context.legalLinks} close={close} />, {
173
61
  panelClassName: "k2b-dialog k2b-dialog--large is-bare",
174
62
  contentClassName: "k2b-dialog__viewport is-bare",
@@ -178,7 +66,7 @@ export function openAppLaunchpad(apps?: AppLaunchpadApp[], legalLinks?: AppLaunc
178
66
 
179
67
  export function AppLaunchpadProvider(props: AppLaunchpadContext) {
180
68
  createEffect(() => {
181
- setAppLaunchpadContext(props.apps, props.legalLinks);
69
+ setAppLaunchpadContext(props.apps, props.legalLinks, props.profile);
182
70
  });
183
71
 
184
72
  return <span class="hidden" data-cloud-app-launchpad-provider />;
@@ -187,13 +75,14 @@ export function AppLaunchpadProvider(props: AppLaunchpadContext) {
187
75
  export function AppLaunchpadButton(props: AppLaunchpadContext & { variant: "rail" | "header" | "menu"; label?: string }) {
188
76
  const locale = useLocale();
189
77
  const t = () => platformMessages.resolve([locale()]).t;
190
- const open = () => openAppLaunchpad(props.apps, props.legalLinks);
78
+ const open = () => openAppLaunchpad(props.apps, props.legalLinks, props.profile);
191
79
 
192
80
  if (props.variant === "rail") {
193
81
  return (
194
82
  <Tooltip.Trigger
195
83
  type="button"
196
84
  class="rail-item shrink-0"
85
+ data-cloud-launchpad
197
86
  content={props.label ?? t().apps}
198
87
  placement="right"
199
88
  delay={0}
@@ -227,10 +116,18 @@ export function AppLaunchpadButton(props: AppLaunchpadContext & { variant: "rail
227
116
 
228
117
  export function AppLaunchpad(props: AppLaunchpadContext & { variant?: "provider" | "rail" | "header" | "menu"; label?: string }) {
229
118
  if (!props.variant || props.variant === "provider") {
230
- return <AppLaunchpadProvider apps={props.apps} legalLinks={props.legalLinks} />;
119
+ return <AppLaunchpadProvider apps={props.apps} legalLinks={props.legalLinks} profile={props.profile} />;
231
120
  }
232
121
 
233
- return <AppLaunchpadButton apps={props.apps} legalLinks={props.legalLinks} variant={props.variant} label={props.label} />;
122
+ return (
123
+ <AppLaunchpadButton
124
+ apps={props.apps}
125
+ legalLinks={props.legalLinks}
126
+ profile={props.profile}
127
+ variant={props.variant}
128
+ label={props.label}
129
+ />
130
+ );
234
131
  }
235
132
 
236
133
  export default AppLaunchpad;