@assistkick/create 1.6.0 → 1.8.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 (214) hide show
  1. package/package.json +2 -2
  2. package/templates/assistkick-product-system/.env.example +1 -0
  3. package/templates/assistkick-product-system/local.db +0 -0
  4. package/templates/assistkick-product-system/package.json +4 -2
  5. package/templates/assistkick-product-system/packages/backend/package.json +2 -0
  6. package/templates/assistkick-product-system/packages/backend/src/routes/agents.ts +165 -0
  7. package/templates/assistkick-product-system/packages/backend/src/routes/files.test.ts +358 -0
  8. package/templates/assistkick-product-system/packages/backend/src/routes/files.ts +356 -0
  9. package/templates/assistkick-product-system/packages/backend/src/routes/git.ts +96 -1
  10. package/templates/assistkick-product-system/packages/backend/src/routes/graph.ts +1 -0
  11. package/templates/assistkick-product-system/packages/backend/src/routes/kanban.ts +43 -4
  12. package/templates/assistkick-product-system/packages/backend/src/routes/pipeline.ts +200 -84
  13. package/templates/assistkick-product-system/packages/backend/src/routes/projects.ts +6 -3
  14. package/templates/assistkick-product-system/packages/backend/src/routes/terminal.ts +53 -17
  15. package/templates/assistkick-product-system/packages/backend/src/routes/video.ts +218 -0
  16. package/templates/assistkick-product-system/packages/backend/src/routes/workflow_groups.ts +119 -0
  17. package/templates/assistkick-product-system/packages/backend/src/routes/workflows.ts +154 -0
  18. package/templates/assistkick-product-system/packages/backend/src/server.ts +81 -9
  19. package/templates/assistkick-product-system/packages/backend/src/services/agent_service.test.ts +489 -0
  20. package/templates/assistkick-product-system/packages/backend/src/services/agent_service.ts +416 -0
  21. package/templates/assistkick-product-system/packages/backend/src/services/bundle_service.test.ts +189 -0
  22. package/templates/assistkick-product-system/packages/backend/src/services/bundle_service.ts +182 -0
  23. package/templates/assistkick-product-system/packages/backend/src/services/init.ts +28 -78
  24. package/templates/assistkick-product-system/packages/backend/src/services/project_service.test.ts +16 -0
  25. package/templates/assistkick-product-system/packages/backend/src/services/project_service.ts +73 -2
  26. package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.test.ts +4 -4
  27. package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.ts +87 -11
  28. package/templates/assistkick-product-system/packages/backend/src/services/pty_session_manager.test.ts +210 -69
  29. package/templates/assistkick-product-system/packages/backend/src/services/pty_session_manager.ts +210 -215
  30. package/templates/assistkick-product-system/packages/backend/src/services/ssh_key_service.test.ts +162 -0
  31. package/templates/assistkick-product-system/packages/backend/src/services/ssh_key_service.ts +148 -0
  32. package/templates/assistkick-product-system/packages/backend/src/services/terminal_ws_handler.ts +11 -5
  33. package/templates/assistkick-product-system/packages/backend/src/services/tts_service.test.ts +64 -0
  34. package/templates/assistkick-product-system/packages/backend/src/services/tts_service.ts +134 -0
  35. package/templates/assistkick-product-system/packages/backend/src/services/video_render_service.test.ts +256 -0
  36. package/templates/assistkick-product-system/packages/backend/src/services/video_render_service.ts +258 -0
  37. package/templates/assistkick-product-system/packages/backend/src/services/workflow_group_service.ts +106 -0
  38. package/templates/assistkick-product-system/packages/backend/src/services/workflow_service.test.ts +275 -0
  39. package/templates/assistkick-product-system/packages/backend/src/services/workflow_service.ts +222 -0
  40. package/templates/assistkick-product-system/packages/frontend/index.html +3 -0
  41. package/templates/assistkick-product-system/packages/frontend/package-lock.json +800 -11
  42. package/templates/assistkick-product-system/packages/frontend/package.json +11 -1
  43. package/templates/assistkick-product-system/packages/frontend/src/App.tsx +24 -7
  44. package/templates/assistkick-product-system/packages/frontend/src/api/client.ts +456 -16
  45. package/templates/assistkick-product-system/packages/frontend/src/api/client_files.test.ts +172 -0
  46. package/templates/assistkick-product-system/packages/frontend/src/api/client_video.test.ts +238 -0
  47. package/templates/assistkick-product-system/packages/frontend/src/components/AgentsView.tsx +307 -0
  48. package/templates/assistkick-product-system/packages/frontend/src/components/CoherenceView.tsx +82 -66
  49. package/templates/assistkick-product-system/packages/frontend/src/components/CompositionPlaceholder.tsx +97 -0
  50. package/templates/assistkick-product-system/packages/frontend/src/components/DesignSystemView.tsx +383 -0
  51. package/templates/assistkick-product-system/packages/frontend/src/components/EditorTabBar.tsx +57 -0
  52. package/templates/assistkick-product-system/packages/frontend/src/components/FileTree.tsx +313 -0
  53. package/templates/assistkick-product-system/packages/frontend/src/components/FileTreeContextMenu.tsx +61 -0
  54. package/templates/assistkick-product-system/packages/frontend/src/components/FileTreeInlineInput.tsx +73 -0
  55. package/templates/assistkick-product-system/packages/frontend/src/components/FilesView.tsx +404 -0
  56. package/templates/assistkick-product-system/packages/frontend/src/components/GitRepoModal.tsx +193 -64
  57. package/templates/assistkick-product-system/packages/frontend/src/components/GraphLegend.tsx +71 -73
  58. package/templates/assistkick-product-system/packages/frontend/src/components/GraphSettings.tsx +8 -8
  59. package/templates/assistkick-product-system/packages/frontend/src/components/GraphView.tsx +1 -1
  60. package/templates/assistkick-product-system/packages/frontend/src/components/InviteUserDialog.tsx +15 -11
  61. package/templates/assistkick-product-system/packages/frontend/src/components/KanbanView.tsx +226 -291
  62. package/templates/assistkick-product-system/packages/frontend/src/components/LoginPage.tsx +14 -14
  63. package/templates/assistkick-product-system/packages/frontend/src/components/ProjectSelector.tsx +54 -33
  64. package/templates/assistkick-product-system/packages/frontend/src/components/QaIssueSheet.tsx +40 -66
  65. package/templates/assistkick-product-system/packages/frontend/src/components/SidePanel.tsx +55 -115
  66. package/templates/assistkick-product-system/packages/frontend/src/components/TerminalView.tsx +121 -52
  67. package/templates/assistkick-product-system/packages/frontend/src/components/Toolbar.tsx +155 -77
  68. package/templates/assistkick-product-system/packages/frontend/src/components/UsersView.tsx +52 -52
  69. package/templates/assistkick-product-system/packages/frontend/src/components/VideoGallery.tsx +313 -0
  70. package/templates/assistkick-product-system/packages/frontend/src/components/VideographyView.tsx +250 -0
  71. package/templates/assistkick-product-system/packages/frontend/src/components/WorkflowsView.tsx +474 -0
  72. package/templates/assistkick-product-system/packages/frontend/src/components/ds/AccentBorderList.tsx +53 -0
  73. package/templates/assistkick-product-system/packages/frontend/src/components/ds/Button.tsx +87 -0
  74. package/templates/assistkick-product-system/packages/frontend/src/components/ds/ButtonGroup.tsx +29 -0
  75. package/templates/assistkick-product-system/packages/frontend/src/components/ds/ButtonShowcase.tsx +221 -0
  76. package/templates/assistkick-product-system/packages/frontend/src/components/ds/CardGlass.tsx +141 -0
  77. package/templates/assistkick-product-system/packages/frontend/src/components/ds/CompletionRing.tsx +30 -0
  78. package/templates/assistkick-product-system/packages/frontend/src/components/ds/ContentCard.tsx +34 -0
  79. package/templates/assistkick-product-system/packages/frontend/src/components/ds/IconButton.tsx +74 -0
  80. package/templates/assistkick-product-system/packages/frontend/src/components/ds/KanbanCard.tsx +270 -0
  81. package/templates/assistkick-product-system/packages/frontend/src/components/ds/KanbanCardShowcase.tsx +37 -0
  82. package/templates/assistkick-product-system/packages/frontend/src/components/ds/Kbd.tsx +11 -0
  83. package/templates/assistkick-product-system/packages/frontend/src/components/ds/KindBadge.tsx +21 -0
  84. package/templates/assistkick-product-system/packages/frontend/src/components/ds/NavBarSidekick.tsx +207 -0
  85. package/templates/assistkick-product-system/packages/frontend/src/components/ds/SidePanelShowcase.tsx +370 -0
  86. package/templates/assistkick-product-system/packages/frontend/src/components/ds/SideSheet.tsx +64 -0
  87. package/templates/assistkick-product-system/packages/frontend/src/components/ds/StatusDot.tsx +18 -0
  88. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/CheckCardPositionNode.tsx +36 -0
  89. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/CheckCycleCountNode.tsx +60 -0
  90. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/EndNode.tsx +42 -0
  91. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/GroupNode.tsx +189 -0
  92. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/NodePalette.tsx +123 -0
  93. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/RunAgentNode.tsx +51 -0
  94. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/SetCardMetadataNode.tsx +53 -0
  95. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/StartNode.tsx +18 -0
  96. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/TransitionCardNode.tsx +59 -0
  97. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/WorkflowCanvas.tsx +335 -0
  98. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/WorkflowMonitorModal.tsx +634 -0
  99. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/autoLayout.ts +103 -0
  100. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/edgeColors.ts +35 -0
  101. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/monitor_nodes.tsx +208 -0
  102. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/workflow_types.test.ts +119 -0
  103. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/workflow_types.ts +107 -0
  104. package/templates/assistkick-product-system/packages/frontend/src/constants/graph.ts +13 -11
  105. package/templates/assistkick-product-system/packages/frontend/src/hooks/useAutoSave.ts +75 -0
  106. package/templates/assistkick-product-system/packages/frontend/src/hooks/useGraph.ts +6 -21
  107. package/templates/assistkick-product-system/packages/frontend/src/hooks/useProjects.ts +15 -80
  108. package/templates/assistkick-product-system/packages/frontend/src/hooks/useToast.tsx +16 -3
  109. package/templates/assistkick-product-system/packages/frontend/src/pages/accept_invitation_page.tsx +30 -27
  110. package/templates/assistkick-product-system/packages/frontend/src/pages/forgot_password_page.tsx +18 -15
  111. package/templates/assistkick-product-system/packages/frontend/src/pages/register_page.tsx +21 -18
  112. package/templates/assistkick-product-system/packages/frontend/src/pages/reset_password_page.tsx +28 -25
  113. package/templates/assistkick-product-system/packages/frontend/src/routes/AgentsRoute.tsx +6 -0
  114. package/templates/assistkick-product-system/packages/frontend/src/routes/CoherenceRoute.tsx +19 -0
  115. package/templates/assistkick-product-system/packages/frontend/src/routes/DashboardLayout.tsx +54 -0
  116. package/templates/assistkick-product-system/packages/frontend/src/routes/DesignSystemRoute.tsx +6 -0
  117. package/templates/assistkick-product-system/packages/frontend/src/routes/FilesRoute.tsx +13 -0
  118. package/templates/assistkick-product-system/packages/frontend/src/routes/GraphRoute.tsx +93 -0
  119. package/templates/assistkick-product-system/packages/frontend/src/routes/KanbanRoute.tsx +30 -0
  120. package/templates/assistkick-product-system/packages/frontend/src/routes/TerminalRoute.tsx +9 -0
  121. package/templates/assistkick-product-system/packages/frontend/src/routes/UsersRoute.tsx +6 -0
  122. package/templates/assistkick-product-system/packages/frontend/src/routes/VideographyRoute.tsx +13 -0
  123. package/templates/assistkick-product-system/packages/frontend/src/routes/WorkflowsRoute.tsx +6 -0
  124. package/templates/assistkick-product-system/packages/frontend/src/stores/useGitModalStore.ts +14 -0
  125. package/templates/assistkick-product-system/packages/frontend/src/stores/useGraphStore.ts +36 -0
  126. package/templates/assistkick-product-system/packages/frontend/src/stores/useGraphUIStore.ts +25 -0
  127. package/templates/assistkick-product-system/packages/frontend/src/stores/useProjectStore.ts +90 -0
  128. package/templates/assistkick-product-system/packages/frontend/src/stores/useQaSheetStore.ts +27 -0
  129. package/templates/assistkick-product-system/packages/frontend/src/stores/useSidePanelStore.ts +76 -0
  130. package/templates/assistkick-product-system/packages/frontend/src/styles/index.css +336 -3632
  131. package/templates/assistkick-product-system/packages/frontend/src/utils/auto_save_service.test.ts +167 -0
  132. package/templates/assistkick-product-system/packages/frontend/src/utils/auto_save_service.ts +101 -0
  133. package/templates/assistkick-product-system/packages/frontend/src/utils/composition_matcher.test.ts +42 -0
  134. package/templates/assistkick-product-system/packages/frontend/src/utils/composition_matcher.ts +17 -0
  135. package/templates/assistkick-product-system/packages/frontend/src/utils/file_utils.test.ts +145 -0
  136. package/templates/assistkick-product-system/packages/frontend/src/utils/file_utils.ts +42 -0
  137. package/templates/assistkick-product-system/packages/frontend/src/utils/task_status.test.ts +4 -10
  138. package/templates/assistkick-product-system/packages/frontend/src/utils/task_status.ts +19 -1
  139. package/templates/assistkick-product-system/packages/frontend/vite.config.ts +7 -1
  140. package/templates/assistkick-product-system/packages/shared/db/local.db +0 -0
  141. package/templates/assistkick-product-system/packages/shared/db/migrations/0004_tidy_matthew_murdock.sql +9 -0
  142. package/templates/assistkick-product-system/packages/shared/db/migrations/0005_mysterious_falcon.sql +692 -0
  143. package/templates/assistkick-product-system/packages/shared/db/migrations/0006_next_venom.sql +9 -0
  144. package/templates/assistkick-product-system/packages/shared/db/migrations/0007_deep_barracuda.sql +39 -0
  145. package/templates/assistkick-product-system/packages/shared/db/migrations/0008_puzzling_hannibal_king.sql +1 -0
  146. package/templates/assistkick-product-system/packages/shared/db/migrations/0009_amused_beast.sql +8 -0
  147. package/templates/assistkick-product-system/packages/shared/db/migrations/0010_spotty_moira_mactaggert.sql +9 -0
  148. package/templates/assistkick-product-system/packages/shared/db/migrations/0011_goofy_snowbird.sql +3 -0
  149. package/templates/assistkick-product-system/packages/shared/db/migrations/0011_supreme_doctor_octopus.sql +3 -0
  150. package/templates/assistkick-product-system/packages/shared/db/migrations/0013_reflective_prowler.sql +15 -0
  151. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0004_snapshot.json +921 -0
  152. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0005_snapshot.json +1042 -0
  153. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0006_snapshot.json +1101 -0
  154. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0007_snapshot.json +1336 -0
  155. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0008_snapshot.json +1275 -0
  156. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0009_snapshot.json +1327 -0
  157. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0010_snapshot.json +1393 -0
  158. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0011_snapshot.json +1436 -0
  159. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0013_snapshot.json +1538 -0
  160. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/_journal.json +70 -0
  161. package/templates/assistkick-product-system/packages/shared/db/schema.ts +113 -0
  162. package/templates/assistkick-product-system/packages/shared/lib/claude-service.ts +32 -7
  163. package/templates/assistkick-product-system/packages/shared/lib/constants.ts +9 -0
  164. package/templates/assistkick-product-system/packages/shared/lib/git_workflow.ts +12 -4
  165. package/templates/assistkick-product-system/packages/shared/lib/graph.ts +16 -5
  166. package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.test.ts +1753 -0
  167. package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.ts +1281 -0
  168. package/templates/assistkick-product-system/packages/shared/lib/workflow_orchestrator.ts +211 -0
  169. package/templates/assistkick-product-system/packages/shared/tools/add_node.test.ts +43 -0
  170. package/templates/assistkick-product-system/packages/shared/tools/add_node.ts +13 -2
  171. package/templates/assistkick-product-system/packages/shared/tools/get_kanban.ts +1 -1
  172. package/templates/assistkick-product-system/packages/shared/tools/migrate_epics.test.ts +226 -0
  173. package/templates/assistkick-product-system/packages/shared/tools/migrate_epics.ts +251 -0
  174. package/templates/assistkick-product-system/packages/shared/tools/update_node.ts +2 -2
  175. package/templates/assistkick-product-system/packages/shared/utils/hello_workflow.test.ts +10 -0
  176. package/templates/assistkick-product-system/packages/shared/utils/hello_workflow.ts +6 -0
  177. package/templates/assistkick-product-system/packages/video/Root.tsx +85 -0
  178. package/templates/assistkick-product-system/packages/video/components/email_scene.tsx +231 -0
  179. package/templates/assistkick-product-system/packages/video/components/outro_scene.tsx +153 -0
  180. package/templates/assistkick-product-system/packages/video/components/part_divider.tsx +90 -0
  181. package/templates/assistkick-product-system/packages/video/components/scene.tsx +226 -0
  182. package/templates/assistkick-product-system/packages/video/components/theme.ts +22 -0
  183. package/templates/assistkick-product-system/packages/video/components/title_scene.tsx +169 -0
  184. package/templates/assistkick-product-system/packages/video/components/video_split_layout.tsx +84 -0
  185. package/templates/assistkick-product-system/packages/video/compositions/.gitkeep +0 -0
  186. package/templates/assistkick-product-system/packages/video/index.ts +4 -0
  187. package/templates/assistkick-product-system/packages/video/package.json +28 -0
  188. package/templates/assistkick-product-system/packages/video/remotion.config.ts +11 -0
  189. package/templates/assistkick-product-system/packages/video/scripts/process_script.test.ts +326 -0
  190. package/templates/assistkick-product-system/packages/video/scripts/process_script.ts +630 -0
  191. package/templates/assistkick-product-system/packages/video/style.css +1 -0
  192. package/templates/assistkick-product-system/packages/video/tsconfig.json +18 -0
  193. package/templates/assistkick-product-system/tests/graph_legend.test.ts +2 -1
  194. package/templates/assistkick-product-system/tests/video_render_service.test.ts +179 -0
  195. package/templates/assistkick-product-system/tests/web_terminal.test.ts +219 -455
  196. package/templates/assistkick-product-system/tests/workflow_integration.test.ts +341 -0
  197. package/templates/skills/assistkick-bootstrap/SKILL.md +3 -3
  198. package/templates/skills/assistkick-code-reviewer/SKILL.md +2 -2
  199. package/templates/skills/assistkick-debugger/SKILL.md +2 -2
  200. package/templates/skills/assistkick-developer/SKILL.md +6 -3
  201. package/templates/skills/assistkick-developer/references/react_development_guidelines.md +225 -0
  202. package/templates/skills/assistkick-interview/SKILL.md +2 -2
  203. package/templates/skills/product-system/graph.json +1890 -0
  204. package/templates/skills/product-system/kanban.json +304 -0
  205. package/templates/skills/product-system/nodes/comp_001.md +56 -0
  206. package/templates/skills/product-system/nodes/comp_002.md +57 -0
  207. package/templates/skills/product-system/nodes/data_001.md +51 -0
  208. package/templates/skills/product-system/nodes/data_002.md +40 -0
  209. package/templates/skills/product-system/nodes/data_004.md +38 -0
  210. package/templates/skills/product-system/nodes/dec_001.md +34 -0
  211. package/templates/skills/product-system/nodes/dec_016.md +32 -0
  212. package/templates/skills/product-system/nodes/feat_008.md +30 -0
  213. package/templates/skills/video-composition-agent/SKILL.md +232 -0
  214. package/templates/skills/video-script-writer/SKILL.md +136 -0
