@polderlabs/bizar 6.3.0 → 7.0.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 (245) hide show
  1. package/.claude/hooks/sessionend-recall.mjs +3 -3
  2. package/.claude/hooks/worker-suggest.mjs +110 -0
  3. package/.claude/settings.json +9 -0
  4. package/bizar-dash/dist/assets/{EnvVarsSection-B58aiJiE.js → EnvVarsSection-CW6fWKds.js} +3 -3
  5. package/bizar-dash/dist/assets/{EnvVarsSection-B58aiJiE.js.map → EnvVarsSection-CW6fWKds.js.map} +1 -1
  6. package/bizar-dash/dist/assets/MobileChat-D7zRhU9K.js +1 -0
  7. package/bizar-dash/dist/assets/{MobileChat-BJrqwVDd.js.map → MobileChat-D7zRhU9K.js.map} +1 -1
  8. package/bizar-dash/dist/assets/MobileSettings-K-sNsn_r.js +1 -0
  9. package/bizar-dash/dist/assets/{MobileSettings-CEQNJNLJ.js.map → MobileSettings-K-sNsn_r.js.map} +1 -1
  10. package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js → Toast-WTxc3m2g.js} +1 -1
  11. package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js.map → Toast-WTxc3m2g.js.map} +1 -1
  12. package/bizar-dash/dist/assets/flow-BpU0-gK2.js +1 -0
  13. package/bizar-dash/dist/assets/flow-BpU0-gK2.js.map +1 -0
  14. package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js +1 -0
  15. package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js.map +1 -0
  16. package/bizar-dash/dist/assets/{icons-Do5N2jmX.js → icons-B0AKnYI3.js} +98 -103
  17. package/bizar-dash/dist/assets/icons-B0AKnYI3.js.map +1 -0
  18. package/bizar-dash/dist/assets/main-C-Md3DaY.css +1 -0
  19. package/bizar-dash/dist/assets/main-CO8fIxQK.js +18 -0
  20. package/bizar-dash/dist/assets/main-CO8fIxQK.js.map +1 -0
  21. package/bizar-dash/dist/assets/markdown-w2bDDkAH.js +1 -0
  22. package/bizar-dash/dist/assets/{markdown-tOLaD6nm.js.map → markdown-w2bDDkAH.js.map} +1 -1
  23. package/bizar-dash/dist/assets/mobile-DXYCA0hC.js +1 -0
  24. package/bizar-dash/dist/assets/{mobile-DYCHcUpq.js.map → mobile-DXYCA0hC.js.map} +1 -1
  25. package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js +2 -0
  26. package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js.map +1 -0
  27. package/bizar-dash/dist/assets/react-vendor-BnuhLJ6X.css +1 -0
  28. package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js +46 -0
  29. package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js.map +1 -0
  30. package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js +2 -0
  31. package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js.map +1 -0
  32. package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js +45 -0
  33. package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js.map +1 -0
  34. package/bizar-dash/dist/index.html +12 -10
  35. package/bizar-dash/dist/mobile.html +7 -4
  36. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  37. package/bizar-dash/src/server/api.mjs +11 -0
  38. package/bizar-dash/src/server/memory-consolidator.mjs +218 -0
  39. package/bizar-dash/src/server/memory-distillation.mjs +296 -0
  40. package/bizar-dash/src/server/routes/distill.mjs +129 -0
  41. package/bizar-dash/src/server/routes/goal-planner.mjs +236 -0
  42. package/bizar-dash/src/web/App.tsx +4 -0
  43. package/bizar-dash/src/web/components/Tag.tsx +18 -5
  44. package/bizar-dash/src/web/components/Topbar.tsx +3 -0
  45. package/bizar-dash/src/web/components/agents/CommunicationLog.tsx +126 -0
  46. package/bizar-dash/src/web/components/agents/DependencyGraph.tsx +163 -0
  47. package/bizar-dash/src/web/components/agents/QualityGates.tsx +123 -0
  48. package/bizar-dash/src/web/components/agents/RealTimeEventLog.tsx +127 -0
  49. package/bizar-dash/src/web/components/agents/RoutingDecisions.test.tsx +148 -0
  50. package/bizar-dash/src/web/components/agents/RoutingDecisions.tsx +160 -0
  51. package/bizar-dash/src/web/components/goals/GoalInput.tsx +86 -0
  52. package/bizar-dash/src/web/components/goals/PlanVisualization.tsx +111 -0
  53. package/bizar-dash/src/web/lib/goapPlanner.ts +614 -0
  54. package/bizar-dash/src/web/lib/types.ts +25 -0
  55. package/bizar-dash/src/web/styles/agents-redesign.css +311 -0
  56. package/bizar-dash/src/web/styles/main.css +251 -0
  57. package/bizar-dash/src/web/styles/tasks-redesign.css +231 -0
  58. package/bizar-dash/src/web/ui/controls/Button.tsx +77 -0
  59. package/bizar-dash/src/web/ui/controls/Checkbox.tsx +95 -0
  60. package/bizar-dash/src/web/ui/controls/IconButton.tsx +66 -0
  61. package/bizar-dash/src/web/ui/controls/Kbd.tsx +24 -0
  62. package/bizar-dash/src/web/ui/controls/NumberInput.tsx +77 -0
  63. package/bizar-dash/src/web/ui/controls/RadioGroup.tsx +109 -0
  64. package/bizar-dash/src/web/ui/controls/SearchInput.tsx +91 -0
  65. package/bizar-dash/src/web/ui/controls/Select.tsx +92 -0
  66. package/bizar-dash/src/web/ui/controls/Slider.tsx +70 -0
  67. package/bizar-dash/src/web/ui/controls/TextInput.tsx +67 -0
  68. package/bizar-dash/src/web/ui/controls/Toggle.tsx +79 -0
  69. package/bizar-dash/src/web/ui/controls/controls.css +454 -0
  70. package/bizar-dash/src/web/ui/controls/index.ts +33 -0
  71. package/bizar-dash/src/web/ui/data/BarChart.tsx +60 -0
  72. package/bizar-dash/src/web/ui/data/DataTable.tsx +216 -0
  73. package/bizar-dash/src/web/ui/data/EmptyState.tsx +60 -0
  74. package/bizar-dash/src/web/ui/data/ErrorState.tsx +56 -0
  75. package/bizar-dash/src/web/ui/data/KeyValueList.tsx +106 -0
  76. package/bizar-dash/src/web/ui/data/LoadingState.tsx +65 -0
  77. package/bizar-dash/src/web/ui/data/Sparkline.tsx +87 -0
  78. package/bizar-dash/src/web/ui/data/StatTile.tsx +87 -0
  79. package/bizar-dash/src/web/ui/data/data.css +535 -0
  80. package/bizar-dash/src/web/ui/data/index.ts +31 -0
  81. package/bizar-dash/src/web/ui/feedback/Badge.tsx +49 -0
  82. package/bizar-dash/src/web/ui/feedback/Dialog.tsx +209 -0
  83. package/bizar-dash/src/web/ui/feedback/ProgressBar.tsx +69 -0
  84. package/bizar-dash/src/web/ui/feedback/StatusDot.tsx +50 -0
  85. package/bizar-dash/src/web/ui/feedback/Toast.tsx +200 -0
  86. package/bizar-dash/src/web/ui/feedback/Tooltip.tsx +126 -0
  87. package/bizar-dash/src/web/ui/feedback/feedback.css +314 -0
  88. package/bizar-dash/src/web/ui/feedback/index.ts +43 -0
  89. package/bizar-dash/src/web/ui/index.ts +56 -0
  90. package/bizar-dash/src/web/ui/layout/AppShell.tsx +51 -0
  91. package/bizar-dash/src/web/ui/layout/Breadcrumbs.tsx +97 -0
  92. package/bizar-dash/src/web/ui/layout/Panel.tsx +73 -0
  93. package/bizar-dash/src/web/ui/layout/PanelHeader.tsx +39 -0
  94. package/bizar-dash/src/web/ui/layout/Sidebar.tsx +131 -0
  95. package/bizar-dash/src/web/ui/layout/Tabs.tsx +133 -0
  96. package/bizar-dash/src/web/ui/layout/Topbar.tsx +42 -0
  97. package/bizar-dash/src/web/ui/layout/index.ts +33 -0
  98. package/bizar-dash/src/web/ui/layout/layout.css +413 -0
  99. package/bizar-dash/src/web/ui/navigation/CommandPalette.tsx +199 -0
  100. package/bizar-dash/src/web/ui/navigation/NavGroup.tsx +95 -0
  101. package/bizar-dash/src/web/ui/navigation/NavLink.tsx +93 -0
  102. package/bizar-dash/src/web/ui/navigation/index.ts +17 -0
  103. package/bizar-dash/src/web/ui/navigation/navigation.css +343 -0
  104. package/bizar-dash/src/web/ui/primitives/Box.tsx +91 -0
  105. package/bizar-dash/src/web/ui/primitives/Grid.tsx +49 -0
  106. package/bizar-dash/src/web/ui/primitives/Inline.tsx +55 -0
  107. package/bizar-dash/src/web/ui/primitives/Separator.tsx +46 -0
  108. package/bizar-dash/src/web/ui/primitives/Stack.tsx +54 -0
  109. package/bizar-dash/src/web/ui/primitives/VisuallyHidden.tsx +26 -0
  110. package/bizar-dash/src/web/ui/primitives/index.ts +23 -0
  111. package/bizar-dash/src/web/ui/primitives/primitives.css +183 -0
  112. package/bizar-dash/src/web/ui/styles/globals.css +86 -0
  113. package/bizar-dash/src/web/ui/styles/reset.css +125 -0
  114. package/bizar-dash/src/web/ui/styles/tokens.css +195 -0
  115. package/bizar-dash/src/web/ui/theme/ThemeProvider.tsx +142 -0
  116. package/bizar-dash/src/web/ui/theme/tokens.ts +131 -0
  117. package/bizar-dash/src/web/ui/theme/useTheme.ts +22 -0
  118. package/bizar-dash/src/web/ui/utils/cx.ts +42 -0
  119. package/bizar-dash/src/web/views/Agents.tsx +506 -266
  120. package/bizar-dash/src/web/views/GoalPlanner.tsx +158 -0
  121. package/bizar-dash/src/web/views/Overview.tsx +996 -448
  122. package/bizar-dash/src/web/views/Tasks.tsx +277 -273
  123. package/bizar-dash/tests/communication-log.test.tsx +67 -0
  124. package/bizar-dash/tests/dep-graph.test.tsx +40 -0
  125. package/bizar-dash/tests/event-log.test.tsx +61 -0
  126. package/bizar-dash/tests/goal-input.test.tsx +72 -0
  127. package/bizar-dash/tests/goap-planner.test.ts +68 -0
  128. package/bizar-dash/tests/quality-gates.test.tsx +59 -0
  129. package/bizar-dash/tests/setup.ts +31 -1
  130. package/bizar-dash/tests/ui/controls/Button.test.tsx +50 -0
  131. package/bizar-dash/tests/ui/controls/Checkbox.test.tsx +44 -0
  132. package/bizar-dash/tests/ui/controls/IconButton.test.tsx +37 -0
  133. package/bizar-dash/tests/ui/controls/Kbd.test.tsx +39 -0
  134. package/bizar-dash/tests/ui/controls/NumberInput.test.tsx +56 -0
  135. package/bizar-dash/tests/ui/controls/RadioGroup.test.tsx +58 -0
  136. package/bizar-dash/tests/ui/controls/SearchInput.test.tsx +52 -0
  137. package/bizar-dash/tests/ui/controls/Select.test.tsx +66 -0
  138. package/bizar-dash/tests/ui/controls/Slider.test.tsx +41 -0
  139. package/bizar-dash/tests/ui/controls/TextInput.test.tsx +44 -0
  140. package/bizar-dash/tests/ui/controls/Toggle.test.tsx +39 -0
  141. package/bizar-dash/tests/ui/data/BarChart.test.tsx +55 -0
  142. package/bizar-dash/tests/ui/data/DataTable.test.tsx +112 -0
  143. package/bizar-dash/tests/ui/data/EmptyState.test.tsx +57 -0
  144. package/bizar-dash/tests/ui/data/ErrorState.test.tsx +47 -0
  145. package/bizar-dash/tests/ui/data/KeyValueList.test.tsx +59 -0
  146. package/bizar-dash/tests/ui/data/LoadingState.test.tsx +37 -0
  147. package/bizar-dash/tests/ui/data/Sparkline.test.tsx +56 -0
  148. package/bizar-dash/tests/ui/data/StatTile.test.tsx +69 -0
  149. package/bizar-dash/tests/ui/feedback/Badge.test.tsx +41 -0
  150. package/bizar-dash/tests/ui/feedback/Dialog.test.tsx +99 -0
  151. package/bizar-dash/tests/ui/feedback/ProgressBar.test.tsx +66 -0
  152. package/bizar-dash/tests/ui/feedback/StatusDot.test.tsx +41 -0
  153. package/bizar-dash/tests/ui/feedback/Toast.test.tsx +124 -0
  154. package/bizar-dash/tests/ui/feedback/Tooltip.test.tsx +102 -0
  155. package/bizar-dash/tests/ui/layout/AppShell.test.tsx +50 -0
  156. package/bizar-dash/tests/ui/layout/Breadcrumbs.test.tsx +85 -0
  157. package/bizar-dash/tests/ui/layout/Panel.test.tsx +52 -0
  158. package/bizar-dash/tests/ui/layout/PanelHeader.test.tsx +32 -0
  159. package/bizar-dash/tests/ui/layout/Sidebar.test.tsx +95 -0
  160. package/bizar-dash/tests/ui/layout/Tabs.test.tsx +87 -0
  161. package/bizar-dash/tests/ui/layout/Topbar.test.tsx +41 -0
  162. package/bizar-dash/tests/ui/navigation/CommandPalette.test.tsx +105 -0
  163. package/bizar-dash/tests/ui/navigation/NavGroup.test.tsx +55 -0
  164. package/bizar-dash/tests/ui/navigation/NavLink.test.tsx +61 -0
  165. package/bizar-dash/tests/ui/primitives/Box.test.tsx +49 -0
  166. package/bizar-dash/tests/ui/primitives/Grid.test.tsx +37 -0
  167. package/bizar-dash/tests/ui/primitives/Inline.test.tsx +33 -0
  168. package/bizar-dash/tests/ui/primitives/Separator.test.tsx +34 -0
  169. package/bizar-dash/tests/ui/primitives/Stack.test.tsx +45 -0
  170. package/bizar-dash/tests/ui/primitives/VisuallyHidden.test.tsx +27 -0
  171. package/bizar-dash/tests/views/Agents.test.tsx +359 -0
  172. package/bizar-dash/tests/views/Overview.test.tsx +413 -0
  173. package/bizar-dash/tests/views/Tasks.test.tsx +250 -0
  174. package/bizar-dash/vitest.config.ts +3 -1
  175. package/cli/__tests__/cost-gate.test.mjs +301 -0
  176. package/cli/__tests__/feature-list-bridge.test.mjs +371 -0
  177. package/cli/bin.mjs +38 -0
  178. package/cli/commands/claim.mjs +282 -0
  179. package/cli/commands/cost.mjs +279 -0
  180. package/cli/cost-gate.mjs +501 -0
  181. package/cli/feature-list-bridge.mjs +400 -0
  182. package/cli/memory-constants.mjs +17 -0
  183. package/cli/worker-dispatcher.mjs +259 -0
  184. package/cli/worker-dispatcher.test.mjs +204 -0
  185. package/config/trigger-patterns.json +186 -0
  186. package/package.json +2 -2
  187. package/packages/sdk/package.json +1 -1
  188. package/packages/sdk/src/agent-registry.ts +304 -0
  189. package/packages/sdk/src/consensus/byzantine.ts +587 -0
  190. package/packages/sdk/src/consensus/index.ts +147 -0
  191. package/packages/sdk/src/consensus/queen.ts +173 -0
  192. package/packages/sdk/src/consensus/types.ts +199 -0
  193. package/packages/sdk/src/federation/audit.ts +156 -0
  194. package/packages/sdk/src/federation/budget.ts +269 -0
  195. package/packages/sdk/src/federation/envelope.ts +144 -0
  196. package/packages/sdk/src/federation/hmac.ts +160 -0
  197. package/packages/sdk/src/federation/index.ts +443 -0
  198. package/packages/sdk/src/federation/pii.ts +241 -0
  199. package/packages/sdk/src/federation/policy.ts +112 -0
  200. package/packages/sdk/src/federation/trust.ts +146 -0
  201. package/packages/sdk/src/index.ts +67 -0
  202. package/packages/sdk/src/mcp/server.ts +351 -1
  203. package/packages/sdk/src/router/codemod-intent.ts +125 -0
  204. package/packages/sdk/src/router/index.ts +247 -0
  205. package/packages/sdk/src/router/memory-distillation-shim.mjs +18 -0
  206. package/packages/sdk/src/router/memory-distillation.ts +249 -0
  207. package/packages/sdk/src/router/model-router.ts +235 -0
  208. package/packages/sdk/src/router/q-learning-router.ts +304 -0
  209. package/packages/sdk/src/swarm-topology.ts +279 -0
  210. package/packages/sdk/tests/agent-registry.test.ts +285 -0
  211. package/packages/sdk/tests/consensus.test.ts +376 -0
  212. package/packages/sdk/tests/federation/audit.test.ts +164 -0
  213. package/packages/sdk/tests/federation/budget.test.ts +189 -0
  214. package/packages/sdk/tests/federation/envelope.test.ts +120 -0
  215. package/packages/sdk/tests/federation/hmac.test.ts +194 -0
  216. package/packages/sdk/tests/federation/orchestrator.test.ts +176 -0
  217. package/packages/sdk/tests/federation/pii.test.ts +106 -0
  218. package/packages/sdk/tests/federation/policy.test.ts +140 -0
  219. package/packages/sdk/tests/federation/trust.test.ts +124 -0
  220. package/packages/sdk/tests/mcp-tools.test.ts +204 -0
  221. package/packages/sdk/tests/memory-distillation.test.mjs +186 -0
  222. package/packages/sdk/tests/model-router.test.mjs +108 -0
  223. package/packages/sdk/tests/q-learning-router.test.mjs +100 -0
  224. package/packages/sdk/tests/router-orchestrator.test.mjs +172 -0
  225. package/packages/sdk/tests/router.test.mjs +91 -0
  226. package/packages/sdk/tests/sdk.test.mjs +26 -2
  227. package/packages/sdk/tests/swarm-topology.test.ts +258 -0
  228. package/scripts/bh-full-e2e.mjs +11 -15
  229. package/bizar-dash/dist/assets/MobileChat-BJrqwVDd.js +0 -1
  230. package/bizar-dash/dist/assets/MobileSettings-CEQNJNLJ.js +0 -1
  231. package/bizar-dash/dist/assets/icons-Do5N2jmX.js.map +0 -1
  232. package/bizar-dash/dist/assets/main-IvfQAOfy.js +0 -18
  233. package/bizar-dash/dist/assets/main-IvfQAOfy.js.map +0 -1
  234. package/bizar-dash/dist/assets/main-ietCEg_R.css +0 -1
  235. package/bizar-dash/dist/assets/markdown-tOLaD6nm.js +0 -1
  236. package/bizar-dash/dist/assets/mobile-DYCHcUpq.js +0 -1
  237. package/bizar-dash/dist/assets/mobile-layout-CBHjpwsb.js +0 -2
  238. package/bizar-dash/dist/assets/mobile-layout-CBHjpwsb.js.map +0 -1
  239. package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js +0 -40
  240. package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js.map +0 -1
  241. package/bizar-dash/dist/assets/useSlashCommands-Bd7_FA6U.js +0 -2
  242. package/bizar-dash/dist/assets/useSlashCommands-Bd7_FA6U.js.map +0 -1
  243. package/bizar-dash/dist/assets/vendor-C843201K.js +0 -29
  244. package/bizar-dash/dist/assets/vendor-C843201K.js.map +0 -1
  245. package/packages/sdk/package-lock.json +0 -32
