@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,230 @@
1
+ // Geometry helpers shared by all typed renderers. Every function here is
2
+ // pure; renderers own their layout tables and pass measured rects
3
+ // ({x, y, width, height, cx, cy}) in.
4
+
5
+ // Keep layout checks defensive even after standalone schema validation.
6
+ // Coerce non-arrays to [] so the module-level Maps build without throwing and
7
+ // the friendly validator checks (which run later) report the real problem.
8
+ export function asArray(value) {
9
+ return Array.isArray(value) ? value : [];
10
+ }
11
+
12
+ // A computed coordinate must be a finite number; NaN/undefined would silently
13
+ // write `<rect x="NaN">` into the output. Used by the validators as a backstop.
14
+ export function isFinitePoint(...coords) {
15
+ return coords.every((c) => Number.isFinite(c));
16
+ }
17
+
18
+ export function rectsOverlap(a, b, gap = 0) {
19
+ return !(
20
+ a.x + a.width + gap <= b.x ||
21
+ b.x + b.width + gap <= a.x ||
22
+ a.y + a.height + gap <= b.y ||
23
+ b.y + b.height + gap <= a.y
24
+ );
25
+ }
26
+
27
+ export function segmentIntersectsRect(segment, rect, gap = 0) {
28
+ const box = {
29
+ x1: rect.x - gap,
30
+ y1: rect.y - gap,
31
+ x2: rect.x + rect.width + gap,
32
+ y2: rect.y + rect.height + gap
33
+ };
34
+ const [a, b] = [segment.start, segment.end];
35
+ if (pointInBox(a, box) || pointInBox(b, box)) return true;
36
+ return (
37
+ segmentsIntersect(a, b, [box.x1, box.y1], [box.x2, box.y1]) ||
38
+ segmentsIntersect(a, b, [box.x2, box.y1], [box.x2, box.y2]) ||
39
+ segmentsIntersect(a, b, [box.x2, box.y2], [box.x1, box.y2]) ||
40
+ segmentsIntersect(a, b, [box.x1, box.y2], [box.x1, box.y1])
41
+ );
42
+ }
43
+
44
+ function pointInBox(point, box) {
45
+ return point[0] >= box.x1 && point[0] <= box.x2 && point[1] >= box.y1 && point[1] <= box.y2;
46
+ }
47
+
48
+ function segmentsIntersect(a, b, c, d) {
49
+ const o1 = orientation(a, b, c);
50
+ const o2 = orientation(a, b, d);
51
+ const o3 = orientation(c, d, a);
52
+ const o4 = orientation(c, d, b);
53
+
54
+ if (o1 === 0 && onSegment(a, c, b)) return true;
55
+ if (o2 === 0 && onSegment(a, d, b)) return true;
56
+ if (o3 === 0 && onSegment(c, a, d)) return true;
57
+ if (o4 === 0 && onSegment(c, b, d)) return true;
58
+
59
+ return o1 !== o2 && o3 !== o4;
60
+ }
61
+
62
+ function orientation(a, b, c) {
63
+ const value = (b[1] - a[1]) * (c[0] - b[0]) - (b[0] - a[0]) * (c[1] - b[1]);
64
+ if (Math.abs(value) < 0.0001) return 0;
65
+ return value > 0 ? 1 : 2;
66
+ }
67
+
68
+ function onSegment(a, b, c) {
69
+ return (
70
+ b[0] <= Math.max(a[0], c[0]) &&
71
+ b[0] >= Math.min(a[0], c[0]) &&
72
+ b[1] <= Math.max(a[1], c[1]) &&
73
+ b[1] >= Math.min(a[1], c[1])
74
+ );
75
+ }
76
+
77
+ export function anchor(rect, side) {
78
+ switch (side) {
79
+ case 'left': return [rect.x, rect.cy];
80
+ case 'right': return [rect.x + rect.width, rect.cy];
81
+ case 'top': return [rect.cx, rect.y];
82
+ case 'bottom': return [rect.cx, rect.y + rect.height];
83
+ default:
84
+ return [rect.x + rect.width, rect.cy];
85
+ }
86
+ }
87
+
88
+ export function defaultFromSide(from, to) {
89
+ if (to.cx < from.cx) return 'left';
90
+ if (to.cx > from.cx) return 'right';
91
+ if (to.cy > from.cy) return 'bottom';
92
+ return 'top';
93
+ }
94
+
95
+ export function defaultToSide(from, to) {
96
+ if (to.cx < from.cx) return 'right';
97
+ if (to.cx > from.cx) return 'left';
98
+ if (to.cy > from.cy) return 'top';
99
+ return 'bottom';
100
+ }
101
+
102
+ export function chosenSide(side, fallback) {
103
+ return side && side !== 'auto' ? side : fallback;
104
+ }
105
+
106
+ export function polylinePath(points) {
107
+ return points.map(([x, y], index) => `${index === 0 ? 'M' : 'L'} ${x} ${y}`).join(' ');
108
+ }
109
+
110
+ export function roundedPath(points, radius) {
111
+ if (points.length < 3 || radius <= 0) {
112
+ return polylinePath(points);
113
+ }
114
+
115
+ const commands = [`M ${points[0][0]} ${points[0][1]}`];
116
+ for (let i = 1; i < points.length - 1; i += 1) {
117
+ const [px, py] = points[i - 1];
118
+ const [cx, cy] = points[i];
119
+ const [nx, ny] = points[i + 1];
120
+ const prevLen = Math.hypot(cx - px, cy - py);
121
+ const nextLen = Math.hypot(nx - cx, ny - cy);
122
+ const r = Math.min(radius, prevLen / 2, nextLen / 2);
123
+ if (r < 1) {
124
+ commands.push(`L ${cx} ${cy}`);
125
+ continue;
126
+ }
127
+ const before = [cx - ((cx - px) / prevLen) * r, cy - ((cy - py) / prevLen) * r];
128
+ const after = [cx + ((nx - cx) / nextLen) * r, cy + ((ny - cy) / nextLen) * r];
129
+ commands.push(`L ${before[0]} ${before[1]}`);
130
+ commands.push(`Q ${cx} ${cy} ${after[0]} ${after[1]}`);
131
+ }
132
+ const [endX, endY] = points[points.length - 1];
133
+ commands.push(`L ${endX} ${endY}`);
134
+ return commands.join(' ');
135
+ }
136
+
137
+ // Shared by edges/flows/transitions: all carry the same optional
138
+ // labelAt/labelDx/labelDy/labelSegment knobs.
139
+ export function labelPoint(item, points) {
140
+ if (item.labelAt) return item.labelAt;
141
+ if (points.length === 2) {
142
+ return [
143
+ (points[0][0] + points[1][0]) / 2 + (item.labelDx || 0),
144
+ points[0][1] - 10 + (item.labelDy || 0)
145
+ ];
146
+ }
147
+ const segmentIndex = Math.min(points.length - 2, Math.max(0, item.labelSegment ?? 1));
148
+ const a = points[segmentIndex];
149
+ const b = points[segmentIndex + 1];
150
+ return [(a[0] + b[0]) / 2 + (item.labelDx || 0), (a[1] + b[1]) / 2 - 10 + (item.labelDy || 0)];
151
+ }
152
+
153
+ export const componentFill = {
154
+ frontend: 'c-frontend',
155
+ backend: 'c-backend',
156
+ database: 'c-database',
157
+ cloud: 'c-cloud',
158
+ security: 'c-security',
159
+ messagebus: 'c-messagebus',
160
+ external: 'c-external'
161
+ };
162
+
163
+ export const componentText = {
164
+ frontend: 't-frontend',
165
+ backend: 't-backend',
166
+ database: 't-database',
167
+ cloud: 't-cloud',
168
+ security: 't-security',
169
+ messagebus: 't-messagebus',
170
+ external: 't-external'
171
+ };
172
+
173
+ export const arrowClassMap = {
174
+ default: ['a-default', 'arrowhead'],
175
+ emphasis: ['a-emphasis', 'arrowhead-emphasis'],
176
+ security: ['a-security', 'arrowhead-security'],
177
+ dashed: ['a-dashed', 'arrowhead-dashed']
178
+ };
179
+
180
+ // Label accent per edge variant. Workflow colors dashed (async trace) labels
181
+ // like the trace store it points at; the other renderers use the bus color.
182
+ export function variantAccent(variant, { dashed = 't-messagebus' } = {}) {
183
+ return variant === 'security'
184
+ ? 't-security'
185
+ : variant === 'emphasis'
186
+ ? 't-backend'
187
+ : variant === 'dashed'
188
+ ? dashed
189
+ : 't-muted';
190
+ }
191
+
192
+ export function formatRect(r) {
193
+ return `[${Math.round(r.x)}, ${Math.round(r.y)}, ${Math.round(r.width)}, ${Math.round(r.height)}]`;
194
+ }
195
+
196
+ function formatDelta(n) {
197
+ const v = Math.round(n);
198
+ return v >= 0 ? `+${v}` : String(v);
199
+ }
200
+
201
+ /** Actionable hint when an edge label rect hits a node/component box (#7). */
202
+ export function suggestLabelObstacleFix(labelRect, lx, ly, obstacle, obstacleKind = 'component') {
203
+ const lxR = Math.round(lx);
204
+ const lyR = Math.round(ly);
205
+ const belowY = Math.round(obstacle.y + obstacle.height + 14);
206
+ const aboveY = Math.round(obstacle.y - 4);
207
+ return [
208
+ ` label rect: ${formatRect(labelRect)}`,
209
+ ` ${obstacleKind} "${obstacle.id}" rect: ${formatRect(obstacle)}`,
210
+ ` Suggested fix: labelAt [${lxR}, ${belowY}] or labelDy ${formatDelta(belowY - lyR)} (below); or labelAt [${lxR}, ${aboveY}] or labelDy ${formatDelta(aboveY - lyR)} (above)`,
211
+ ].join('\n');
212
+ }
213
+
214
+ /** Hint when two edge labels collide. */
215
+ export function suggestLabelPairFix(a, b) {
216
+ return [
217
+ ` "${a.label}" ${formatRect(a)}; "${b.label}" ${formatRect(b)}`,
218
+ ' Suggested fix: add labelDy +24 on one edge, adjust labelDx, or remove one label',
219
+ ].join('\n');
220
+ }
221
+
222
+ /** Hint when two components/nodes are too close. */
223
+ export function suggestComponentSeparation(a, b, minGap = 8) {
224
+ const rightX = Math.round(a.x + a.width + minGap);
225
+ const belowY = Math.round(a.y + a.height + minGap);
226
+ return [
227
+ ` "${a.id}" ${formatRect(a)}; "${b.id}" ${formatRect(b)}`,
228
+ ` Suggested fix: move "${b.id}" pos to [${rightX}, ${Math.round(b.y)}] (right of "${a.id}") or [${Math.round(b.x)}, ${belowY}] (below)`,
229
+ ].join('\n');
230
+ }
@@ -0,0 +1,40 @@
1
+ /** Serialize computed layout for dry-run / inspect (#9). */
2
+
3
+ export function componentBox(c) {
4
+ return {
5
+ id: c.id,
6
+ type: c.type,
7
+ label: c.label,
8
+ x: Math.round(c.x),
9
+ y: Math.round(c.y),
10
+ width: c.width,
11
+ height: c.height,
12
+ ...(Number.isInteger(c.row) ? { row: c.row } : {}),
13
+ ...(Number.isInteger(c.col) ? { col: c.col } : {}),
14
+ ...(Array.isArray(c.pos) ? { pos: c.pos.map(Math.round) } : {}),
15
+ };
16
+ }
17
+
18
+ export function boundaryBox(b) {
19
+ return {
20
+ kind: b.kind,
21
+ label: b.label,
22
+ x: Math.round(b.x),
23
+ y: Math.round(b.y),
24
+ width: Math.round(b.width),
25
+ height: Math.round(b.height),
26
+ wraps: b.wraps,
27
+ };
28
+ }
29
+
30
+ export function connectionPath(conn, routed, labelAt) {
31
+ return {
32
+ from: conn.from,
33
+ to: conn.to,
34
+ label: conn.label ?? null,
35
+ variant: conn.variant ?? 'default',
36
+ route: conn.route ?? 'auto',
37
+ points: routed.points.map(([x, y]) => [Math.round(x), Math.round(y)]),
38
+ ...(labelAt ? { labelAt: labelAt.map(Math.round) } : {}),
39
+ };
40
+ }
@@ -0,0 +1,88 @@
1
+ const ESCAPE_MAP = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' };
2
+
3
+ export function esc(value) {
4
+ return String(value ?? '').replace(/[&<>"']/g, (c) => ESCAPE_MAP[c]);
5
+ }
6
+
7
+ export function renderDefinitions() {
8
+ return ` <!-- Definitions -->
9
+ <defs>
10
+ <marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
11
+ <polygon points="0 0, 10 3.5, 0 7" class="m-default" />
12
+ </marker>
13
+ <marker id="arrowhead-emphasis" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
14
+ <polygon points="0 0, 10 3.5, 0 7" class="m-emphasis" />
15
+ </marker>
16
+ <marker id="arrowhead-security" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
17
+ <polygon points="0 0, 10 3.5, 0 7" class="m-security" />
18
+ </marker>
19
+ <marker id="arrowhead-dashed" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
20
+ <polygon points="0 0, 10 3.5, 0 7" class="m-dashed" />
21
+ </marker>
22
+ <pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
23
+ <path d="M 40 0 L 0 0 0 40" class="c-grid" stroke-width="0.5"/>
24
+ </pattern>
25
+ </defs>`;
26
+ }
27
+
28
+ export function renderCards(cards) {
29
+ const list = Array.isArray(cards) ? cards : [];
30
+ return ` <!-- Info Cards -->
31
+ <div class="cards">
32
+ ${list.map((card) => ` <div class="card">
33
+ <div class="card-header">
34
+ <div class="card-dot ${esc(card.dot)}"></div>
35
+ <h3>${esc(card.title)}</h3>
36
+ </div>
37
+ <ul>
38
+ ${card.items.map((item) => ` <li>&bull; ${esc(item)}</li>`).join('\n')}
39
+ </ul>
40
+ </div>`).join('\n\n')}
41
+ </div>`;
42
+ }
43
+
44
+ const SVG_SLOT_RE = / <!-- ARCHIFY:SVG_SLOT_START -->[\s\S]*? <!-- ARCHIFY:SVG_SLOT_END -->/;
45
+ const CARDS_SLOT_RE = / <!-- ARCHIFY:CARDS_SLOT_START -->[\s\S]*? <!-- ARCHIFY:CARDS_SLOT_END -->/;
46
+
47
+ const TEMPLATE_PLACEHOLDERS = [
48
+ '<title>[PROJECT NAME] Architecture Diagram</title>',
49
+ '<h1>[PROJECT NAME] Architecture</h1>',
50
+ '<p class="subtitle">[Subtitle description]</p>',
51
+ '[Project Name] &bull; [Additional metadata]',
52
+ ];
53
+
54
+ // `footer` is injected as raw HTML so callers can embed <kbd> hints;
55
+ // pass only trusted strings here, never user input.
56
+ export function applyTemplate(template, { title, subtitle, footer, svg, cards }) {
57
+ if (!SVG_SLOT_RE.test(template)) {
58
+ throw new Error('applyTemplate: template missing ARCHIFY:SVG_SLOT sentinel');
59
+ }
60
+ if (!CARDS_SLOT_RE.test(template)) {
61
+ throw new Error('applyTemplate: template missing ARCHIFY:CARDS_SLOT sentinel');
62
+ }
63
+ for (const ph of TEMPLATE_PLACEHOLDERS) {
64
+ if (!template.includes(ph)) {
65
+ throw new Error(`applyTemplate: template missing placeholder ${JSON.stringify(ph)}`);
66
+ }
67
+ }
68
+ // Function replacers: a literal `$&`, `$'`, `$\`` or `$$` in titles, labels,
69
+ // or rendered SVG must not be interpreted as a replacement pattern.
70
+ return template
71
+ .replace(TEMPLATE_PLACEHOLDERS[0], () => `<title>${esc(title)} Diagram</title>`)
72
+ .replace(TEMPLATE_PLACEHOLDERS[1], () => `<h1>${esc(title)}</h1>`)
73
+ .replace(TEMPLATE_PLACEHOLDERS[2], () => `<p class="subtitle">${esc(subtitle ?? '')}</p>`)
74
+ .replace(SVG_SLOT_RE, () => svg)
75
+ .replace(CARDS_SLOT_RE, () => cards)
76
+ .replace(TEMPLATE_PLACEHOLDERS[3], () => footer);
77
+ }
78
+
79
+ // CJK and other fullwidth glyphs render at roughly twice the advance width of
80
+ // ASCII in the monospace stacks the template uses. Includes the supplementary
81
+ // CJK extensions and emoji, which also render double-width.
82
+ const FULLWIDTH_RE = /[ᄀ-ᅟ⺀-꓏가-힣豈-﫿︰-﹏＀-⦆¢-₩ -〿\u{1F000}-\u{1FAFF}\u{20000}-\u{3FFFD}]/u;
83
+
84
+ export function textUnits(text) {
85
+ let units = 0;
86
+ for (const ch of String(text ?? '')) units += FULLWIDTH_RE.test(ch) ? 2 : 1;
87
+ return units;
88
+ }
@@ -0,0 +1,40 @@
1
+ import * as validators from './generated-validators.mjs';
2
+
3
+ // "/nodes/3/label" reads much better as "/nodes/3 (id: "router") /label" for the
4
+ // LLM fixing the JSON; resolve the nearest enclosing element's id or label.
5
+ function annotatePath(instancePath, data) {
6
+ if (!instancePath) return '/';
7
+ let node = data;
8
+ let hint = null;
9
+ for (const seg of instancePath.split('/').slice(1)) {
10
+ if (node == null || typeof node !== 'object') break;
11
+ node = node[/^\d+$/.test(seg) ? Number(seg) : seg];
12
+ if (node && typeof node === 'object' && !Array.isArray(node)) {
13
+ const tag = node.id ?? node.label;
14
+ if (tag != null) hint = String(tag);
15
+ }
16
+ }
17
+ return hint != null ? `${instancePath} (id/label: ${JSON.stringify(hint)})` : instancePath;
18
+ }
19
+
20
+ function formatErrors(errors, data) {
21
+ return errors.map((e) => {
22
+ const where = annotatePath(e.instancePath, data);
23
+ const detail = e.params && Object.keys(e.params).length
24
+ ? ' ' + JSON.stringify(e.params)
25
+ : '';
26
+ return ` ${where} ${e.message}${detail}`;
27
+ }).join('\n');
28
+ }
29
+
30
+ export function validateSchema(diagramType, data) {
31
+ const validate = validators[diagramType];
32
+ if (!validate) {
33
+ throw new Error(`validateSchema: unknown diagram type "${diagramType}"`);
34
+ }
35
+ if (!validate(data)) {
36
+ throw new Error(
37
+ `${diagramType} schema validation failed:\n${formatErrors(validate.errors, data)}`
38
+ );
39
+ }
40
+ }
@@ -0,0 +1,103 @@
1
+ # Workflow Renderer
2
+
3
+ Render `diagram_type: "workflow"` JSON files into the standalone technical diagram HTML
4
+ template.
5
+
6
+ ```bash
7
+ bun --config=.claude/skills/stacks-technical-diagrams/bunfig.toml --no-env-file .claude/skills/stacks-technical-diagrams/renderers/workflow/render-workflow.mjs input.workflow.json output.html
8
+ ```
9
+
10
+ The renderer validates input against `.claude/skills/stacks-technical-diagrams/schemas/workflow.schema.json`
11
+ with the bundled standalone validator. No dependency installation is required.
12
+
13
+ If `output.html` is omitted, the renderer uses `meta.output` from the JSON file
14
+ or falls back to `workflow.html` in the current working directory.
15
+
16
+ After rendering, run the artifact checker:
17
+
18
+ ```bash
19
+ bun --config=.claude/skills/stacks-technical-diagrams/bunfig.toml --no-env-file .claude/skills/stacks-technical-diagrams/scripts/check-render-output.mjs output.html
20
+ ```
21
+
22
+ It catches final-SVG issues that are easiest to see in a browser: non-finite
23
+ SVG values, accidental two-point diagonal arrows, and arrows crossing the
24
+ legend.
25
+
26
+ ## Input
27
+
28
+ Workflow JSON files must set:
29
+
30
+ ```json
31
+ {
32
+ "schema_version": 1,
33
+ "diagram_type": "workflow",
34
+ "meta": {
35
+ "title": "Agent Tool Call Workflow",
36
+ "subtitle": "Renderer-driven workflow prototype"
37
+ },
38
+ "lanes": [],
39
+ "phases": [],
40
+ "groups": [],
41
+ "mainPath": [],
42
+ "nodes": [],
43
+ "edges": [],
44
+ "cards": []
45
+ }
46
+ ```
47
+
48
+ Omit `meta.viewBox` for the common case: the width is fixed at 720 and the
49
+ height is derived from the lane count, so lanes and legend always fit. A
50
+ complete worked example lives at
51
+ `.claude/skills/stacks-technical-diagrams/examples/agent-tool-call.workflow.json`.
52
+
53
+ The schema lives at:
54
+
55
+ ```text
56
+ .claude/skills/stacks-technical-diagrams/schemas/workflow.schema.json
57
+ ```
58
+
59
+ ## Layout budget
60
+
61
+ | Constant | Value |
62
+ |----------|-------|
63
+ | viewBox | default `[720, auto]` - auto height = 52 + lanes×104 + (lanes−1)×20 + 124 |
64
+ | Lane frame | x 40, width 640, height 104, gap 20; first lane top at y 52 |
65
+ | Lane title strip | top 30px of each lane; node boxes must stay below it |
66
+ | Column centers (`col` 0-5) | x = 88, 220, 300, 430, 500, 625 |
67
+ | Phase headers | Optional `phases[]` render above the first lane, spanning `fromCol..toCol` |
68
+ | Lane groups | Optional `groups[]` frame parallel work or branch work inside one lane |
69
+ | Exception lanes | Set `lane.variant: "exception"` for retry, denial, fallback, or failure paths |
70
+ | Main path lint | Optional `mainPath[]` checks that happy-path steps have matching edges and do not move backward |
71
+ | Default node | 92×52 (height 68 when `tag` is set) |
72
+ | Node spacing | ≥8px between nodes in the same lane |
73
+ | Edge length | straight segments must span ≥28px |
74
+ | Legend row | y = lane bottom + 44; viewBox height must be ≥ legend y + 18 |
75
+
76
+ Column-center gaps are 132 / 80 / 130 / 70 / 125 px: columns 1↔2 (80px) and
77
+ 3↔4 (70px) cannot both hold default-width 92px nodes in the same lane - skip a
78
+ column or reduce `width`.
79
+
80
+ ## Design Rules
81
+
82
+ - Use lanes for ownership or runtime boundaries.
83
+ - Use phase headers for high-level story beats such as Intake, Plan, Execute, and Report.
84
+ - Use groups for parallel checks, branch handling, or bounded work within a lane; every group must contain at least one node.
85
+ - Use `lane.variant: "exception"` for human wait, denial, retry, fallback, and failure lanes instead of mixing those paths into the happy path.
86
+ - Set `mainPath` when the diagram has a clear happy path; the renderer validates that consecutive ids have matching edges and move left-to-right.
87
+ - Place nodes with lane IDs and column indexes, not raw SVG coordinates.
88
+ - Leave short adjacent links unlabeled; the arrow is enough.
89
+ - Use labels for cross-lane decisions, approvals, async traces, and return paths.
90
+ - Prefer route presets - `drop` (bend between lanes; `bias` 0-1 picks where),
91
+ `outside-right`, `return-left`, `bottom-channel`, and `up-channel` - before
92
+ using raw `via` points. `straight` and the default `auto` cover the rest.
93
+ - Keep workflow examples compact enough to render well in narrow chat/browser
94
+ previews.
95
+
96
+ Schema violations exit non-zero with path-prefixed messages annotated with the
97
+ element's id or label. The renderer additionally fails when it can detect
98
+ layout problems, including node overlap, nodes outside their lanes, invalid
99
+ phase/group column ranges, empty groups, broken `mainPath` steps, unknown edge
100
+ targets, labels colliding with nodes or other labels, labels wider than their
101
+ node, legends outside the viewBox, or straight arrows that are too short to
102
+ read cleanly. Text width is estimated CJK-aware: fullwidth glyphs count as two
103
+ units.