@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,149 @@
1
+ import { mutation } from "@k2b/stdlib/solid";
2
+ import { Button, type ChatAction, type ChatAttachment, dialogCore, PanelDialog, panelDialogOptions, TextInput } from "@k2b/ui";
3
+ import { createSignal, Show } from "solid-js";
4
+ import type { AiTurnBlock } from "../protocol";
5
+ import type { AiStoredMessage, AiUserContentPart } from "../types";
6
+ import type { AiChatActions } from "./message-actions";
7
+ import {
8
+ type AiRetryMessageInput,
9
+ copyTextFromMessage,
10
+ resourcesFromMessage,
11
+ textAttachmentSummariesFromMessage,
12
+ userContentWithEditedVisibleText,
13
+ userVisibleTextFromMessage,
14
+ vfsAttachmentsFromMessage,
15
+ } from "./message-utils";
16
+
17
+ const openModifyRetryDialog = (
18
+ entry: AiStoredMessage,
19
+ onRetryMessage: (entry: AiStoredMessage, input?: AiRetryMessageInput) => void | Promise<void>,
20
+ ) => {
21
+ void dialogCore.open<void>((close) => {
22
+ const [draft, setDraft] = createSignal(userVisibleTextFromMessage(entry.message));
23
+ const content = () => userContentWithEditedVisibleText(entry.message, draft());
24
+ const retryMutation = mutation.create<void, AiUserContentPart[]>({
25
+ mutation: async (nextContent) => onRetryMessage(entry, { content: nextContent }),
26
+ onSuccess: () => close(),
27
+ });
28
+ const canRetry = () => content().length > 0 && !retryMutation.loading();
29
+ const retry = () => {
30
+ const nextContent = content();
31
+ if (nextContent.length === 0 || retryMutation.loading()) return;
32
+ void retryMutation.mutate(nextContent);
33
+ };
34
+
35
+ return (
36
+ <PanelDialog>
37
+ <PanelDialog.Header title="Edit and try again" icon="ti ti-pencil" close={close} />
38
+ <PanelDialog.Body>
39
+ <TextInput
40
+ label="Prompt"
41
+ description="Attachments from the original message stay attached."
42
+ multiline
43
+ lines={8}
44
+ value={draft}
45
+ onValueChange={setDraft}
46
+ onSubmit={retry}
47
+ />
48
+ <Show when={retryMutation.error()}>
49
+ <p class="text-xs text-red-600 dark:text-red-400" role="alert">
50
+ Could not retry this message. Your changes are still here.
51
+ </p>
52
+ </Show>
53
+ </PanelDialog.Body>
54
+ <PanelDialog.Footer>
55
+ <div class="ml-auto flex items-center gap-2">
56
+ <Button type="button" variant="secondary" size="sm" onClick={() => close()}>
57
+ Cancel
58
+ </Button>
59
+ <Button type="button" variant="ai" size="sm" disabled={!canRetry()} onClick={retry}>
60
+ <i class={`ti ${retryMutation.loading() ? "ti-loader-2 animate-spin" : "ti-refresh"}`} aria-hidden="true" />
61
+ {retryMutation.loading() ? "Trying again" : "Try again"}
62
+ </Button>
63
+ </div>
64
+ </PanelDialog.Footer>
65
+ </PanelDialog>
66
+ );
67
+ }, panelDialogOptions);
68
+ };
69
+
70
+ export const aiUserMessageText = (entry: AiStoredMessage): string => userVisibleTextFromMessage(entry.message);
71
+
72
+ export const aiUserMessageAttachments = (entry: AiStoredMessage, actions: AiChatActions = {}): ChatAttachment[] => [
73
+ ...textAttachmentSummariesFromMessage(entry.message).map((attachment, index) => ({
74
+ id: `${entry.id}-text-${index}`,
75
+ name: attachment.name,
76
+ kind: "file" as const,
77
+ icon: `ti ${attachment.icon}`,
78
+ })),
79
+ ...vfsAttachmentsFromMessage(entry.message).map((attachment, index) => ({
80
+ id: `${entry.id}-vfs-${index}`,
81
+ name: attachment.name,
82
+ size: attachment.size,
83
+ kind: attachment.mediaType.startsWith("image/") ? ("image" as const) : ("file" as const),
84
+ previewUrl: attachment.mediaType.startsWith("image/") ? (actions.fileUrl?.(attachment.path) ?? undefined) : undefined,
85
+ icon: attachment.mediaType.startsWith("image/") ? "ti ti-photo" : `ti ${attachment.icon}`,
86
+ })),
87
+ ...resourcesFromMessage(entry.message).map((resource, index) => ({
88
+ id: `${entry.id}-resource-${index}`,
89
+ name: resource.title ?? resource.ref.id,
90
+ kind: "resource" as const,
91
+ icon: resource.icon ?? "ti ti-cloud",
92
+ href: resource.href,
93
+ })),
94
+ ];
95
+
96
+ export const createAiUserMessageActions = (entry: AiStoredMessage, actions: AiChatActions): ChatAction[] => {
97
+ const result: ChatAction[] = [];
98
+ const copyText = copyTextFromMessage(entry.message);
99
+
100
+ if (copyText) {
101
+ result.push({ id: "copy", label: "Copy", icon: "ti ti-copy", copyText });
102
+ }
103
+ if (!entry.compactedAt && actions.onRetryMessage) {
104
+ result.push(
105
+ {
106
+ id: "retry",
107
+ label: "Try again",
108
+ icon: "ti ti-refresh",
109
+ onSelect: () => actions.onRetryMessage?.(entry, { mode: "retry" }),
110
+ },
111
+ {
112
+ id: "details",
113
+ label: "More detailed",
114
+ icon: "ti ti-list-details",
115
+ onSelect: () => actions.onRetryMessage?.(entry, { mode: "details" }),
116
+ },
117
+ {
118
+ id: "concise",
119
+ label: "More concise",
120
+ icon: "ti ti-align-left",
121
+ onSelect: () => actions.onRetryMessage?.(entry, { mode: "concise" }),
122
+ },
123
+ {
124
+ id: "edit",
125
+ label: "Edit prompt",
126
+ icon: "ti ti-pencil",
127
+ onSelect: () => openModifyRetryDialog(entry, actions.onRetryMessage!),
128
+ },
129
+ );
130
+ }
131
+ return result;
132
+ };
133
+
134
+ export const aiSteerMessageText = (block: Extract<AiTurnBlock, { kind: "steer_message" }>): string => block.text;
135
+
136
+ export const createAiSteerMessageActions = (
137
+ block: Extract<AiTurnBlock, { kind: "steer_message" }>,
138
+ actions: AiChatActions,
139
+ ): ChatAction[] => {
140
+ if (block.status !== "failed" || !actions.onRetrySteer) return [];
141
+ return [
142
+ {
143
+ id: "retry-steer",
144
+ label: "Retry guidance",
145
+ icon: "ti ti-refresh",
146
+ onSelect: () => actions.onRetrySteer?.(block),
147
+ },
148
+ ];
149
+ };
@@ -0,0 +1,435 @@
1
+ import { mutation } from "@k2b/stdlib/solid";
2
+ import { Button, MarkdownEditor, prompts, Slider, useLocale } from "@k2b/ui";
3
+ import { createSignal, createUniqueId, For, Show } from "solid-js";
4
+ import { CLOUD_AI_TEXT_EDITOR_FEEDBACK_MAX_CHARS, CLOUD_AI_TEXT_EDITOR_MAX_CHARS } from "../default-tool-contracts";
5
+ import { isRecord, jsonPreview } from "./message-utils";
6
+ import { aiChatMessages } from "./messages";
7
+ import { useAiToolDisclosure } from "./tool-disclosure";
8
+
9
+ const toneClass = (tone: unknown) => {
10
+ if (tone === "blue") return "border-blue-200 bg-blue-50/65 text-blue-950 dark:border-blue-900/70 dark:bg-blue-950/25 dark:text-blue-100";
11
+ if (tone === "green")
12
+ return "border-emerald-200 bg-emerald-50/65 text-emerald-950 dark:border-emerald-900/70 dark:bg-emerald-950/25 dark:text-emerald-100";
13
+ if (tone === "amber")
14
+ return "border-amber-200 bg-amber-50/70 text-amber-950 dark:border-amber-900/70 dark:bg-amber-950/25 dark:text-amber-100";
15
+ if (tone === "red") return "border-red-200 bg-red-50/70 text-red-950 dark:border-red-900/70 dark:bg-red-950/25 dark:text-red-100";
16
+ if (tone === "teal") return "border-cyan-200 bg-teal-50/70 text-cyan-950 dark:border-cyan-900/70 dark:bg-cyan-950/25 dark:text-cyan-100";
17
+ return "border-zinc-200 bg-white text-primary dark:border-zinc-800 dark:bg-zinc-900";
18
+ };
19
+
20
+ export function CloudCardBlock(props: { args: unknown }) {
21
+ const card = () => (isRecord(props.args) ? props.args : null);
22
+ const emoji = () => (typeof card()?.emoji === "string" ? String(card()?.emoji).trim() : "");
23
+ const title = () => String(card()?.title ?? "Card");
24
+ const value = () => String(card()?.value ?? "");
25
+ const caption = () => (typeof card()?.caption === "string" ? String(card()!.caption) : "");
26
+ const legacyTrend = () => (isRecord(card()?.trend) ? (card()!.trend as Record<string, unknown>) : null);
27
+ const trendValue = () => (typeof card()?.trendValue === "string" ? String(card()!.trendValue) : String(legacyTrend()?.value ?? ""));
28
+ const trendLabel = () => (typeof card()?.trendLabel === "string" ? String(card()!.trendLabel) : String(legacyTrend()?.label ?? ""));
29
+ const trendDirection = () => {
30
+ const direction = card()?.trendDirection ?? legacyTrend()?.direction;
31
+ return direction === "up" || direction === "down" || direction === "flat" ? direction : "flat";
32
+ };
33
+ const hasTrend = () => Boolean(trendValue() || trendLabel());
34
+
35
+ return (
36
+ <div class={`max-w-xl rounded-md border p-2.5 ${toneClass(card()?.tone)}`}>
37
+ <Show
38
+ when={card()}
39
+ fallback={
40
+ <pre class="max-h-52 overflow-auto rounded-md bg-zinc-950/5 p-2 text-xs text-primary dark:bg-white/5">
41
+ {jsonPreview(props.args)}
42
+ </pre>
43
+ }
44
+ >
45
+ <div class="flex items-start gap-2">
46
+ <Show when={emoji()}>
47
+ <span class="shrink-0 text-2xl leading-7" aria-hidden="true">
48
+ {emoji()}
49
+ </span>
50
+ </Show>
51
+ <div class="min-w-0 flex-1">
52
+ <p class="text-sm font-semibold">{title()}</p>
53
+ <p class="mt-2 text-3xl font-semibold tracking-normal">{value()}</p>
54
+ <Show when={hasTrend()}>
55
+ <p class="mt-1 inline-flex items-center gap-1 rounded-md bg-white/55 px-1.5 py-0.5 text-xs dark:bg-white/10">
56
+ <i
57
+ class={`ti ${
58
+ trendDirection() === "up" ? "ti-trending-up" : trendDirection() === "down" ? "ti-trending-down" : "ti-minus"
59
+ } text-sm`}
60
+ aria-hidden="true"
61
+ />
62
+ <Show when={trendValue()}>{trendValue()}</Show>
63
+ <Show when={trendLabel()}>
64
+ <span class="opacity-70">{trendLabel()}</span>
65
+ </Show>
66
+ </p>
67
+ </Show>
68
+ <Show when={caption()}>
69
+ <p class="mt-2 text-xs opacity-70">{caption()}</p>
70
+ </Show>
71
+ </div>
72
+ </div>
73
+ </Show>
74
+ </div>
75
+ );
76
+ }
77
+
78
+ export function CloudSurveyBlock(props: {
79
+ args: unknown;
80
+ disabled?: boolean;
81
+ disabledLabel?: string;
82
+ onSubmit?: (result: unknown) => void | Promise<void>;
83
+ }) {
84
+ const survey = () => (isRecord(props.args) ? props.args : null);
85
+ const questions = () => (Array.isArray(survey()?.questions) ? (survey()!.questions as unknown[]).filter(isRecord) : []);
86
+ const surveyId = createUniqueId();
87
+ const [answers, setAnswers] = createSignal<Record<string, unknown>>({});
88
+ const [error, setError] = createSignal<string | null>(null);
89
+ const [submitted, setSubmitted] = createSignal(false);
90
+ const submission = mutation.create<void, unknown>({
91
+ mutation: async (result) => {
92
+ if (!props.onSubmit) throw new Error("Survey submission is unavailable.");
93
+ await props.onSubmit(result);
94
+ },
95
+ onSuccess: () => setSubmitted(true),
96
+ onError: (submissionError) => setError(submissionError.message || "Could not submit the survey. Try again."),
97
+ });
98
+
99
+ const setAnswer = (id: string, value: unknown) => setAnswers((prev) => ({ ...prev, [id]: value }));
100
+ const toggleAnswer = (id: string, value: string, checked: boolean) => {
101
+ const current = Array.isArray(answers()[id]) ? ([...(answers()[id] as string[])] as string[]) : [];
102
+ setAnswer(id, checked ? [...current, value] : current.filter((entry) => entry !== value));
103
+ };
104
+ const submit = async () => {
105
+ const missing = questions().find((question) => {
106
+ if (!question.required) return false;
107
+ const value = answers()[String(question.id ?? "")];
108
+ return Array.isArray(value) ? value.length === 0 : value === undefined || value === "";
109
+ });
110
+ if (missing) {
111
+ setError("Please answer all required questions.");
112
+ return;
113
+ }
114
+ setError(null);
115
+ if (!submission.loading()) await submission.mutate({ submitted: true, answers: answers() });
116
+ };
117
+ const disabled = () => Boolean(props.disabled || submitted() || submission.loading() || !props.onSubmit);
118
+
119
+ return (
120
+ <div class="w-full min-w-0 overflow-hidden rounded-xl border border-[var(--k2b-border)] bg-[var(--k2b-surface)]">
121
+ <div class="p-4">
122
+ <div class="flex items-center gap-3">
123
+ <span class="inline-flex size-8 shrink-0 items-center justify-center rounded-lg bg-[color-mix(in_srgb,var(--k2b-ai-accent)_10%,var(--k2b-surface))] text-base text-[var(--k2b-ai-accent)]">
124
+ <i class="ti ti-forms" aria-hidden="true" />
125
+ </span>
126
+ <div class="min-w-0">
127
+ <p class="truncate text-sm font-semibold text-primary">{String(survey()?.title ?? "Survey")}</p>
128
+ <p class="text-xs text-dimmed">Survey</p>
129
+ </div>
130
+ </div>
131
+ <div class="min-w-0">
132
+ <Show when={typeof survey()?.description === "string"}>
133
+ <p class="mt-4 text-xs text-secondary">{String(survey()?.description)}</p>
134
+ </Show>
135
+
136
+ <div class="mt-4 space-y-4">
137
+ <For each={questions()}>
138
+ {(question) => {
139
+ const id = () => String(question.id ?? "");
140
+ const options = () => (Array.isArray(question.options) ? (question.options as unknown[]).filter(isRecord) : []);
141
+ return (
142
+ <div>
143
+ <p class="text-xs font-medium text-primary">
144
+ {String(question.label ?? "")}
145
+ <Show when={question.required}>
146
+ <span class="text-red-500"> *</span>
147
+ </Show>
148
+ </p>
149
+ <Show when={question.type === "single"}>
150
+ <div class="mt-2 grid gap-1.5">
151
+ <For each={options()}>
152
+ {(option) => (
153
+ <label
154
+ class="flex min-h-9 cursor-pointer items-center gap-2.5 rounded-lg border border-[var(--k2b-border)] px-3 py-2 text-xs text-secondary transition-colors focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-[var(--k2b-focus-ring)]"
155
+ classList={{
156
+ "border-[var(--k2b-ai-accent)] text-primary": answers()[id()] === option.value,
157
+ "cursor-not-allowed opacity-60": disabled(),
158
+ }}
159
+ >
160
+ <input
161
+ type="radio"
162
+ name={`${surveyId}-${id()}`}
163
+ value={String(option.value ?? "")}
164
+ checked={answers()[id()] === option.value}
165
+ disabled={disabled()}
166
+ class="accent-[var(--k2b-ai-accent)]"
167
+ onChange={() => setAnswer(id(), option.value)}
168
+ />
169
+ {String(option.label ?? option.value ?? "")}
170
+ </label>
171
+ )}
172
+ </For>
173
+ </div>
174
+ </Show>
175
+ <Show when={question.type === "multiple"}>
176
+ <div class="mt-2 grid gap-1.5">
177
+ <For each={options()}>
178
+ {(option) => (
179
+ <label
180
+ class="flex min-h-9 cursor-pointer items-center gap-2.5 rounded-lg border border-[var(--k2b-border)] px-3 py-2 text-xs text-secondary transition-colors focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-[var(--k2b-focus-ring)]"
181
+ classList={{
182
+ "border-[var(--k2b-ai-accent)] text-primary":
183
+ Array.isArray(answers()[id()]) && (answers()[id()] as string[]).includes(String(option.value)),
184
+ "cursor-not-allowed opacity-60": disabled(),
185
+ }}
186
+ >
187
+ <input
188
+ type="checkbox"
189
+ disabled={disabled()}
190
+ checked={Array.isArray(answers()[id()]) && (answers()[id()] as string[]).includes(String(option.value))}
191
+ class="accent-[var(--k2b-ai-accent)]"
192
+ onChange={(event) => toggleAnswer(id(), String(option.value), event.currentTarget.checked)}
193
+ />
194
+ {String(option.label ?? option.value ?? "")}
195
+ </label>
196
+ )}
197
+ </For>
198
+ </div>
199
+ </Show>
200
+ <Show when={question.type === "text"}>
201
+ <input
202
+ class="input mt-1 h-9 w-full text-sm"
203
+ disabled={disabled()}
204
+ placeholder={typeof question.placeholder === "string" ? question.placeholder : ""}
205
+ value={String(answers()[id()] ?? "")}
206
+ onInput={(event) => setAnswer(id(), event.currentTarget.value)}
207
+ />
208
+ </Show>
209
+ <Show when={question.type === "rating"}>
210
+ <Slider
211
+ class="mt-2"
212
+ disabled={disabled()}
213
+ min={typeof question.min === "number" ? question.min : 1}
214
+ max={typeof question.max === "number" ? question.max : 5}
215
+ value={() => Number(answers()[id()] ?? question.min ?? 1)}
216
+ showValue={false}
217
+ onValueChange={(value) => setAnswer(id(), value)}
218
+ />
219
+ </Show>
220
+ </div>
221
+ );
222
+ }}
223
+ </For>
224
+ </div>
225
+
226
+ <Show when={error()}>
227
+ <p class="mt-2 text-xs text-red-600 dark:text-red-300">{error()}</p>
228
+ </Show>
229
+ </div>
230
+ </div>
231
+ <footer class="flex min-h-12 items-center gap-3 border-t border-[var(--k2b-border)] bg-[var(--k2b-surface-subtle)] px-4 py-2.5">
232
+ <Show when={submitted()}>
233
+ <span class="inline-flex items-center gap-1.5 text-xs font-medium text-secondary">
234
+ <i class="ti ti-check text-[var(--k2b-ai-accent)]" aria-hidden="true" />
235
+ Answer submitted. Assistant is continuing…
236
+ </span>
237
+ </Show>
238
+ <Show
239
+ when={!props.disabled && !submitted() && props.onSubmit}
240
+ fallback={
241
+ <Show when={!submitted()}>
242
+ <p class="ml-auto text-xs text-dimmed">{props.disabledLabel ?? "Waiting for the assistant to continue."}</p>
243
+ </Show>
244
+ }
245
+ >
246
+ <Button
247
+ variant="ai"
248
+ size="sm"
249
+ class="ml-auto"
250
+ loading={submission.loading()}
251
+ loadingLabel="Submitting"
252
+ onClick={() => void submit()}
253
+ >
254
+ {String(survey()?.submitLabel ?? "Submit")}
255
+ </Button>
256
+ </Show>
257
+ </footer>
258
+ </div>
259
+ );
260
+ }
261
+
262
+ const surveyAnswerLabel = (question: Record<string, unknown> | null, value: unknown, noAnswer: string) => {
263
+ const options = Array.isArray(question?.options) ? (question!.options as unknown[]).filter(isRecord) : [];
264
+ const optionLabel = (entry: unknown) => {
265
+ const match = options.find((option) => String(option.value ?? "") === String(entry));
266
+ return String(match?.label ?? entry ?? "");
267
+ };
268
+ if (Array.isArray(value)) return value.map(optionLabel).filter(Boolean).join(", ") || noAnswer;
269
+ if (typeof value === "object" && value !== null) return jsonPreview(value);
270
+ if (value === undefined || value === null || value === "") return noAnswer;
271
+ return optionLabel(value);
272
+ };
273
+
274
+ export function CloudSurveyResultBlock(props: { args?: unknown; result: unknown }) {
275
+ const locale = useLocale();
276
+ const t = () => aiChatMessages(locale());
277
+ const survey = () => (isRecord(props.args) ? props.args : null);
278
+ const result = () => (isRecord(props.result) ? props.result : null);
279
+ const answers = () => (isRecord(result()?.answers) ? (result()!.answers as Record<string, unknown>) : {});
280
+ const questions = () => (Array.isArray(survey()?.questions) ? (survey()!.questions as unknown[]).filter(isRecord) : []);
281
+ const rows = () => {
282
+ const knownQuestions = questions().map((question) => {
283
+ const id = String(question.id ?? "");
284
+ return {
285
+ id,
286
+ label: String(question.label ?? id),
287
+ value: surveyAnswerLabel(question, answers()[id], t().surveyNoAnswer),
288
+ };
289
+ });
290
+ const knownIds = new Set(knownQuestions.map((question) => question.id));
291
+ const extraAnswers = Object.entries(answers())
292
+ .filter(([id]) => !knownIds.has(id))
293
+ .map(([id, value]) => ({ id, label: id, value: surveyAnswerLabel(null, value, t().surveyNoAnswer) }));
294
+ return [...knownQuestions, ...extraAnswers].filter((row) => row.id);
295
+ };
296
+
297
+ return (
298
+ <Show when={rows().length > 0} fallback={<p>{t().surveyNoAnswers}</p>}>
299
+ <dl class="flex min-w-0 flex-col gap-3">
300
+ <For each={rows()}>
301
+ {(row) => (
302
+ <div class="min-w-0">
303
+ <dt class="mb-1 whitespace-pre-wrap break-words text-xs text-dimmed">{row.label}</dt>
304
+ <dd class="whitespace-pre-wrap break-words">{row.value}</dd>
305
+ </div>
306
+ )}
307
+ </For>
308
+ </dl>
309
+ </Show>
310
+ );
311
+ }
312
+
313
+ export function CloudTextEditorBlock(props: {
314
+ args: unknown;
315
+ disabled?: boolean;
316
+ disabledLabel?: string;
317
+ onSubmit?: (result: unknown) => void | Promise<void>;
318
+ }) {
319
+ const locale = useLocale();
320
+ const editor = () => (isRecord(props.args) ? props.args : null);
321
+ const format = () => (editor()?.format === "markdown" ? "markdown" : "plain");
322
+ const initialContent = () => (typeof editor()?.content === "string" ? String(editor()!.content) : "");
323
+ const [content, setContent] = createSignal(initialContent());
324
+ const [error, setError] = createSignal<string | null>(null);
325
+ const [submitted, setSubmitted] = createSignal(false);
326
+ const submission = mutation.create<void, unknown>({
327
+ mutation: async (result) => {
328
+ if (!props.onSubmit) throw new Error("Text submission is unavailable.");
329
+ await props.onSubmit(result);
330
+ },
331
+ onSuccess: () => setSubmitted(true),
332
+ onError: (submissionError) => setError(submissionError.message || "Could not submit the text. Try again."),
333
+ });
334
+ const disabled = () => Boolean(props.disabled || submitted() || submission.loading() || !props.onSubmit);
335
+ const submit = async () => {
336
+ setError(null);
337
+ if (!submission.loading()) await submission.mutate({ submitted: true, content: content(), format: format() });
338
+ };
339
+ const requestChanges = async () => {
340
+ setError(null);
341
+ if (submission.loading()) return;
342
+ const result = await prompts.form({
343
+ title: "Suggest changes",
344
+ icon: "ti ti-message",
345
+ confirmText: "Send feedback",
346
+ size: "medium",
347
+ fields: {
348
+ feedback: {
349
+ type: "text",
350
+ label: "What should change?",
351
+ placeholder: "Describe what you want to be different.",
352
+ multiline: true,
353
+ lines: 4,
354
+ required: true,
355
+ maxLength: CLOUD_AI_TEXT_EDITOR_FEEDBACK_MAX_CHARS,
356
+ },
357
+ },
358
+ });
359
+ const feedback = result?.feedback.trim();
360
+ if (feedback) await submission.mutate({ submitted: false, feedback });
361
+ };
362
+
363
+ return (
364
+ <div class="w-full min-w-0">
365
+ <MarkdownEditor
366
+ value={content}
367
+ onValueChange={setContent}
368
+ lines={14}
369
+ maxLength={CLOUD_AI_TEXT_EDITOR_MAX_CHARS}
370
+ aria-label={String(editor()?.title ?? "Review text")}
371
+ spellcheck
372
+ disabled={disabled()}
373
+ showStats={false}
374
+ />
375
+ <Show when={error()}>
376
+ <p class="mt-2 text-xs text-red-600 dark:text-red-300" role="alert">
377
+ {error()}
378
+ </p>
379
+ </Show>
380
+ <div class="mt-3 flex min-h-9 flex-wrap items-center gap-2">
381
+ <span class="text-xs tabular-nums text-dimmed">
382
+ {content().length.toLocaleString(locale())} / {CLOUD_AI_TEXT_EDITOR_MAX_CHARS.toLocaleString(locale())}
383
+ </span>
384
+ <Show
385
+ when={!props.disabled && !submitted() && props.onSubmit}
386
+ fallback={<p class="ml-auto text-xs text-dimmed">{props.disabledLabel ?? "Waiting for the assistant to continue."}</p>}
387
+ >
388
+ <div class="ml-auto flex flex-wrap justify-end gap-2">
389
+ <Button variant="secondary" size="sm" disabled={submission.loading()} onClick={() => void requestChanges()}>
390
+ Suggest changes
391
+ </Button>
392
+ <Button variant="ai" size="sm" loading={submission.loading()} loadingLabel="Submitting" onClick={() => void submit()}>
393
+ {String(editor()?.submitLabel ?? "Continue")}
394
+ </Button>
395
+ </div>
396
+ </Show>
397
+ </div>
398
+ </div>
399
+ );
400
+ }
401
+
402
+ export function CloudTextEditorResultBlock(props: { blockId?: string; args?: unknown; result: unknown; continuing?: boolean }) {
403
+ const disclosure = useAiToolDisclosure(() => props.blockId);
404
+ const editor = () => (isRecord(props.args) ? props.args : null);
405
+ const result = () => (isRecord(props.result) ? props.result : null);
406
+ const content = () => (typeof result()?.content === "string" ? String(result()!.content) : "");
407
+ const feedback = () => (result()?.submitted === false && typeof result()?.feedback === "string" ? String(result()!.feedback) : "");
408
+ const format = () => (result()?.format === "markdown" ? "Markdown" : "Plain text");
409
+ const state = () => (feedback() ? (props.continuing ? "revising" : "changes requested") : props.continuing ? "waiting" : "submitted");
410
+ return (
411
+ <details
412
+ class="group w-full min-w-0 text-xs"
413
+ open={disclosure.open()}
414
+ onToggle={(event) => disclosure.onOpenChange(event.currentTarget.open)}
415
+ >
416
+ <summary class="inline-flex min-h-7 max-w-full cursor-pointer list-none items-center gap-1.5 py-1 leading-none text-dimmed transition-colors hover:text-primary">
417
+ <i class="ti ti-edit shrink-0 text-base leading-none" aria-hidden="true" />
418
+ <span class="shrink-0 font-medium">text editor</span>
419
+ <span class="min-w-0 truncate">
420
+ {String(editor()?.title ?? "Review text")} · {state()}
421
+ </span>
422
+ <i
423
+ class="ti ti-chevron-right shrink-0 text-base leading-none opacity-60 transition-transform group-open:rotate-90"
424
+ aria-hidden="true"
425
+ />
426
+ </summary>
427
+ <div class="mt-1 w-full min-w-0 rounded-md bg-zinc-100/70 px-2.5 py-2 [box-shadow:var(--ui-control-recess)] dark:bg-zinc-950/70">
428
+ <p class="mb-1.5 text-[10px] font-medium uppercase tracking-wide text-dimmed">{feedback() ? "Feedback" : format()}</p>
429
+ <pre class="max-h-72 overflow-auto whitespace-pre-wrap break-words font-sans text-xs leading-5 text-primary">
430
+ {feedback() || content() || "Empty text submitted."}
431
+ </pre>
432
+ </div>
433
+ </details>
434
+ );
435
+ }