@@ -0,0 +1,231 @@
1
+ /*
2
+ * tasks-redesign.css — Wave 3 task board view (Supabase-style simplicity).
3
+ *
4
+ * Imports are intentionally narrow: this file ships the visual surface for
5
+ * the redesigned Tasks view (kanban columns + compact task rows). Every
6
+ * value references a design-system token from ui/styles/tokens.css — no
7
+ * hardcoded colours, no gradients, no shadows beyond hairline, no radii
8
+ * greater than --radius-lg (6px). Legacy classes (`.task-card`, etc.) in
9
+ * main.css are intentionally bypassed in favour of the redesigned shapes.
10
+ *
11
+ * Class scoping: every selector is namespaced under `.tasks-wave3` so the
12
+ * new rules never collide with the legacy kanban/task-card styles that
13
+ * remain in main.css for the mobile view.
14
+ */
15
+
16
+ .tasks-wave3 {
17
+ display: flex;
18
+ flex-direction: column;
19
+ gap: var(--space-4);
20
+ }
21
+
22
+ /* ── Header ─────────────────────────────────────────────────────── */
23
+
24
+ .tasks-wave3__header {
25
+ display: flex;
26
+ align-items: center;
27
+ justify-content: space-between;
28
+ gap: var(--space-4);
29
+ }
30
+
31
+ .tasks-wave3__title-row {
32
+ display: flex;
33
+ align-items: center;
34
+ gap: var(--space-2);
35
+ font-size: var(--text-lg);
36
+ font-weight: var(--weight-semibold);
37
+ color: var(--text-primary);
38
+ margin: 0;
39
+ }
40
+
41
+ .tasks-wave3__subtitle {
42
+ margin: var(--space-1) 0 0;
43
+ font-size: var(--text-sm);
44
+ color: var(--text-secondary);
45
+ }
46
+
47
+ /* ── Toolbar ────────────────────────────────────────────────────── */
48
+
49
+ .tasks-wave3__toolbar {
50
+ display: flex;
51
+ align-items: center;
52
+ gap: var(--space-3);
53
+ flex-wrap: wrap;
54
+ padding: var(--space-3);
55
+ background: var(--surface-1);
56
+ border: 1px solid var(--border-subtle);
57
+ border-radius: var(--radius-md);
58
+ }
59
+
60
+ .tasks-wave3__toolbar-group {
61
+ display: flex;
62
+ align-items: center;
63
+ gap: var(--space-2);
64
+ }
65
+
66
+ .tasks-wave3__toolbar-label {
67
+ font-size: var(--text-xs);
68
+ text-transform: uppercase;
69
+ letter-spacing: 0.04em;
70
+ color: var(--text-tertiary);
71
+ }
72
+
73
+ .tasks-wave3__toolbar-spacer {
74
+ flex: 1;
75
+ }
76
+
77
+ /* ── Kanban grid ────────────────────────────────────────────────── */
78
+
79
+ .tasks-wave3__kanban {
80
+ align-items: stretch;
81
+ }
82
+
83
+ .tasks-wave3__column {
84
+ min-width: 0;
85
+ height: 100%;
86
+ }
87
+
88
+ .tasks-wave3__column-body {
89
+ display: flex;
90
+ flex-direction: column;
91
+ gap: var(--space-2);
92
+ min-height: 120px;
93
+ }
94
+
95
+ .tasks-wave3__column-count {
96
+ display: inline-flex;
97
+ align-items: center;
98
+ justify-content: center;
99
+ min-width: 22px;
100
+ padding: 0 var(--space-2);
101
+ height: 18px;
102
+ font-family: var(--font-mono);
103
+ font-size: var(--text-xs);
104
+ font-weight: var(--weight-medium);
105
+ color: var(--text-secondary);
106
+ background: var(--surface-overlay);
107
+ border-radius: var(--radius-full);
108
+ font-variant-numeric: tabular-nums;
109
+ }
110
+
111
+ .tasks-wave3__column-title {
112
+ display: inline-flex;
113
+ align-items: center;
114
+ gap: var(--space-2);
115
+ font-size: var(--text-base);
116
+ font-weight: var(--weight-semibold);
117
+ color: var(--text-primary);
118
+ line-height: var(--leading-tight);
119
+ }
120
+
121
+ .tasks-wave3__column-empty {
122
+ padding: var(--space-5) var(--space-3);
123
+ font-size: var(--text-sm);
124
+ color: var(--text-tertiary);
125
+ text-align: center;
126
+ font-style: italic;
127
+ }
128
+
129
+ /* ── Task row ───────────────────────────────────────────────────── */
130
+
131
+ .tasks-wave3__row {
132
+ display: flex;
133
+ flex-direction: column;
134
+ gap: var(--space-2);
135
+ padding: var(--space-3);
136
+ background: var(--surface-0);
137
+ border: 1px solid var(--border-subtle);
138
+ border-left-width: 3px;
139
+ border-radius: var(--radius-md);
140
+ cursor: pointer;
141
+ transition: border-color var(--duration-fast) var(--ease-out),
142
+ background var(--duration-fast) var(--ease-out);
143
+ min-height: 76px;
144
+ }
145
+
146
+ .tasks-wave3__row:hover {
147
+ border-color: var(--border-default);
148
+ background: var(--surface-1);
149
+ }
150
+
151
+ .tasks-wave3__row:focus-visible {
152
+ outline: 2px solid var(--border-focus);
153
+ outline-offset: 1px;
154
+ }
155
+
156
+ .tasks-wave3__row--priority-high {
157
+ border-left-color: var(--danger);
158
+ }
159
+
160
+ .tasks-wave3__row--priority-normal {
161
+ border-left-color: var(--info);
162
+ }
163
+
164
+ .tasks-wave3__row--priority-low {
165
+ border-left-color: var(--text-tertiary);
166
+ }
167
+
168
+ .tasks-wave3__row-title-row {
169
+ display: flex;
170
+ align-items: flex-start;
171
+ justify-content: space-between;
172
+ gap: var(--space-2);
173
+ }
174
+
175
+ .tasks-wave3__row-title {
176
+ flex: 1;
177
+ min-width: 0;
178
+ font-size: var(--text-base);
179
+ font-weight: var(--weight-medium);
180
+ color: var(--text-primary);
181
+ line-height: var(--leading-snug);
182
+ overflow: hidden;
183
+ display: -webkit-box;
184
+ -webkit-line-clamp: 2;
185
+ line-clamp: 2;
186
+ -webkit-box-orient: vertical;
187
+ word-break: break-word;
188
+ }
189
+
190
+ .tasks-wave3__row-badges {
191
+ display: flex;
192
+ flex-wrap: wrap;
193
+ gap: var(--space-1);
194
+ align-items: center;
195
+ }
196
+
197
+ .tasks-wave3__row-footer {
198
+ display: flex;
199
+ align-items: center;
200
+ justify-content: space-between;
201
+ gap: var(--space-2);
202
+ margin-top: auto;
203
+ padding-top: var(--space-1);
204
+ }
205
+
206
+ .tasks-wave3__row-time {
207
+ font-family: var(--font-mono);
208
+ font-size: var(--text-xs);
209
+ color: var(--text-tertiary);
210
+ font-variant-numeric: tabular-nums;
211
+ }
212
+
213
+ .tasks-wave3__row-actions {
214
+ display: flex;
215
+ gap: var(--space-1);
216
+ align-items: center;
217
+ }
218
+
219
+ /* Status dot accent for column header — pairs with the redesigned Badge variants. */
220
+ .tasks-wave3__dot {
221
+ width: 8px;
222
+ height: 8px;
223
+ border-radius: var(--radius-full);
224
+ flex-shrink: 0;
225
+ }
226
+
227
+ .tasks-wave3__dot--info { background: var(--info); }
228
+ .tasks-wave3__dot--accent { background: var(--accent); }
229
+ .tasks-wave3__dot--success { background: var(--success); }
230
+ .tasks-wave3__dot--warning { background: var(--warning); }
231
+ .tasks-wave3__dot--danger { background: var(--danger); }
@@ -0,0 +1,77 @@
1
+ /*
2
+ * Button.tsx — primary action control (Wave 2A).
3
+ *
4
+ * Variants: primary (green accent CTA), secondary (neutral chrome), ghost
5
+ * (transparent chrome), subtle (accent tint), danger (red destructive).
6
+ * Sizes: xs/sm/md/lg. `loading` replaces the click target with a spinner
7
+ * and sets `disabled` so the user cannot double-fire while the request is
8
+ * in flight. `icon` (left) and `iconRight` slot arbitrary ReactNode — most
9
+ * callers pass a lucide-react icon. Styled by controls.css; use cx() to
10
+ * compose classes.
11
+ */
12
+
13
+ import {
14
+ forwardRef,
15
+ type ButtonHTMLAttributes,
16
+ type ReactNode,
17
+ } from 'react';
18
+ import { cx } from '../utils/cx';
19
+
20
+ export type ButtonVariant =
21
+ | 'primary'
22
+ | 'secondary'
23
+ | 'ghost'
24
+ | 'subtle'
25
+ | 'danger';
26
+ export type ButtonSize = 'xs' | 'sm' | 'md' | 'lg';
27
+
28
+ export type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
29
+ variant?: ButtonVariant;
30
+ size?: ButtonSize;
31
+ loading?: boolean;
32
+ fullWidth?: boolean;
33
+ icon?: ReactNode;
34
+ iconRight?: ReactNode;
35
+ };
36
+
37
+ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
38
+ function Button(
39
+ {
40
+ variant = 'secondary',
41
+ size = 'md',
42
+ loading = false,
43
+ fullWidth = false,
44
+ icon,
45
+ iconRight,
46
+ disabled,
47
+ className,
48
+ children,
49
+ type = 'button',
50
+ ...rest
51
+ },
52
+ ref,
53
+ ) {
54
+ return (
55
+ <button
56
+ ref={ref}
57
+ type={type}
58
+ disabled={disabled || loading}
59
+ aria-busy={loading || undefined}
60
+ className={cx(
61
+ 'btn',
62
+ `btn-${variant}`,
63
+ `btn-size-${size}`,
64
+ loading && 'btn-loading',
65
+ fullWidth && 'btn-full',
66
+ className,
67
+ )}
68
+ {...rest}
69
+ >
70
+ {loading && <span className="btn-spinner" aria-hidden />}
71
+ {icon}
72
+ {children}
73
+ {iconRight}
74
+ </button>
75
+ );
76
+ },
77
+ );
@@ -0,0 +1,95 @@
1
+ /*
2
+ * Checkbox.tsx — tri-state checkbox (Wave 2A).
3
+ *
4
+ * Three visual states: unchecked, checked, indeterminate (set the
5
+ * `indeterminate` boolean when partial selection applies — e.g. a
6
+ * parent whose children are partially selected). Built as a label +
7
+ * visually-hidden input pattern so the entire row is clickable and
8
+ * keyboard activatable (space).
9
+ *
10
+ * Wrapper-level props (data-testid, id, aria-*, className) flow to the
11
+ * <label>; the inner <input> only takes its own concerns.
12
+ */
13
+
14
+ import {
15
+ forwardRef,
16
+ useEffect,
17
+ useRef,
18
+ type HTMLAttributes,
19
+ type ReactNode,
20
+ } from 'react';
21
+ import { Check, Minus } from 'lucide-react';
22
+ import { cx } from '../utils/cx';
23
+
24
+ export type CheckboxProps = Omit<
25
+ HTMLAttributes<HTMLLabelElement>,
26
+ 'onChange' | 'children'
27
+ > & {
28
+ checked: boolean;
29
+ onChange: (next: boolean) => void;
30
+ label?: ReactNode;
31
+ indeterminate?: boolean;
32
+ disabled?: boolean;
33
+ name?: string;
34
+ autoFocus?: boolean;
35
+ required?: boolean;
36
+ };
37
+
38
+ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
39
+ function Checkbox(
40
+ {
41
+ checked,
42
+ onChange,
43
+ label,
44
+ indeterminate = false,
45
+ disabled,
46
+ name,
47
+ autoFocus,
48
+ required,
49
+ className,
50
+ ...labelProps
51
+ },
52
+ ref,
53
+ ) {
54
+ const innerRef = useRef<HTMLInputElement | null>(null);
55
+ useEffect(() => {
56
+ if (innerRef.current) innerRef.current.indeterminate = indeterminate;
57
+ }, [indeterminate]);
58
+ const setRef = (el: HTMLInputElement | null) => {
59
+ innerRef.current = el;
60
+ if (typeof ref === 'function') ref(el);
61
+ else if (ref) ref.current = el;
62
+ };
63
+ return (
64
+ <label
65
+ {...labelProps}
66
+ className={cx(
67
+ 'checkbox',
68
+ checked && 'checkbox-checked',
69
+ indeterminate && 'checkbox-indeterminate',
70
+ className,
71
+ )}
72
+ >
73
+ <input
74
+ ref={setRef}
75
+ type="checkbox"
76
+ name={name}
77
+ checked={checked}
78
+ disabled={disabled}
79
+ required={required}
80
+ autoFocus={autoFocus}
81
+ onChange={(e) => onChange(e.target.checked)}
82
+ className="checkbox-input"
83
+ />
84
+ <span className="checkbox-box" aria-hidden>
85
+ {indeterminate ? (
86
+ <Minus strokeWidth={3} />
87
+ ) : checked ? (
88
+ <Check strokeWidth={3} />
89
+ ) : null}
90
+ </span>
91
+ {label !== undefined && <span className="checkbox-label">{label}</span>}
92
+ </label>
93
+ );
94
+ },
95
+ );
@@ -0,0 +1,66 @@
1
+ /*
2
+ * IconButton.tsx — square icon-only button (Wave 2A).
3
+ *
4
+ * Use for toolbar actions, dialog close buttons, and other in-line controls
5
+ * that need only a glyph. Always pair with `aria-label` (or `aria-labelledby`)
6
+ * — the rendered children are the icon, so sighted-only labels are absent.
7
+ * Mirrors Button's variant taxonomy (primary/secondary/ghost/danger/subtle)
8
+ * with sizes sm/md/lg (24/32/40 px squares).
9
+ */
10
+
11
+ import {
12
+ forwardRef,
13
+ type ButtonHTMLAttributes,
14
+ type ReactNode,
15
+ } from 'react';
16
+ import { cx } from '../utils/cx';
17
+
18
+ export type IconButtonVariant =
19
+ | 'primary'
20
+ | 'secondary'
21
+ | 'ghost'
22
+ | 'danger'
23
+ | 'subtle';
24
+ export type IconButtonSize = 'sm' | 'md' | 'lg';
25
+
26
+ export type IconButtonProps = Omit<
27
+ ButtonHTMLAttributes<HTMLButtonElement>,
28
+ 'children'
29
+ > & {
30
+ variant?: IconButtonVariant;
31
+ size?: IconButtonSize;
32
+ icon: ReactNode;
33
+ 'aria-label': string;
34
+ };
35
+
36
+ export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
37
+ function IconButton(
38
+ {
39
+ variant = 'secondary',
40
+ size = 'md',
41
+ icon,
42
+ disabled,
43
+ className,
44
+ type = 'button',
45
+ ...rest
46
+ },
47
+ ref,
48
+ ) {
49
+ return (
50
+ <button
51
+ ref={ref}
52
+ type={type}
53
+ disabled={disabled}
54
+ className={cx(
55
+ 'icon-btn',
56
+ `icon-btn-${variant}`,
57
+ `icon-btn-size-${size}`,
58
+ className,
59
+ )}
60
+ {...rest}
61
+ >
62
+ {icon}
63
+ </button>
64
+ );
65
+ },
66
+ );
@@ -0,0 +1,24 @@
1
+ /*
2
+ * Kbd.tsx — keyboard-shortcut affordance (Wave 2A).
3
+ *
4
+ * Renders a single key glyph (or short label) inside a <kbd> element
5
+ * styled with a hairline border + monospace font. Use for inline
6
+ * shortcut hints next to menu items, command palette entries, or any
7
+ * place a user needs to see "this is a keyboard shortcut". Stacking
8
+ * multiple Kbds inline renders a "⌘ K" / "Ctrl K" style hint.
9
+ */
10
+
11
+ import type { HTMLAttributes, ReactNode } from 'react';
12
+ import { cx } from '../utils/cx';
13
+
14
+ export type KbdProps = HTMLAttributes<HTMLElement> & {
15
+ children?: ReactNode;
16
+ };
17
+
18
+ export function Kbd({ children, className, ...rest }: KbdProps): React.JSX.Element {
19
+ return (
20
+ <kbd className={cx('kbd', className)} {...rest}>
21
+ {children}
22
+ </kbd>
23
+ );
24
+ }
@@ -0,0 +1,77 @@
1
+ /*
2
+ * NumberInput.tsx — numeric input (Wave 2A).
3
+ *
4
+ * Wraps <input type="number"> and accepts string | number for `value`
5
+ * (the native input gives back a string from typing but consumers
6
+ * typically want to work with numbers). `onChange` normalises: if the
7
+ * field is empty, emit ''; otherwise coerce to Number. When the parsed
8
+ * number is NaN we emit the raw string so the consumer can decide.
9
+ */
10
+
11
+ import { forwardRef, type InputHTMLAttributes } from 'react';
12
+ import { cx } from '../utils/cx';
13
+
14
+ export type NumberInputSize = 'sm' | 'md' | 'lg';
15
+
16
+ export type NumberInputProps = Omit<
17
+ InputHTMLAttributes<HTMLInputElement>,
18
+ 'type' | 'value' | 'onChange' | 'size' | 'children'
19
+ > & {
20
+ inputSize?: NumberInputSize;
21
+ error?: string | null;
22
+ value: string | number;
23
+ onChange: (next: string | number) => void;
24
+ min?: number;
25
+ max?: number;
26
+ step?: number;
27
+ };
28
+
29
+ export const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
30
+ function NumberInput(
31
+ {
32
+ inputSize = 'md',
33
+ error,
34
+ value,
35
+ onChange,
36
+ min,
37
+ max,
38
+ step,
39
+ disabled,
40
+ className,
41
+ ...rest
42
+ },
43
+ ref,
44
+ ) {
45
+ return (
46
+ <span
47
+ className={cx(
48
+ 'field',
49
+ `field-size-${inputSize}`,
50
+ className,
51
+ )}
52
+ >
53
+ <input
54
+ ref={ref}
55
+ type="number"
56
+ disabled={disabled}
57
+ value={value}
58
+ min={min}
59
+ max={max}
60
+ step={step}
61
+ aria-invalid={error ? true : undefined}
62
+ className={cx('field-input', error && 'field-error')}
63
+ onChange={(e) => {
64
+ const raw = e.target.value;
65
+ if (raw === '') {
66
+ onChange('');
67
+ return;
68
+ }
69
+ const n = Number(raw);
70
+ onChange(Number.isFinite(n) ? n : raw);
71
+ }}
72
+ {...rest}
73
+ />
74
+ </span>
75
+ );
76
+ },
77
+ );
@@ -0,0 +1,109 @@
1
+ /*
2
+ * RadioGroup.tsx — single-select radio group (Wave 2A).
3
+ *
4
+ * Renders a radiogroup shell and lays out one label-wrapping-input per
5
+ * option. Keyboard navigation (arrow keys) is inherited from native
6
+ * <input type="radio"> inside a single name group. `orientation`
7
+ * controls horizontal vs vertical layout; CSS handles the actual flex
8
+ * direction. Wrapper-level props (data-testid, id, aria-*, className)
9
+ * land on the radiogroup container, not on each input.
10
+ */
11
+
12
+ import {
13
+ forwardRef,
14
+ type HTMLAttributes,
15
+ type ReactNode,
16
+ } from 'react';
17
+ import { cx } from '../utils/cx';
18
+
19
+ export type RadioOption = {
20
+ value: string;
21
+ label: ReactNode;
22
+ description?: ReactNode;
23
+ disabled?: boolean;
24
+ };
25
+
26
+ export type RadioOrientation = 'horizontal' | 'vertical';
27
+
28
+ export type RadioGroupProps = Omit<
29
+ HTMLAttributes<HTMLDivElement>,
30
+ 'onChange' | 'children'
31
+ > & {
32
+ name: string;
33
+ value: string;
34
+ onChange: (next: string) => void;
35
+ options: RadioOption[];
36
+ orientation?: RadioOrientation;
37
+ legend?: ReactNode;
38
+ disabled?: boolean;
39
+ required?: boolean;
40
+ };
41
+
42
+ export const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
43
+ function RadioGroup(
44
+ {
45
+ name,
46
+ value,
47
+ onChange,
48
+ options,
49
+ orientation = 'vertical',
50
+ legend,
51
+ disabled: groupDisabled,
52
+ required,
53
+ className,
54
+ ...wrapperProps
55
+ },
56
+ ref,
57
+ ) {
58
+ return (
59
+ <div
60
+ ref={ref}
61
+ role="radiogroup"
62
+ {...wrapperProps}
63
+ className={cx(
64
+ 'radio-group',
65
+ orientation === 'horizontal' && 'radio-group-horizontal',
66
+ className,
67
+ )}
68
+ >
69
+ {legend !== undefined && (
70
+ <p className="radio-option-label" style={{ marginBottom: 4 }}>
71
+ {legend}
72
+ </p>
73
+ )}
74
+ {options.map((opt) => {
75
+ const isChecked = opt.value === value;
76
+ return (
77
+ <label
78
+ key={opt.value}
79
+ className={cx(
80
+ 'radio-option',
81
+ isChecked && 'radio-option-checked',
82
+ )}
83
+ >
84
+ <input
85
+ type="radio"
86
+ name={name}
87
+ value={opt.value}
88
+ checked={isChecked}
89
+ disabled={groupDisabled || opt.disabled}
90
+ required={required}
91
+ onChange={() => onChange(opt.value)}
92
+ className="radio-option-input"
93
+ />
94
+ <span className="radio-option-box" aria-hidden>
95
+ <span className="radio-option-dot" />
96
+ </span>
97
+ <span className="radio-option-content">
98
+ <span className="radio-option-label">{opt.label}</span>
99
+ {opt.description !== undefined && (
100
+ <span className="radio-option-desc">{opt.description}</span>
101
+ )}
102
+ </span>
103
+ </label>
104
+ );
105
+ })}
106
+ </div>
107
+ );
108
+ },
109
+ );