@stacksjs/defaults 0.70.207 → 0.70.208

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 (408) hide show
  1. package/TODO.md +21 -0
  2. package/ai/AGENTS.md +79 -0
  3. package/ai/README.md +45 -0
  4. package/ai/claude/launch.json +12 -0
  5. package/ai/skills/stacks-actions/SKILL.md +128 -0
  6. package/ai/skills/stacks-ai/SKILL.md +276 -0
  7. package/ai/skills/stacks-alias/SKILL.md +94 -0
  8. package/ai/skills/stacks-analytics/SKILL.md +91 -0
  9. package/ai/skills/stacks-api/SKILL.md +738 -0
  10. package/ai/skills/stacks-arrays/SKILL.md +277 -0
  11. package/ai/skills/stacks-auth/SKILL.md +422 -0
  12. package/ai/skills/stacks-auto-imports/SKILL.md +138 -0
  13. package/ai/skills/stacks-brandkit/SKILL.md +811 -0
  14. package/ai/skills/stacks-browse/SKILL.md +127 -0
  15. package/ai/skills/stacks-browse/scripts/browse.ts +492 -0
  16. package/ai/skills/stacks-browser/SKILL.md +145 -0
  17. package/ai/skills/stacks-buddy/SKILL.md +676 -0
  18. package/ai/skills/stacks-build/SKILL.md +163 -0
  19. package/ai/skills/stacks-cache/SKILL.md +125 -0
  20. package/ai/skills/stacks-calendar/SKILL.md +113 -0
  21. package/ai/skills/stacks-chat/SKILL.md +371 -0
  22. package/ai/skills/stacks-cli/SKILL.md +112 -0
  23. package/ai/skills/stacks-cloud/SKILL.md +192 -0
  24. package/ai/skills/stacks-cms/SKILL.md +217 -0
  25. package/ai/skills/stacks-collections/SKILL.md +82 -0
  26. package/ai/skills/stacks-commerce/SKILL.md +114 -0
  27. package/ai/skills/stacks-composables/SKILL.md +161 -0
  28. package/ai/skills/stacks-config/SKILL.md +144 -0
  29. package/ai/skills/stacks-configuration/SKILL.md +154 -0
  30. package/ai/skills/stacks-cron/SKILL.md +123 -0
  31. package/ai/skills/stacks-crosswind/SKILL.md +190 -0
  32. package/ai/skills/stacks-dashboard/SKILL.md +173 -0
  33. package/ai/skills/stacks-database/SKILL.md +286 -0
  34. package/ai/skills/stacks-datetime/SKILL.md +269 -0
  35. package/ai/skills/stacks-dependencies/SKILL.md +111 -0
  36. package/ai/skills/stacks-deploy/SKILL.md +102 -0
  37. package/ai/skills/stacks-design-brutalist/SKILL.md +110 -0
  38. package/ai/skills/stacks-design-minimalist/SKILL.md +115 -0
  39. package/ai/skills/stacks-design-output/SKILL.md +55 -0
  40. package/ai/skills/stacks-design-soft/SKILL.md +156 -0
  41. package/ai/skills/stacks-design-taste/SKILL.md +1012 -0
  42. package/ai/skills/stacks-design-taste-codex/SKILL.md +294 -0
  43. package/ai/skills/stacks-desktop/SKILL.md +78 -0
  44. package/ai/skills/stacks-development/SKILL.md +298 -0
  45. package/ai/skills/stacks-dns/SKILL.md +149 -0
  46. package/ai/skills/stacks-docs/SKILL.md +109 -0
  47. package/ai/skills/stacks-email/SKILL.md +236 -0
  48. package/ai/skills/stacks-enums/SKILL.md +100 -0
  49. package/ai/skills/stacks-env/SKILL.md +181 -0
  50. package/ai/skills/stacks-error-handling/SKILL.md +137 -0
  51. package/ai/skills/stacks-events/SKILL.md +228 -0
  52. package/ai/skills/stacks-faker/SKILL.md +158 -0
  53. package/ai/skills/stacks-git/SKILL.md +158 -0
  54. package/ai/skills/stacks-guard/SKILL.md +98 -0
  55. package/ai/skills/stacks-health/SKILL.md +75 -0
  56. package/ai/skills/stacks-http/SKILL.md +316 -0
  57. package/ai/skills/stacks-i18n/SKILL.md +198 -0
  58. package/ai/skills/stacks-image-to-code/SKILL.md +629 -0
  59. package/ai/skills/stacks-imagegen-mobile/SKILL.md +1474 -0
  60. package/ai/skills/stacks-imagegen-web/SKILL.md +998 -0
  61. package/ai/skills/stacks-investigate/SKILL.md +119 -0
  62. package/ai/skills/stacks-jobs/SKILL.md +136 -0
  63. package/ai/skills/stacks-lint/SKILL.md +184 -0
  64. package/ai/skills/stacks-listeners/SKILL.md +99 -0
  65. package/ai/skills/stacks-logging/SKILL.md +78 -0
  66. package/ai/skills/stacks-mail/SKILL.md +120 -0
  67. package/ai/skills/stacks-middleware/SKILL.md +249 -0
  68. package/ai/skills/stacks-migrations/SKILL.md +105 -0
  69. package/ai/skills/stacks-models/SKILL.md +267 -0
  70. package/ai/skills/stacks-new-feature/SKILL.md +206 -0
  71. package/ai/skills/stacks-notifications/SKILL.md +210 -0
  72. package/ai/skills/stacks-objects/SKILL.md +205 -0
  73. package/ai/skills/stacks-office-hours/SKILL.md +134 -0
  74. package/ai/skills/stacks-orm/SKILL.md +342 -0
  75. package/ai/skills/stacks-path/SKILL.md +118 -0
  76. package/ai/skills/stacks-payments/SKILL.md +373 -0
  77. package/ai/skills/stacks-plan-review/SKILL.md +152 -0
  78. package/ai/skills/stacks-plugins/SKILL.md +149 -0
  79. package/ai/skills/stacks-push/SKILL.md +376 -0
  80. package/ai/skills/stacks-query-builder/SKILL.md +128 -0
  81. package/ai/skills/stacks-queue/SKILL.md +559 -0
  82. package/ai/skills/stacks-realtime/SKILL.md +442 -0
  83. package/ai/skills/stacks-redesign/SKILL.md +182 -0
  84. package/ai/skills/stacks-registry/SKILL.md +58 -0
  85. package/ai/skills/stacks-repl/SKILL.md +80 -0
  86. package/ai/skills/stacks-retro/SKILL.md +122 -0
  87. package/ai/skills/stacks-review/SKILL.md +135 -0
  88. package/ai/skills/stacks-router/SKILL.md +231 -0
  89. package/ai/skills/stacks-routes/SKILL.md +105 -0
  90. package/ai/skills/stacks-scaffolding/SKILL.md +162 -0
  91. package/ai/skills/stacks-scheduler/SKILL.md +363 -0
  92. package/ai/skills/stacks-search-engine/SKILL.md +112 -0
  93. package/ai/skills/stacks-security/SKILL.md +129 -0
  94. package/ai/skills/stacks-security-audit/SKILL.md +128 -0
  95. package/ai/skills/stacks-server/SKILL.md +458 -0
  96. package/ai/skills/stacks-shell/SKILL.md +62 -0
  97. package/ai/skills/stacks-slug/SKILL.md +87 -0
  98. package/ai/skills/stacks-sms/SKILL.md +385 -0
  99. package/ai/skills/stacks-socials/SKILL.md +303 -0
  100. package/ai/skills/stacks-storage/SKILL.md +576 -0
  101. package/ai/skills/stacks-strings/SKILL.md +416 -0
  102. package/ai/skills/stacks-stx/SKILL.md +176 -0
  103. package/ai/skills/stacks-technical-diagrams/LICENSE +22 -0
  104. package/ai/skills/stacks-technical-diagrams/SKILL.md +290 -0
  105. package/ai/skills/stacks-technical-diagrams/agents/openai.yaml +4 -0
  106. package/ai/skills/stacks-technical-diagrams/assets/template.html +1252 -0
  107. package/ai/skills/stacks-technical-diagrams/bin/technical-diagrams.mjs +289 -0
  108. package/ai/skills/stacks-technical-diagrams/bunfig.toml +1 -0
  109. package/ai/skills/stacks-technical-diagrams/examples/agent-run.lifecycle.json +64 -0
  110. package/ai/skills/stacks-technical-diagrams/examples/agent-tool-call.workflow.json +88 -0
  111. package/ai/skills/stacks-technical-diagrams/examples/cache-miss-request.sequence.json +75 -0
  112. package/ai/skills/stacks-technical-diagrams/examples/product-analytics.dataflow.json +70 -0
  113. package/ai/skills/stacks-technical-diagrams/examples/web-app.architecture.json +41 -0
  114. package/ai/skills/stacks-technical-diagrams/renderers/architecture/grid.mjs +62 -0
  115. package/ai/skills/stacks-technical-diagrams/renderers/architecture/render-architecture.mjs +371 -0
  116. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/README.md +82 -0
  117. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/render-dataflow.mjs +295 -0
  118. package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/README.md +91 -0
  119. package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/render-lifecycle.mjs +384 -0
  120. package/ai/skills/stacks-technical-diagrams/renderers/sequence/README.md +84 -0
  121. package/ai/skills/stacks-technical-diagrams/renderers/sequence/render-sequence.mjs +257 -0
  122. package/ai/skills/stacks-technical-diagrams/renderers/shared/cli.mjs +42 -0
  123. package/ai/skills/stacks-technical-diagrams/renderers/shared/generated-validators.mjs +13 -0
  124. package/ai/skills/stacks-technical-diagrams/renderers/shared/geometry.mjs +230 -0
  125. package/ai/skills/stacks-technical-diagrams/renderers/shared/layout-report.mjs +40 -0
  126. package/ai/skills/stacks-technical-diagrams/renderers/shared/utils.mjs +88 -0
  127. package/ai/skills/stacks-technical-diagrams/renderers/shared/validator.mjs +40 -0
  128. package/ai/skills/stacks-technical-diagrams/renderers/workflow/README.md +103 -0
  129. package/ai/skills/stacks-technical-diagrams/renderers/workflow/render-workflow.mjs +481 -0
  130. package/ai/skills/stacks-technical-diagrams/schemas/README.md +68 -0
  131. package/ai/skills/stacks-technical-diagrams/schemas/architecture.schema.json +121 -0
  132. package/ai/skills/stacks-technical-diagrams/schemas/common.schema.json +43 -0
  133. package/ai/skills/stacks-technical-diagrams/schemas/dataflow.schema.json +221 -0
  134. package/ai/skills/stacks-technical-diagrams/schemas/lifecycle.schema.json +241 -0
  135. package/ai/skills/stacks-technical-diagrams/schemas/sequence.schema.json +186 -0
  136. package/ai/skills/stacks-technical-diagrams/schemas/workflow.schema.json +332 -0
  137. package/ai/skills/stacks-technical-diagrams/scripts/check-render-output.mjs +297 -0
  138. package/ai/skills/stacks-technical-diagrams/scripts/render-examples.mjs +28 -0
  139. package/ai/skills/stacks-testing/SKILL.md +129 -0
  140. package/ai/skills/stacks-tunnel/SKILL.md +125 -0
  141. package/ai/skills/stacks-types/SKILL.md +178 -0
  142. package/ai/skills/stacks-ui/SKILL.md +246 -0
  143. package/ai/skills/stacks-utils/SKILL.md +444 -0
  144. package/ai/skills/stacks-validation/SKILL.md +371 -0
  145. package/ai/skills/stacks-whois/SKILL.md +315 -0
  146. package/assets/world-map-data.ts +121 -0
  147. package/bootstrap.ts +114 -0
  148. package/docs/api-examples.md +46 -0
  149. package/docs/index.md +24 -0
  150. package/docs/markdown-examples.md +87 -0
  151. package/functions/analytics.ts +97 -0
  152. package/functions/api.ts +143 -0
  153. package/functions/auth.ts +208 -0
  154. package/functions/billing/payments.ts +149 -0
  155. package/functions/blog.ts +120 -0
  156. package/functions/cms/categorizables.ts +107 -0
  157. package/functions/cms/pages.ts +108 -0
  158. package/functions/cms/posts.ts +100 -0
  159. package/functions/cms/taggables.ts +102 -0
  160. package/functions/commerce/coupons.ts +128 -0
  161. package/functions/commerce/customers.ts +128 -0
  162. package/functions/commerce/gift-cards.ts +119 -0
  163. package/functions/commerce/orders.ts +112 -0
  164. package/functions/commerce/payments.ts +119 -0
  165. package/functions/commerce/products/categories.ts +123 -0
  166. package/functions/commerce/products/manufacturers.ts +123 -0
  167. package/functions/commerce/products/products.ts +123 -0
  168. package/functions/commerce/products/reviews.ts +123 -0
  169. package/functions/commerce/products/units.ts +123 -0
  170. package/functions/commerce/products/variants.ts +123 -0
  171. package/functions/commerce/shippings/delivery-routes.ts +123 -0
  172. package/functions/commerce/shippings/digital-deliveries.ts +119 -0
  173. package/functions/commerce/shippings/drivers.ts +123 -0
  174. package/functions/commerce/shippings/license-keys.ts +123 -0
  175. package/functions/commerce/shippings/shipping-methods.ts +123 -0
  176. package/functions/commerce/shippings/shipping-rates.ts +119 -0
  177. package/functions/commerce/shippings/shipping-zones.ts +119 -0
  178. package/functions/commerce/taxes.ts +119 -0
  179. package/functions/commerce/waitlist/products.ts +123 -0
  180. package/functions/commerce/waitlist/restaurants.ts +123 -0
  181. package/functions/craft.ts +107 -0
  182. package/functions/dashboard.ts +153 -0
  183. package/functions/inbox.ts +95 -0
  184. package/functions/jobs.ts +86 -0
  185. package/functions/monitoring/errors.ts +295 -0
  186. package/functions/queue.ts +111 -0
  187. package/functions/realtime/websockets.ts +96 -0
  188. package/functions/realtime.ts +52 -0
  189. package/functions/releases.ts +49 -0
  190. package/functions/search.ts +126 -0
  191. package/functions/toasts.ts +95 -0
  192. package/functions/uploads.ts +216 -0
  193. package/ide/.gitignore +4 -0
  194. package/ide/cursor/rules/auto-imports.mdc +574 -0
  195. package/ide/cursor/rules/code-style.mdc +12 -0
  196. package/ide/cursor/rules/documentation.mdc +9 -0
  197. package/ide/cursor/rules/error-handling-validation.mdc +11 -0
  198. package/ide/cursor/rules/key-conventions.mdc +11 -0
  199. package/ide/cursor/rules/project-structure.mdc +169 -0
  200. package/ide/cursor/rules/readme.mdc +318 -0
  201. package/ide/cursor/rules/syntax-formatting.mdc +9 -0
  202. package/ide/cursor/rules/testing.mdc +10 -0
  203. package/ide/cursor/rules/typescript.mdc +9 -0
  204. package/ide/cursor/rules/ui-styling.mdc +0 -0
  205. package/ide/dictionary.txt +397 -0
  206. package/ide/jetbrains/.fleet/settings.json +4 -0
  207. package/ide/jetbrains/.idea/.gitignore +5 -0
  208. package/ide/jetbrains/.idea/.name +1 -0
  209. package/ide/jetbrains/.idea/inspectionProfiles/Project_Default.xml +6 -0
  210. package/ide/jetbrains/.idea/jsLinters/eslint.xml +7 -0
  211. package/ide/jetbrains/.idea/modules.xml +8 -0
  212. package/ide/jetbrains/.idea/stacks.iml +22 -0
  213. package/ide/jetbrains/.idea/vcs.xml +6 -0
  214. package/ide/jetbrains/.idea/webResources.xml +14 -0
  215. package/ide/jetbrains/IntelliJ IDEA Global Settings +0 -0
  216. package/ide/jetbrains/installed.txt +4 -0
  217. package/ide/jetbrains/options/github-copilot.xml +5 -0
  218. package/ide/jetbrains/options/nodejs.xml +7 -0
  219. package/ide/jetbrains/options/templates.xml +124 -0
  220. package/ide/jetbrains/templates/JavaScript.xml +6 -0
  221. package/ide/jetbrains/templates/Stacks.xml +8 -0
  222. package/ide/vscode/.vscode/README.md +23 -0
  223. package/ide/vscode/.vscode/extensions.json +5 -0
  224. package/ide/vscode/.vscode/settings.json +176 -0
  225. package/ide/vscode/.vscode/stacks.code-snippets +181 -0
  226. package/ide/vscode/LICENSE.md +21 -0
  227. package/ide/vscode/README.md +36 -0
  228. package/ide/vscode/logo.png +0 -0
  229. package/ide/vscode/package.json +79 -0
  230. package/ide/zed/.zed/settings.json +139 -0
  231. package/lang/README.md +28 -0
  232. package/lang/de.yml +14 -0
  233. package/lang/en.yml +15 -0
  234. package/package.json +19 -3
  235. package/project/bootstrap +161 -0
  236. package/project/buddy +175 -0
  237. package/project/storage/framework/tsconfig.app.json +50 -0
  238. package/project/storage/framework/tsconfig.base.json +58 -0
  239. package/routes/core.ts +78 -0
  240. package/routes/dashboard-api.ts +233 -0
  241. package/routes/dashboard.ts +739 -0
  242. package/routes/email.ts +129 -0
  243. package/stores/[name].stx +16 -0
  244. package/stores/git.ts +71 -0
  245. package/stores/payment.ts +474 -0
  246. package/stores/queue.ts +43 -0
  247. package/stores/user.ts +29 -0
  248. package/stx-components-plugin.ts +25 -0
  249. package/styles/design-tokens.css +597 -0
  250. package/types/dashboard.ts +70 -0
  251. package/types/defaults.ts +438 -0
  252. package/vcs/github/CODE_OF_CONDUCT.md +83 -0
  253. package/vcs/github/CONTRIBUTING.md +187 -0
  254. package/vcs/github/EXPLANATIONS.md +41 -0
  255. package/vcs/github/FUNDING.yml +1 -0
  256. package/vcs/github/ISSUE_TEMPLATE/bug_report.yml +49 -0
  257. package/vcs/github/ISSUE_TEMPLATE/config.yml +10 -0
  258. package/vcs/github/ISSUE_TEMPLATE/feature_request.yml +44 -0
  259. package/vcs/github/SECURITY.md +70 -0
  260. package/vcs/github/renovate.json +5 -0
  261. package/vcs/github/stale.yml +14 -0
  262. package/vcs/github/workflows/README.md +16 -0
  263. package/vcs/github/workflows/ci.yml +114 -0
  264. package/vcs/github/workflows/export-size.yml +25 -0
  265. package/vcs/github/workflows/labeler.yml +13 -0
  266. package/vcs/github/workflows/release.yml +219 -0
  267. package/views/[...all].stx +8 -0
  268. package/views/about.md +3 -0
  269. package/views/auth/login.stx +1 -0
  270. package/views/auth/signup.stx +85 -0
  271. package/views/dashboard/.discovered-models.json +542 -0
  272. package/views/dashboard/AUDIT.md +904 -0
  273. package/views/dashboard/[...all].stx +89 -0
  274. package/views/dashboard/access-tokens/index.stx +177 -0
  275. package/views/dashboard/actions/index.stx +129 -0
  276. package/views/dashboard/analytics/blog/index.stx +356 -0
  277. package/views/dashboard/analytics/browsers/index.stx +263 -0
  278. package/views/dashboard/analytics/commerce/sales/index.stx +329 -0
  279. package/views/dashboard/analytics/commerce/web/index.stx +379 -0
  280. package/views/dashboard/analytics/countries/index.stx +289 -0
  281. package/views/dashboard/analytics/devices/index.stx +305 -0
  282. package/views/dashboard/analytics/events/index.stx +536 -0
  283. package/views/dashboard/analytics/index.stx +88 -0
  284. package/views/dashboard/analytics/marketing/index.stx +315 -0
  285. package/views/dashboard/analytics/pages/index.stx +271 -0
  286. package/views/dashboard/analytics/referrers/index.stx +319 -0
  287. package/views/dashboard/analytics/web/index.stx +356 -0
  288. package/views/dashboard/buddy/index.stx +198 -0
  289. package/views/dashboard/ci/index.stx +462 -0
  290. package/views/dashboard/cloud/index.stx +452 -0
  291. package/views/dashboard/commands/index.stx +295 -0
  292. package/views/dashboard/commerce/categories/index.stx +406 -0
  293. package/views/dashboard/commerce/coupons/index.stx +485 -0
  294. package/views/dashboard/commerce/customers/index.stx +410 -0
  295. package/views/dashboard/commerce/dashboard/index.stx +287 -0
  296. package/views/dashboard/commerce/delivery/delivery-routes.stx +305 -0
  297. package/views/dashboard/commerce/delivery/digital-delivery.stx +332 -0
  298. package/views/dashboard/commerce/delivery/drivers.stx +397 -0
  299. package/views/dashboard/commerce/delivery/index.stx +18 -0
  300. package/views/dashboard/commerce/delivery/license-keys.stx +380 -0
  301. package/views/dashboard/commerce/delivery/shipping-methods.stx +346 -0
  302. package/views/dashboard/commerce/delivery/shipping-rates.stx +338 -0
  303. package/views/dashboard/commerce/delivery/shipping-zones.stx +302 -0
  304. package/views/dashboard/commerce/delivery/tabs.ts +25 -0
  305. package/views/dashboard/commerce/gift-cards/index.stx +561 -0
  306. package/views/dashboard/commerce/manufacturers/index.stx +308 -0
  307. package/views/dashboard/commerce/orders/index.stx +247 -0
  308. package/views/dashboard/commerce/payments/index.stx +535 -0
  309. package/views/dashboard/commerce/pos/index.stx +653 -0
  310. package/views/dashboard/commerce/printers/devices/index.stx +273 -0
  311. package/views/dashboard/commerce/printers/receipts/index.stx +308 -0
  312. package/views/dashboard/commerce/products/detail.stx +563 -0
  313. package/views/dashboard/commerce/products/index.stx +370 -0
  314. package/views/dashboard/commerce/reviews/index.stx +656 -0
  315. package/views/dashboard/commerce/reviews/index.ts +0 -0
  316. package/views/dashboard/commerce/taxes/index.stx +377 -0
  317. package/views/dashboard/commerce/units/index.stx +317 -0
  318. package/views/dashboard/commerce/variants/index.stx +319 -0
  319. package/views/dashboard/commerce/waitlist/products.stx +942 -0
  320. package/views/dashboard/commerce/waitlist/restaurant.stx +1024 -0
  321. package/views/dashboard/components/index.stx +330 -0
  322. package/views/dashboard/composables/index.ts +19 -0
  323. package/views/dashboard/composables/useChart.ts +77 -0
  324. package/views/dashboard/composables/useNavigation.ts +99 -0
  325. package/views/dashboard/composables/useRole.ts +58 -0
  326. package/views/dashboard/composables/useTheme.ts +74 -0
  327. package/views/dashboard/content/authors/index.stx +171 -0
  328. package/views/dashboard/content/blog/index.stx +493 -0
  329. package/views/dashboard/content/categories/index.stx +169 -0
  330. package/views/dashboard/content/comments/index.stx +189 -0
  331. package/views/dashboard/content/dashboard.stx +383 -0
  332. package/views/dashboard/content/files/index.stx +706 -0
  333. package/views/dashboard/content/pages/index.stx +174 -0
  334. package/views/dashboard/content/posts/index.stx +269 -0
  335. package/views/dashboard/content/seo/index.stx +240 -0
  336. package/views/dashboard/content/tags/index.stx +167 -0
  337. package/views/dashboard/data/activity/index.stx +261 -0
  338. package/views/dashboard/data/dashboard/index.stx +116 -0
  339. package/views/dashboard/data/subscribers.stx +270 -0
  340. package/views/dashboard/data/teams.stx +275 -0
  341. package/views/dashboard/data/users.stx +279 -0
  342. package/views/dashboard/dependencies/index.stx +178 -0
  343. package/views/dashboard/deployments/[id].stx +234 -0
  344. package/views/dashboard/deployments/index.stx +9 -0
  345. package/views/dashboard/dns/index.stx +163 -0
  346. package/views/dashboard/environment/index.stx +283 -0
  347. package/views/dashboard/errors/index.stx +274 -0
  348. package/views/dashboard/forgot-password.stx +57 -0
  349. package/views/dashboard/functions/index.stx +159 -0
  350. package/views/dashboard/health/index.stx +248 -0
  351. package/views/dashboard/inbox/activity.stx +350 -0
  352. package/views/dashboard/inbox/index.stx +452 -0
  353. package/views/dashboard/inbox/settings.stx +290 -0
  354. package/views/dashboard/index.stx +252 -0
  355. package/views/dashboard/insights/index.stx +529 -0
  356. package/views/dashboard/jobs/[id].stx +430 -0
  357. package/views/dashboard/jobs/history.stx +222 -0
  358. package/views/dashboard/jobs/index.stx +214 -0
  359. package/views/dashboard/kanban/[id].stx +899 -0
  360. package/views/dashboard/kanban/index.stx +260 -0
  361. package/views/dashboard/layouts/default.stx +565 -0
  362. package/views/dashboard/layouts/guest.stx +10 -0
  363. package/views/dashboard/login.stx +48 -0
  364. package/views/dashboard/logs/index.stx +540 -0
  365. package/views/dashboard/mailboxes/index.stx +149 -0
  366. package/views/dashboard/management/permissions/index.stx +490 -0
  367. package/views/dashboard/marketing/campaigns/index.stx +604 -0
  368. package/views/dashboard/marketing/lists/index.stx +514 -0
  369. package/views/dashboard/marketing/reviews/index.stx +475 -0
  370. package/views/dashboard/marketing/social-posts/index.stx +560 -0
  371. package/views/dashboard/models/[model].stx +195 -0
  372. package/views/dashboard/models/index.stx +159 -0
  373. package/views/dashboard/monitoring/errors/index.stx +415 -0
  374. package/views/dashboard/notifications/dashboard.stx +383 -0
  375. package/views/dashboard/notifications/email.stx +336 -0
  376. package/views/dashboard/notifications/history.stx +373 -0
  377. package/views/dashboard/notifications/sms.stx +332 -0
  378. package/views/dashboard/packages/index.stx +195 -0
  379. package/views/dashboard/queries/[id].stx +381 -0
  380. package/views/dashboard/queries/history.stx +227 -0
  381. package/views/dashboard/queries/index.stx +335 -0
  382. package/views/dashboard/queries/slow.stx +318 -0
  383. package/views/dashboard/queue/index.stx +427 -0
  384. package/views/dashboard/realtime/index.stx +429 -0
  385. package/views/dashboard/register.stx +46 -0
  386. package/views/dashboard/releases/index.stx +389 -0
  387. package/views/dashboard/requests/index.stx +462 -0
  388. package/views/dashboard/serverless/index.stx +475 -0
  389. package/views/dashboard/servers/[id].stx +299 -0
  390. package/views/dashboard/servers/index.stx +483 -0
  391. package/views/dashboard/settings/billing.stx +50 -0
  392. package/views/dashboard/settings/index.stx +256 -0
  393. package/views/dashboard/settings/mail.stx +252 -0
  394. package/views/dashboard/stores/auth.ts +123 -0
  395. package/views/dashboard/stores/ci.ts +342 -0
  396. package/views/dashboard/stores/index.ts +129 -0
  397. package/views/dashboard/stores/kanban.ts +723 -0
  398. package/views/dashboard/stores/rbac.ts +350 -0
  399. package/views/dashboard/stx.config.ts +34 -0
  400. package/views/dashboard/teams/[id].stx +170 -0
  401. package/views/forum/category.stx +92 -0
  402. package/views/forum/index.stx +209 -0
  403. package/views/forum/new-topic.stx +113 -0
  404. package/views/forum/profile.stx +1 -0
  405. package/views/forum/topic.stx +143 -0
  406. package/views/hello-world/[name].stx +47 -0
  407. package/views/index.stx +21 -0
  408. package/views/system-tray/index.stx +147 -0
