minutework 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/EXTERNAL_ALPHA.md +74 -0
  2. package/README.md +57 -0
  3. package/assets/claude-local/CLAUDE.md.template +45 -0
  4. package/assets/claude-local/bundle.json +22 -0
  5. package/assets/claude-local/skills/README.md +6 -0
  6. package/assets/claude-local/skills/app-pack-authoring.md +8 -0
  7. package/assets/claude-local/skills/event-bus.md +8 -0
  8. package/assets/claude-local/skills/ontology-mapping.md +8 -0
  9. package/assets/claude-local/skills/openclaw-skill-importer.md +7 -0
  10. package/assets/claude-local/skills/schema-engine.md +8 -0
  11. package/assets/claude-local/skills/secrets-runtime-bridge.md +9 -0
  12. package/assets/claude-local/skills/sidecar-generation.md +9 -0
  13. package/assets/templates/fastapi-sidecar/.env.example +8 -0
  14. package/assets/templates/fastapi-sidecar/README.md +77 -0
  15. package/assets/templates/fastapi-sidecar/poetry.lock +757 -0
  16. package/assets/templates/fastapi-sidecar/pyproject.toml +42 -0
  17. package/assets/templates/fastapi-sidecar/src/fastapi_sidecar/__init__.py +3 -0
  18. package/assets/templates/fastapi-sidecar/src/fastapi_sidecar/auth.py +70 -0
  19. package/assets/templates/fastapi-sidecar/src/fastapi_sidecar/bridge/__init__.py +3 -0
  20. package/assets/templates/fastapi-sidecar/src/fastapi_sidecar/bridge/client.py +71 -0
  21. package/assets/templates/fastapi-sidecar/src/fastapi_sidecar/logging_utils.py +25 -0
  22. package/assets/templates/fastapi-sidecar/src/fastapi_sidecar/main.py +85 -0
  23. package/assets/templates/fastapi-sidecar/src/fastapi_sidecar/receipts.py +24 -0
  24. package/assets/templates/fastapi-sidecar/src/fastapi_sidecar/settings.py +41 -0
  25. package/assets/templates/fastapi-sidecar/src/fastapi_sidecar/template_validation.py +26 -0
  26. package/assets/templates/fastapi-sidecar/src/fastapi_sidecar/worker.py +33 -0
  27. package/assets/templates/fastapi-sidecar/template.json +43 -0
  28. package/assets/templates/fastapi-sidecar/template.schema.json +160 -0
  29. package/assets/templates/fastapi-sidecar/tests/conftest.py +36 -0
  30. package/assets/templates/fastapi-sidecar/tests/test_app.py +39 -0
  31. package/assets/templates/fastapi-sidecar/tests/test_auth.py +32 -0
  32. package/assets/templates/fastapi-sidecar/tests/test_bridge_client.py +31 -0
  33. package/assets/templates/fastapi-sidecar/tests/test_materialization.py +55 -0
  34. package/assets/templates/fastapi-sidecar/tests/test_template_contract.py +49 -0
  35. package/assets/templates/fastapi-sidecar/tests/test_worker.py +7 -0
  36. package/assets/templates/fastapi-sidecar/tools/template/validate_template.py +20 -0
  37. package/assets/templates/next-tenant-app/.env.example +8 -0
  38. package/assets/templates/next-tenant-app/.storybook/main.ts +19 -0
  39. package/assets/templates/next-tenant-app/.storybook/preview.tsx +38 -0
  40. package/assets/templates/next-tenant-app/README.md +115 -0
  41. package/assets/templates/next-tenant-app/components.json +21 -0
  42. package/assets/templates/next-tenant-app/eslint.config.mjs +41 -0
  43. package/assets/templates/next-tenant-app/next-env.d.ts +6 -0
  44. package/assets/templates/next-tenant-app/next.config.ts +8 -0
  45. package/assets/templates/next-tenant-app/package-lock.json +9682 -0
  46. package/assets/templates/next-tenant-app/package.json +59 -0
  47. package/assets/templates/next-tenant-app/pnpm-lock.yaml +6062 -0
  48. package/assets/templates/next-tenant-app/postcss.config.mjs +8 -0
  49. package/assets/templates/next-tenant-app/src/app/api/auth/context/route.test.ts +90 -0
  50. package/assets/templates/next-tenant-app/src/app/api/auth/context/route.ts +78 -0
  51. package/assets/templates/next-tenant-app/src/app/api/auth/login/route.ts +31 -0
  52. package/assets/templates/next-tenant-app/src/app/api/auth/logout/route.ts +16 -0
  53. package/assets/templates/next-tenant-app/src/app/api/auth/password-change/route.test.ts +79 -0
  54. package/assets/templates/next-tenant-app/src/app/api/auth/password-change/route.ts +40 -0
  55. package/assets/templates/next-tenant-app/src/app/api/auth/password-status/route.test.ts +42 -0
  56. package/assets/templates/next-tenant-app/src/app/api/auth/password-status/route.ts +29 -0
  57. package/assets/templates/next-tenant-app/src/app/api/auth/session/route.ts +26 -0
  58. package/assets/templates/next-tenant-app/src/app/api/gateway/commands/[runId]/route.test.ts +40 -0
  59. package/assets/templates/next-tenant-app/src/app/api/gateway/commands/[runId]/route.ts +47 -0
  60. package/assets/templates/next-tenant-app/src/app/api/gateway/commands/route.test.ts +43 -0
  61. package/assets/templates/next-tenant-app/src/app/api/gateway/commands/route.ts +45 -0
  62. package/assets/templates/next-tenant-app/src/app/app/examples/runtime-commands/page.test.ts +83 -0
  63. package/assets/templates/next-tenant-app/src/app/app/examples/runtime-commands/page.tsx +30 -0
  64. package/assets/templates/next-tenant-app/src/app/app/layout.tsx +20 -0
  65. package/assets/templates/next-tenant-app/src/app/app/page.test.ts +62 -0
  66. package/assets/templates/next-tenant-app/src/app/app/page.tsx +24 -0
  67. package/assets/templates/next-tenant-app/src/app/blog/[slug]/page.test.ts +70 -0
  68. package/assets/templates/next-tenant-app/src/app/blog/[slug]/page.tsx +57 -0
  69. package/assets/templates/next-tenant-app/src/app/blog/page.test.ts +42 -0
  70. package/assets/templates/next-tenant-app/src/app/blog/page.tsx +37 -0
  71. package/assets/templates/next-tenant-app/src/app/docs/[...slug]/page.test.ts +70 -0
  72. package/assets/templates/next-tenant-app/src/app/docs/[...slug]/page.tsx +55 -0
  73. package/assets/templates/next-tenant-app/src/app/docs/page.test.ts +42 -0
  74. package/assets/templates/next-tenant-app/src/app/docs/page.tsx +37 -0
  75. package/assets/templates/next-tenant-app/src/app/globals.css +70 -0
  76. package/assets/templates/next-tenant-app/src/app/layout.tsx +69 -0
  77. package/assets/templates/next-tenant-app/src/app/login/page.test.ts +55 -0
  78. package/assets/templates/next-tenant-app/src/app/login/page.tsx +33 -0
  79. package/assets/templates/next-tenant-app/src/app/page.test.ts +56 -0
  80. package/assets/templates/next-tenant-app/src/app/page.tsx +35 -0
  81. package/assets/templates/next-tenant-app/src/app/pricing/page.test.ts +55 -0
  82. package/assets/templates/next-tenant-app/src/app/pricing/page.tsx +35 -0
  83. package/assets/templates/next-tenant-app/src/app/providers.tsx +25 -0
  84. package/assets/templates/next-tenant-app/src/app/robots.test.ts +20 -0
  85. package/assets/templates/next-tenant-app/src/app/robots.ts +18 -0
  86. package/assets/templates/next-tenant-app/src/app/sitemap.test.ts +49 -0
  87. package/assets/templates/next-tenant-app/src/app/sitemap.ts +54 -0
  88. package/assets/templates/next-tenant-app/src/components/ui/button.tsx +59 -0
  89. package/assets/templates/next-tenant-app/src/components/ui/input.tsx +21 -0
  90. package/assets/templates/next-tenant-app/src/design-system/docs/governance.mdx +26 -0
  91. package/assets/templates/next-tenant-app/src/design-system/patterns/panel-frame.stories.tsx +48 -0
  92. package/assets/templates/next-tenant-app/src/design-system/patterns/panel-frame.tsx +26 -0
  93. package/assets/templates/next-tenant-app/src/design-system/patterns/status-badge.stories.tsx +26 -0
  94. package/assets/templates/next-tenant-app/src/design-system/patterns/status-badge.tsx +35 -0
  95. package/assets/templates/next-tenant-app/src/design-system/patterns/theme-mode-toggle.stories.tsx +21 -0
  96. package/assets/templates/next-tenant-app/src/design-system/patterns/theme-mode-toggle.tsx +75 -0
  97. package/assets/templates/next-tenant-app/src/design-system/primitives/button.stories.tsx +37 -0
  98. package/assets/templates/next-tenant-app/src/design-system/primitives/button.ts +1 -0
  99. package/assets/templates/next-tenant-app/src/design-system/primitives/input.stories.tsx +26 -0
  100. package/assets/templates/next-tenant-app/src/design-system/primitives/input.ts +1 -0
  101. package/assets/templates/next-tenant-app/src/design-system/recipes/chrome.ts +28 -0
  102. package/assets/templates/next-tenant-app/src/design-system/tokens/foundation.css +31 -0
  103. package/assets/templates/next-tenant-app/src/design-system/tokens/index.css +3 -0
  104. package/assets/templates/next-tenant-app/src/design-system/tokens/manifest.json +85 -0
  105. package/assets/templates/next-tenant-app/src/design-system/tokens/manifest.ts +87 -0
  106. package/assets/templates/next-tenant-app/src/design-system/tokens/semantic.css +105 -0
  107. package/assets/templates/next-tenant-app/src/design-system/tokens/theme.css +59 -0
  108. package/assets/templates/next-tenant-app/src/design-system/tokens/tokens.stories.tsx +71 -0
  109. package/assets/templates/next-tenant-app/src/features/auth/components/login-screen.tsx +198 -0
  110. package/assets/templates/next-tenant-app/src/features/dashboard/components/tenant-dashboard.tsx +153 -0
  111. package/assets/templates/next-tenant-app/src/features/examples/runtime-command-demo/components/runtime-command-demo.tsx +342 -0
  112. package/assets/templates/next-tenant-app/src/features/public-shell/components/content-article.tsx +66 -0
  113. package/assets/templates/next-tenant-app/src/features/public-shell/components/content-collection.tsx +108 -0
  114. package/assets/templates/next-tenant-app/src/features/public-shell/components/marketing-page-canvas.tsx +111 -0
  115. package/assets/templates/next-tenant-app/src/features/public-shell/components/public-site-shell.tsx +111 -0
  116. package/assets/templates/next-tenant-app/src/features/shell/components/private-app-shell.tsx +624 -0
  117. package/assets/templates/next-tenant-app/src/lib/app-routes.test.ts +20 -0
  118. package/assets/templates/next-tenant-app/src/lib/app-routes.ts +59 -0
  119. package/assets/templates/next-tenant-app/src/lib/content/__fixtures__/public-site-snapshot.ts +189 -0
  120. package/assets/templates/next-tenant-app/src/lib/content/adapter.server.test.ts +318 -0
  121. package/assets/templates/next-tenant-app/src/lib/content/adapter.server.ts +232 -0
  122. package/assets/templates/next-tenant-app/src/lib/content/contracts.ts +339 -0
  123. package/assets/templates/next-tenant-app/src/lib/content/custom-adapter.ts +5 -0
  124. package/assets/templates/next-tenant-app/src/lib/content/empty-state.ts +96 -0
  125. package/assets/templates/next-tenant-app/src/lib/platform/auth.server.test.ts +75 -0
  126. package/assets/templates/next-tenant-app/src/lib/platform/auth.server.ts +25 -0
  127. package/assets/templates/next-tenant-app/src/lib/platform/client.server.test.ts +170 -0
  128. package/assets/templates/next-tenant-app/src/lib/platform/client.server.ts +661 -0
  129. package/assets/templates/next-tenant-app/src/lib/platform/contracts.ts +131 -0
  130. package/assets/templates/next-tenant-app/src/lib/platform/endpoints.server.ts +34 -0
  131. package/assets/templates/next-tenant-app/src/lib/platform/env.server.test.ts +102 -0
  132. package/assets/templates/next-tenant-app/src/lib/platform/env.server.ts +87 -0
  133. package/assets/templates/next-tenant-app/src/lib/platform/route-response.ts +33 -0
  134. package/assets/templates/next-tenant-app/src/lib/platform/session.server.ts +108 -0
  135. package/assets/templates/next-tenant-app/src/lib/public-site.test.ts +20 -0
  136. package/assets/templates/next-tenant-app/src/lib/public-site.ts +49 -0
  137. package/assets/templates/next-tenant-app/src/lib/theme-config.ts +10 -0
  138. package/assets/templates/next-tenant-app/src/lib/theme.tsx +159 -0
  139. package/assets/templates/next-tenant-app/src/lib/utils.ts +6 -0
  140. package/assets/templates/next-tenant-app/template.json +27 -0
  141. package/assets/templates/next-tenant-app/template.schema.json +160 -0
  142. package/assets/templates/next-tenant-app/test/server-only-stub.ts +1 -0
  143. package/assets/templates/next-tenant-app/tools/design-system/build-token-manifest.mjs +3 -0
  144. package/assets/templates/next-tenant-app/tools/design-system/check-imports.mjs +9 -0
  145. package/assets/templates/next-tenant-app/tools/design-system/check-stories.mjs +9 -0
  146. package/assets/templates/next-tenant-app/tools/design-system/check-values.mjs +9 -0
  147. package/assets/templates/next-tenant-app/tools/design-system/checks.mjs +238 -0
  148. package/assets/templates/next-tenant-app/tools/design-system/eslint-plugin-design-system.mjs +184 -0
  149. package/assets/templates/next-tenant-app/tools/design-system/playwright.config.mjs +34 -0
  150. package/assets/templates/next-tenant-app/tools/design-system/run-checks.mjs +22 -0
  151. package/assets/templates/next-tenant-app/tools/design-system/shared.mjs +166 -0
  152. package/assets/templates/next-tenant-app/tools/design-system/visual.spec.ts +41 -0
  153. package/assets/templates/next-tenant-app/tools/template/validate-route-contract.mjs +39 -0
  154. package/assets/templates/next-tenant-app/tools/template/validate-template.mjs +45 -0
  155. package/assets/templates/next-tenant-app/tsconfig.json +42 -0
  156. package/assets/templates/next-tenant-app/vitest.config.ts +25 -0
  157. package/bin/minutework.js +40 -0
  158. package/dist/auth.d.ts +59 -0
  159. package/dist/auth.js +338 -0
  160. package/dist/auth.js.map +1 -0
  161. package/dist/browser.d.ts +1 -0
  162. package/dist/browser.js +26 -0
  163. package/dist/browser.js.map +1 -0
  164. package/dist/cli.d.ts +2 -0
  165. package/dist/cli.js +5 -0
  166. package/dist/cli.js.map +1 -0
  167. package/dist/compile.d.ts +20 -0
  168. package/dist/compile.js +121 -0
  169. package/dist/compile.js.map +1 -0
  170. package/dist/config.d.ts +25 -0
  171. package/dist/config.js +102 -0
  172. package/dist/config.js.map +1 -0
  173. package/dist/deploy-state.d.ts +35 -0
  174. package/dist/deploy-state.js +30 -0
  175. package/dist/deploy-state.js.map +1 -0
  176. package/dist/deploy.d.ts +22 -0
  177. package/dist/deploy.js +308 -0
  178. package/dist/deploy.js.map +1 -0
  179. package/dist/developer-client.d.ts +88 -0
  180. package/dist/developer-client.js +78 -0
  181. package/dist/developer-client.js.map +1 -0
  182. package/dist/index.d.ts +27 -0
  183. package/dist/index.js +290 -0
  184. package/dist/index.js.map +1 -0
  185. package/dist/init.d.ts +22 -0
  186. package/dist/init.js +421 -0
  187. package/dist/init.js.map +1 -0
  188. package/dist/launcher.d.ts +1 -0
  189. package/dist/launcher.js +50 -0
  190. package/dist/launcher.js.map +1 -0
  191. package/dist/paths.d.ts +12 -0
  192. package/dist/paths.js +33 -0
  193. package/dist/paths.js.map +1 -0
  194. package/dist/sandbox.d.ts +30 -0
  195. package/dist/sandbox.js +852 -0
  196. package/dist/sandbox.js.map +1 -0
  197. package/dist/state.d.ts +46 -0
  198. package/dist/state.js +82 -0
  199. package/dist/state.js.map +1 -0
  200. package/dist/tokens.d.ts +14 -0
  201. package/dist/tokens.js +293 -0
  202. package/dist/tokens.js.map +1 -0
  203. package/package.json +43 -0
