@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,307 @@
1
+ /**
2
+ * Agents View — management UI for agent prompts.
3
+ * Supports global and project-scoped views with create, edit, delete, and reset.
4
+ */
5
+
6
+ import React, { useState, useEffect, useCallback } from 'react';
7
+ import { apiClient } from '../api/client';
8
+ import { useProjectStore } from '../stores/useProjectStore';
9
+ import { Button } from './ds/Button';
10
+ import { Plus, RotateCcw, Trash2, Save, ChevronDown } from 'lucide-react';
11
+
12
+ interface Agent {
13
+ id: string;
14
+ name: string;
15
+ promptTemplate: string;
16
+ projectId: string | null;
17
+ isDefault: number;
18
+ createdAt: string;
19
+ updatedAt: string;
20
+ }
21
+
22
+ const PLACEHOLDER_DOCS = [
23
+ { name: '{{featureId}}', description: 'The feature ID being worked on', stages: 'All' },
24
+ { name: '{{projectId}}', description: 'The current project ID', stages: 'All' },
25
+ { name: '{{mainToolsDir}}', description: 'Absolute path to the tools directory', stages: 'All' },
26
+ { name: '{{mainSkillDir}}', description: 'Absolute path to shared data directory', stages: 'All' },
27
+ { name: '{{pidFlag}}', description: 'The --project-id flag string (or empty)', stages: 'All' },
28
+ { name: '{{cycle}}', description: 'Current development cycle number', stages: 'Developer' },
29
+ { name: '{{previousReviewNotes}}', description: 'Review feedback from prior cycle', stages: 'Developer' },
30
+ { name: '{{debuggerFindings}}', description: 'Root cause analysis from debugger', stages: 'Developer' },
31
+ { name: '{{unaddressedNotes}}', description: 'QA rejection notes to investigate', stages: 'Debugger' },
32
+ ];
33
+
34
+ export function AgentsView() {
35
+ const projects = useProjectStore((s) => s.projects);
36
+ const selectedProjectId = useProjectStore((s) => s.selectedProjectId);
37
+
38
+ const [scope, setScope] = useState<'global' | 'project'>('global');
39
+ const [projectId, setProjectId] = useState(selectedProjectId || '');
40
+ const [agents, setAgents] = useState<Agent[]>([]);
41
+ const [selectedAgent, setSelectedAgent] = useState<Agent | null>(null);
42
+ const [editName, setEditName] = useState('');
43
+ const [editPrompt, setEditPrompt] = useState('');
44
+ const [loading, setLoading] = useState(true);
45
+ const [saving, setSaving] = useState(false);
46
+ const [error, setError] = useState('');
47
+ const [successMsg, setSuccessMsg] = useState('');
48
+
49
+ const fetchData = useCallback(async () => {
50
+ setLoading(true);
51
+ setError('');
52
+ try {
53
+ const pid = scope === 'project' ? projectId : undefined;
54
+ const agentsResp = await apiClient.fetchAgents(scope, pid);
55
+ setAgents(agentsResp.agents);
56
+ } catch (err: any) {
57
+ setError(err.message || 'Failed to load agents');
58
+ } finally {
59
+ setLoading(false);
60
+ }
61
+ }, [scope, projectId]);
62
+
63
+ useEffect(() => {
64
+ fetchData();
65
+ }, [fetchData]);
66
+
67
+ useEffect(() => {
68
+ if (selectedProjectId) setProjectId(selectedProjectId);
69
+ }, [selectedProjectId]);
70
+
71
+ const showSuccess = (msg: string) => {
72
+ setSuccessMsg(msg);
73
+ setTimeout(() => setSuccessMsg(''), 3000);
74
+ };
75
+
76
+ const selectAgent = (agent: Agent) => {
77
+ setSelectedAgent(agent);
78
+ setEditName(agent.name);
79
+ setEditPrompt(agent.promptTemplate);
80
+ setError('');
81
+ };
82
+
83
+ const handleCreate = async () => {
84
+ try {
85
+ const data: any = {
86
+ name: 'New Agent',
87
+ promptTemplate: 'You are a helpful agent.\n\nFeature: {{featureId}}\nProject: {{projectId}}',
88
+ };
89
+ if (scope === 'project' && projectId) data.projectId = projectId;
90
+ const resp = await apiClient.createAgent(data);
91
+ await fetchData();
92
+ selectAgent(resp.agent);
93
+ showSuccess('Agent created');
94
+ } catch (err: any) {
95
+ setError(err.message);
96
+ }
97
+ };
98
+
99
+ const handleSave = async () => {
100
+ if (!selectedAgent) return;
101
+ setSaving(true);
102
+ setError('');
103
+ try {
104
+ const resp = await apiClient.updateAgent(selectedAgent.id, {
105
+ name: editName.trim(),
106
+ promptTemplate: editPrompt,
107
+ });
108
+ setSelectedAgent(resp.agent);
109
+ await fetchData();
110
+ showSuccess('Agent saved');
111
+ } catch (err: any) {
112
+ setError(err.message);
113
+ } finally {
114
+ setSaving(false);
115
+ }
116
+ };
117
+
118
+ const handleDelete = async () => {
119
+ if (!selectedAgent) return;
120
+ setError('');
121
+ try {
122
+ await apiClient.deleteAgent(selectedAgent.id);
123
+ setSelectedAgent(null);
124
+ await fetchData();
125
+ showSuccess('Agent deleted');
126
+ } catch (err: any) {
127
+ setError(err.message);
128
+ }
129
+ };
130
+
131
+ const handleReset = async () => {
132
+ if (!selectedAgent) return;
133
+ setError('');
134
+ try {
135
+ const resp = await apiClient.resetAgent(selectedAgent.id);
136
+ selectAgent(resp.agent);
137
+ await fetchData();
138
+ showSuccess('Agent reset to default');
139
+ } catch (err: any) {
140
+ setError(err.message);
141
+ }
142
+ };
143
+
144
+ const hasChanges = selectedAgent && (editName !== selectedAgent.name || editPrompt !== selectedAgent.promptTemplate);
145
+
146
+ return (
147
+ <div className="flex h-full">
148
+ {/* Left Panel — Agent List */}
149
+ <div className="w-80 border-r border-edge flex flex-col shrink-0">
150
+ {/* Scope Toggle */}
151
+ <div className="p-3 border-b border-edge space-y-2">
152
+ <div className="flex gap-1 p-0.5 rounded-lg bg-surface-raised">
153
+ <button
154
+ onClick={() => setScope('global')}
155
+ className={`flex-1 px-3 py-1.5 rounded-md text-[12px] font-medium transition-all ${
156
+ scope === 'global'
157
+ ? 'bg-accent text-surface shadow-sm'
158
+ : 'text-content-muted hover:text-content'
159
+ }`}
160
+ >
161
+ Global
162
+ </button>
163
+ <button
164
+ onClick={() => setScope('project')}
165
+ className={`flex-1 px-3 py-1.5 rounded-md text-[12px] font-medium transition-all ${
166
+ scope === 'project'
167
+ ? 'bg-accent text-surface shadow-sm'
168
+ : 'text-content-muted hover:text-content'
169
+ }`}
170
+ >
171
+ Project
172
+ </button>
173
+ </div>
174
+
175
+ {scope === 'project' && (
176
+ <div className="relative">
177
+ <select
178
+ value={projectId}
179
+ onChange={(e) => setProjectId(e.target.value)}
180
+ className="w-full px-3 py-1.5 rounded-md border border-edge bg-surface text-[12px] text-content appearance-none pr-7"
181
+ >
182
+ {projects.map(p => (
183
+ <option key={p.id} value={p.id}>{p.name}</option>
184
+ ))}
185
+ </select>
186
+ <ChevronDown size={12} className="absolute right-2 top-1/2 -translate-y-1/2 text-content-muted pointer-events-none" />
187
+ </div>
188
+ )}
189
+ </div>
190
+
191
+ {/* Agent List */}
192
+ <div className="flex-1 overflow-y-auto">
193
+ {loading ? (
194
+ <div className="p-4 text-center text-[12px] text-content-muted">Loading...</div>
195
+ ) : agents.length === 0 ? (
196
+ <div className="p-4 text-center text-[12px] text-content-muted">No agents found</div>
197
+ ) : (
198
+ agents.map(agent => {
199
+ const isSelected = selectedAgent?.id === agent.id;
200
+ return (
201
+ <button
202
+ key={agent.id}
203
+ onClick={() => selectAgent(agent)}
204
+ className={`w-full text-left px-3 py-2.5 border-b border-edge transition-all ${
205
+ isSelected
206
+ ? 'bg-accent/10 border-l-2 border-l-accent'
207
+ : 'hover:bg-surface-raised border-l-2 border-l-transparent'
208
+ }`}
209
+ >
210
+ <div className="flex items-center gap-2">
211
+ <span className="text-[13px] font-medium text-content truncate">{agent.name}</span>
212
+ {agent.isDefault === 1 && (
213
+ <span className="shrink-0 px-1.5 py-0.5 rounded text-[9px] font-semibold uppercase bg-accent/10 text-accent">Default</span>
214
+ )}
215
+ </div>
216
+ </button>
217
+ );
218
+ })
219
+ )}
220
+ </div>
221
+
222
+ {/* Create Agent Button */}
223
+ <div className="p-3 border-t border-edge">
224
+ <Button variant="primary" size="sm" icon={<Plus size={12} />} onClick={handleCreate} className="w-full justify-center">
225
+ Create Agent
226
+ </Button>
227
+ </div>
228
+ </div>
229
+
230
+ {/* Right Panel — Agent Detail */}
231
+ <div className="flex-1 flex flex-col overflow-hidden">
232
+ {error && (
233
+ <div className="mx-4 mt-3 px-3 py-2 rounded-md bg-error/10 border border-error/20 text-error text-[12px] flex items-center justify-between">
234
+ <span>{error}</span>
235
+ <button onClick={() => setError('')} className="text-error hover:text-error/80">&times;</button>
236
+ </div>
237
+ )}
238
+ {successMsg && (
239
+ <div className="mx-4 mt-3 px-3 py-2 rounded-md bg-accent/10 border border-accent/20 text-accent text-[12px]">
240
+ {successMsg}
241
+ </div>
242
+ )}
243
+
244
+ {!selectedAgent ? (
245
+ <div className="flex-1 flex items-center justify-center text-content-muted text-[13px]">
246
+ Select an agent to view details
247
+ </div>
248
+ ) : (
249
+ <>
250
+ {/* Header */}
251
+ <div className="p-4 border-b border-edge flex items-center justify-between gap-3">
252
+ <input
253
+ value={editName}
254
+ onChange={e => setEditName(e.target.value)}
255
+ className="flex-1 px-3 py-1.5 rounded-md border border-edge bg-surface text-[14px] font-medium text-content"
256
+ placeholder="Agent name"
257
+ />
258
+ <div className="flex items-center gap-2">
259
+ {selectedAgent.isDefault === 1 && (
260
+ <Button variant="ghost" size="sm" icon={<RotateCcw size={12} />} onClick={handleReset}>
261
+ Reset
262
+ </Button>
263
+ )}
264
+ {selectedAgent.isDefault !== 1 && (
265
+ <Button variant="danger" size="sm" icon={<Trash2 size={12} />} onClick={handleDelete}>
266
+ Delete
267
+ </Button>
268
+ )}
269
+ <Button variant="primary" size="sm" icon={<Save size={12} />} onClick={handleSave} disabled={saving || !hasChanges}>
270
+ {saving ? 'Saving...' : 'Save'}
271
+ </Button>
272
+ </div>
273
+ </div>
274
+
275
+ {/* Prompt Template Editor */}
276
+ <div className="flex-1 flex overflow-hidden">
277
+ <div className="flex-1 flex flex-col p-4 overflow-hidden">
278
+ <div className="text-[11px] font-medium text-content-muted uppercase tracking-wider mb-2">Prompt Template</div>
279
+ <textarea
280
+ value={editPrompt}
281
+ onChange={e => setEditPrompt(e.target.value)}
282
+ className="flex-1 w-full px-3 py-2 rounded-md border border-edge bg-surface text-[12px] text-content font-mono resize-none focus:border-accent/40 focus:outline-none"
283
+ placeholder="Enter agent prompt template..."
284
+ spellCheck={false}
285
+ />
286
+ </div>
287
+
288
+ {/* Placeholder Info Panel */}
289
+ <div className="w-64 border-l border-edge p-3 overflow-y-auto shrink-0">
290
+ <div className="text-[11px] font-medium text-content-muted uppercase tracking-wider mb-3">Placeholder Variables</div>
291
+ <div className="space-y-2.5">
292
+ {PLACEHOLDER_DOCS.map(p => (
293
+ <div key={p.name} className="text-[11px]">
294
+ <code className="px-1 py-0.5 rounded bg-accent/10 text-accent font-mono text-[10px]">{p.name}</code>
295
+ <div className="mt-0.5 text-content-muted">{p.description}</div>
296
+ <div className="text-[9px] text-content-muted/60">{p.stages}</div>
297
+ </div>
298
+ ))}
299
+ </div>
300
+ </div>
301
+ </div>
302
+ </>
303
+ )}
304
+ </div>
305
+ </div>
306
+ );
307
+ }
@@ -7,12 +7,25 @@ const TYPE_LABELS: Record<string, string> = {
7
7
  deprecate_node: 'Remove Node', update_description: 'Update Description',
8
8
  edge: 'Add Edge', node: 'Add Node',
9
9
  };