@@ -0,0 +1,481 @@
1
+ import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { esc, renderDefinitions, textUnits } from '../shared/utils.mjs';
4
+ import { animateAttr, loadDiagram, writeDiagram, svgRootAttrs } from '../shared/cli.mjs';
5
+ import {
6
+ asArray,
7
+ isFinitePoint,
8
+ rectsOverlap,
9
+ segmentIntersectsRect,
10
+ suggestLabelObstacleFix,
11
+ suggestLabelPairFix,
12
+ anchor,
13
+ defaultFromSide,
14
+ defaultToSide,
15
+ chosenSide,
16
+ polylinePath,
17
+ labelPoint,
18
+ componentFill,
19
+ componentText,
20
+ arrowClassMap,
21
+ variantAccent
22
+ } from '../shared/geometry.mjs';
23
+
24
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
25
+ const { diagram: workflow, template, outPath } = loadDiagram({
26
+ rendererDir: __dirname,
27
+ diagramType: 'workflow',
28
+ defaultExample: 'agent-tool-call.workflow.json'
29
+ });
30
+
31
+ const layout = {
32
+ laneX: 40,
33
+ laneY: 52,
34
+ laneW: 640,
35
+ laneH: 104,
36
+ laneGap: 20,
37
+ laneTitleH: 30,
38
+ colXs: [88, 220, 300, 430, 500, 625],
39
+ nodeW: 92,
40
+ nodeH: 52
41
+ };
42
+
43
+ // Content is 680px wide (laneX + laneW); auto height fits the lanes plus legend.
44
+ const autoHeight = layout.laneY
45
+ + (workflow.lanes?.length || 1) * layout.laneH
46
+ + ((workflow.lanes?.length || 1) - 1) * layout.laneGap
47
+ + 124;
48
+ const viewBox = workflow.meta?.viewBox || [720, autoHeight];
49
+
50
+ const laneIndex = new Map(asArray(workflow.lanes).map((lane, index) => [lane.id, index]));
51
+
52
+ function laneTop(id) {
53
+ return layout.laneY + laneIndex.get(id) * (layout.laneH + layout.laneGap);
54
+ }
55
+
56
+ function lastLaneBottom() {
57
+ return layout.laneY + workflow.lanes.length * layout.laneH + (workflow.lanes.length - 1) * layout.laneGap;
58
+ }
59
+
60
+ function legendY() {
61
+ return lastLaneBottom() + 44;
62
+ }
63
+
64
+ function measureNode(node) {
65
+ const width = node.width || layout.nodeW;
66
+ const height = node.height || (node.tag ? 68 : layout.nodeH);
67
+ const cx = layout.colXs[node.col];
68
+ const contentH = layout.laneH - layout.laneTitleH;
69
+ const y = laneTop(node.lane) + layout.laneTitleH + (contentH - height) / 2 + (node.yOffset || 0);
70
+ return {
71
+ ...node,
72
+ width,
73
+ height,
74
+ x: cx - width / 2,
75
+ y,
76
+ cx,
77
+ cy: y + height / 2
78
+ };
79
+ }
80
+
81
+ const nodes = new Map(asArray(workflow.nodes).map((node) => [node.id, measureNode(node)]));
82
+
83
+ const mainPathSteps = new Map(asArray(workflow.mainPath).map((id, index) => [id, index]));
84
+ const edgeSteps = new Map(asArray(workflow.edges).map((edge, index) => {
85
+ const fromStep = mainPathSteps.get(edge.from);
86
+ const toStep = mainPathSteps.get(edge.to);
87
+ const mainStep = Number.isInteger(fromStep) && toStep === fromStep + 1 ? fromStep : null;
88
+ return [edge, mainStep ?? asArray(workflow.mainPath).length + index];
89
+ }));
90
+
91
+ function nodeStep(node) {
92
+ return mainPathSteps.get(node.id) ?? asArray(workflow.mainPath).length + asArray(workflow.nodes).findIndex((item) => item.id === node.id);
93
+ }
94
+
95
+ function validateWorkflow() {
96
+ const problems = [];
97
+ if (workflow.schema_version !== 1) {
98
+ problems.push('Workflow files must set "schema_version": 1.');
99
+ }
100
+ if (workflow.diagram_type !== 'workflow') {
101
+ problems.push(`Unsupported diagram_type "${workflow.diagram_type}". Expected "workflow".`);
102
+ }
103
+ if (!workflow.meta || !workflow.meta.title) {
104
+ problems.push('Workflow files must include meta.title.');
105
+ }
106
+ if (!Array.isArray(workflow.lanes) || !workflow.lanes.length) {
107
+ problems.push('Workflow files must include at least one lane.');
108
+ }
109
+ if (!Array.isArray(workflow.nodes)) {
110
+ problems.push('Workflow files must include a nodes array.');
111
+ }
112
+ if (!Array.isArray(workflow.edges)) {
113
+ problems.push('Workflow files must include an edges array.');
114
+ }
115
+ if (workflow.phases !== undefined && !Array.isArray(workflow.phases)) {
116
+ problems.push('Workflow "phases" must be an array.');
117
+ }
118
+ if (workflow.groups !== undefined && !Array.isArray(workflow.groups)) {
119
+ problems.push('Workflow "groups" must be an array.');
120
+ }
121
+ if (workflow.mainPath !== undefined && !Array.isArray(workflow.mainPath)) {
122
+ problems.push('Workflow "mainPath" must be an array of node ids.');
123
+ }
124
+ if (workflow.cards !== undefined && !Array.isArray(workflow.cards)) {
125
+ problems.push('Workflow "cards" must be an array.');
126
+ }
127
+ if (problems.length) {
128
+ throw new Error(`Workflow layout validation failed:\n- ${problems.join('\n- ')}`);
129
+ }
130
+
131
+ const laneIds = new Set(workflow.lanes.map((lane) => lane.id));
132
+ if (laneIds.size !== workflow.lanes.length) {
133
+ problems.push('Lane ids must be unique.');
134
+ }
135
+ if (nodes.size !== workflow.nodes.length) {
136
+ problems.push('Node ids must be unique.');
137
+ }
138
+ const phaseIds = new Set(asArray(workflow.phases).map((phase) => phase.id));
139
+ if (phaseIds.size !== asArray(workflow.phases).length) {
140
+ problems.push('Phase ids must be unique.');
141
+ }
142
+ const groupIds = new Set(asArray(workflow.groups).map((group) => group.id));
143
+ if (groupIds.size !== asArray(workflow.groups).length) {
144
+ problems.push('Group ids must be unique.');
145
+ }
146
+
147
+ for (const node of nodes.values()) {
148
+ if (!laneIds.has(node.lane)) {
149
+ problems.push(`Node "${node.id}" uses unknown lane "${node.lane}".`);
150
+ continue;
151
+ }
152
+ if (!Number.isInteger(node.col) || node.col < 0 || node.col >= layout.colXs.length) {
153
+ problems.push(`Node "${node.id}" uses column ${node.col}, but valid columns are integers 0..${layout.colXs.length - 1}.`);
154
+ continue;
155
+ }
156
+ if (!isFinitePoint(node.x, node.y, node.cx, node.cy)) {
157
+ problems.push(`Node "${node.id}" produced non-finite coordinates - check col, width, height, and yOffset are numbers.`);
158
+ continue;
159
+ }
160
+ const estLabelW = textUnits(node.label) * 6.8;
161
+ if (estLabelW > node.width + 6) {
162
+ problems.push(`Label "${node.label}" (~${Math.round(estLabelW)}px) is wider than node "${node.id}" (${node.width}px) - shorten the label, move detail to sublabel, or increase node.width.`);
163
+ }
164
+
165
+ const top = laneTop(node.lane);
166
+ const contentTop = top + layout.laneTitleH;
167
+ const laneRight = layout.laneX + layout.laneW;
168
+ if (node.x < layout.laneX || node.x + node.width > laneRight) {
169
+ problems.push(`Node "${node.id}" exceeds the horizontal bounds of lane "${node.lane}".`);
170
+ }
171
+ if (node.y < contentTop || node.y + node.height > top + layout.laneH) {
172
+ problems.push(`Node "${node.id}" collides with the title or boundary of lane "${node.lane}".`);
173
+ }
174
+ }
175
+
176
+ for (const phase of asArray(workflow.phases)) {
177
+ if (!Number.isInteger(phase.fromCol) || !Number.isInteger(phase.toCol)) {
178
+ problems.push(`Phase "${phase.id}" must use integer fromCol/toCol values.`);
179
+ continue;
180
+ }
181
+ if (phase.fromCol < 0 || phase.toCol >= layout.colXs.length || phase.fromCol > phase.toCol) {
182
+ problems.push(`Phase "${phase.id}" uses invalid columns ${phase.fromCol}..${phase.toCol}; use an ordered range within 0..${layout.colXs.length - 1}.`);
183
+ }
184
+ const estLabelW = textUnits(phase.label) * 5.6;
185
+ const width = spanForCols(phase.fromCol, phase.toCol).width;
186
+ if (estLabelW > width + 8) {
187
+ problems.push(`Phase label "${phase.label}" (~${Math.round(estLabelW)}px) is wider than its ${Math.round(width)}px span - shorten the label or widen the phase range.`);
188
+ }
189
+ }
190
+
191
+ for (const group of asArray(workflow.groups)) {
192
+ if (!laneIds.has(group.lane)) {
193
+ problems.push(`Group "${group.id}" uses unknown lane "${group.lane}".`);
194
+ continue;
195
+ }
196
+ if (!Number.isInteger(group.fromCol) || !Number.isInteger(group.toCol)) {
197
+ problems.push(`Group "${group.id}" must use integer fromCol/toCol values.`);
198
+ continue;
199
+ }
200
+ if (group.fromCol < 0 || group.toCol >= layout.colXs.length || group.fromCol > group.toCol) {
201
+ problems.push(`Group "${group.id}" uses invalid columns ${group.fromCol}..${group.toCol}; use an ordered range within 0..${layout.colXs.length - 1}.`);
202
+ }
203
+ const contained = [...nodes.values()].some((node) => node.lane === group.lane && node.col >= group.fromCol && node.col <= group.toCol);
204
+ if (!contained) {
205
+ problems.push(`Group "${group.id}" does not contain any nodes - align its lane/columns with the parallel or branch work it frames.`);
206
+ }
207
+ }
208
+
209
+ const byLane = new Map();
210
+ for (const node of nodes.values()) {
211
+ byLane.set(node.lane, [...(byLane.get(node.lane) || []), node]);
212
+ }
213
+ for (const [lane, laneNodes] of byLane) {
214
+ for (let i = 0; i < laneNodes.length; i += 1) {
215
+ for (let j = i + 1; j < laneNodes.length; j += 1) {
216
+ if (rectsOverlap(laneNodes[i], laneNodes[j], 8)) {
217
+ problems.push(`Nodes "${laneNodes[i].id}" and "${laneNodes[j].id}" are less than 8px apart in lane "${lane}" - move one to another col, adjust yOffset, or reduce width/height.`);
218
+ }
219
+ }
220
+ }
221
+ }
222
+
223
+ for (const edge of workflow.edges) {
224
+ if (!nodes.has(edge.from)) problems.push(`Edge "${edge.label || edge.from}" references unknown source "${edge.from}".`);
225
+ if (!nodes.has(edge.to)) problems.push(`Edge "${edge.label || edge.to}" references unknown target "${edge.to}".`);
226
+ if (nodes.has(edge.from) && nodes.has(edge.to)) {
227
+ const routed = pathFor(edge);
228
+ if (routed.points.length === 2) {
229
+ const [start, end] = routed.points;
230
+ const segmentLength = Math.hypot(end[0] - start[0], end[1] - start[1]);
231
+ if (segmentLength < 28) {
232
+ problems.push(`Edge "${edge.from}" -> "${edge.to}" is too short (${Math.round(segmentLength)}px; minimum 28px) - drop its label or route it through a channel.`);
233
+ }
234
+ }
235
+ const segments = [];
236
+ for (let i = 1; i < routed.points.length; i += 1) {
237
+ segments.push({ start: routed.points[i - 1], end: routed.points[i] });
238
+ }
239
+ for (const node of nodes.values()) {
240
+ if (node.id === edge.from || node.id === edge.to) continue;
241
+ if (segments.some((segment) => segmentIntersectsRect(segment, node, 2))) {
242
+ problems.push(`Edge "${edge.from}" -> "${edge.to}" crosses node "${node.id}" - adjust fromSide/toSide, route it through a channel, or move one node to a clearer lane/column.`);
243
+ }
244
+ }
245
+ }
246
+ }
247
+
248
+ if (Array.isArray(workflow.mainPath)) {
249
+ for (const id of workflow.mainPath) {
250
+ if (!nodes.has(id)) {
251
+ problems.push(`mainPath references unknown node "${id}".`);
252
+ }
253
+ }
254
+ for (let i = 0; i < workflow.mainPath.length - 1; i += 1) {
255
+ const fromId = workflow.mainPath[i];
256
+ const toId = workflow.mainPath[i + 1];
257
+ const from = nodes.get(fromId);
258
+ const to = nodes.get(toId);
259
+ if (!from || !to) continue;
260
+ const linked = workflow.edges.some((edge) => edge.from === fromId && edge.to === toId);
261
+ if (!linked) {
262
+ problems.push(`mainPath step "${fromId}" -> "${toId}" has no matching edge - add the edge or remove the pair from mainPath.`);
263
+ }
264
+ if (to.col < from.col) {
265
+ problems.push(`mainPath step "${fromId}" -> "${toId}" moves backward from col ${from.col} to ${to.col} - use a return edge outside mainPath for loops.`);
266
+ }
267
+ }
268
+ }
269
+
270
+ const labelRects = [];
271
+ for (const edge of workflow.edges) {
272
+ if (!edge.label || !nodes.has(edge.from) || !nodes.has(edge.to)) continue;
273
+ const [lx, ly] = labelPoint(edge, pathFor(edge).points);
274
+ const width = Math.max(30, textUnits(edge.label) * 4.8 + 10);
275
+ labelRects.push({ label: edge.label, x: lx - width / 2, y: ly - 10, width, height: 14, lx, ly });
276
+ }
277
+ for (const rect of labelRects) {
278
+ for (const node of nodes.values()) {
279
+ if (rectsOverlap(rect, node, -2)) {
280
+ problems.push(`Label "${rect.label}" overlaps node "${node.id}" - adjust labelDx/labelDy/labelSegment or set labelAt.\n${suggestLabelObstacleFix(rect, rect.lx, rect.ly, node, 'node')}`);
281
+ }
282
+ }
283
+ }
284
+ for (let i = 0; i < labelRects.length; i += 1) {
285
+ for (let j = i + 1; j < labelRects.length; j += 1) {
286
+ if (rectsOverlap(labelRects[i], labelRects[j], -2)) {
287
+ problems.push(`Labels "${labelRects[i].label}" and "${labelRects[j].label}" overlap - adjust labelDx/labelDy or remove one label.\n${suggestLabelPairFix(labelRects[i], labelRects[j])}`);
288
+ }
289
+ }
290
+ }
291
+
292
+ if (viewBox[0] < layout.laneX + layout.laneW + 16) {
293
+ problems.push(`viewBox width ${viewBox[0]} clips the ${layout.laneW}px lanes - set meta.viewBox[0] to at least ${layout.laneX + layout.laneW + 16}.`);
294
+ }
295
+ if (legendY() + 18 > viewBox[1]) {
296
+ problems.push(`Legend exceeds viewBox height ${viewBox[1]} - set meta.viewBox[1] to at least ${legendY() + 18}.`);
297
+ }
298
+
299
+ if (problems.length) {
300
+ throw new Error(`Workflow layout validation failed:\n- ${problems.join('\n- ')}`);
301
+ }
302
+ }
303
+
304
+ function gapYBetween(fromLane, toLane, bias = 0.5) {
305
+ const a = laneTop(fromLane) + layout.laneH;
306
+ const b = laneTop(toLane);
307
+ return a + (b - a) * bias;
308
+ }
309
+
310
+ function spanForCols(fromCol, toCol, pad = 46) {
311
+ const start = layout.colXs[fromCol] - pad;
312
+ const end = layout.colXs[toCol] + pad;
313
+ return { x: start, width: end - start, cx: (start + end) / 2 };
314
+ }
315
+
316
+ function sameLaneAutoVia(start, end) {
317
+ if (start[0] === end[0] || start[1] === end[1]) return [];
318
+ const midX = (start[0] + end[0]) / 2;
319
+ return [[midX, start[1]], [midX, end[1]]];
320
+ }
321
+
322
+ function routeVia(edge, from, to, start, end) {
323
+ if (edge.via) return edge.via;
324
+ switch (edge.route || 'auto') {
325
+ case 'straight':
326
+ return [];
327
+ case 'drop': {
328
+ const y = gapYBetween(from.lane, to.lane, edge.bias ?? 0.5);
329
+ return [[start[0], y], [end[0], y]];
330
+ }
331
+ case 'outside-right': {
332
+ const x = edge.channelX ?? layout.laneX + layout.laneW + 12;
333
+ return [[x, start[1]], [x, end[1]]];
334
+ }
335
+ case 'return-left': {
336
+ const x = edge.channelX ?? Math.min(from.x, to.x) - 28;
337
+ return [[x, start[1]], [x, end[1]]];
338
+ }
339
+ case 'bottom-channel': {
340
+ const y = edge.channelY ?? Math.max(from.y + from.height, to.y + to.height) + 32;
341
+ return [[start[0], y], [end[0], y]];
342
+ }
343
+ case 'up-channel': {
344
+ const y = edge.channelY ?? Math.min(from.y, to.y) - 28;
345
+ return [[start[0], y], [end[0], y]];
346
+ }
347
+ case 'auto':
348
+ default: {
349
+ if (from.lane === to.lane) return sameLaneAutoVia(start, end);
350
+ const y = gapYBetween(from.lane, to.lane, edge.bias ?? 0.5);
351
+ return [[start[0], y], [end[0], y]];
352
+ }
353
+ }
354
+ }
355
+
356
+ const pathCache = new Map();
357
+
358
+ function pathFor(edge) {
359
+ if (pathCache.has(edge)) return pathCache.get(edge);
360
+ const from = nodes.get(edge.from);
361
+ const to = nodes.get(edge.to);
362
+ const start = anchor(from, chosenSide(edge.fromSide, defaultFromSide(from, to)));
363
+ const end = anchor(to, chosenSide(edge.toSide, defaultToSide(from, to)));
364
+ const points = [start, ...routeVia(edge, from, to, start, end), end];
365
+ const routed = { d: polylinePath(points), points };
366
+ pathCache.set(edge, routed);
367
+ return routed;
368
+ }
369
+
370
+ function renderLane(lane, index) {
371
+ const y = layout.laneY + index * (layout.laneH + layout.laneGap);
372
+ const exception = lane.variant === 'exception'
373
+ ? `\n <rect x="${layout.laneX + 6}" y="${y + 6}" width="${layout.laneW - 12}" height="${layout.laneH - 12}" rx="8" class="c-security-group" stroke-width="1"/>`
374
+ : '';
375
+ const labelClass = lane.variant === 'exception' ? 't-security' : 't-dim';
376
+ const prefix = lane.variant === 'exception' ? 'EX' : String(index + 1).padStart(2, '0');
377
+ return ` <rect x="${layout.laneX}" y="${y}" width="${layout.laneW}" height="${layout.laneH}" rx="10" class="c-lane" stroke-width="1"/>${exception}
378
+ <text x="${layout.laneX + 14}" y="${y + 22}" class="${labelClass}" font-size="10" font-weight="600">${prefix} / ${esc(lane.label)}</text>`;
379
+ }
380
+
381
+ function renderPhase(phase) {
382
+ const span = spanForCols(phase.fromCol, phase.toCol, 46);
383
+ const accent = variantAccent(phase.variant);
384
+ const [lineClass] = arrowClassMap[phase.variant || 'default'] || arrowClassMap.default;
385
+ return ` <line x1="${span.x}" y1="35" x2="${span.x + span.width}" y2="35" class="${lineClass}" stroke-width="1.1"/>
386
+ <rect x="${span.x}" y="27" width="${span.width}" height="16" rx="4" class="c-mask"/>
387
+ <text x="${span.cx}" y="39" class="${accent}" font-size="8" font-weight="600" text-anchor="middle">${esc(phase.label)}</text>`;
388
+ }
389
+
390
+ function renderGroup(group) {
391
+ const span = spanForCols(group.fromCol, group.toCol, 50);
392
+ const y = laneTop(group.lane) + layout.laneTitleH + 8;
393
+ const height = layout.laneH - layout.laneTitleH - 16;
394
+ const cls = group.variant === 'security' ? 'c-security-group' : 'c-lane';
395
+ const textClass = variantAccent(group.variant);
396
+ return ` <rect x="${span.x}" y="${y}" width="${span.width}" height="${height}" rx="9" class="${cls}" stroke-width="1"/>
397
+ <text x="${span.x + 10}" y="${y + 14}" class="${textClass}" font-size="7" font-weight="600">${esc(group.label)}</text>`;
398
+ }
399
+
400
+ function renderNode(node) {
401
+ const fill = componentFill[node.type] || 'c-external';
402
+ const accent = componentText[node.type] || 't-muted';
403
+ const tag = node.tag
404
+ ? `\n <text x="${node.cx}" y="${node.y + node.height - 12}" class="${accent}" font-size="7" text-anchor="middle">${esc(node.tag)}</text>`
405
+ : '';
406
+ return ` <rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="6" class="c-mask"/>
407
+ <rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="6" class="${fill}"${animateAttr(workflow.meta, 'node', nodeStep(node))} stroke-width="1.5"/>
408
+ <text x="${node.cx}" y="${node.y + 21}" class="t-primary" font-size="11" font-weight="600" text-anchor="middle">${esc(node.label)}</text>
409
+ <text x="${node.cx}" y="${node.y + 38}" class="t-muted" font-size="8" text-anchor="middle">${esc(node.sublabel || '')}</text>${tag}`;
410
+ }
411
+
412
+ function renderEdgePath(edge) {
413
+ const [cls, marker] = arrowClassMap[edge.variant || 'default'] || arrowClassMap.default;
414
+ const routed = pathFor(edge);
415
+ const strokeWidth = edge.width || (edge.variant === 'emphasis' ? 1.8 : 1.4);
416
+ return ` <path d="${routed.d}" class="${cls}"${animateAttr(workflow.meta, 'edge', edgeSteps.get(edge))} stroke-width="${strokeWidth}" marker-end="url(#${marker})"/>`;
417
+ }
418
+
419
+ function renderEdgeLabel(edge) {
420
+ if (!edge.label) return '';
421
+ const routed = pathFor(edge);
422
+ const [lx, ly] = labelPoint(edge, routed.points);
423
+ const labelW = Math.max(30, textUnits(edge.label) * 4.8 + 10);
424
+ return ` <rect x="${lx - labelW / 2}" y="${ly - 10}" width="${labelW}" height="14" rx="3" class="c-mask"/>
425
+ <text x="${lx}" y="${ly}" class="${variantAccent(edge.variant, { dashed: 't-database' })}" font-size="8" text-anchor="middle">${esc(edge.label)}</text>`;
426
+ }
427
+
428
+ function renderLegend() {
429
+ const y = legendY();
430
+ return ` <text x="175" y="${y - 20}" class="t-primary" font-size="10" font-weight="600">Legend</text>
431
+ <rect x="175" y="${y - 8}" width="14" height="9" rx="2" class="c-frontend" stroke-width="1"/>
432
+ <text x="195" y="${y}" class="t-muted" font-size="7">User UI</text>
433
+ <rect x="260" y="${y - 8}" width="14" height="9" rx="2" class="c-backend" stroke-width="1"/>
434
+ <text x="280" y="${y}" class="t-muted" font-size="7">Agent logic</text>
435
+ <rect x="370" y="${y - 8}" width="14" height="9" rx="2" class="c-security" stroke-width="1"/>
436
+ <text x="390" y="${y}" class="t-muted" font-size="7">Policy</text>
437
+ <rect x="455" y="${y - 8}" width="14" height="9" rx="2" class="c-messagebus" stroke-width="1"/>
438
+ <text x="475" y="${y}" class="t-muted" font-size="7">Tool action</text>
439
+ <rect x="565" y="${y - 8}" width="14" height="9" rx="2" class="c-database" stroke-width="1"/>
440
+ <text x="585" y="${y}" class="t-muted" font-size="7">Context / trace</text>`;
441
+ }
442
+
443
+ function renderSvg() {
444
+ return ` <svg viewBox="0 0 ${viewBox[0]} ${viewBox[1]}" ${svgRootAttrs(workflow.meta, 'workflow diagram')}>
445
+ ${renderDefinitions()}
446
+
447
+ <!-- Background Grid -->
448
+ <rect width="100%" height="100%" fill="url(#grid)" />
449
+
450
+ <!-- Swimlanes -->
451
+ ${workflow.lanes.map(renderLane).join('\n\n')}
452
+
453
+ <!-- Phase headers -->
454
+ ${asArray(workflow.phases).map(renderPhase).join('\n')}
455
+
456
+ <!-- Workflow groups -->
457
+ ${asArray(workflow.groups).map(renderGroup).join('\n')}
458
+
459
+ <!-- Edge paths -->
460
+ ${workflow.edges.map(renderEdgePath).join('\n')}
461
+
462
+ <!-- Nodes -->
463
+ ${[...nodes.values()].map(renderNode).join('\n\n')}
464
+
465
+ <!-- Edge labels -->
466
+ ${workflow.edges.map(renderEdgeLabel).join('\n')}
467
+
468
+ <!-- Legend -->
469
+ ${renderLegend()}
470
+ </svg>`;
471
+ }
472
+
473
+ validateWorkflow();
474
+ writeDiagram({
475
+ outPath,
476
+ template,
477
+ meta: workflow.meta,
478
+ footerLabel: 'Workflow diagram',
479
+ svg: renderSvg(),
480
+ cards: workflow.cards,
481
+ });
@@ -0,0 +1,68 @@
1
+ # Technical Diagram JSON IR Schemas
2
+
3
+ Each typed renderer consumes a JSON intermediate representation (IR) validated
4
+ against one of the schemas in this folder before any layout work happens.
5
+
6
+ ## Files
7
+
8
+ | Schema | Governs | Structural arrays |
9
+ |--------|---------|-------------------|
10
+ | `workflow.schema.json` | `diagram_type: "workflow"` | `lanes`, `phases`, `groups`, `mainPath`, `nodes`, `edges` |
11
+ | `sequence.schema.json` | `diagram_type: "sequence"` | `participants`, `segments`, `messages`, `activations` |
12
+ | `dataflow.schema.json` | `diagram_type: "dataflow"` | `stages`, `nodes`, `flows` |
13
+ | `lifecycle.schema.json` | `diagram_type: "lifecycle"` | `lanes`, `states`, `transitions` |
14
+ | `architecture.schema.json` | `diagram_type: "architecture"` | `components`, `boundaries`, `connections` |
15
+ | `common.schema.json` | shared `$defs` only (no top-level document) | - |
16
+
17
+ Every diagram schema requires `schema_version`, `diagram_type`, `meta` (with
18
+ `title`), and its structural arrays - except `segments`, `activations`, and
19
+ `cards`, which are optional - and sets `additionalProperties: false` at every
20
+ level, so unknown fields are rejected rather than silently ignored.
21
+
22
+ Every `meta` object also accepts `animation: "trace"` for opt-in SVG/CSS motion
23
+ in generated HTML. Omit it, or set `"none"`, for the default static output.
24
+
25
+ ## schema_version policy
26
+
27
+ `schema_version` is `"const": 1`. The constant pins the IR contract: a file
28
+ that validates today keeps rendering identically on every 2.x release. A
29
+ breaking change to any IR shape bumps the constant to `2`; renderers will then
30
+ reject version-1 files with a clear schema error instead of misrendering them.
31
+ Additive, backwards-compatible fields do not bump the version.
32
+
33
+ ## Shared definitions (common.schema.json)
34
+
35
+ The five diagram schemas reference `common.schema.json#/$defs/...`:
36
+
37
+ - `id` - element identifiers, pattern `^[a-zA-Z][a-zA-Z0-9_-]*$`
38
+ - `point` - an `[x, y]` pair of numbers (used by `via` and `labelAt`)
39
+ - `componentType` - `frontend`, `backend`, `database`, `cloud`, `security`,
40
+ `messagebus`, `external`
41
+ - `variant` - `default`, `emphasis`, `security`, `dashed` (sequence messages
42
+ extend this list locally with `return`)
43
+ - `cards` - the summary-card blocks rendered below the SVG
44
+
45
+ Lifecycle state `type` is mode-specific (`start`/`active`/`waiting`/...) and
46
+ stays in `lifecycle.schema.json`.
47
+
48
+ ## Runtime validation
49
+
50
+ `renderers/shared/generated-validators.mjs` contains the precompiled
51
+ standalone validators from the credited upstream source. It has no imports,
52
+ package dependencies, or network dependency. Do not add a schema compiler to
53
+ this skill. `renderers/shared/validator.mjs` applies the matching standalone
54
+ validator before the renderer's own layout checks.
55
+
56
+ ## Error format
57
+
58
+ Schema violations exit non-zero. Each validation error is reported on its own line as
59
+ the instance path - annotated with the nearest enclosing element's `id` or
60
+ `label` - followed by the message and parameters:
61
+
62
+ ```text
63
+ workflow schema validation failed:
64
+ /nodes/3 (id/label: "router") must NOT have additional properties {"additionalProperty":"colour"}
65
+ ```
66
+
67
+ Schemas catch shape errors (types, enums, ranges, unknown fields); geometry
68
+ problems such as overlaps and label collisions are the renderers' job.
@@ -0,0 +1,121 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/tt-a1i/archify/schemas/architecture.schema.json",
4
+ "title": "Technical Architecture Diagram",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["schema_version", "diagram_type", "meta", "components"],
8
+ "properties": {
9
+ "schema_version": { "const": 1 },
10
+ "diagram_type": { "const": "architecture" },
11
+ "meta": {
12
+ "type": "object",
13
+ "additionalProperties": false,
14
+ "required": ["title"],
15
+ "properties": {
16
+ "title": { "type": "string", "minLength": 1 },
17
+ "subtitle": { "type": "string" },
18
+ "output": { "type": "string" },
19
+ "animation": { "enum": ["trace", "none"] },
20
+ "viewBox": {
21
+ "type": "array",
22
+ "prefixItems": [
23
+ { "type": "number", "minimum": 320 },
24
+ { "type": "number", "minimum": 240 }
25
+ ],
26
+ "items": false,
27
+ "minItems": 2,
28
+ "maxItems": 2
29
+ }
30
+ }
31
+ },
32
+ "layout": {
33
+ "type": "object",
34
+ "additionalProperties": false,
35
+ "required": ["mode"],
36
+ "properties": {
37
+ "mode": { "enum": ["grid"] },
38
+ "origin": { "$ref": "common.schema.json#/$defs/point" },
39
+ "cols": { "type": "integer", "minimum": 1, "maximum": 12 },
40
+ "gapX": { "type": "number", "minimum": 0 },
41
+ "gapY": { "type": "number", "minimum": 0 },
42
+ "cellW": { "type": "number", "minimum": 40 },
43
+ "cellH": { "type": "number", "minimum": 24 }
44
+ }
45
+ },
46
+ "components": {
47
+ "type": "array",
48
+ "minItems": 1,
49
+ "items": {
50
+ "type": "object",
51
+ "additionalProperties": false,
52
+ "required": ["id", "type", "label"],
53
+ "properties": {
54
+ "id": { "$ref": "common.schema.json#/$defs/id" },
55
+ "type": { "$ref": "common.schema.json#/$defs/componentType" },
56
+ "label": { "type": "string", "minLength": 1 },
57
+ "sublabel": { "type": "string" },
58
+ "tag": { "type": "string" },
59
+ "row": { "type": "integer", "minimum": 0 },
60
+ "col": { "type": "integer", "minimum": 0 },
61
+ "pos": { "$ref": "common.schema.json#/$defs/point" },
62
+ "size": {
63
+ "type": "array",
64
+ "prefixItems": [
65
+ { "type": "number", "exclusiveMinimum": 0 },
66
+ { "type": "number", "exclusiveMinimum": 0 }
67
+ ],
68
+ "items": false,
69
+ "minItems": 2,
70
+ "maxItems": 2
71
+ }
72
+ }
73
+ }
74
+ },
75
+ "boundaries": {
76
+ "type": "array",
77
+ "items": {
78
+ "type": "object",
79
+ "additionalProperties": false,
80
+ "required": ["kind", "label", "wraps"],
81
+ "properties": {
82
+ "kind": { "enum": ["region", "security-group"] },
83
+ "label": { "type": "string", "minLength": 1 },
84
+ "wraps": {
85
+ "type": "array",
86
+ "minItems": 1,
87
+ "items": { "$ref": "common.schema.json#/$defs/id" }
88
+ },
89
+ "pad": { "type": "number", "minimum": 0 }
90
+ }
91
+ }
92
+ },
93
+ "connections": {
94
+ "type": "array",
95
+ "items": {
96
+ "type": "object",
97
+ "additionalProperties": false,
98
+ "required": ["from", "to"],
99
+ "properties": {
100
+ "from": { "$ref": "common.schema.json#/$defs/id" },
101
+ "to": { "$ref": "common.schema.json#/$defs/id" },
102
+ "label": { "type": "string" },
103
+ "variant": { "$ref": "common.schema.json#/$defs/variant" },
104
+ "fromSide": { "enum": ["left", "right", "top", "bottom"] },
105
+ "toSide": { "enum": ["left", "right", "top", "bottom"] },
106
+ "route": { "enum": ["auto", "straight", "orthogonal-h", "orthogonal-v"] },
107
+ "via": {
108
+ "type": "array",
109
+ "items": { "$ref": "common.schema.json#/$defs/point" }
110
+ },
111
+ "labelAt": { "$ref": "common.schema.json#/$defs/point" },
112
+ "labelDx": { "type": "number" },
113
+ "labelDy": { "type": "number" },
114
+ "labelSegment": { "type": "integer", "minimum": 0 },
115
+ "width": { "type": "number", "minimum": 0.5 }
116
+ }
117
+ }
118
+ },
119
+ "cards": { "$ref": "common.schema.json#/$defs/cards" }
120
+ }
121
+ }