@@ -0,0 +1,270 @@
1
+ import React from 'react';
2
+ import {
3
+ Play, AlertTriangle, Lock, CircleDot, Copy, Check, ChevronDown,
4
+ } from 'lucide-react';
5
+ import { KindBadge } from './KindBadge';
6
+
7
+ /* ── Types ── */
8
+
9
+ export interface KanbanCardProps {
10
+ id: string;
11
+ name: string;
12
+ /** 0–100 */
13
+ pct: number;
14
+ kind?: string;
15
+ rejectionCount: number;
16
+ blocked: boolean;
17
+ /** Workflow execution status string */
18
+ pipeline: string;
19
+ /** Status badge label (e.g. "Running", "Completed") */
20
+ pipelineLabel?: string;
21
+ /** Number of issues / notes */
22
+ issueCount: number;
23
+ /** Issue button label override */
24
+ issueLabel?: string;
25
+ /** Show play button */
26
+ showPlay?: boolean;
27
+ /** Show dropdown arrow next to play button for workflow selection */
28
+ showPlayDropdown?: boolean;
29
+ /** Show stop button (for epic cards when orchestrator is running) */
30
+ showStop?: boolean;
31
+ /** Show resume button */
32
+ showResume?: boolean;
33
+ /** Whether copy was just triggered */
34
+ copied?: boolean;
35
+ /** Is this the currently-playing card in Play All */
36
+ playAllActive?: boolean;
37
+ /** Name of the currently executing agent (when on a RunAgent node) */
38
+ agentName?: string | null;
39
+ /** Error message from a failed workflow execution */
40
+ errorMessage?: string | null;
41
+ /** Whether this card represents an epic node */
42
+ isEpic?: boolean;
43
+
44
+ /* Callbacks */
45
+ onClick?: () => void;
46
+ onCopy?: () => void;
47
+ onPlay?: () => void;
48
+ onPlayDropdown?: () => void;
49
+ onStop?: () => void;
50
+ onResume?: () => void;
51
+ onUnblock?: () => void;
52
+ onIssuesClick?: () => void;
53
+ onMonitorClick?: () => void;
54
+
55
+ /* Drag */
56
+ draggable?: boolean;
57
+ onDragStart?: (e: React.DragEvent) => void;
58
+ onDragEnd?: (e: React.DragEvent) => void;
59
+ }
60
+
61
+ /* ── Status style helpers ── */
62
+
63
+ function statusCls(status: string): string {
64
+ if (status === 'running') return 'bg-accent/10 text-accent animate-pulse';
65
+ switch (status) {
66
+ case 'completed': return 'bg-emerald-500/10 text-emerald-400';
67
+ case 'failed': return 'bg-error/10 text-error';
68
+ default: return 'bg-white/[0.06] text-content-muted';
69
+ }
70
+ }
71
+
72
+ function statusIcon(status: string) {
73
+ if (status === 'running') return <CircleDot size={12} strokeWidth={2.5} />;
74
+ if (status === 'failed') return <AlertTriangle size={12} strokeWidth={2.5} />;
75
+ return null;
76
+ }
77
+
78
+ /* ── Component ── */
79
+
80
+ export const KanbanCard = ({
81
+ id, name, pct, kind, rejectionCount, blocked, pipeline, pipelineLabel: pipLabel,
82
+ issueCount, issueLabel, showPlay, showPlayDropdown, showStop, showResume, copied,
83
+ playAllActive, agentName, errorMessage,
84
+ isEpic,
85
+ onClick, onCopy, onPlay, onPlayDropdown, onStop, onResume, onUnblock, onIssuesClick, onMonitorClick,
86
+ draggable, onDragStart, onDragEnd,
87
+ }: KanbanCardProps) => {
88
+ const hasPipeline = pipeline !== 'idle' && !!pipLabel;
89
+ const hasStatusRow = rejectionCount > 0 || hasPipeline;
90
+
91
+ const stripColor = blocked
92
+ ? 'from-error/60 to-error/20'
93
+ : rejectionCount >= 3
94
+ ? 'from-error/40 to-amber-500/20'
95
+ : pipeline === 'running'
96
+ ? 'from-accent/60 to-accent/20'
97
+ : pipeline === 'completed'
98
+ ? 'from-emerald-400/60 to-emerald-400/20'
99
+ : playAllActive
100
+ ? 'from-accent/60 to-accent/20'
101
+ : 'from-edge to-transparent';
102
+
103
+ const handleCardClick = (e: React.MouseEvent) => {
104
+ if ((e.target as HTMLElement).closest('button')) return;
105
+ onClick?.();
106
+ };
107
+
108
+ return (
109
+ <div
110
+ className={[
111
+ 'group relative shrink-0 overflow-hidden rounded-2xl border shadow-lg shadow-black/10 backdrop-blur-sm transition-all duration-200 hover:border-content/15 hover:shadow-xl hover:shadow-black/15 cursor-pointer',
112
+ isEpic
113
+ ? 'bg-gradient-to-br from-accent/[0.06] to-accent/[0.02] border-accent/15'
114
+ : 'bg-surface border-edge',
115
+ ].join(' ')}
116
+ draggable={draggable}
117
+ onDragStart={onDragStart}
118
+ onDragEnd={onDragEnd}
119
+ onClick={handleCardClick}
120
+ data-feature-id={id}
121
+ >
122
+ {/* Left accent strip */}
123
+ <div className={`absolute left-0 top-0 h-full w-1 bg-gradient-to-b ${stripColor}`} />
124
+
125
+ <div className="p-4 pl-5">
126
+ {/* Header */}
127
+ <div className="flex items-center gap-2">
128
+ <span className="font-mono text-[12px] text-content-secondary">{id}</span>
129
+ <KindBadge kind={kind || 'new'} />
130
+ <button
131
+ className="flex h-6 w-6 items-center justify-center rounded-md bg-white/[0.08] text-content-secondary transition-colors hover:bg-white/15 hover:text-content cursor-pointer"
132
+ title="Copy feature ID and name"
133
+ onClick={(e) => { e.stopPropagation(); onCopy?.(); }}
134
+ >
135
+ {copied ? <Check size={12} strokeWidth={2.5} className="text-emerald-400" /> : <Copy size={12} strokeWidth={2} />}
136
+ </button>
137
+ <div className="flex-1" />
138
+ {blocked ? (
139
+ <span className="flex items-center gap-1.5 rounded-full bg-error/15 px-2.5 py-1 text-[11px] font-bold text-error backdrop-blur">
140
+ <Lock size={11} strokeWidth={2.5} /> Blocked
141
+ </span>
142
+ ) : showStop ? (
143
+ <button
144
+ className="flex h-7 w-7 items-center justify-center rounded-full border border-error text-error text-[12px] hover:bg-error hover:text-surface transition-colors cursor-pointer"
145
+ title="Stop processing epic"
146
+ onClick={(e) => { e.stopPropagation(); onStop?.(); }}
147
+ >
148
+ {'\u25A0'}
149
+ </button>
150
+ ) : showPlay ? (
151
+ <div className="flex items-center">
152
+ <button
153
+ className="flex h-7 w-7 items-center justify-center rounded-full bg-accent/10 text-accent backdrop-blur transition-all hover:bg-accent hover:text-surface hover:shadow-[0_0_12px_-2px_var(--accent)] cursor-pointer"
154
+ title="Start default workflow"
155
+ onClick={(e) => { e.stopPropagation(); onPlay?.(); }}
156
+ >
157
+ <Play size={12} strokeWidth={2.5} fill="currentColor" />
158
+ </button>
159
+ {showPlayDropdown && (
160
+ <button
161
+ className="flex h-7 w-5 items-center justify-center rounded-r-full text-accent/60 hover:text-accent transition-colors cursor-pointer"
162
+ title="Choose workflow"
163
+ onClick={(e) => { e.stopPropagation(); onPlayDropdown?.(); }}
164
+ >
165
+ <ChevronDown size={12} strokeWidth={2.5} />
166
+ </button>
167
+ )}
168
+ </div>
169
+ ) : showResume ? (
170
+ <button
171
+ className="flex h-7 w-7 items-center justify-center rounded-full bg-accent/10 text-accent backdrop-blur transition-all hover:bg-accent hover:text-surface hover:shadow-[0_0_12px_-2px_var(--accent)] cursor-pointer"
172
+ title="Resume workflow from last completed step"
173
+ onClick={(e) => { e.stopPropagation(); onResume?.(); }}
174
+ >
175
+ <Play size={12} strokeWidth={2.5} fill="currentColor" />
176
+ </button>
177
+ ) : null}
178
+ </div>
179
+
180
+ {/* Name */}
181
+ <div className="mt-2.5 text-[14px] font-semibold leading-snug text-content">{name}</div>
182
+
183
+ {/* Agent tag — shows when a RunAgent node is executing */}
184
+ {agentName && (
185
+ <div className="mt-2 inline-flex items-center gap-1.5 rounded-full bg-accent/10 px-2.5 py-1 text-[10px] font-semibold text-accent animate-pulse backdrop-blur">
186
+ <CircleDot size={10} strokeWidth={2.5} />
187
+ {agentName}
188
+ </div>
189
+ )}
190
+
191
+ {/* Error tag — shows when workflow failed, clickable to open monitor */}
192
+ {errorMessage && pipeline === 'failed' && (
193
+ <button
194
+ className="mt-2 inline-flex items-center gap-1.5 rounded-full bg-error/10 px-2.5 py-1 text-[10px] font-semibold text-error backdrop-blur cursor-pointer transition-opacity hover:opacity-80"
195
+ title={errorMessage}
196
+ onClick={(e) => { e.stopPropagation(); onMonitorClick?.(); }}
197
+ >
198
+ <AlertTriangle size={10} strokeWidth={2.5} />
199
+ Error
200
+ </button>
201
+ )}
202
+
203
+ {/* Spec disc */}
204
+ <div className="mt-3 flex items-center gap-2">
205
+ <svg width="22" height="22" viewBox="0 0 22 22" className="shrink-0 -rotate-90">
206
+ <circle cx="11" cy="11" r="9" fill="none" stroke="currentColor" strokeWidth="2.5" className="text-white/5" />
207
+ <circle
208
+ cx="11" cy="11" r="9" fill="none" strokeWidth="2.5"
209
+ stroke="url(#specGrad)" strokeLinecap="round"
210
+ strokeDasharray={`${(pct / 100) * 2 * Math.PI * 9} ${2 * Math.PI * 9}`}
211
+ />
212
+ <defs>
213
+ <linearGradient id="specGrad" x1="0" y1="0" x2="1" y2="1">
214
+ <stop offset="0%" stopColor="var(--completeness-fill)" />
215
+ <stop offset="100%" stopColor="var(--accent)" stopOpacity="0.6" />
216
+ </linearGradient>
217
+ </defs>
218
+ </svg>
219
+ <span className="font-mono text-[11px] text-content-secondary">{pct}%</span>
220
+ </div>
221
+
222
+ {/* Status pills */}
223
+ {hasStatusRow && (
224
+ <div className="mt-3" onClick={(e) => e.stopPropagation()}>
225
+ <div className="flex gap-1">
226
+ {rejectionCount > 0 && (
227
+ <span className="flex-1 rounded-full bg-amber-400/15 py-1 text-center text-[10px] font-semibold text-amber-400 backdrop-blur">
228
+ {rejectionCount}x rejected
229
+ </span>
230
+ )}
231
+ {hasPipeline && (
232
+ <button
233
+ className={`flex-1 inline-flex items-center justify-center gap-1.5 rounded-full py-1 text-[10px] font-semibold backdrop-blur cursor-pointer transition-opacity hover:opacity-80 ${statusCls(pipeline)}`}
234
+ onClick={(e) => { e.stopPropagation(); onMonitorClick?.(); }}
235
+ title="Open workflow monitor"
236
+ >
237
+ {statusIcon(pipeline)}
238
+ {pipLabel}
239
+ </button>
240
+ )}
241
+ </div>
242
+ </div>
243
+ )}
244
+
245
+ {/* Unblock */}
246
+ {blocked && (
247
+ <button
248
+ className="mt-3 w-full rounded-full border border-error/30 py-1.5 text-center text-[11px] font-mono text-error backdrop-blur transition-all hover:bg-error/10 cursor-pointer"
249
+ onClick={(e) => { e.stopPropagation(); onUnblock?.(); }}
250
+ >
251
+ Unblock
252
+ </button>
253
+ )}
254
+
255
+ {/* Issues */}
256
+ <button
257
+ className={[
258
+ 'mt-3 w-full rounded-full border py-1.5 text-center text-[11px] font-mono backdrop-blur transition-all cursor-pointer',
259
+ issueCount > 0
260
+ ? 'border-white/10 text-content-secondary hover:border-accent/30 hover:text-accent'
261
+ : 'border-white/5 text-content-muted/50 hover:border-white/10 hover:text-content-muted',
262
+ ].join(' ')}
263
+ onClick={(e) => { e.stopPropagation(); onIssuesClick?.(); }}
264
+ >
265
+ {issueLabel}
266
+ </button>
267
+ </div>
268
+ </div>
269
+ );
270
+ };
@@ -0,0 +1,37 @@
1
+ import { CardGlass } from './CardGlass';
2
+ import type { DemoCard } from './CardGlass';
3
+
4
+ /* ── Demo data ── */
5
+
6
+ const DEMO_CARDS: DemoCard[] = [
7
+ {
8
+ id: 'feat_0f2d6616', name: 'TailwindCSS Integration', pct: 100, kind: 'new',
9
+ rejections: 1, pipeline: 'interrupted', blocked: false, issues: 1,
10
+ stage: 'in_review',
11
+ },
12
+ {
13
+ id: 'feat_a3c71b02', name: 'Auth Flow Redesign', pct: 72, kind: 'improvement',
14
+ rejections: 0, pipeline: 'active', blocked: false, issues: 0,
15
+ stage: 'in_progress',
16
+ },
17
+ {
18
+ id: 'feat_9e45f1d8', name: 'WebSocket Events', pct: 45, kind: 'new',
19
+ rejections: 3, pipeline: 'failed', blocked: false, issues: 3,
20
+ stage: 'qa',
21
+ },
22
+ {
23
+ id: 'feat_b7d20cc4', name: 'Rate Limiter Middleware', pct: 88, kind: 'bugfix',
24
+ rejections: 0, pipeline: 'idle', blocked: true, issues: 0,
25
+ stage: 'in_progress',
26
+ },
27
+ ];
28
+
29
+ /* ── Component ── */
30
+
31
+ export const KanbanCardShowcase = () => {
32
+ return (
33
+ <div className="grid grid-cols-2 gap-3 lg:grid-cols-4">
34
+ {DEMO_CARDS.map(c => <CardGlass key={c.id} card={c} />)}
35
+ </div>
36
+ );
37
+ };
@@ -0,0 +1,11 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ interface Props {
4
+ children: ReactNode;
5
+ }
6
+
7
+ export const Kbd = ({ children }: Props) => (
8
+ <kbd className="inline-block px-1.5 py-px text-[11px] font-inherit bg-surface-raised border border-edge rounded text-content">
9
+ {children}
10
+ </kbd>
11
+ );
@@ -0,0 +1,21 @@
1
+ /* ── Types ── */
2
+
3
+ interface Props {
4
+ kind: string;
5
+ }
6
+
7
+ /* ── Component ── */
8
+
9
+ export const KindBadge = ({ kind }: Props) => {
10
+ if (!kind || kind === 'new') return null;
11
+
12
+ const cls = kind === 'improvement'
13
+ ? 'text-blue-400 bg-blue-400/15'
14
+ : 'text-amber-400 bg-amber-400/15';
15
+
16
+ return (
17
+ <span className={`rounded px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide ${cls}`}>
18
+ {kind}
19
+ </span>
20
+ );
21
+ };
@@ -0,0 +1,207 @@
1
+ import React, { useState } from 'react';
2
+ import { Link, useNavigate } from 'react-router-dom';
3
+ import { Search } from 'lucide-react';
4
+
5
+ export interface NavItem {
6
+ id: string;
7
+ label: string;
8
+ icon?: React.ReactNode;
9
+ description?: string;
10
+ href?: string;
11
+ }
12
+
13
+ export interface NavBarSidekickProps {
14
+ /** Navigation items shown in the segmented control */
15
+ items: NavItem[];
16
+ /** Currently active item id — controlled externally */
17
+ activeId?: string;
18
+ /** Called when a nav item is selected */
19
+ onNavigate?: (id: string) => void;
20
+ /** Left-side brand / project slot */
21
+ brand?: React.ReactNode;
22
+ /** Content between the segmented control and the right-side actions */
23
+ center?: React.ReactNode;
24
+ /** Right-side actions rendered before the search trigger */
25
+ actions?: React.ReactNode;
26
+ /** Far-right trailing element (avatar, etc.) */
27
+ trailing?: React.ReactNode;
28
+ }
29
+
30
+ export const NavBarSidekick = ({
31
+ items, activeId, onNavigate, brand, center, actions, trailing,
32
+ }: NavBarSidekickProps) => {
33
+ const navigate = useNavigate();
34
+
35
+ // Fallback to internal state when no external activeId is provided (design system demo mode)
36
+ const [internalActive, setInternalActive] = useState(items[0]?.id ?? '');
37
+ const active = activeId ?? internalActive;
38
+
39
+ const [cmdOpen, setCmdOpen] = useState(false);
40
+ const [cmdQuery, setCmdQuery] = useState('');
41
+
42
+ const filteredItems = cmdQuery
43
+ ? items.filter((i) =>
44
+ i.label.toLowerCase().includes(cmdQuery.toLowerCase()) ||
45
+ (i.description?.toLowerCase().includes(cmdQuery.toLowerCase()) ?? false))
46
+ : items;
47
+
48
+ const handleSelect = (id: string) => {
49
+ if (onNavigate) {
50
+ onNavigate(id);
51
+ } else {
52
+ setInternalActive(id);
53
+ }
54
+ };
55
+
56
+ return (
57
+ <nav className="bg-surface-alt">
58
+ {/* Top bar */}
59
+ <div className="flex items-center gap-3 px-5 py-2">
60
+ {brand && <div className="mr-1 shrink-0">{brand}</div>}
61
+
62
+ {/* Segmented control */}
63
+ <div className="flex items-center rounded-xl bg-surface p-1 border border-edge">
64
+ {items.map((item) => {
65
+ const isActive = active === item.id;
66
+ const classes = [
67
+ 'flex items-center gap-1.5 rounded-lg px-3.5 py-1.5',
68
+ 'text-[12px] font-semibold uppercase tracking-wider',
69
+ 'transition-all duration-150 cursor-pointer outline-none no-underline',
70
+ isActive
71
+ ? 'bg-accent text-surface shadow-sm'
72
+ : 'text-content-muted hover:text-content hover:bg-surface-raised',
73
+ ].join(' ');
74
+ const style = isActive ? { boxShadow: '0 2px 8px -2px var(--accent)' } : {};
75
+ const children = (
76
+ <>
77
+ {item.icon && <span className="flex items-center">{item.icon}</span>}
78
+ {item.label}
79
+ </>
80
+ );
81
+
82
+ return item.href ? (
83
+ <Link
84
+ key={item.id}
85
+ to={item.href}
86
+ className={classes}
87
+ style={style}
88
+ >
89
+ {children}
90
+ </Link>
91
+ ) : (
92
+ <button
93
+ key={item.id}
94
+ onClick={() => handleSelect(item.id)}
95
+ className={classes}
96
+ style={style}
97
+ >
98
+ {children}
99
+ </button>
100
+ );
101
+ })}
102
+ </div>
103
+
104
+ <div className="flex-1">
105
+ {center}
106
+ </div>
107
+
108
+ {/* Actions slot */}
109
+ {actions}
110
+
111
+ {/* Command palette trigger */}
112
+ <button
113
+ data-cmd-trigger
114
+ onClick={() => { setCmdOpen(!cmdOpen); setCmdQuery(''); }}
115
+ className={[
116
+ 'flex items-center gap-2 rounded-lg border px-3 py-1.5',
117
+ 'text-[12px] transition-all duration-150 cursor-pointer outline-none',
118
+ cmdOpen
119
+ ? 'border-accent/40 bg-surface text-content'
120
+ : 'border-edge text-content-muted hover:border-content/20 hover:text-content-secondary',
121
+ ].join(' ')}
122
+ >
123
+ <Search size={13} strokeWidth={2} />
124
+ <span className="hidden sm:inline">Search</span>
125
+ <kbd className="hidden sm:inline-flex items-center rounded border border-edge bg-surface-raised px-1.5 py-0.5 text-[10px] font-mono text-content-muted">
126
+ /
127
+ </kbd>
128
+ </button>
129
+
130
+ {trailing && <div className="ml-1 shrink-0">{trailing}</div>}
131
+ </div>
132
+
133
+ {/* Command palette dropdown */}
134
+ {cmdOpen && (
135
+ <div className="border-t border-edge bg-surface px-5 py-3">
136
+ <input
137
+ autoFocus
138
+ value={cmdQuery}
139
+ onChange={(e) => setCmdQuery(e.target.value)}
140
+ placeholder="Type to search pages..."
141
+ className="w-full bg-transparent text-[13px] text-content outline-none placeholder:text-content-muted"
142
+ onKeyDown={(e) => {
143
+ if (e.key === 'Escape') { setCmdOpen(false); setCmdQuery(''); }
144
+ if (e.key === 'Enter' && filteredItems.length > 0) {
145
+ const first = filteredItems[0];
146
+ if (first.href) {
147
+ navigate(first.href);
148
+ } else {
149
+ handleSelect(first.id);
150
+ }
151
+ setCmdOpen(false);
152
+ setCmdQuery('');
153
+ }
154
+ }}
155
+ />
156
+ {cmdQuery && (
157
+ <div className="mt-2 flex flex-col gap-1">
158
+ {filteredItems.length === 0 ? (
159
+ <div className="py-2 text-[12px] text-content-muted">No results</div>
160
+ ) : (
161
+ filteredItems.map((item) => {
162
+ const cmdClasses = [
163
+ 'flex items-center gap-3 rounded-lg px-3 py-2 text-left no-underline',
164
+ 'text-[13px] transition-colors duration-100 cursor-pointer outline-none',
165
+ active === item.id
166
+ ? 'bg-accent/10 text-accent'
167
+ : 'text-content-secondary hover:bg-surface-raised hover:text-content',
168
+ ].join(' ');
169
+ const cmdChildren = (
170
+ <>
171
+ {item.icon && <span className="flex items-center">{item.icon}</span>}
172
+ <div>
173
+ <div className="font-medium">{item.label}</div>
174
+ {item.description && (
175
+ <div className="text-[11px] text-content-muted">{item.description}</div>
176
+ )}
177
+ </div>
178
+ </>
179
+ );
180
+
181
+ return item.href ? (
182
+ <Link
183
+ key={item.id}
184
+ to={item.href}
185
+ onClick={() => { setCmdOpen(false); setCmdQuery(''); }}
186
+ className={cmdClasses}
187
+ >
188
+ {cmdChildren}
189
+ </Link>
190
+ ) : (
191
+ <button
192
+ key={item.id}
193
+ onClick={() => { handleSelect(item.id); setCmdOpen(false); setCmdQuery(''); }}
194
+ className={cmdClasses}
195
+ >
196
+ {cmdChildren}
197
+ </button>
198
+ );
199
+ })
200
+ )}
201
+ </div>
202
+ )}
203
+ </div>
204
+ )}
205
+ </nav>
206
+ );
207
+ };