10
- const TYPE_CSS: Record<string, string> = {
11
- add_edge: 'add-edge', add_node: 'add-node', remove_edge: 'remove-edge',
12
- deprecate_node: 'deprecate-node', update_description: 'update-desc',
13
- edge: 'add-edge', node: 'add-node',
10
+ const TYPE_TW: Record<string, string> = {
11
+ add_edge: 'text-accent bg-[rgba(77,171,247,0.12)]',
12
+ add_node: 'text-[#ffd43b] bg-[rgba(255,212,59,0.12)]',
13
+ remove_edge: 'text-[#ff6b6b] bg-[rgba(255,107,107,0.12)]',
14
+ deprecate_node: 'text-[#ff6b6b] bg-[rgba(255,107,107,0.12)]',
15
+ update_description: 'text-[#51cf66] bg-[rgba(81,207,102,0.12)]',
16
+ edge: 'text-accent bg-[rgba(77,171,247,0.12)]',
17
+ node: 'text-[#ffd43b] bg-[rgba(255,212,59,0.12)]',
18
+ };
19
+ const CONFIDENCE_TW: Record<string, string> = {
20
+ high: 'text-[#40c057] bg-[rgba(64,192,87,0.12)]',
21
+ medium: 'text-[#fab005] bg-[rgba(250,176,5,0.12)]',
22
+ low: 'text-content-muted bg-surface-raised',
14
23
  };
15
24
  const CONFIDENCE_LABELS: Record<string, string> = { high: 'High', medium: 'Medium', low: 'Low' };
25
+ const STATUS_TW: Record<string, string> = {
26
+ approved: 'text-[#40c057] bg-[rgba(64,192,87,0.12)]',
27
+ dismissed: 'text-content-muted bg-surface-raised',
28
+ };
16
29
 
17
30
  interface CoherenceViewProps {
18
31
  graphData: any;
@@ -161,9 +174,8 @@ export function CoherenceView({ graphData, onNodeClick, projectId }: CoherenceVi
161
174
  const node = findNode(nodeId);
162
175
  return (
163
176
  <span
164
- className="coherence-node-ref"
177
+ className={`text-accent ${node ? 'cursor-pointer' : 'cursor-default'} no-underline hover:underline`}
165
178
  onClick={() => { if (node) onNodeClick(node); }}
166
- style={{ cursor: node ? 'pointer' : 'default' }}
167
179
  >
168
180
  {node ? node.name : nodeId}
169
181
  </span>
@@ -174,34 +186,34 @@ export function CoherenceView({ graphData, onNodeClick, projectId }: CoherenceVi
174
186
  switch (proposal.type) {
175
187
  case 'add_edge': case 'edge':
176
188
  return (
177
- <div className="coherence-proposal-edge">
189
+ <div className="text-xs mb-2 leading-relaxed">
178
190
  <NodeRef nodeId={proposal.from_id} />
179
- <span className="coherence-edge-arrow"> --{proposal.relation}--&gt; </span>
191
+ <span className="text-content-muted text-[11px]"> --{proposal.relation}--&gt; </span>
180
192
  <NodeRef nodeId={proposal.to_id} />
181
193
  </div>
182
194
  );
183
195
  case 'remove_edge':
184
196
  return (
185
- <div className="coherence-proposal-edge coherence-proposal-remove">
197
+ <div className="text-xs mb-2 leading-relaxed line-through opacity-80">
186
198
  <NodeRef nodeId={proposal.from_id} />
187
- <span className="coherence-edge-arrow"> --{proposal.relation}--&gt; </span>
199
+ <span className="text-content-muted text-[11px]"> --{proposal.relation}--&gt; </span>
188
200
  <NodeRef nodeId={proposal.to_id} />
189
201
  </div>
190
202
  );
191
203
  case 'add_node': case 'node':
192
204
  return (
193
205
  <>
194
- <div className="coherence-proposal-node">
195
- <span className="coherence-node-type-badge">{proposal.proposed_node_type}</span>
196
- <span className="coherence-node-name">{proposal.proposed_node_name}</span>
206
+ <div className="flex items-center gap-2 mb-2">
207
+ <span className="text-[10px] text-content-muted uppercase tracking-wider bg-surface-raised px-2 py-0.5 rounded-sm">{proposal.proposed_node_type}</span>
208
+ <span className="text-xs font-medium text-content">{proposal.proposed_node_name}</span>
197
209
  </div>
198
210
  {proposal.suggested_edges?.length > 0 && (
199
- <div className="coherence-suggested-edges">
200
- <span className="coherence-suggested-label">Suggested edges:</span>
211
+ <div className="mb-2 pl-3">
212
+ <span className="text-[10px] text-content-muted uppercase tracking-wider">Suggested edges:</span>
201
213
  {proposal.suggested_edges.map((edge: any, i: number) => {
202
214
  const fromName = edge.from_id === 'NEW' ? proposal.proposed_node_name : (findNode(edge.from_id)?.name || edge.from_id);
203
215
  const toName = edge.to_id === 'NEW' ? proposal.proposed_node_name : (findNode(edge.to_id)?.name || edge.to_id);
204
- return <div key={i} className="coherence-suggested-edge">{fromName} --{edge.relation}--&gt; {toName}</div>;
216
+ return <div key={i} className="text-[11px] text-content-secondary py-0.5">{fromName} --{edge.relation}--&gt; {toName}</div>;
205
217
  })}
206
218
  </div>
207
219
  )}
@@ -210,16 +222,16 @@ export function CoherenceView({ graphData, onNodeClick, projectId }: CoherenceVi
210
222
  case 'deprecate_node':
211
223
  return (
212
224
  <>
213
- <div className="coherence-proposal-node coherence-proposal-remove">
225
+ <div className="flex items-center gap-2 mb-2 line-through opacity-80">
214
226
  <NodeRef nodeId={proposal.target_node_id} />
215
227
  </div>
216
228
  {proposal.affected_edges?.length > 0 && (
217
- <div className="coherence-affected-edges">
218
- <span className="coherence-suggested-label">
229
+ <div className="mb-2 pl-3">
230
+ <span className="text-[10px] text-content-muted uppercase tracking-wider">
219
231
  Will also remove {proposal.affected_edges.length} edge{proposal.affected_edges.length > 1 ? 's' : ''}:
220
232
  </span>
221
233
  {proposal.affected_edges.map((edge: any, i: number) => (
222
- <div key={i} className="coherence-suggested-edge coherence-removal-edge">
234
+ <div key={i} className="text-[11px] text-content-secondary py-0.5 text-[#ff6b6b]">
223
235
  {findNode(edge.from)?.name || edge.from} --{edge.relation}--&gt; {findNode(edge.to)?.name || edge.to}
224
236
  </div>
225
237
  ))}
@@ -230,63 +242,67 @@ export function CoherenceView({ graphData, onNodeClick, projectId }: CoherenceVi
230
242
  case 'update_description':
231
243
  return (
232
244
  <>
233
- <div className="coherence-proposal-update">
245
+ <div className="mb-2">
234
246
  <NodeRef nodeId={proposal.target_node_id} />
235
247
  </div>
236
248
  {proposal.proposed_description && (
237
- <div className="coherence-proposed-desc">
238
- <span className="coherence-suggested-label">Suggested description:</span>
239
- <div className="coherence-desc-preview">{proposal.proposed_description}</div>
249
+ <div className="mb-2">
250
+ <span className="text-[10px] text-content-muted uppercase tracking-wider">Suggested description:</span>
251
+ <div className="text-[11px] text-content-secondary bg-surface-raised rounded px-2.5 py-2 mt-1 whitespace-pre-wrap max-h-[120px] overflow-y-auto">{proposal.proposed_description}</div>
240
252
  </div>
241
253
  )}
242
254
  </>
243
255
  );
244
256
  default:
245
- return <div className="coherence-proposal-generic">{JSON.stringify(proposal)}</div>;
257
+ return <div>{JSON.stringify(proposal)}</div>;
246
258
  }
247
259
  };
248
260
 
249
261
  const ProposalCard = ({ proposal, resolved, conflicts, inBatch }: { proposal: any; resolved: boolean; conflicts: any; inBatch?: boolean }) => {
250
262
  const hasConflict = conflicts?.[proposal.id]?.length > 0;
251
- const statusClass = proposal.status === 'approved' ? 'approved' : proposal.status === 'dismissed' ? 'dismissed' : '';
263
+ const isApproved = proposal.status === 'approved';
264
+ const isDismissed = proposal.status === 'dismissed';
252
265
 
253
266
  return (
254
- <div className={`coherence-proposal ${statusClass}${hasConflict ? ' coherence-proposal-conflict' : ''}`} data-id={proposal.id}>
255
- <div className="coherence-proposal-header">
256
- <span className={`coherence-proposal-type coherence-type-${TYPE_CSS[proposal.type] || 'default'}`}>
267
+ <div
268
+ className={`bg-surface-alt border border-edge rounded-md px-4 py-3.5 mb-2.5 transition-[border-color] duration-150 hover:border-content-muted${isApproved ? ' border-l-[3px] border-l-[#40c057] opacity-70' : ''}${isDismissed ? ' border-l-[3px] border-l-content-muted opacity-50' : ''}${hasConflict ? ' border-[#ff6b6b]' : ''}`}
269
+ data-id={proposal.id}
270
+ >
271
+ <div className="flex items-center gap-2 mb-2">
272
+ <span className={`text-[10px] font-semibold uppercase tracking-wide px-2 py-0.5 rounded-sm ${TYPE_TW[proposal.type] || ''}`}>
257
273
  {TYPE_LABELS[proposal.type] || proposal.type}
258
274
  </span>
259
275
  {proposal.confidence && (
260
- <span className={`coherence-confidence coherence-confidence-${proposal.confidence}`}>
276
+ <span className={`text-[10px] font-semibold px-2 py-0.5 rounded-sm capitalize ${CONFIDENCE_TW[proposal.confidence] || ''}`}>
261
277
  {CONFIDENCE_LABELS[proposal.confidence] || proposal.confidence}
262
278
  </span>
263
279
  )}
264
280
  {resolved && (
265
- <span className={`coherence-proposal-status-badge coherence-status-${proposal.status}`}>{proposal.status}</span>
281
+ <span className={`text-[10px] px-2 py-0.5 rounded-sm font-semibold capitalize ${STATUS_TW[proposal.status] || ''}`}>{proposal.status}</span>
266
282
  )}
267
283
  </div>
268
284
  {hasConflict && (
269
- <div className="coherence-conflict-warning">Conflicts with other proposals — resolve the conflict before approving.</div>
285
+ <div className="text-[11px] text-[#ff6b6b] bg-[rgba(255,107,107,0.08)] border border-[rgba(255,107,107,0.2)] rounded px-2.5 py-1.5 mb-2">Conflicts with other proposals — resolve the conflict before approving.</div>
270
286
  )}
271
287
  <ProposalContent proposal={proposal} />
272
- {!inBatch && <div className="coherence-proposal-reasoning">{proposal.reasoning}</div>}
288
+ {!inBatch && <div className="text-xs text-content-secondary leading-relaxed mb-2.5 px-2.5 py-2 bg-surface-raised rounded">{proposal.reasoning}</div>}
273
289
  {!resolved && (
274
- <div className="coherence-proposal-actions">
290
+ <div className="flex gap-2">
275
291
  <button
276
- className="coherence-approve-btn"
292
+ className="px-3.5 py-[5px] rounded font-mono text-[11px] cursor-pointer transition-[background,color] duration-150 bg-transparent border border-[#40c057] text-[#40c057] hover:enabled:bg-[#40c057] hover:enabled:text-white disabled:opacity-60 disabled:cursor-not-allowed"
277
293
  disabled={applyingIds.has(proposal.id)}
278
294
  onClick={() => handleApprove(proposal.id)}
279
295
  >
280
296
  {applyingIds.has(proposal.id) ? 'Applying...' : 'Approve'}
281
297
  </button>
282
- <button className="coherence-dismiss-btn" onClick={() => handleDismiss(proposal.id)}>Dismiss</button>
298
+ <button className="px-3.5 py-[5px] rounded font-mono text-[11px] cursor-pointer transition-[background,color] duration-150 bg-transparent border border-edge text-content-secondary hover:border-content hover:text-content" onClick={() => handleDismiss(proposal.id)}>Dismiss</button>
283
299
  </div>
284
300
  )}
285
301
  </div>
286
302
  );
287
303
  };
288
304
 
289
- if (error) return <div className="coherence-error">Failed to load coherence data: {error}</div>;
305
+ if (error) return <div className="text-error text-[13px] p-6 text-center">Failed to load coherence data: {error}</div>;
290
306
  if (!data) return <div>Loading...</div>;
291
307
 
292
308
  const isRunning = data.review_status === 'running';
@@ -301,14 +317,14 @@ export function CoherenceView({ graphData, onNodeClick, projectId }: CoherenceVi
301
317
  const { batched, unbatched } = groupByBatch(sortedPending);
302
318
 
303
319
  return (
304
- <div className="coherence-panel">
305
- <div className="coherence-header">
306
- <div className="coherence-header-left">
307
- <h2 className="coherence-title">Coherence Review</h2>
308
- <span className="coherence-last-review">Last review: {lastReview}</span>
320
+ <div className="max-w-[800px] mx-auto">
321
+ <div className="flex items-center justify-between mb-5 pb-4 border-b border-edge">
322
+ <div className="flex flex-col gap-1">
323
+ <h2 className="text-base font-semibold text-content">Coherence Review</h2>
324
+ <span className="text-[11px] text-content-muted">Last review: {lastReview}</span>
309
325
  </div>
310
326
  <button
311
- className={`coherence-run-btn${isRunning ? ' running' : ''}`}
327
+ className={`px-4 py-2 bg-transparent border border-accent rounded text-accent font-mono text-xs cursor-pointer transition-[background,color] duration-150 hover:enabled:bg-accent hover:enabled:text-white disabled:opacity-60 disabled:cursor-not-allowed${isRunning ? ' animate-pulse' : ''}`}
312
328
  disabled={runDisabled}
313
329
  title={hasPending && !isRunning ? 'Resolve all pending proposals first' : ''}
314
330
  onClick={handleRunReview}
@@ -318,24 +334,24 @@ export function CoherenceView({ graphData, onNodeClick, projectId }: CoherenceVi
318
334
  </div>
319
335
 
320
336
  {data.partial_run && !isRunning && (
321
- <div className="coherence-warning-banner">
337
+ <div className="bg-[rgba(250,176,5,0.08)] border border-[rgba(250,176,5,0.2)] rounded px-4 py-2.5 mb-4 text-xs text-[#fab005]">
322
338
  The last review did not complete fully. Some proposals may be missing.
323
339
  </div>
324
340
  )}
325
341
 
326
342
  {isRunning && (
327
- <div className="coherence-running-banner">
343
+ <div className="bg-[rgba(77,171,247,0.08)] border border-[rgba(77,171,247,0.2)] rounded px-4 py-3 mb-4 text-xs text-accent animate-pulse">
328
344
  {data.progress?.message || 'AI agent is analyzing the graph for inconsistencies...'}
329
345
  </div>
330
346
  )}
331
347
 
332
- <div className="coherence-section">
333
- <h3 className="coherence-section-title">
348
+ <div className="mb-6">
349
+ <h3 className="text-[13px] font-semibold text-content mb-3 uppercase tracking-wide">
334
350
  Pending Proposals{hasPending ? ` (${pendingProposals.length})` : ''}
335
351
  </h3>
336
352
 
337
353
  {!hasPending && !isRunning && (
338
- <div className={`coherence-empty${data.last_review_timestamp && resolvedProposals.length === 0 ? ' coherence-no-issues' : ''}`}>
354
+ <div className={`text-xs text-content-muted p-6 text-center bg-surface-alt border border-dashed border-edge rounded-md${data.last_review_timestamp && resolvedProposals.length === 0 ? ' text-[#40c057] border-[rgba(64,192,87,0.3)] bg-[rgba(64,192,87,0.06)]' : ''}`}>
339
355
  {data.last_review_timestamp && resolvedProposals.length === 0
340
356
  ? 'No issues found. The graph is coherent.'
341
357
  : data.last_review_timestamp
@@ -349,18 +365,18 @@ export function CoherenceView({ graphData, onNodeClick, projectId }: CoherenceVi
349
365
  const typeLabels = [...new Set(batchProposals.map((p: any) => TYPE_LABELS[p.type] || p.type))].join(', ');
350
366
 
351
367
  return (
352
- <div key={batchId} className="coherence-batch" data-batch={batchId}>
353
- <div className="coherence-batch-header">
354
- <div className="coherence-batch-info">
355
- <span className="coherence-batch-badge">Batch ({batchProposals.length})</span>
356
- <span className="coherence-batch-types">{typeLabels}</span>
368
+ <div key={batchId} className="bg-surface-alt border border-edge rounded-md px-4 py-3.5 mb-2.5" data-batch={batchId}>
369
+ <div className="flex items-center justify-between mb-2">
370
+ <div className="flex items-center gap-2">
371
+ <span className="text-[10px] font-semibold text-accent bg-[rgba(77,171,247,0.12)] px-2 py-0.5 rounded-sm">Batch ({batchProposals.length})</span>
372
+ <span className="text-[11px] text-content-muted">{typeLabels}</span>
357
373
  </div>
358
- <div className="coherence-batch-actions">
359
- <button className="coherence-batch-expand-btn" onClick={() => toggleBatch(batchId)}>
374
+ <div className="flex gap-2">
375
+ <button className="px-2.5 py-1 bg-transparent border border-edge rounded text-content-secondary font-mono text-[10px] cursor-pointer hover:border-content hover:text-content" onClick={() => toggleBatch(batchId)}>
360
376
  {isExpanded ? 'Collapse' : 'Expand to cherry-pick'}
361
377
  </button>
362
378
  <button
363
- className="coherence-approve-btn coherence-batch-approve-btn"
379
+ className="px-3.5 py-[5px] rounded font-mono text-[11px] cursor-pointer transition-[background,color] duration-150 bg-transparent border border-[#40c057] text-[#40c057] hover:enabled:bg-[#40c057] hover:enabled:text-white disabled:opacity-60 disabled:cursor-not-allowed"
364
380
  disabled={applyingIds.has(batchId)}
365
381
  onClick={() => handleBatchApprove(batchId)}
366
382
  >
@@ -368,21 +384,21 @@ export function CoherenceView({ graphData, onNodeClick, projectId }: CoherenceVi
368
384
  </button>
369
385
  </div>
370
386
  </div>
371
- <div className="coherence-proposal-reasoning">{batchProposals[0]?.reasoning || ''}</div>
387
+ <div className="text-xs text-content-secondary leading-relaxed mb-2.5 px-2.5 py-2 bg-surface-raised rounded">{batchProposals[0]?.reasoning || ''}</div>
372
388
  {isExpanded ? (
373
- <div className="coherence-batch-items">
389
+ <div className="mt-2 pt-2 border-t border-edge">
374
390
  {batchProposals.map((p: any) => (
375
391
  <ProposalCard key={p.id} proposal={p} resolved={false} conflicts={conflicts} inBatch />
376
392
  ))}
377
393
  </div>
378
394
  ) : (
379
- <div className="coherence-batch-summary">
395
+ <div className="flex flex-col gap-1 mt-2">
380
396
  {batchProposals.map((p: any) => (
381
- <div key={p.id} className="coherence-batch-summary-item">
382
- <span className={`coherence-proposal-type coherence-type-${TYPE_CSS[p.type] || 'default'}`}>
397
+ <div key={p.id} className="flex items-center gap-2 text-[11px]">
398
+ <span className={`text-[10px] font-semibold uppercase tracking-wide px-2 py-0.5 rounded-sm ${TYPE_TW[p.type] || ''}`}>
383
399
  {TYPE_LABELS[p.type] || p.type}
384
400
  </span>
385
- <span className="coherence-batch-summary-text">{getProposalSummary(p)}</span>
401
+ <span className="text-content-secondary">{getProposalSummary(p)}</span>
386
402
  </div>
387
403
  ))}
388
404
  </div>
@@ -397,12 +413,12 @@ export function CoherenceView({ graphData, onNodeClick, projectId }: CoherenceVi
397
413
  </div>
398
414
 
399
415
  {resolvedProposals.length > 0 && (
400
- <div className="coherence-section">
401
- <button className="coherence-resolved-toggle" onClick={() => setResolvedExpanded(v => !v)}>
402
- <span className="coherence-toggle-icon" dangerouslySetInnerHTML={{ __html: resolvedExpanded ? '&#9660;' : '&#9654;' }} />
416
+ <div className="mb-6">
417
+ <button className="flex items-center gap-1.5 w-full py-2 bg-transparent border-none text-content-secondary font-mono text-xs font-semibold cursor-pointer uppercase tracking-wide mb-2 hover:text-content" onClick={() => setResolvedExpanded(v => !v)}>
418
+ <span className="text-[9px]" dangerouslySetInnerHTML={{ __html: resolvedExpanded ? '&#9660;' : '&#9654;' }} />
403
419
  {' '}Resolved ({resolvedProposals.length})
404
420
  </button>
405
- <div className={`coherence-resolved-list${resolvedExpanded ? '' : ' collapsed'}`}>
421
+ <div className={resolvedExpanded ? '' : 'hidden'}>
406
422
  {resolvedProposals.map((p: any) => (
407
423
  <ProposalCard key={p.id} proposal={p} resolved={true} conflicts={{}} />
408
424
  ))}