@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,130 @@
1
+ /**
2
+ * Initialize Mermaid diagrams within a container element.
3
+ * Call this in onMount() of your client-side component.
4
+ *
5
+ * @param container - The container element containing rendered markdown
6
+ */
7
+ export async function initMermaid(container: HTMLElement): Promise<void> {
8
+ const mermaid = (await import("mermaid")).default;
9
+ // Initialize mermaid with theme detection
10
+ const isDark = document.documentElement.classList.contains("dark");
11
+ mermaid.initialize({
12
+ startOnLoad: false,
13
+ theme: "base",
14
+ themeVariables: isDark
15
+ ? {
16
+ darkMode: true,
17
+ background: "#09090b",
18
+ textColor: "#e5e7eb",
19
+ lineColor: "#6b7280",
20
+ primaryTextColor: "#e5e7eb",
21
+ secondaryTextColor: "#e5e7eb",
22
+ tertiaryTextColor: "#e5e7eb",
23
+ noteTextColor: "#e5e7eb",
24
+ mainBkg: "#111827",
25
+ secondBkg: "#1f2937",
26
+ tertiaryColor: "#374151",
27
+ }
28
+ : {
29
+ darkMode: false,
30
+ background: "#ffffff",
31
+ textColor: "#111827",
32
+ lineColor: "#6b7280",
33
+ primaryTextColor: "#111827",
34
+ secondaryTextColor: "#111827",
35
+ tertiaryTextColor: "#111827",
36
+ noteTextColor: "#111827",
37
+ mainBkg: "#ffffff",
38
+ secondBkg: "#f9fafb",
39
+ tertiaryColor: "#f3f4f6",
40
+ },
41
+ });
42
+
43
+ // Find mermaid blocks (rendered with fixed-height container from server)
44
+ const mermaidBlocks = container.querySelectorAll(".md-mermaid-block");
45
+ if (mermaidBlocks.length === 0) return;
46
+
47
+ const renderPromises = Array.from(mermaidBlocks).map(async (block, index) => {
48
+ const codeElement = block.querySelector("code.language-mermaid");
49
+ const innerContainer = block.querySelector(".h-full.w-full.flex") as HTMLElement;
50
+ if (!codeElement || !innerContainer) return;
51
+
52
+ const code = codeElement.textContent || "";
53
+ const mermaidId = `mermaid-${index}-${Date.now()}`;
54
+
55
+ try {
56
+ // Render mermaid to SVG
57
+ const { svg } = await mermaid.render(mermaidId, code);
58
+
59
+ // Remove loading indicator and hidden pre
60
+ const loading = innerContainer.querySelector(".md-mermaid-loading");
61
+ const pre = innerContainer.querySelector("pre");
62
+ loading?.remove();
63
+ pre?.remove();
64
+
65
+ // Create container for SVG with scaling
66
+ const svgContainer = document.createElement("div");
67
+ svgContainer.className = "flex items-center justify-center w-full h-full";
68
+ svgContainer.innerHTML = svg;
69
+
70
+ // Scale SVG to fit container
71
+ const svgElement = svgContainer.querySelector("svg");
72
+ if (svgElement) {
73
+ svgElement.style.maxWidth = "100%";
74
+ svgElement.style.maxHeight = "100%";
75
+ svgElement.style.width = "auto";
76
+ svgElement.style.height = "auto";
77
+ }
78
+
79
+ innerContainer.appendChild(svgContainer);
80
+ } catch (error) {
81
+ // Show error
82
+ const loading = innerContainer.querySelector(".md-mermaid-loading");
83
+ if (loading) {
84
+ loading.innerHTML = `
85
+ <div class="flex flex-col items-center gap-2 text-red-500">
86
+ <i class="ti ti-alert-circle text-xl"></i>
87
+ <span class="text-sm">Invalid mermaid syntax</span>
88
+ </div>
89
+ `;
90
+ }
91
+ }
92
+ });
93
+
94
+ await Promise.all(renderPromises);
95
+ }
96
+
97
+ /**
98
+ * Set external links to open in new tab.
99
+ * Call this in onMount() of your client-side component.
100
+ *
101
+ * @param container - The container element containing rendered markdown
102
+ */
103
+ export function initExternalLinks(container: HTMLElement): void {
104
+ const links = container.querySelectorAll("a");
105
+ links.forEach((link) => {
106
+ if (link.href && !link.href.startsWith(window.location.origin)) {
107
+ link.target = "_blank";
108
+ link.rel = "noopener noreferrer";
109
+ }
110
+ });
111
+ }
112
+
113
+ /**
114
+ * Initialize all markdown enhancements (Mermaid + external links).
115
+ * KaTeX is rendered server-side and doesn't need client initialization.
116
+ * Call this in onMount() of your client-side component.
117
+ *
118
+ * @param container - The container element containing rendered markdown
119
+ */
120
+ export async function initMarkdownEnhancements(container: HTMLElement): Promise<void> {
121
+ await initMermaid(container);
122
+ initExternalLinks(container);
123
+ }
124
+
125
+ export const markdownClient = {
126
+ initMermaid,
127
+ initExternalLinks,
128
+ initEnhancements: initMarkdownEnhancements,
129
+ initMarkdownEnhancements,
130
+ } as const;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Code extension for marked
3
+ *
4
+ * Renders code blocks and inline code with consistent styling.
5
+ * Uses the dependency-free stdlib highlighter for common languages. Custom
6
+ * documentation languages stay shallow on purpose: highlighting must never
7
+ * change source text or require a browser-side parser.
8
+ */
9
+
10
+ import { type Highlighter, highlight } from "@k2b/stdlib";
11
+ import type { MarkedExtension, Tokens } from "marked";
12
+ import { escapeHtml } from "../shared";
13
+
14
+ const gqlHighlighter = highlight.compile([
15
+ { kind: "comment", match: /#[^\n]*/ },
16
+ { kind: "string", match: /"""[\s\S]*?"""|"(?:\\[\s\S]|[^"\\])*"/ },
17
+ { kind: "variable", match: /\$[a-zA-Z_][a-zA-Z0-9_]*/ },
18
+ {
19
+ kind: "keyword",
20
+ match: /\b(?:query|mutation|subscription|fragment|on|type|input|enum|interface|union|scalar|schema|extend|directive)\b/,
21
+ },
22
+ { kind: "number", match: /\b-?\d+(?:\.\d+)?\b/ },
23
+ { kind: "operator", match: /[!$():=@[\]{|}]+/ },
24
+ ]);
25
+
26
+ const yamlHighlighter = highlight.compile([
27
+ { kind: "comment", match: /#[^\n]*/ },
28
+ { kind: "string", match: /"(?:\\[\s\S]|[^"\\])*"|'(?:''|[^'])*'/ },
29
+ { kind: "variable", match: /[&*!][a-zA-Z_][a-zA-Z0-9_-]*/ },
30
+ { kind: "keyword", match: /\b(?:true|false|null|yes|no|on|off)\b/i },
31
+ { kind: "number", match: /\b-?\d+(?:\.\d+)?\b/ },
32
+ { kind: "operator", match: /---|\.\.\.|[|>{}[\],:&*!?-]+/ },
33
+ ]);
34
+
35
+ const languageHighlighters: Readonly<Record<string, Highlighter>> = {
36
+ bash: highlight.presets.shell,
37
+ gql: gqlHighlighter,
38
+ graphql: gqlHighlighter,
39
+ javascript: highlight.presets.code,
40
+ js: highlight.presets.code,
41
+ jsx: highlight.presets.code,
42
+ script: highlight.presets.code,
43
+ sh: highlight.presets.shell,
44
+ shell: highlight.presets.shell,
45
+ ts: highlight.presets.code,
46
+ tsx: highlight.presets.code,
47
+ typescript: highlight.presets.code,
48
+ yaml: yamlHighlighter,
49
+ yml: yamlHighlighter,
50
+ zsh: highlight.presets.shell,
51
+ };
52
+
53
+ const renderCode = (source: string, language?: string): string => {
54
+ const highlighter = language ? languageHighlighters[language.toLowerCase()] : undefined;
55
+ return highlighter ? highlighter(source) : escapeHtml(source);
56
+ };
57
+
58
+ export function codeExtension(): MarkedExtension {
59
+ return {
60
+ renderer: {
61
+ code(token: Tokens.Code): string {
62
+ const { text, lang } = token;
63
+ const langLower = lang?.toLowerCase();
64
+ const renderedCode = renderCode(text, langLower);
65
+ const isMermaid = langLower === "mermaid";
66
+
67
+ // Language class for syntax highlighting / mermaid detection
68
+ const langClass = lang ? ` language-${escapeHtml(lang)}` : "";
69
+
70
+ // Special rendering for mermaid blocks with fixed height container
71
+ if (isMermaid) {
72
+ return (
73
+ `<div class="md-mermaid-block my-3 rounded-md border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800" style="height: 400px;">` +
74
+ `<div class="h-full w-full flex items-center justify-center p-4">` +
75
+ `<pre class="hidden"><code class="language-mermaid">${renderedCode}</code></pre>` +
76
+ `<div class="md-mermaid-loading text-dimmed text-sm flex items-center gap-2">` +
77
+ `<i class="ti ti-loader-2 animate-spin"></i> Loading diagram...` +
78
+ `</div>` +
79
+ `</div>` +
80
+ `</div>`
81
+ );
82
+ }
83
+
84
+ // Language badge if specified
85
+ const langBadge = lang
86
+ ? `<span class="absolute top-2 right-2 text-xs text-gray-400 dark:text-gray-500 font-mono select-none">${escapeHtml(lang)}</span>`
87
+ : "";
88
+
89
+ return (
90
+ `<div class="md-code-block relative my-3">` +
91
+ langBadge +
92
+ `<pre class="bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-md p-4 overflow-x-auto">` +
93
+ `<code class="text-sm font-mono text-gray-800 dark:text-gray-200 whitespace-pre${langClass}">${renderedCode}</code>` +
94
+ `</pre>` +
95
+ `</div>`
96
+ );
97
+ },
98
+
99
+ codespan(token: Tokens.Codespan): string {
100
+ const escapedCode = escapeHtml(token.text);
101
+ return `<code class="bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 px-1.5 py-0.5 rounded text-sm font-mono">${escapedCode}</code>`;
102
+ },
103
+ },
104
+ };
105
+ }
@@ -0,0 +1,100 @@
1
+ import type { MarkedExtension, Tokens } from "marked";
2
+
3
+ type GuidedBlock = "compare" | "reference" | "steps";
4
+
5
+ const guidedBlocks = new Set<GuidedBlock>(["compare", "reference", "steps"]);
6
+ const headingMetaPattern = /\s+\{icon="([a-z0-9-]+)"\}\s*$/i;
7
+
8
+ const slug = (value: string): string =>
9
+ value
10
+ .toLocaleLowerCase()
11
+ .normalize("NFKD")
12
+ .replace(/[\u0300-\u036f]/g, "")
13
+ .replace(/[^a-z0-9]+/g, "-")
14
+ .replace(/^-+|-+$/g, "") || "section";
15
+
16
+ const headingTitleTokens = (token: Tokens.Heading, hasMetadata: boolean): Tokens.Heading["tokens"] => {
17
+ if (!hasMetadata) return token.tokens;
18
+
19
+ const tokens = [...token.tokens];
20
+ const trailingToken = tokens.at(-1);
21
+ if (trailingToken?.type !== "text") return tokens;
22
+
23
+ const raw = trailingToken.raw.replace(headingMetaPattern, "");
24
+ const text = trailingToken.text.replace(headingMetaPattern, "");
25
+ if (!raw && !text) {
26
+ tokens.pop();
27
+ } else {
28
+ tokens[tokens.length - 1] = { ...trailingToken, raw, text };
29
+ }
30
+
31
+ return tokens;
32
+ };
33
+
34
+ /**
35
+ * Help-only Markdown affordances. The source stays useful as plain Markdown:
36
+ * the directives merely add reading semantics to otherwise ordinary lists.
37
+ */
38
+ export function guidedHelpExtension(): MarkedExtension {
39
+ const headingIds = new Map<string, number>();
40
+
41
+ return {
42
+ hooks: {
43
+ preprocess(source) {
44
+ headingIds.clear();
45
+ return source;
46
+ },
47
+ },
48
+ renderer: {
49
+ paragraph(token: Tokens.Paragraph) {
50
+ if (token.tokens.length !== 1 || token.tokens[0]?.type !== "strong") return false;
51
+ return `<p class="help-eyebrow">${this.parser.parseInline(token.tokens)}</p>`;
52
+ },
53
+ heading(token: Tokens.Heading) {
54
+ const metadata = token.text.match(headingMetaPattern);
55
+ const title = metadata ? token.text.slice(0, metadata.index).trim() : token.text;
56
+ const baseId = slug(title);
57
+ const occurrence = headingIds.get(baseId) ?? 0;
58
+ headingIds.set(baseId, occurrence + 1);
59
+ const id = occurrence === 0 ? baseId : `${baseId}-${occurrence + 1}`;
60
+
61
+ if (token.depth === 2) {
62
+ const icon = metadata?.[1] ? `ti ti-${metadata[1]}` : "ti ti-point";
63
+ return `<h2 id="${id}" class="help-section-title" data-help-icon="${icon}">
64
+ <span class="help-section-icon" aria-hidden="true"><i class="${icon}"></i></span>
65
+ <span>${this.parser.parseInline(headingTitleTokens(token, Boolean(metadata)))}</span>
66
+ </h2>`;
67
+ }
68
+
69
+ return `<h${token.depth} id="${id}">${this.parser.parseInline(token.tokens)}</h${token.depth}>`;
70
+ },
71
+ },
72
+ extensions: [
73
+ {
74
+ name: "guidedHelpBlock",
75
+ level: "block",
76
+ start(source) {
77
+ return source.match(/^:::(?:compare|reference|steps)\b/)?.index;
78
+ },
79
+ tokenizer(source) {
80
+ const match = source.match(/^:::(compare|reference|steps)[ \t]*\n([\s\S]*?)\n:::(?:\n|$)/);
81
+ if (!match) return undefined;
82
+ const kind = match[1] as GuidedBlock;
83
+ if (!guidedBlocks.has(kind)) return undefined;
84
+ const content = match[2]?.trim() ?? "";
85
+ return {
86
+ type: "guidedHelpBlock",
87
+ raw: match[0],
88
+ kind,
89
+ tokens: this.lexer.blockTokens(content),
90
+ };
91
+ },
92
+ renderer(token: Tokens.Generic) {
93
+ const kind = token.kind as GuidedBlock;
94
+ return `<div class="help-${kind}">${this.parser.parse(token.tokens as Tokens.Generic[])}</div>`;
95
+ },
96
+ childTokens: ["tokens"],
97
+ },
98
+ ],
99
+ };
100
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Images extension for marked
3
+ *
4
+ * Renders images with the same visual style as the CodeMirror editor:
5
+ * - Centered figure with max-height constraint
6
+ * - Rounded border
7
+ * - Optional caption from alt text
8
+ *
9
+ * Supports an optional Pandoc/HFM-style size suffix on the URL:
10
+ *
11
+ * ![alt](https://example.com/photo.png =400x300) // both
12
+ * ![alt](https://example.com/photo.png =400x) // width only
13
+ * ![alt](https://example.com/photo.png =x300) // height only
14
+ *
15
+ * Marked's default tokenizer treats the trailing ` =WxH` as part of the
16
+ * URL — we parse and strip it here before emitting the `<img>` tag.
17
+ */
18
+
19
+ import type { MarkedExtension, Tokens } from "marked";
20
+ import { escapeHtml, IMAGE_STYLES } from "../shared";
21
+
22
+ const SIZE_SUFFIX_REGEX = /\s+=(\d+)?x(\d+)?$/;
23
+
24
+ type ParsedImage = {
25
+ href: string;
26
+ width: string | null;
27
+ height: string | null;
28
+ };
29
+
30
+ const parseImageUrl = (href: string): ParsedImage => {
31
+ const match = SIZE_SUFFIX_REGEX.exec(href);
32
+ if (!match) return { href, width: null, height: null };
33
+ return {
34
+ href: href.slice(0, match.index),
35
+ width: match[1] ?? null,
36
+ height: match[2] ?? null,
37
+ };
38
+ };
39
+
40
+ export function imagesExtension(): MarkedExtension {
41
+ return {
42
+ renderer: {
43
+ image(token: Tokens.Image): string {
44
+ const { href: rawHref, title, text: alt } = token;
45
+ const { href, width, height } = parseImageUrl(rawHref);
46
+
47
+ // Build the image element
48
+ const imgAttrs = [`src="${escapeHtml(href)}"`, `alt="${escapeHtml(alt || "")}"`, `loading="lazy"`, `class="${IMAGE_STYLES.img}"`];
49
+
50
+ if (title) imgAttrs.push(`title="${escapeHtml(title)}"`);
51
+ if (width) imgAttrs.push(`width="${width}"`);
52
+ if (height) imgAttrs.push(`height="${height}"`);
53
+
54
+ // Inline style overrides the global `max-height: 400px` from
55
+ // IMAGE_STYLES.img only when the user opted into a custom size.
56
+ if (width || height) {
57
+ const styles: string[] = ["max-height: none"];
58
+ if (width) styles.push(`max-width: ${width}px`);
59
+ imgAttrs.push(`style="${styles.join("; ")}"`);
60
+ }
61
+
62
+ const imgHtml = `<img ${imgAttrs.join(" ")} />`;
63
+
64
+ // Build caption if alt text provided
65
+ const captionHtml = alt ? `<figcaption class="${IMAGE_STYLES.caption}">${escapeHtml(alt)}</figcaption>` : "";
66
+
67
+ // Wrap in figure for centering
68
+ return (
69
+ `<div class="${IMAGE_STYLES.wrapper}">` +
70
+ `<figure class="${IMAGE_STYLES.figure}">` +
71
+ imgHtml +
72
+ captionHtml +
73
+ `</figure>` +
74
+ `</div>`
75
+ );
76
+ },
77
+ },
78
+ };
79
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Info Blocks Extension for Marked
3
+ *
4
+ * Renders custom info blocks with syntax:
5
+ * :::note
6
+ * Content here
7
+ * :::
8
+ *
9
+ * The type follows the colons directly — `::: note` with a space does not
10
+ * match. An optional argument after the type overrides the label:
11
+ * `:::warning Before deleting`.
12
+ *
13
+ * Supported types: note, info, success, warning, danger
14
+ */
15
+
16
+ import type { MarkedExtension, Tokens } from "marked";
17
+ import { NOTICE_CARD_CLASSES, NOTICE_CARD_ICONS, type NoticeTone } from "@k2b/ui";
18
+ import { escapeHtml } from "../shared";
19
+
20
+ type BlockType = "note" | "info" | "success" | "warning" | "danger";
21
+
22
+ const blockConfig: Record<BlockType, { label: string; tone: NoticeTone }> = {
23
+ note: {
24
+ label: "Note",
25
+ tone: "neutral",
26
+ },
27
+ info: {
28
+ label: "Info",
29
+ tone: "info",
30
+ },
31
+ success: {
32
+ label: "Success",
33
+ tone: "success",
34
+ },
35
+ warning: {
36
+ label: "Warning",
37
+ tone: "warning",
38
+ },
39
+ danger: {
40
+ label: "Danger",
41
+ tone: "danger",
42
+ },
43
+ };
44
+
45
+ const renderInlineContent = (content: string): string => {
46
+ return content
47
+ .replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>")
48
+ .replace(/(?<!\*)\*([^*]+)\*(?!\*)/g, "<em>$1</em>")
49
+ .replace(/`([^`]+)`/g, '<code class="bg-black/10 dark:bg-white/10 px-1 py-0.5 rounded text-sm">$1</code>')
50
+ .replace(/\n/g, "<br>");
51
+ };
52
+
53
+ export function infoBlocksExtension(): MarkedExtension {
54
+ return {
55
+ extensions: [
56
+ {
57
+ name: "infoBlock",
58
+ level: "block",
59
+ start(src: string) {
60
+ return src.match(/^:::/)?.index;
61
+ },
62
+ tokenizer(src: string) {
63
+ const match = src.match(/^:::(\w+)(?:[ \t]+([^\n]+))?\s*\n([\s\S]*?)\n:::/);
64
+ if (!match) return undefined;
65
+
66
+ const typeStr = match[1]?.toLowerCase() as BlockType;
67
+ if (!blockConfig[typeStr]) return undefined;
68
+
69
+ return {
70
+ type: "infoBlock",
71
+ raw: match[0],
72
+ blockType: typeStr,
73
+ title: match[2]?.trim(),
74
+ content: match[3]?.trim() ?? "",
75
+ };
76
+ },
77
+ renderer(token: Tokens.Generic) {
78
+ const blockType = token.blockType as BlockType;
79
+ const config = blockConfig[blockType];
80
+ const content = escapeHtml(token.content as string);
81
+ const title = escapeHtml((token.title as string | undefined) ?? config.label);
82
+ const renderedContent = renderInlineContent(content);
83
+
84
+ return `<aside class="${NOTICE_CARD_CLASSES.root}" data-tone="${config.tone}">
85
+ <div class="${NOTICE_CARD_CLASSES.inner}">
86
+ <i class="${NOTICE_CARD_ICONS[config.tone]} ${NOTICE_CARD_CLASSES.icon}" aria-hidden="true"></i>
87
+ <div class="${NOTICE_CARD_CLASSES.content}">
88
+ <p class="${NOTICE_CARD_CLASSES.title}">${title}</p>
89
+ <div class="${NOTICE_CARD_CLASSES.body}">${renderedContent}</div>
90
+ </div>
91
+ </div>
92
+ </aside>`;
93
+ },
94
+ },
95
+ ],
96
+ };
97
+ }
@@ -0,0 +1,120 @@
1
+ /**
2
+ * KaTeX extension for marked
3
+ *
4
+ * Renders LaTeX math expressions server-side:
5
+ * - Inline: $..$ or \(..\)
6
+ * - Block: $$...$$ or \[..\] or ```math
7
+ */
8
+
9
+ import katex from "katex";
10
+ import type { MarkedExtension, Tokens } from "marked";
11
+
12
+ /**
13
+ * Token shape produced by the math tokenizers below. The marked extension API
14
+ * types renderer params as `Tokens.Generic` (open `[index: string]: any`), so
15
+ * we narrow at the call boundary by reading `latex` off the typed sub-shape.
16
+ */
17
+ type MathToken = Tokens.Generic & { latex: string };
18
+
19
+ function renderBlockMath(latex: string): string {
20
+ try {
21
+ const html = katex.renderToString(latex, {
22
+ throwOnError: false,
23
+ displayMode: true,
24
+ });
25
+ return `<div class="md-katex-block my-3 flex items-center justify-center">${html}</div>`;
26
+ } catch {
27
+ return `<div class="md-katex-block my-3 flex items-center justify-center text-red-500 text-sm"><i class="ti ti-alert-circle mr-1"></i> Invalid LaTeX</div>`;
28
+ }
29
+ }
30
+
31
+ function renderInlineMath(latex: string): string {
32
+ try {
33
+ const html = katex.renderToString(latex, {
34
+ throwOnError: false,
35
+ displayMode: false,
36
+ });
37
+ return `<span class="md-katex-inline">${html}</span>`;
38
+ } catch {
39
+ return `<span class="md-katex-inline text-red-500 font-mono text-sm">$${latex}$</span>`;
40
+ }
41
+ }
42
+
43
+ export function katexExtension(): MarkedExtension {
44
+ return {
45
+ extensions: [
46
+ // ```math code blocks
47
+ {
48
+ name: "mathCodeBlock",
49
+ level: "block",
50
+ start(src: string) {
51
+ const match = src.match(/^```math/m);
52
+ return match ? match.index : undefined;
53
+ },
54
+ tokenizer(src: string) {
55
+ const match = /^```math\n([\s\S]*?)\n```/.exec(src);
56
+ if (match) {
57
+ return {
58
+ type: "mathCodeBlock",
59
+ raw: match[0],
60
+ latex: match[1]!.trim(),
61
+ };
62
+ }
63
+ return undefined;
64
+ },
65
+ renderer(token: Tokens.Generic) {
66
+ const latex = (token as MathToken).latex;
67
+ return renderBlockMath(latex);
68
+ },
69
+ },
70
+ // Block math with $$ ... $$
71
+ {
72
+ name: "blockMath",
73
+ level: "block",
74
+ start(src: string) {
75
+ const match = src.match(/\$\$/);
76
+ return match ? match.index : undefined;
77
+ },
78
+ tokenizer(src: string) {
79
+ const match = /^\$\$([\s\S]+?)\$\$/.exec(src);
80
+ if (match) {
81
+ return {
82
+ type: "blockMath",
83
+ raw: match[0],
84
+ latex: match[1]!.trim(),
85
+ };
86
+ }
87
+ return undefined;
88
+ },
89
+ renderer(token: Tokens.Generic) {
90
+ const latex = (token as MathToken).latex;
91
+ return renderBlockMath(latex);
92
+ },
93
+ },
94
+ // Inline math with $ ... $
95
+ {
96
+ name: "inlineMath",
97
+ level: "inline",
98
+ start(src: string) {
99
+ const match = src.match(/(?<!\$)\$(?!\$)/);
100
+ return match ? match.index : undefined;
101
+ },
102
+ tokenizer(src: string) {
103
+ const match = /^(?<!\$)\$(?!\$)([^$\n]+)\$(?!\$)/.exec(src);
104
+ if (match) {
105
+ return {
106
+ type: "inlineMath",
107
+ raw: match[0],
108
+ latex: match[1]!.trim(),
109
+ };
110
+ }
111
+ return undefined;
112
+ },
113
+ renderer(token: Tokens.Generic) {
114
+ const latex = (token as MathToken).latex;
115
+ return renderInlineMath(latex);
116
+ },
117
+ },
118
+ ],
119
+ };
120
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Links extension for marked
3
+ *
4
+ * Renders links with the same visual style as the CodeMirror editor:
5
+ * - Shows [label] in bold followed by an arrow icon
6
+ * - Opens in new tab with noopener,noreferrer
7
+ */
8
+
9
+ import type { MarkedExtension, Tokens } from "marked";
10
+ import { escapeHtml, LINK_STYLES } from "../shared";
11
+
12
+ export type LinksExtensionOptions = {
13
+ /** Open external links in a new tab by default. */
14
+ externalTarget?: "_blank" | "_self";
15
+ /** Existing content keeps `_blank`; help opts into in-app navigation. */
16
+ internalTarget?: "_blank" | "_self";
17
+ };
18
+
19
+ const isExternalHref = (href: string) => /^(?:https?:)?\/\//i.test(href);
20
+
21
+ export function linksExtension(options: LinksExtensionOptions = {}): MarkedExtension {
22
+ return {
23
+ renderer: {
24
+ link(token: Tokens.Link): string {
25
+ const { href, title, text } = token;
26
+
27
+ // Build title attribute if provided
28
+ const titleAttr = title ? ` title="${escapeHtml(title)}"` : "";
29
+
30
+ // Match CodeMirror style: [label] with arrow icon
31
+ const target = isExternalHref(href) ? (options.externalTarget ?? "_blank") : (options.internalTarget ?? "_blank");
32
+ const targetAttrs = target === "_blank" ? ' target="_blank" rel="noopener noreferrer"' : "";
33
+
34
+ return (
35
+ `<a href="${escapeHtml(href)}"${titleAttr}${targetAttrs} class="${LINK_STYLES.link}">` +
36
+ `<span class="${LINK_STYLES.label}">[${escapeHtml(text)}]</span>` +
37
+ `<i class="${LINK_STYLES.icon} ti ti-arrow-up-right text-xs" aria-hidden="true"></i>` +
38
+ `</a>`
39
+ );
40
+ },
41
+ },
42
+ };
43
+ }