@@ -0,0 +1,105 @@
1
+ :root {
2
+ --background: #f6fafc;
3
+ --foreground: var(--ds-foundation-neutral-950);
4
+ --card: #fcfdff;
5
+ --card-foreground: var(--ds-foundation-neutral-950);
6
+ --popover: #fcfdff;
7
+ --popover-foreground: var(--ds-foundation-neutral-950);
8
+ --primary: var(--ds-foundation-cyan-600);
9
+ --primary-foreground: var(--ds-foundation-white);
10
+ --secondary: #edf3f7;
11
+ --secondary-foreground: var(--ds-foundation-neutral-950);
12
+ --muted: #eef5f8;
13
+ --muted-foreground: #617487;
14
+ --accent: var(--ds-foundation-cyan-100);
15
+ --accent-foreground: var(--ds-foundation-neutral-950);
16
+ --destructive: var(--ds-foundation-red-500);
17
+ --destructive-foreground: var(--ds-foundation-white);
18
+ --border: #d7e5ed;
19
+ --input: #d7e5ed;
20
+ --ring: var(--ds-foundation-cyan-500);
21
+ --chart-1: var(--ds-foundation-cyan-500);
22
+ --chart-2: var(--ds-foundation-green-500);
23
+ --chart-3: var(--ds-foundation-blue-500);
24
+ --chart-4: var(--ds-foundation-yellow-500);
25
+ --chart-5: var(--ds-foundation-red-500);
26
+ --radius: 0.5rem;
27
+ --sidebar: #f8fbfd;
28
+ --sidebar-foreground: var(--ds-foundation-neutral-950);
29
+ --sidebar-primary: var(--ds-foundation-cyan-600);
30
+ --sidebar-primary-foreground: var(--ds-foundation-white);
31
+ --sidebar-accent: #edf5f8;
32
+ --sidebar-accent-foreground: var(--ds-foundation-neutral-950);
33
+ --sidebar-border: #d7e5ed;
34
+ --sidebar-ring: var(--ds-foundation-cyan-500);
35
+
36
+ --surface: #ffffff;
37
+ --surface-raised: #f3f8fb;
38
+ --text-link: var(--ds-foundation-cyan-700);
39
+ --success: var(--ds-foundation-green-500);
40
+ --warning: var(--ds-foundation-yellow-500);
41
+ --danger: var(--ds-foundation-red-500);
42
+ --info: var(--ds-foundation-blue-500);
43
+ --ai-bubble: #eef5f8;
44
+ --user-bubble: var(--ds-foundation-cyan-600);
45
+ --tenant-rail: var(--ds-foundation-cyan-50);
46
+ --tenant-rail-foreground: var(--ds-foundation-ink-500);
47
+ --tenant-rail-muted: #627789;
48
+ --tenant-rail-border: rgb(148 163 184 / 0.24);
49
+ --tenant-rail-surface: rgb(255 255 255 / 0.72);
50
+ --overlay: var(--ds-foundation-overlay-50);
51
+ --overlay-strong: var(--ds-foundation-overlay-60);
52
+ --strong-foreground: var(--ds-foundation-white);
53
+ }
54
+
55
+ .dark {
56
+ --background: var(--ds-foundation-neutral-950);
57
+ --foreground: var(--ds-foundation-neutral-100);
58
+ --card: var(--ds-foundation-neutral-850);
59
+ --card-foreground: var(--ds-foundation-neutral-100);
60
+ --popover: var(--ds-foundation-neutral-850);
61
+ --popover-foreground: var(--ds-foundation-neutral-100);
62
+ --primary: var(--ds-foundation-cyan-500);
63
+ --primary-foreground: var(--ds-foundation-white);
64
+ --secondary: var(--ds-foundation-neutral-800);
65
+ --secondary-foreground: var(--ds-foundation-neutral-100);
66
+ --muted: var(--ds-foundation-neutral-850);
67
+ --muted-foreground: var(--ds-foundation-neutral-500);
68
+ --accent: var(--ds-foundation-ink-700);
69
+ --accent-foreground: var(--ds-foundation-neutral-100);
70
+ --destructive: var(--ds-foundation-red-500);
71
+ --destructive-foreground: var(--ds-foundation-white);
72
+ --border: var(--ds-foundation-neutral-700);
73
+ --input: var(--ds-foundation-neutral-800);
74
+ --ring: var(--ds-foundation-cyan-500);
75
+ --chart-1: var(--ds-foundation-cyan-500);
76
+ --chart-2: var(--ds-foundation-green-500);
77
+ --chart-3: var(--ds-foundation-blue-500);
78
+ --chart-4: var(--ds-foundation-yellow-500);
79
+ --chart-5: var(--ds-foundation-red-500);
80
+ --sidebar: var(--ds-foundation-neutral-900);
81
+ --sidebar-foreground: var(--ds-foundation-neutral-100);
82
+ --sidebar-primary: var(--ds-foundation-cyan-500);
83
+ --sidebar-primary-foreground: var(--ds-foundation-white);
84
+ --sidebar-accent: var(--ds-foundation-neutral-800);
85
+ --sidebar-accent-foreground: var(--ds-foundation-neutral-100);
86
+ --sidebar-border: var(--ds-foundation-neutral-700);
87
+ --sidebar-ring: var(--ds-foundation-cyan-500);
88
+ --surface: var(--ds-foundation-neutral-850);
89
+ --surface-raised: var(--ds-foundation-neutral-800);
90
+ --text-link: var(--ds-foundation-cyan-300);
91
+ --success: var(--ds-foundation-green-500);
92
+ --warning: var(--ds-foundation-yellow-500);
93
+ --danger: var(--ds-foundation-red-500);
94
+ --info: var(--ds-foundation-blue-500);
95
+ --ai-bubble: var(--ds-foundation-neutral-850);
96
+ --user-bubble: var(--ds-foundation-cyan-600);
97
+ --tenant-rail: var(--ds-foundation-neutral-950);
98
+ --tenant-rail-foreground: var(--ds-foundation-white);
99
+ --tenant-rail-muted: rgb(255 255 255 / 0.72);
100
+ --tenant-rail-border: rgb(255 255 255 / 0.08);
101
+ --tenant-rail-surface: rgb(255 255 255 / 0.06);
102
+ --overlay: var(--ds-foundation-overlay-50);
103
+ --overlay-strong: var(--ds-foundation-overlay-60);
104
+ --strong-foreground: var(--ds-foundation-white);
105
+ }
@@ -0,0 +1,59 @@
1
+ @custom-variant dark (&:is(.dark *));
2
+
3
+ @theme inline {
4
+ --font-sans: "Geist", "Geist Fallback";
5
+ --font-mono: "Geist Mono", "Geist Mono Fallback";
6
+ --color-background: var(--background);
7
+ --color-foreground: var(--foreground);
8
+ --color-card: var(--card);
9
+ --color-card-foreground: var(--card-foreground);
10
+ --color-popover: var(--popover);
11
+ --color-popover-foreground: var(--popover-foreground);
12
+ --color-primary: var(--primary);
13
+ --color-primary-foreground: var(--primary-foreground);
14
+ --color-secondary: var(--secondary);
15
+ --color-secondary-foreground: var(--secondary-foreground);
16
+ --color-muted: var(--muted);
17
+ --color-muted-foreground: var(--muted-foreground);
18
+ --color-accent: var(--accent);
19
+ --color-accent-foreground: var(--accent-foreground);
20
+ --color-destructive: var(--destructive);
21
+ --color-destructive-foreground: var(--destructive-foreground);
22
+ --color-border: var(--border);
23
+ --color-input: var(--input);
24
+ --color-ring: var(--ring);
25
+ --color-chart-1: var(--chart-1);
26
+ --color-chart-2: var(--chart-2);
27
+ --color-chart-3: var(--chart-3);
28
+ --color-chart-4: var(--chart-4);
29
+ --color-chart-5: var(--chart-5);
30
+ --radius-sm: calc(var(--radius) - 4px);
31
+ --radius-md: calc(var(--radius) - 2px);
32
+ --radius-lg: var(--radius);
33
+ --radius-xl: calc(var(--radius) + 4px);
34
+ --color-sidebar: var(--sidebar);
35
+ --color-sidebar-foreground: var(--sidebar-foreground);
36
+ --color-sidebar-primary: var(--sidebar-primary);
37
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
38
+ --color-sidebar-accent: var(--sidebar-accent);
39
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
40
+ --color-sidebar-border: var(--sidebar-border);
41
+ --color-sidebar-ring: var(--sidebar-ring);
42
+ --color-surface: var(--surface);
43
+ --color-surface-raised: var(--surface-raised);
44
+ --color-text-link: var(--text-link);
45
+ --color-success: var(--success);
46
+ --color-warning: var(--warning);
47
+ --color-danger: var(--danger);
48
+ --color-info: var(--info);
49
+ --color-ai-bubble: var(--ai-bubble);
50
+ --color-user-bubble: var(--user-bubble);
51
+ --color-tenant-rail: var(--tenant-rail);
52
+ --color-tenant-rail-foreground: var(--tenant-rail-foreground);
53
+ --color-tenant-rail-muted: var(--tenant-rail-muted);
54
+ --color-tenant-rail-border: var(--tenant-rail-border);
55
+ --color-tenant-rail-surface: var(--tenant-rail-surface);
56
+ --color-overlay: var(--overlay);
57
+ --color-overlay-strong: var(--overlay-strong);
58
+ --color-strong-foreground: var(--strong-foreground);
59
+ }
@@ -0,0 +1,71 @@
1
+ import type { Meta, StoryObj } from "@storybook/nextjs-vite";
2
+
3
+ import tokenManifest from "@/design-system/tokens/manifest";
4
+
5
+ function TokenGrid({
6
+ entries,
7
+ }: {
8
+ entries: Array<[string, string]>;
9
+ }) {
10
+ return (
11
+ <div className="grid gap-3 sm:grid-cols-2">
12
+ {entries.map(([name, value]) => (
13
+ <div
14
+ key={name}
15
+ className="flex items-center gap-3 rounded-lg border border-border bg-surface p-3"
16
+ >
17
+ <div
18
+ className="h-10 w-10 rounded-md border border-border"
19
+ style={{ backgroundColor: `var(--${name})` }}
20
+ />
21
+ <div className="min-w-0">
22
+ <p className="truncate text-sm font-medium text-foreground">{name}</p>
23
+ <p className="truncate text-xs text-muted-foreground">{value}</p>
24
+ </div>
25
+ </div>
26
+ ))}
27
+ </div>
28
+ );
29
+ }
30
+
31
+ function TokenShowcase() {
32
+ return (
33
+ <div className="w-[720px] space-y-8">
34
+ <section className="space-y-3">
35
+ <div>
36
+ <p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
37
+ Semantic
38
+ </p>
39
+ <h2 className="text-xl font-semibold text-foreground">Shared UI roles</h2>
40
+ </div>
41
+ <TokenGrid entries={Object.entries(tokenManifest.semantic)} />
42
+ </section>
43
+ <section className="space-y-3">
44
+ <div>
45
+ <p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
46
+ Foundation
47
+ </p>
48
+ <h2 className="text-xl font-semibold text-foreground">Literal sources</h2>
49
+ </div>
50
+ <TokenGrid entries={Object.entries(tokenManifest.foundation)} />
51
+ </section>
52
+ </div>
53
+ );
54
+ }
55
+
56
+ const meta = {
57
+ title: "Design System/Tokens",
58
+ component: TokenShowcase,
59
+ tags: ["autodocs"],
60
+ parameters: {
61
+ layout: "fullscreen",
62
+ },
63
+ } satisfies Meta<typeof TokenShowcase>;
64
+
65
+ export default meta;
66
+
67
+ type Story = StoryObj<typeof meta>;
68
+
69
+ export const Overview: Story = {
70
+ render: () => <TokenShowcase />,
71
+ };
@@ -0,0 +1,198 @@
1
+ "use client";
2
+
3
+ import { startTransition, useEffect, useState } from "react";
4
+ import type { FormEvent } from "react";
5
+
6
+ import { ArrowRight, ShieldCheck, TerminalSquare } from "lucide-react";
7
+ import { useRouter } from "next/navigation";
8
+
9
+ import { Button } from "@/design-system/primitives/button";
10
+ import { Input } from "@/design-system/primitives/input";
11
+ import { PanelFrame } from "@/design-system/patterns/panel-frame";
12
+ import { ThemeModeToggle } from "@/design-system/patterns/theme-mode-toggle";
13
+ import { appRoutes } from "@/lib/app-routes";
14
+
15
+ export function LoginScreen({
16
+ appName,
17
+ operatorConsoleHref,
18
+ }: {
19
+ appName: string;
20
+ operatorConsoleHref: string;
21
+ }) {
22
+ const router = useRouter();
23
+ const [username, setUsername] = useState("demo-user");
24
+ const [password, setPassword] = useState("demo-password");
25
+ const [error, setError] = useState("");
26
+ const [submitting, setSubmitting] = useState(false);
27
+
28
+ useEffect(() => {
29
+ void fetch("/api/auth/session", {
30
+ method: "GET",
31
+ cache: "no-store",
32
+ }).catch(() => null);
33
+ }, []);
34
+
35
+ async function handleSubmit(event: FormEvent<HTMLFormElement>) {
36
+ event.preventDefault();
37
+ setSubmitting(true);
38
+ setError("");
39
+
40
+ try {
41
+ const response = await fetch("/api/auth/login", {
42
+ method: "POST",
43
+ headers: { "Content-Type": "application/json" },
44
+ body: JSON.stringify({ username, password }),
45
+ });
46
+
47
+ if (!response.ok) {
48
+ const payload = (await response.json().catch(() => ({}))) as {
49
+ detail?: string;
50
+ };
51
+ setError(payload.detail || "Login failed.");
52
+ setSubmitting(false);
53
+ return;
54
+ }
55
+
56
+ startTransition(() => {
57
+ router.replace(appRoutes.appHome);
58
+ router.refresh();
59
+ });
60
+ } catch {
61
+ setError("Unable to reach the platform right now.");
62
+ setSubmitting(false);
63
+ }
64
+ }
65
+
66
+ return (
67
+ <main className="min-h-screen bg-background text-foreground">
68
+ <div className="mx-auto flex min-h-screen max-w-6xl flex-col gap-10 px-6 py-8 lg:flex-row lg:items-center lg:justify-between">
69
+ <div className="flex justify-end lg:hidden">
70
+ <ThemeModeToggle className="max-w-xs" />
71
+ </div>
72
+
73
+ <section className="max-w-2xl space-y-6">
74
+ <div className="space-y-3">
75
+ <p className="text-sm font-semibold uppercase tracking-widest text-muted-foreground">
76
+ Combined Web Starter
77
+ </p>
78
+ <h1 className="max-w-xl text-4xl font-semibold tracking-tight text-balance sm:text-5xl">
79
+ Cross the public-to-private boundary without splitting the app.
80
+ </h1>
81
+ <p className="max-w-xl text-base leading-7 text-muted-foreground sm:text-lg">
82
+ {appName} keeps marketing, docs, and blog routes public at the
83
+ root while preserving a server-owned platform session BFF under
84
+ `/app`.
85
+ </p>
86
+ </div>
87
+
88
+ <div className="grid gap-3 sm:grid-cols-2">
89
+ <PanelFrame tone="raised" radius="xl" padding="lg" className="space-y-2">
90
+ <TerminalSquare className="size-5 text-primary" />
91
+ <p className="text-sm font-medium">Generic tenant shell</p>
92
+ <p className="text-sm leading-6 text-muted-foreground">
93
+ Start with public storytelling at the root and authenticated
94
+ workspace routing under `/app` instead of a private-only home page.
95
+ </p>
96
+ </PanelFrame>
97
+ <PanelFrame tone="raised" radius="xl" padding="lg" className="space-y-2">
98
+ <ShieldCheck className="size-5 text-primary" />
99
+ <p className="text-sm font-medium">Server-owned session</p>
100
+ <p className="text-sm leading-6 text-muted-foreground">
101
+ Session cookies stay on the server boundary while public pages
102
+ remain free of tenant-context reads and private BFF assumptions.
103
+ </p>
104
+ </PanelFrame>
105
+ </div>
106
+ </section>
107
+
108
+ <div className="flex w-full max-w-md flex-col gap-4 self-center lg:self-auto">
109
+ <div className="hidden justify-end lg:flex">
110
+ <ThemeModeToggle className="max-w-xs" />
111
+ </div>
112
+
113
+ <PanelFrame tone="floating" radius="xl" padding="lg" className="space-y-6 shadow-2xl">
114
+ <div className="space-y-2">
115
+ <p className="text-sm font-semibold uppercase tracking-widest text-muted-foreground">
116
+ Template sign-in
117
+ </p>
118
+ <h2 className="text-2xl font-semibold tracking-tight">
119
+ Log into {appName}
120
+ </h2>
121
+ <p className="text-sm leading-6 text-muted-foreground">
122
+ Use platform tenant credentials to establish a server-owned
123
+ session before entering the authenticated shell under `/app`.
124
+ </p>
125
+ </div>
126
+
127
+ <form className="space-y-5" onSubmit={handleSubmit}>
128
+ <div className="space-y-2">
129
+ <label
130
+ className="text-xs font-semibold uppercase tracking-widest text-muted-foreground"
131
+ htmlFor="username"
132
+ >
133
+ Username
134
+ </label>
135
+ <Input
136
+ id="username"
137
+ name="username"
138
+ autoComplete="username"
139
+ className="h-12 text-base"
140
+ value={username}
141
+ onChange={(event) => {
142
+ setUsername(event.target.value);
143
+ setError("");
144
+ }}
145
+ />
146
+ </div>
147
+
148
+ <div className="space-y-2">
149
+ <label
150
+ className="text-xs font-semibold uppercase tracking-widest text-muted-foreground"
151
+ htmlFor="password"
152
+ >
153
+ Password
154
+ </label>
155
+ <Input
156
+ id="password"
157
+ name="password"
158
+ type="password"
159
+ autoComplete="current-password"
160
+ className="h-12 text-base"
161
+ value={password}
162
+ onChange={(event) => {
163
+ setPassword(event.target.value);
164
+ setError("");
165
+ }}
166
+ />
167
+ </div>
168
+
169
+ {error ? (
170
+ <p className="text-sm leading-6 text-destructive">{error}</p>
171
+ ) : null}
172
+
173
+ <Button
174
+ type="submit"
175
+ className="h-12 w-full text-sm font-semibold"
176
+ disabled={submitting}
177
+ >
178
+ {submitting ? "Signing in" : "Sign In"}
179
+ <ArrowRight className="size-4" />
180
+ </Button>
181
+ </form>
182
+
183
+ <div className="flex flex-wrap items-center justify-between gap-3 border-t border-border pt-4">
184
+ <p className="text-sm text-muted-foreground">
185
+ Need the operator console instead?
186
+ </p>
187
+ <Button asChild type="button" variant="outline">
188
+ <a href={operatorConsoleHref} target="_blank" rel="noreferrer">
189
+ Open /ops
190
+ </a>
191
+ </Button>
192
+ </div>
193
+ </PanelFrame>
194
+ </div>
195
+ </div>
196
+ </main>
197
+ );
198
+ }
@@ -0,0 +1,153 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { Blocks, Building2, FolderKanban, ShieldCheck } from "lucide-react";
5
+
6
+ import { PanelFrame } from "@/design-system/patterns/panel-frame";
7
+ import { StatusBadge } from "@/design-system/patterns/status-badge";
8
+ import { Button } from "@/design-system/primitives/button";
9
+ import { appRoutes } from "@/lib/app-routes";
10
+ import type { AuthenticatedPlatformSession } from "@/lib/platform/contracts";
11
+
12
+ function DashboardMetric({
13
+ label,
14
+ value,
15
+ }: {
16
+ label: string;
17
+ value: string;
18
+ }) {
19
+ return (
20
+ <PanelFrame tone="raised" radius="xl" padding="md" className="space-y-2">
21
+ <p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
22
+ {label}
23
+ </p>
24
+ <p className="text-sm font-semibold text-foreground">{value}</p>
25
+ </PanelFrame>
26
+ );
27
+ }
28
+
29
+ export function TenantDashboard({
30
+ appName,
31
+ runtimeCommandExampleEnabled,
32
+ session,
33
+ }: {
34
+ appName: string;
35
+ runtimeCommandExampleEnabled: boolean;
36
+ session: AuthenticatedPlatformSession;
37
+ }) {
38
+ return (
39
+ <div className="grid gap-6">
40
+ <PanelFrame tone="floating" radius="xl" padding="lg" className="space-y-6">
41
+ <div className="space-y-2">
42
+ <p className="text-sm font-semibold uppercase tracking-widest text-muted-foreground">
43
+ Authenticated Workspace
44
+ </p>
45
+ <h2 className="text-3xl font-semibold tracking-tight">
46
+ {appName} ships with a reusable authenticated shell behind `/app`.
47
+ </h2>
48
+ <p className="max-w-3xl text-sm leading-7 text-muted-foreground">
49
+ This template is designed for Builder materialization into a writable
50
+ sandbox. Public storytelling lives at the root, while the
51
+ authenticated shell, tenant context controls, password settings,
52
+ route gating, and BFF auth boundary remain real under `/app`.
53
+ </p>
54
+ </div>
55
+
56
+ <div className="grid gap-3 md:grid-cols-3">
57
+ <DashboardMetric label="Signed-in user" value={session.user.username} />
58
+ <DashboardMetric
59
+ label="Active tenant"
60
+ value={session.active_tenant.tenant_name}
61
+ />
62
+ <DashboardMetric
63
+ label="Membership count"
64
+ value={`${session.memberships.length}`}
65
+ />
66
+ </div>
67
+ </PanelFrame>
68
+
69
+ <section className="grid gap-6 xl:grid-cols-[1fr,1fr]">
70
+ <PanelFrame tone="raised" radius="xl" padding="lg" className="space-y-4">
71
+ <div className="flex items-center gap-2">
72
+ <ShieldCheck className="size-5 text-primary" />
73
+ <h3 className="text-xl font-semibold tracking-tight">
74
+ Auth profile
75
+ </h3>
76
+ </div>
77
+ <div className="flex flex-wrap gap-3">
78
+ <StatusBadge tone="primary">platform_session_bff</StatusBadge>
79
+ <StatusBadge tone="info">Server-owned cookies</StatusBadge>
80
+ <StatusBadge tone="success">CSRF forwarding</StatusBadge>
81
+ </div>
82
+ <p className="text-sm leading-7 text-muted-foreground">
83
+ The browser talks only to this Next.js app. Upstream platform session
84
+ cookies and CSRF tokens remain server-owned inside route handlers.
85
+ Request-scoped tenant overrides stay scoped to feature actions unless
86
+ the explicit session-context APIs are used.
87
+ </p>
88
+ </PanelFrame>
89
+
90
+ <PanelFrame tone="raised" radius="xl" padding="lg" className="space-y-4">
91
+ <div className="flex items-center gap-2">
92
+ <Building2 className="size-5 text-primary" />
93
+ <h3 className="text-xl font-semibold tracking-tight">
94
+ Builder materialization
95
+ </h3>
96
+ </div>
97
+ <p className="text-sm leading-7 text-muted-foreground">
98
+ The canonical template bundle is meant to be copied into
99
+ `BuilderWorkspace.sandbox_root/app/` before an agent edits it. The
100
+ copied workspace becomes the writable app root; this source bundle stays
101
+ governed and read-only in normal authoring flows.
102
+ </p>
103
+ </PanelFrame>
104
+ </section>
105
+
106
+ <section className="grid gap-6 xl:grid-cols-[1fr,1fr]">
107
+ <PanelFrame tone="raised" radius="xl" padding="lg" className="space-y-4">
108
+ <div className="flex items-center gap-2">
109
+ <Blocks className="size-5 text-primary" />
110
+ <h3 className="text-xl font-semibold tracking-tight">
111
+ Scaffold contents
112
+ </h3>
113
+ </div>
114
+ <ul className="space-y-3 text-sm leading-6 text-muted-foreground">
115
+ <li>Design-system primitives, patterns, docs, and governance checks.</li>
116
+ <li>Public marketing, docs, and blog routes with a swappable content adapter.</li>
117
+ <li>Typed platform session BFF routes for login, context, and password flows.</li>
118
+ <li>Tenant-aware shell components ready for Builder-specific feature work.</li>
119
+ </ul>
120
+ </PanelFrame>
121
+
122
+ <PanelFrame tone="raised" radius="xl" padding="lg" className="space-y-4">
123
+ <div className="flex items-center gap-2">
124
+ <FolderKanban className="size-5 text-primary" />
125
+ <h3 className="text-xl font-semibold tracking-tight">
126
+ Optional example surface
127
+ </h3>
128
+ </div>
129
+ <p className="text-sm leading-7 text-muted-foreground">
130
+ The runtime-command example is bundled as optional sample code rather
131
+ than the template&apos;s default product identity.
132
+ </p>
133
+ {runtimeCommandExampleEnabled ? (
134
+ <Button asChild className="w-fit">
135
+ <Link href={appRoutes.runtimeCommandExample}>
136
+ Open runtime command example
137
+ </Link>
138
+ </Button>
139
+ ) : (
140
+ <div className="space-y-2">
141
+ <StatusBadge tone="default">Disabled by default</StatusBadge>
142
+ <p className="text-sm leading-6 text-muted-foreground">
143
+ Set `MW_ENABLE_RUNTIME_COMMAND_EXAMPLE=true` in the materialized
144
+ workspace to enable the example route and its matching gateway
145
+ proxy handlers.
146
+ </p>
147
+ </div>
148
+ )}
149
+ </PanelFrame>
150
+ </section>
151
+ </div>
152
+ );
153
+ }