groove-dev 0.27.143 → 0.27.145

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 (251) hide show
  1. package/CLAUDE.md +0 -7
  2. package/node_modules/@groove-dev/cli/package.json +1 -1
  3. package/node_modules/@groove-dev/daemon/package.json +1 -1
  4. package/node_modules/@groove-dev/daemon/src/api.js +1086 -6532
  5. package/node_modules/@groove-dev/daemon/src/conversations.js +18 -48
  6. package/node_modules/@groove-dev/daemon/src/gateways/manager.js +35 -1
  7. package/node_modules/@groove-dev/daemon/src/index.js +3 -0
  8. package/node_modules/@groove-dev/daemon/src/journalist.js +23 -13
  9. package/node_modules/@groove-dev/daemon/src/mlx-server.js +365 -0
  10. package/node_modules/@groove-dev/daemon/src/model-lab.js +308 -12
  11. package/node_modules/@groove-dev/daemon/src/pm.js +1 -1
  12. package/node_modules/@groove-dev/daemon/src/process.js +2 -2
  13. package/node_modules/@groove-dev/daemon/src/providers/local.js +36 -8
  14. package/node_modules/@groove-dev/daemon/src/registry.js +21 -5
  15. package/node_modules/@groove-dev/daemon/src/routes/agents.js +812 -0
  16. package/node_modules/@groove-dev/daemon/src/routes/coordination.js +318 -0
  17. package/node_modules/@groove-dev/daemon/src/routes/files.js +751 -0
  18. package/node_modules/@groove-dev/daemon/src/routes/integrations.js +485 -0
  19. package/node_modules/@groove-dev/daemon/src/routes/network.js +1784 -0
  20. package/node_modules/@groove-dev/daemon/src/routes/providers.js +755 -0
  21. package/node_modules/@groove-dev/daemon/src/routes/schedules.js +110 -0
  22. package/node_modules/@groove-dev/daemon/src/routes/teams.js +650 -0
  23. package/node_modules/@groove-dev/daemon/src/scheduler.js +456 -24
  24. package/node_modules/@groove-dev/daemon/src/teams.js +1 -1
  25. package/node_modules/@groove-dev/daemon/src/validate.js +38 -1
  26. package/node_modules/@groove-dev/daemon/templates/mlx-setup.json +12 -0
  27. package/node_modules/@groove-dev/daemon/templates/tgi-setup.json +1 -1
  28. package/node_modules/@groove-dev/daemon/templates/vllm-setup.json +1 -1
  29. package/node_modules/@groove-dev/daemon/test/introducer.test.js +3 -3
  30. package/node_modules/@groove-dev/daemon/test/journalist.test.js +7 -10
  31. package/node_modules/@groove-dev/daemon/test/registry.test.js +38 -0
  32. package/node_modules/@groove-dev/gui/dist/assets/index-Bxc0gU06.js +1006 -0
  33. package/node_modules/@groove-dev/gui/dist/assets/index-C0pztKBn.css +1 -0
  34. package/node_modules/@groove-dev/gui/dist/index.html +2 -2
  35. package/node_modules/@groove-dev/gui/package.json +1 -1
  36. package/node_modules/@groove-dev/gui/src/{app.jsx → App.jsx} +0 -2
  37. package/node_modules/@groove-dev/gui/src/app.css +35 -0
  38. package/node_modules/@groove-dev/gui/src/components/agents/agent-config.jsx +1 -128
  39. package/node_modules/@groove-dev/gui/src/components/agents/agent-feed.jsx +210 -112
  40. package/node_modules/@groove-dev/gui/src/components/agents/agent-node.jsx +8 -13
  41. package/node_modules/@groove-dev/gui/src/components/agents/agent-panel.jsx +2 -70
  42. package/node_modules/@groove-dev/gui/src/components/agents/code-review.jsx +159 -122
  43. package/node_modules/@groove-dev/gui/src/components/agents/diff-viewer.jsx +23 -23
  44. package/node_modules/@groove-dev/gui/src/components/agents/journalist-panel.jsx +1 -1
  45. package/node_modules/@groove-dev/gui/src/components/agents/spawn-wizard.jsx +2 -135
  46. package/node_modules/@groove-dev/gui/src/components/automations/automation-card.jsx +274 -0
  47. package/node_modules/@groove-dev/gui/src/components/automations/automation-wizard.jsx +1136 -0
  48. package/node_modules/@groove-dev/gui/src/components/chat/chat-header.jsx +2 -0
  49. package/node_modules/@groove-dev/gui/src/components/chat/chat-input.jsx +68 -66
  50. package/node_modules/@groove-dev/gui/src/components/chat/chat-view.jsx +4 -8
  51. package/node_modules/@groove-dev/gui/src/components/dashboard/activity-feed.jsx +3 -3
  52. package/node_modules/@groove-dev/gui/src/components/dashboard/cache-ring.jsx +5 -5
  53. package/node_modules/@groove-dev/gui/src/components/dashboard/context-gauges.jsx +6 -8
  54. package/node_modules/@groove-dev/gui/src/components/dashboard/fleet-panel.jsx +8 -14
  55. package/node_modules/@groove-dev/gui/src/components/dashboard/intel-panel.jsx +238 -656
  56. package/node_modules/@groove-dev/gui/src/components/dashboard/kpi-card.jsx +3 -3
  57. package/node_modules/@groove-dev/gui/src/components/dashboard/routing-chart.jsx +3 -3
  58. package/node_modules/@groove-dev/gui/src/components/dashboard/team-burn-panel.jsx +1 -1
  59. package/node_modules/@groove-dev/gui/src/components/dashboard/token-chart.jsx +4 -4
  60. package/node_modules/@groove-dev/gui/src/components/lab/chat-playground.jsx +39 -31
  61. package/node_modules/@groove-dev/gui/src/components/lab/lab-assistant.jsx +316 -82
  62. package/node_modules/@groove-dev/gui/src/components/lab/metrics-panel.jsx +187 -32
  63. package/node_modules/@groove-dev/gui/src/components/lab/parameter-panel.jsx +200 -18
  64. package/node_modules/@groove-dev/gui/src/components/lab/preset-manager.jsx +17 -14
  65. package/node_modules/@groove-dev/gui/src/components/lab/runtime-config.jsx +335 -152
  66. package/node_modules/@groove-dev/gui/src/components/lab/system-prompt-editor.jsx +10 -8
  67. package/node_modules/@groove-dev/gui/src/components/layout/activity-bar.jsx +2 -4
  68. package/node_modules/@groove-dev/gui/src/components/layout/terminal-panel.jsx +4 -2
  69. package/node_modules/@groove-dev/gui/src/components/layout/welcome-splash.jsx +137 -108
  70. package/node_modules/@groove-dev/gui/src/components/network/network-health.jsx +2 -2
  71. package/node_modules/@groove-dev/gui/src/components/network/performance-dashboard.jsx +4 -4
  72. package/node_modules/@groove-dev/gui/src/components/settings/ssh-wizard.jsx +81 -99
  73. package/node_modules/@groove-dev/gui/src/components/ui/sheet.jsx +5 -2
  74. package/node_modules/@groove-dev/gui/src/components/ui/slider.jsx +8 -8
  75. package/node_modules/@groove-dev/gui/src/lib/cron.js +64 -0
  76. package/node_modules/@groove-dev/gui/src/lib/status.js +25 -24
  77. package/node_modules/@groove-dev/gui/src/lib/theme-hex.js +1 -0
  78. package/node_modules/@groove-dev/gui/src/stores/groove.js +51 -3144
  79. package/node_modules/@groove-dev/gui/src/stores/helpers.js +10 -0
  80. package/node_modules/@groove-dev/gui/src/stores/slices/agents-slice.js +459 -0
  81. package/node_modules/@groove-dev/gui/src/stores/slices/automations-slice.js +96 -0
  82. package/node_modules/@groove-dev/gui/src/stores/slices/chat-slice.js +226 -0
  83. package/node_modules/@groove-dev/gui/src/stores/slices/editor-slice.js +285 -0
  84. package/node_modules/@groove-dev/gui/src/stores/slices/marketplace-slice.js +461 -0
  85. package/node_modules/@groove-dev/gui/src/stores/slices/network-slice.js +361 -0
  86. package/node_modules/@groove-dev/gui/src/stores/slices/preview-slice.js +109 -0
  87. package/node_modules/@groove-dev/gui/src/stores/slices/providers-slice.js +897 -0
  88. package/node_modules/@groove-dev/gui/src/stores/slices/teams-slice.js +413 -0
  89. package/node_modules/@groove-dev/gui/src/stores/slices/ui-slice.js +98 -0
  90. package/node_modules/@groove-dev/gui/src/views/agents.jsx +5 -5
  91. package/node_modules/@groove-dev/gui/src/views/dashboard.jsx +12 -13
  92. package/node_modules/@groove-dev/gui/src/views/marketplace.jsx +191 -3
  93. package/node_modules/@groove-dev/gui/src/views/model-lab.jsx +54 -12
  94. package/node_modules/@groove-dev/gui/src/views/models.jsx +419 -496
  95. package/node_modules/@groove-dev/gui/src/views/network.jsx +3 -3
  96. package/node_modules/@groove-dev/gui/src/views/settings.jsx +81 -94
  97. package/node_modules/@groove-dev/gui/src/views/teams.jsx +40 -483
  98. package/node_modules/axios/CHANGELOG.md +260 -0
  99. package/node_modules/axios/README.md +595 -223
  100. package/node_modules/axios/dist/axios.js +1460 -1090
  101. package/node_modules/axios/dist/axios.js.map +1 -1
  102. package/node_modules/axios/dist/axios.min.js +3 -3
  103. package/node_modules/axios/dist/axios.min.js.map +1 -1
  104. package/node_modules/axios/dist/browser/axios.cjs +1560 -1132
  105. package/node_modules/axios/dist/browser/axios.cjs.map +1 -1
  106. package/node_modules/axios/dist/esm/axios.js +1557 -1128
  107. package/node_modules/axios/dist/esm/axios.js.map +1 -1
  108. package/node_modules/axios/dist/esm/axios.min.js +2 -2
  109. package/node_modules/axios/dist/esm/axios.min.js.map +1 -1
  110. package/node_modules/axios/dist/node/axios.cjs +1594 -1057
  111. package/node_modules/axios/dist/node/axios.cjs.map +1 -1
  112. package/node_modules/axios/index.d.cts +40 -41
  113. package/node_modules/axios/index.d.ts +151 -227
  114. package/node_modules/axios/index.js +2 -0
  115. package/node_modules/axios/lib/adapters/adapters.js +4 -2
  116. package/node_modules/axios/lib/adapters/fetch.js +147 -16
  117. package/node_modules/axios/lib/adapters/http.js +306 -58
  118. package/node_modules/axios/lib/adapters/xhr.js +6 -2
  119. package/node_modules/axios/lib/core/Axios.js +7 -3
  120. package/node_modules/axios/lib/core/AxiosError.js +120 -34
  121. package/node_modules/axios/lib/core/AxiosHeaders.js +27 -25
  122. package/node_modules/axios/lib/core/buildFullPath.js +1 -1
  123. package/node_modules/axios/lib/core/dispatchRequest.js +19 -7
  124. package/node_modules/axios/lib/core/mergeConfig.js +21 -4
  125. package/node_modules/axios/lib/core/settle.js +7 -11
  126. package/node_modules/axios/lib/defaults/index.js +14 -9
  127. package/node_modules/axios/lib/env/data.js +1 -1
  128. package/node_modules/axios/lib/helpers/AxiosURLSearchParams.js +1 -2
  129. package/node_modules/axios/lib/helpers/buildURL.js +1 -1
  130. package/node_modules/axios/lib/helpers/cookies.js +14 -2
  131. package/node_modules/axios/lib/helpers/estimateDataURLDecodedBytes.js +28 -1
  132. package/node_modules/axios/lib/helpers/formDataToJSON.js +3 -1
  133. package/node_modules/axios/lib/helpers/formDataToStream.js +3 -2
  134. package/node_modules/axios/lib/helpers/parseProtocol.js +1 -1
  135. package/node_modules/axios/lib/helpers/progressEventReducer.js +5 -5
  136. package/node_modules/axios/lib/helpers/resolveConfig.js +54 -18
  137. package/node_modules/axios/lib/helpers/shouldBypassProxy.js +74 -2
  138. package/node_modules/axios/lib/helpers/toFormData.js +10 -2
  139. package/node_modules/axios/lib/helpers/validator.js +3 -1
  140. package/node_modules/axios/lib/utils.js +33 -21
  141. package/node_modules/axios/package.json +17 -24
  142. package/node_modules/follow-redirects/README.md +7 -5
  143. package/node_modules/follow-redirects/index.js +24 -1
  144. package/node_modules/follow-redirects/package.json +1 -1
  145. package/package.json +1 -1
  146. package/packages/cli/package.json +1 -1
  147. package/packages/daemon/package.json +1 -1
  148. package/packages/daemon/src/api.js +1086 -6532
  149. package/packages/daemon/src/conversations.js +18 -48
  150. package/packages/daemon/src/gateways/manager.js +35 -1
  151. package/packages/daemon/src/index.js +3 -0
  152. package/packages/daemon/src/journalist.js +23 -13
  153. package/packages/daemon/src/mlx-server.js +365 -0
  154. package/packages/daemon/src/model-lab.js +308 -12
  155. package/packages/daemon/src/pm.js +1 -1
  156. package/packages/daemon/src/process.js +2 -2
  157. package/packages/daemon/src/providers/local.js +36 -8
  158. package/packages/daemon/src/registry.js +21 -5
  159. package/packages/daemon/src/routes/agents.js +812 -0
  160. package/packages/daemon/src/routes/coordination.js +318 -0
  161. package/packages/daemon/src/routes/files.js +751 -0
  162. package/packages/daemon/src/routes/integrations.js +485 -0
  163. package/packages/daemon/src/routes/network.js +1784 -0
  164. package/packages/daemon/src/routes/providers.js +755 -0
  165. package/packages/daemon/src/routes/schedules.js +110 -0
  166. package/packages/daemon/src/routes/teams.js +650 -0
  167. package/packages/daemon/src/scheduler.js +456 -24
  168. package/packages/daemon/src/teams.js +1 -1
  169. package/packages/daemon/src/validate.js +38 -1
  170. package/packages/daemon/templates/mlx-setup.json +12 -0
  171. package/packages/daemon/templates/tgi-setup.json +1 -1
  172. package/packages/daemon/templates/vllm-setup.json +1 -1
  173. package/packages/gui/dist/assets/index-Bxc0gU06.js +1006 -0
  174. package/packages/gui/dist/assets/index-C0pztKBn.css +1 -0
  175. package/packages/gui/dist/index.html +2 -2
  176. package/packages/gui/package.json +1 -1
  177. package/packages/gui/src/{app.jsx → App.jsx} +0 -2
  178. package/packages/gui/src/app.css +35 -0
  179. package/packages/gui/src/components/agents/agent-config.jsx +1 -128
  180. package/packages/gui/src/components/agents/agent-feed.jsx +210 -112
  181. package/packages/gui/src/components/agents/agent-node.jsx +8 -13
  182. package/packages/gui/src/components/agents/agent-panel.jsx +2 -70
  183. package/packages/gui/src/components/agents/code-review.jsx +159 -122
  184. package/packages/gui/src/components/agents/diff-viewer.jsx +23 -23
  185. package/packages/gui/src/components/agents/journalist-panel.jsx +1 -1
  186. package/packages/gui/src/components/agents/spawn-wizard.jsx +2 -135
  187. package/packages/gui/src/components/automations/automation-card.jsx +274 -0
  188. package/packages/gui/src/components/automations/automation-wizard.jsx +1136 -0
  189. package/packages/gui/src/components/chat/chat-header.jsx +2 -0
  190. package/packages/gui/src/components/chat/chat-input.jsx +68 -66
  191. package/packages/gui/src/components/chat/chat-view.jsx +4 -8
  192. package/packages/gui/src/components/dashboard/activity-feed.jsx +3 -3
  193. package/packages/gui/src/components/dashboard/cache-ring.jsx +5 -5
  194. package/packages/gui/src/components/dashboard/context-gauges.jsx +6 -8
  195. package/packages/gui/src/components/dashboard/fleet-panel.jsx +8 -14
  196. package/packages/gui/src/components/dashboard/intel-panel.jsx +238 -656
  197. package/packages/gui/src/components/dashboard/kpi-card.jsx +3 -3
  198. package/packages/gui/src/components/dashboard/routing-chart.jsx +3 -3
  199. package/packages/gui/src/components/dashboard/team-burn-panel.jsx +1 -1
  200. package/packages/gui/src/components/dashboard/token-chart.jsx +4 -4
  201. package/packages/gui/src/components/lab/chat-playground.jsx +39 -31
  202. package/packages/gui/src/components/lab/lab-assistant.jsx +316 -82
  203. package/packages/gui/src/components/lab/metrics-panel.jsx +187 -32
  204. package/packages/gui/src/components/lab/parameter-panel.jsx +200 -18
  205. package/packages/gui/src/components/lab/preset-manager.jsx +17 -14
  206. package/packages/gui/src/components/lab/runtime-config.jsx +335 -152
  207. package/packages/gui/src/components/lab/system-prompt-editor.jsx +10 -8
  208. package/packages/gui/src/components/layout/activity-bar.jsx +2 -4
  209. package/packages/gui/src/components/layout/terminal-panel.jsx +4 -2
  210. package/packages/gui/src/components/layout/welcome-splash.jsx +137 -108
  211. package/packages/gui/src/components/network/network-health.jsx +2 -2
  212. package/packages/gui/src/components/network/performance-dashboard.jsx +4 -4
  213. package/packages/gui/src/components/settings/ssh-wizard.jsx +81 -99
  214. package/packages/gui/src/components/ui/sheet.jsx +5 -2
  215. package/packages/gui/src/components/ui/slider.jsx +8 -8
  216. package/packages/gui/src/lib/cron.js +64 -0
  217. package/packages/gui/src/lib/status.js +25 -24
  218. package/packages/gui/src/lib/theme-hex.js +1 -0
  219. package/packages/gui/src/stores/groove.js +51 -3144
  220. package/packages/gui/src/stores/helpers.js +10 -0
  221. package/packages/gui/src/stores/slices/agents-slice.js +459 -0
  222. package/packages/gui/src/stores/slices/automations-slice.js +96 -0
  223. package/packages/gui/src/stores/slices/chat-slice.js +226 -0
  224. package/packages/gui/src/stores/slices/editor-slice.js +285 -0
  225. package/packages/gui/src/stores/slices/marketplace-slice.js +461 -0
  226. package/packages/gui/src/stores/slices/network-slice.js +361 -0
  227. package/packages/gui/src/stores/slices/preview-slice.js +109 -0
  228. package/packages/gui/src/stores/slices/providers-slice.js +897 -0
  229. package/packages/gui/src/stores/slices/teams-slice.js +413 -0
  230. package/packages/gui/src/stores/slices/ui-slice.js +98 -0
  231. package/packages/gui/src/views/agents.jsx +5 -5
  232. package/packages/gui/src/views/dashboard.jsx +12 -13
  233. package/packages/gui/src/views/marketplace.jsx +191 -3
  234. package/packages/gui/src/views/model-lab.jsx +54 -12
  235. package/packages/gui/src/views/models.jsx +419 -496
  236. package/packages/gui/src/views/network.jsx +3 -3
  237. package/packages/gui/src/views/settings.jsx +81 -94
  238. package/packages/gui/src/views/teams.jsx +40 -483
  239. package/SECURITY_SWEEP.md +0 -228
  240. package/TRAINING_DATA_v4.md +0 -6
  241. package/node_modules/@groove-dev/gui/dist/assets/index-CCVvAoQn.css +0 -1
  242. package/node_modules/@groove-dev/gui/dist/assets/index-DGIv_TRm.js +0 -984
  243. package/node_modules/@groove-dev/gui/src/components/agents/agent-chat.jsx +0 -379
  244. package/node_modules/@groove-dev/gui/src/views/preview.jsx +0 -6
  245. package/node_modules/@groove-dev/gui/src/views/subscription-panel.jsx +0 -327
  246. package/packages/gui/dist/assets/index-CCVvAoQn.css +0 -1
  247. package/packages/gui/dist/assets/index-DGIv_TRm.js +0 -984
  248. package/packages/gui/src/components/agents/agent-chat.jsx +0 -379
  249. package/packages/gui/src/views/preview.jsx +0 -6
  250. package/packages/gui/src/views/subscription-panel.jsx +0 -327
  251. package/test.py +0 -571
@@ -62,10 +62,6 @@ export function SpawnWizard() {
62
62
  const [model, setModel] = useState('');
63
63
  const [prompt, setPrompt] = useState('');
64
64
  const [providers, setProviders] = useState([]);
65
- const [installedSkills, setInstalledSkills] = useState([]);
66
- const [selectedSkills, setSelectedSkills] = useState([]);
67
- const [skillModalOpen, setSkillModalOpen] = useState(false);
68
- const [skillSearch, setSkillSearch] = useState('');
69
65
  const [installedIntegrations, setInstalledIntegrations] = useState([]);
70
66
  const [selectedIntegrations, setSelectedIntegrations] = useState([]);
71
67
  const [integrationModalOpen, setIntegrationModalOpen] = useState(false);
@@ -82,7 +78,6 @@ export function SpawnWizard() {
82
78
  const [selectedPeerId, setSelectedPeerId] = useState('');
83
79
  const [recommendations, setRecommendations] = useState([]);
84
80
  const [preflightDialog, setPreflightDialog] = useState(null);
85
- const [claudeAuth, setClaudeAuth] = useState(null);
86
81
  const [ollamaInstalled, setOllamaInstalled] = useState([]);
87
82
  const [ollamaServerRunning, setOllamaServerRunning] = useState(false);
88
83
  const federation = useGrooveStore((s) => s.federation);
@@ -108,9 +103,6 @@ export function SpawnWizard() {
108
103
  setProvider(best);
109
104
  }
110
105
  }).catch(() => {});
111
- api.get('/skills/installed').then((data) => {
112
- setInstalledSkills(Array.isArray(data) ? data : []);
113
- }).catch(() => {});
114
106
  api.get('/integrations/installed').then((data) => {
115
107
  setInstalledIntegrations(Array.isArray(data) ? data : []);
116
108
  }).catch(() => {});
@@ -123,7 +115,6 @@ export function SpawnWizard() {
123
115
  setRole(''); setCustomRole(''); setName('');
124
116
  setProvider(_presetProvider); setModel(_presetModel);
125
117
  setPrompt('');
126
- setSelectedSkills([]);
127
118
  setSelectedIntegrations([]);
128
119
  setIntegrationApproval('manual');
129
120
  setSelectedRepos([]);
@@ -132,7 +123,6 @@ export function SpawnWizard() {
132
123
  setShowAdvanced(false);
133
124
  setRecommendations([]);
134
125
  setPreflightDialog(null);
135
- setClaudeAuth(null);
136
126
  }
137
127
  }, [open, fetchProviders]);
138
128
 
@@ -150,13 +140,6 @@ export function SpawnWizard() {
150
140
  }).catch(() => setRecommendations([]));
151
141
  }, [selectedRole, open]);
152
142
 
153
- useEffect(() => {
154
- if (!open || provider !== 'claude-code') { setClaudeAuth(null); return; }
155
- api.get('/providers/claude-code/auth').then((data) => {
156
- setClaudeAuth(data);
157
- }).catch(() => setClaudeAuth(null));
158
- }, [open, provider]);
159
-
160
143
  useEffect(() => {
161
144
  if (!open || provider !== 'ollama') { setOllamaInstalled([]); return; }
162
145
  api.get('/providers/ollama/models').then((data) => {
@@ -176,7 +159,6 @@ export function SpawnWizard() {
176
159
  ...(provider && { provider }),
177
160
  ...(model && { model }),
178
161
  ...(prompt && { prompt }),
179
- ...(selectedSkills.length > 0 && { skills: selectedSkills }),
180
162
  ...(selectedIntegrations.length > 0 && { integrations: selectedIntegrations }),
181
163
  ...(selectedIntegrations.length > 0 && { integrationApproval }),
182
164
  ...(selectedRepos.length > 0 && { repos: selectedRepos }),
@@ -204,11 +186,9 @@ export function SpawnWizard() {
204
186
  runSpawn();
205
187
  }
206
188
 
207
- const claudeNotAuthed = provider === 'claude-code' && claudeAuth && !claudeAuth.authenticated;
208
-
209
189
  return (
210
190
  <Sheet open={open} onOpenChange={(o) => { if (!o) closeDetail(); }}>
211
- <SheetContent title="Spawn Agent" width={480}>
191
+ <SheetContent title="Spawn Agent" width={480} onClose={() => closeDetail()}>
212
192
  <div className="flex flex-col h-[calc(100%-57px)]">
213
193
  {/* Scrollable content */}
214
194
  <div className="flex-1 overflow-y-auto px-5 py-4 space-y-6">
@@ -479,119 +459,6 @@ export function SpawnWizard() {
479
459
  </div>
480
460
  )}
481
461
 
482
- {/* Claude Code Auth */}
483
- {claudeNotAuthed && (
484
- <div className="rounded-lg border border-warning/30 bg-warning/5 px-4 py-3">
485
- <div className="flex items-center gap-2 mb-2">
486
- <AlertTriangle size={13} className="text-warning flex-shrink-0" />
487
- <span className="text-xs font-semibold text-text-0 font-sans">Claude Code is not signed in</span>
488
- </div>
489
- <p className="text-2xs text-text-2 font-sans">
490
- Open the terminal and run: <code className="font-mono text-accent bg-surface-4 px-1.5 py-0.5 rounded text-2xs">claude</code>
491
- </p>
492
- </div>
493
- )}
494
- {provider === 'claude-code' && claudeAuth?.authenticated && (
495
- <div className="flex items-center gap-2 text-2xs text-text-2 font-sans">
496
- <div className="w-2 h-2 rounded-full bg-success flex-shrink-0" />
497
- Signed in as {claudeAuth.email || 'Claude user'} ({claudeAuth.subscriptionType || 'subscription'})
498
- </div>
499
- )}
500
-
501
- {/* Skills */}
502
- <div className="space-y-1.5">
503
- <label className="text-xs font-medium text-text-2 font-sans">Skills</label>
504
- <div className="flex flex-wrap items-center gap-1.5">
505
- {selectedSkills.map((skillId) => {
506
- const skill = installedSkills.find((s) => s.id === skillId);
507
- return (
508
- <span
509
- key={skillId}
510
- className="inline-flex items-center gap-1 px-2 py-1 rounded bg-accent/12 text-accent border border-accent/25 text-2xs font-sans"
511
- >
512
- <Sparkles size={9} />
513
- {skill?.name || skillId}
514
- <button
515
- onClick={() => setSelectedSkills((prev) => prev.filter((s) => s !== skillId))}
516
- className="ml-0.5 hover:text-text-0 cursor-pointer"
517
- >
518
- <X size={9} />
519
- </button>
520
- </span>
521
- );
522
- })}
523
- <button
524
- onClick={() => { setSkillModalOpen(true); setSkillSearch(''); }}
525
- className={cn(
526
- 'inline-flex items-center gap-1.5 px-2.5 py-1 rounded text-2xs font-sans transition-colors cursor-pointer',
527
- 'bg-surface-0 text-text-2 border border-border-subtle hover:border-border hover:text-text-0',
528
- )}
529
- >
530
- <Sparkles size={10} />
531
- {selectedSkills.length > 0 ? 'Add skill' : 'Attach skill'}
532
- </button>
533
- </div>
534
- </div>
535
-
536
- {/* Skill picker modal */}
537
- <Dialog open={skillModalOpen} onOpenChange={setSkillModalOpen}>
538
- <DialogContent title="Select Skill" className="max-w-sm">
539
- <div className="space-y-3 p-4">
540
- <div className="relative">
541
- <Search size={14} className="absolute left-2.5 top-1/2 -translate-y-1/2 text-text-4" />
542
- <input
543
- value={skillSearch}
544
- onChange={(e) => setSkillSearch(e.target.value)}
545
- placeholder="Search skills..."
546
- autoFocus
547
- className="w-full h-8 pl-8 pr-3 text-xs rounded-md bg-surface-0 border border-border text-text-0 font-sans focus:outline-none focus:ring-1 focus:ring-accent"
548
- />
549
- </div>
550
- <div className="max-h-64 overflow-y-auto space-y-1">
551
- {installedSkills
552
- .filter((s) => {
553
- if (!skillSearch) return true;
554
- const q = skillSearch.toLowerCase();
555
- return (s.name || s.id).toLowerCase().includes(q) || (s.description || '').toLowerCase().includes(q);
556
- })
557
- .map((skill) => {
558
- const active = selectedSkills.includes(skill.id);
559
- return (
560
- <button
561
- key={skill.id}
562
- onClick={() => {
563
- setSelectedSkills((prev) =>
564
- active ? prev.filter((s) => s !== skill.id) : [...prev, skill.id]
565
- );
566
- }}
567
- className={cn(
568
- 'w-full flex items-center gap-2.5 px-3 py-2 rounded-md text-left transition-colors cursor-pointer',
569
- active
570
- ? 'bg-accent/10 border border-accent/25'
571
- : 'hover:bg-surface-3 border border-transparent',
572
- )}
573
- >
574
- <Sparkles size={12} className={active ? 'text-accent' : 'text-text-3'} />
575
- <div className="flex-1 min-w-0">
576
- <div className="text-xs font-semibold text-text-0 font-sans truncate">{skill.name || skill.id}</div>
577
- {skill.description && (
578
- <div className="text-2xs text-text-3 font-sans truncate">{skill.description}</div>
579
- )}
580
- </div>
581
- {active && <CheckMark />}
582
- </button>
583
- );
584
- })}
585
- {installedSkills.length === 0 && (
586
- <div className="text-center py-6 text-xs text-text-3 font-sans">
587
- No skills installed. Visit the Marketplace to install skills.
588
- </div>
589
- )}
590
- </div>
591
- </div>
592
- </DialogContent>
593
- </Dialog>
594
-
595
462
  {/* Integrations */}
596
463
  <div className="space-y-1.5">
597
464
  <label className="text-xs font-medium text-text-2 font-sans">Integrations</label>
@@ -900,7 +767,7 @@ export function SpawnWizard() {
900
767
  variant="primary"
901
768
  size="lg"
902
769
  onClick={handleSpawn}
903
- disabled={!selectedRole || spawning || installedProviders.length === 0 || claudeNotAuthed}
770
+ disabled={!selectedRole || spawning || installedProviders.length === 0}
904
771
  className="w-full"
905
772
  >
906
773
  {spawning ? 'Spawning...' : 'Spawn Agent'}
@@ -0,0 +1,274 @@
1
+ // FSL-1.1-Apache-2.0 — see LICENSE
2
+ import { useState, useRef, useEffect } from 'react';
3
+ import { useGrooveStore } from '../../stores/groove';
4
+ import { Badge } from '../ui/badge';
5
+ import { Button } from '../ui/button';
6
+ import { StatusDot } from '../ui/status-dot';
7
+ import { cronToHuman } from '../../lib/cron';
8
+ import { timeAgo, fmtDollar, fmtUptime } from '../../lib/format';
9
+ import { cn } from '../../lib/cn';
10
+ import {
11
+ Play, Pause, Clock, MoreHorizontal, Copy, Pencil, Trash2,
12
+ FileText, Folder, ExternalLink,
13
+ } from 'lucide-react';
14
+
15
+ export function AutomationCard({ automation }) {
16
+ const toggleAutomation = useGrooveStore((s) => s.toggleAutomation);
17
+ const deleteAutomation = useGrooveStore((s) => s.deleteAutomation);
18
+ const duplicateAutomation = useGrooveStore((s) => s.duplicateAutomation);
19
+ const runAutomation = useGrooveStore((s) => s.runAutomation);
20
+ const setEditingAutomation = useGrooveStore((s) => s.setEditingAutomation);
21
+ const openWizard = useGrooveStore((s) => s.openAutomationWizard);
22
+ const openDetail = useGrooveStore((s) => s.openDetail);
23
+ const agents = useGrooveStore((s) => s.agents);
24
+
25
+ const [menuOpen, setMenuOpen] = useState(false);
26
+ const menuRef = useRef(null);
27
+
28
+ useEffect(() => {
29
+ if (!menuOpen) return;
30
+ function handleClick(e) {
31
+ if (menuRef.current && !menuRef.current.contains(e.target)) setMenuOpen(false);
32
+ }
33
+ document.addEventListener('mousedown', handleClick);
34
+ return () => document.removeEventListener('mousedown', handleClick);
35
+ }, [menuOpen]);
36
+
37
+ const a = automation;
38
+ const roles = a.teamConfig || (a.agentConfig ? [a.agentConfig] : (a.role ? [{ role: a.role }] : []));
39
+ const instructions = a.instructionSource?.type === 'inline'
40
+ ? a.instructionSource.content
41
+ : a.instructionSource?.type === 'file'
42
+ ? null
43
+ : a.prompt || null;
44
+ const filePath = a.instructionSource?.type === 'file' ? a.instructionSource.filePath : null;
45
+ const gatewayIds = a.outputConfig?.gatewayIds || [];
46
+ const lastStatus = a.lastRunStatus || (a.lastRunAt ? 'completed' : null);
47
+
48
+ const activeAgents = (a.activeAgentIds || [])
49
+ .map((id) => agents.find((ag) => ag.id === id))
50
+ .filter(Boolean);
51
+
52
+ const lastRunAgentIds = a.lastRun?.agentId
53
+ ? a.lastRun.agentId.split(',').filter(Boolean)
54
+ : [];
55
+ const lastRunAgents = !a.isRunning
56
+ ? lastRunAgentIds.map((id) => agents.find((ag) => ag.id === id)).filter(Boolean)
57
+ : [];
58
+
59
+ function openAgentPanel(agentId) {
60
+ openDetail({ type: 'agent', agentId });
61
+ }
62
+
63
+ return (
64
+ <div className={cn(
65
+ 'rounded-md border bg-surface-1 overflow-hidden transition-colors',
66
+ a.enabled ? 'border-border-subtle' : 'border-border-subtle/50 opacity-75',
67
+ )}>
68
+ {/* Top row */}
69
+ <div className="px-4 py-3 flex items-start gap-3">
70
+ <div className="flex-1 min-w-0">
71
+ <div className="flex items-center gap-2">
72
+ <span className="text-sm font-semibold text-text-0 font-sans truncate">{a.name}</span>
73
+ <Badge variant={a.enabled ? 'success' : 'default'} className="text-2xs flex-shrink-0">
74
+ {a.enabled ? 'Active' : 'Paused'}
75
+ </Badge>
76
+ </div>
77
+ {a.description && (
78
+ <p className="text-2xs text-text-3 font-sans truncate mt-0.5">{a.description}</p>
79
+ )}
80
+ </div>
81
+
82
+ <div className="flex items-center gap-1.5 flex-shrink-0">
83
+ <button
84
+ onClick={() => toggleAutomation(a.id, a.enabled)}
85
+ className={cn(
86
+ 'p-1.5 rounded transition-colors cursor-pointer',
87
+ a.enabled ? 'text-success hover:text-success/80' : 'text-text-4 hover:text-text-2',
88
+ )}
89
+ title={a.enabled ? 'Pause automation' : 'Enable automation'}
90
+ >
91
+ {a.enabled ? <Pause size={13} /> : <Play size={13} />}
92
+ </button>
93
+
94
+ <div ref={menuRef} className="relative">
95
+ <button
96
+ onClick={() => setMenuOpen(!menuOpen)}
97
+ className="p-1.5 rounded text-text-4 hover:text-text-2 transition-colors cursor-pointer"
98
+ >
99
+ <MoreHorizontal size={13} />
100
+ </button>
101
+ {menuOpen && (
102
+ <div className="absolute right-0 top-full mt-1 z-50 min-w-[150px] bg-surface-2 border border-border rounded-md shadow-lg py-1">
103
+ <button
104
+ onClick={() => { setEditingAutomation(a.id); openWizard(); setMenuOpen(false); }}
105
+ className="w-full text-left px-3 py-1.5 text-xs font-sans text-text-1 hover:bg-surface-5 transition-colors cursor-pointer flex items-center gap-2"
106
+ >
107
+ <Pencil size={10} /> Edit
108
+ </button>
109
+ <button
110
+ onClick={() => { duplicateAutomation(a.id); setMenuOpen(false); }}
111
+ className="w-full text-left px-3 py-1.5 text-xs font-sans text-text-1 hover:bg-surface-5 transition-colors cursor-pointer flex items-center gap-2"
112
+ >
113
+ <Copy size={10} /> Duplicate
114
+ </button>
115
+ <button
116
+ onClick={() => { runAutomation(a.id); setMenuOpen(false); }}
117
+ className="w-full text-left px-3 py-1.5 text-xs font-sans text-text-1 hover:bg-surface-5 transition-colors cursor-pointer flex items-center gap-2"
118
+ >
119
+ <Play size={10} /> Run Now
120
+ </button>
121
+ <div className="h-px my-1 bg-border-subtle" />
122
+ <button
123
+ onClick={() => { deleteAutomation(a.id); setMenuOpen(false); }}
124
+ className="w-full text-left px-3 py-1.5 text-xs font-sans text-danger hover:bg-danger/5 transition-colors cursor-pointer flex items-center gap-2"
125
+ >
126
+ <Trash2 size={10} /> Delete
127
+ </button>
128
+ </div>
129
+ )}
130
+ </div>
131
+ </div>
132
+ </div>
133
+
134
+ {/* Team strip */}
135
+ {roles.length > 0 && (
136
+ <div className="px-4 pb-2 flex items-center gap-1.5 flex-wrap">
137
+ {roles.map((r, i) => (
138
+ <Badge key={i} variant="default" className="text-2xs">
139
+ {r.role}{r.phase ? ` P${r.phase}` : ''}
140
+ </Badge>
141
+ ))}
142
+ {a.integrationIds?.length > 0 && (
143
+ <span className="text-2xs text-text-4 font-sans ml-1">+{a.integrationIds.length} integrations</span>
144
+ )}
145
+ </div>
146
+ )}
147
+
148
+ {/* Instructions preview */}
149
+ {(instructions || filePath) && (
150
+ <div className="px-4 pb-2">
151
+ {filePath ? (
152
+ <div className="flex items-center gap-1.5">
153
+ <Folder size={10} className="text-text-4 flex-shrink-0" />
154
+ <span className="text-2xs font-mono text-text-3 truncate">{filePath}</span>
155
+ </div>
156
+ ) : (
157
+ <p className="text-2xs text-text-3 font-sans truncate">
158
+ <FileText size={10} className="inline mr-1 text-text-4" />
159
+ {instructions.slice(0, 100)}{instructions.length > 100 ? '...' : ''}
160
+ </p>
161
+ )}
162
+ </div>
163
+ )}
164
+
165
+ {/* Schedule + last run row */}
166
+ <div className="px-4 py-2 border-t border-border-subtle bg-surface-0 flex items-center gap-3 flex-wrap">
167
+ <div className="flex items-center gap-1.5">
168
+ <Clock size={10} className="text-text-4" />
169
+ <span className="text-2xs font-mono text-text-2">{cronToHuman(a.cron)}</span>
170
+ </div>
171
+ {a.nextRunAt && (
172
+ <span className="text-2xs font-mono text-text-3">
173
+ Next: {timeAgo(a.nextRunAt)}
174
+ </span>
175
+ )}
176
+ {a.lastRunAt && (
177
+ <div className="flex items-center gap-1.5">
178
+ <span className="text-2xs font-mono text-text-3">Last: {timeAgo(a.lastRunAt)}</span>
179
+ <StatusDot
180
+ status={lastStatus === 'error' ? 'crashed' : lastStatus === 'running' ? 'running' : 'completed'}
181
+ size="sm"
182
+ />
183
+ </div>
184
+ )}
185
+ {!a.lastRunAt && (
186
+ <span className="text-2xs text-text-4 font-sans">Never run</span>
187
+ )}
188
+ </div>
189
+
190
+ {/* Output config */}
191
+ {(gatewayIds.length > 0 || a.outputConfig?.filePath || a.outputConfig?.customInstructions) && (
192
+ <div className="px-4 py-1.5 border-t border-border-subtle bg-surface-0 space-y-1">
193
+ {gatewayIds.length > 0 && (
194
+ <div className="flex items-center gap-1.5">
195
+ <span className="text-2xs text-text-4 font-sans">Gateways:</span>
196
+ <span className="text-2xs font-sans text-text-3">{gatewayIds.join(', ')}</span>
197
+ </div>
198
+ )}
199
+ {a.outputConfig?.filePath && (
200
+ <div className="flex items-center gap-1.5">
201
+ <span className="text-2xs text-text-4 font-sans">File:</span>
202
+ <span className="text-2xs font-mono text-text-3 truncate">{a.outputConfig.filePath}</span>
203
+ </div>
204
+ )}
205
+ {a.outputConfig?.customInstructions && (
206
+ <div className="flex items-center gap-1.5">
207
+ <span className="text-2xs text-text-4 font-sans">Custom:</span>
208
+ <span className="text-2xs font-sans text-text-3 truncate">{a.outputConfig.customInstructions.slice(0, 80)}{a.outputConfig.customInstructions.length > 80 ? '...' : ''}</span>
209
+ </div>
210
+ )}
211
+ </div>
212
+ )}
213
+
214
+ {/* Active agents */}
215
+ {activeAgents.length > 0 && (
216
+ <div className="px-4 py-2 border-t border-border-subtle bg-surface-0">
217
+ <div className="flex items-center gap-1.5 mb-1.5">
218
+ <StatusDot status="running" size="sm" />
219
+ <span className="text-2xs font-sans text-text-2 font-medium">Running</span>
220
+ </div>
221
+ <div className="flex items-center gap-1.5 flex-wrap">
222
+ {activeAgents.map((ag) => (
223
+ <button
224
+ key={ag.id}
225
+ onClick={() => openAgentPanel(ag.id)}
226
+ className="flex items-center gap-1.5 px-2 py-1 rounded bg-surface-4 hover:bg-surface-5 transition-colors cursor-pointer group"
227
+ >
228
+ <StatusDot status={ag.status} size="sm" />
229
+ <span className="text-2xs font-sans text-text-1 group-hover:text-text-0">{ag.name || ag.role}</span>
230
+ <ExternalLink size={9} className="text-text-4 group-hover:text-accent" />
231
+ </button>
232
+ ))}
233
+ </div>
234
+ </div>
235
+ )}
236
+
237
+ {/* Last run agents (when not currently running) */}
238
+ {!a.isRunning && lastRunAgents.length > 0 && (
239
+ <div className="px-4 py-2 border-t border-border-subtle bg-surface-0">
240
+ <div className="flex items-center gap-1.5 mb-1.5">
241
+ <span className="text-2xs font-sans text-text-3">Last run agents</span>
242
+ </div>
243
+ <div className="flex items-center gap-1.5 flex-wrap">
244
+ {lastRunAgents.map((ag) => (
245
+ <button
246
+ key={ag.id}
247
+ onClick={() => openAgentPanel(ag.id)}
248
+ className="flex items-center gap-1.5 px-2 py-1 rounded bg-surface-4 hover:bg-surface-5 transition-colors cursor-pointer group"
249
+ >
250
+ <StatusDot status={ag.status} size="sm" />
251
+ <span className="text-2xs font-sans text-text-2 group-hover:text-text-0">{ag.name || ag.role}</span>
252
+ <ExternalLink size={9} className="text-text-4 group-hover:text-accent" />
253
+ </button>
254
+ ))}
255
+ </div>
256
+ </div>
257
+ )}
258
+
259
+ {/* Bottom bar */}
260
+ <div className="px-4 py-2 border-t border-border-subtle flex items-center gap-3">
261
+ <Button variant="ghost" size="sm" onClick={() => runAutomation(a.id)} className="h-6 px-2 text-2xs gap-1">
262
+ <Play size={10} /> Run Now
263
+ </Button>
264
+ <div className="flex-1" />
265
+ {a.lastRunDuration != null && (
266
+ <span className="text-2xs font-mono text-text-4">{fmtUptime(a.lastRunDuration / 1000)}</span>
267
+ )}
268
+ {a.lastRunCost != null && a.lastRunCost > 0 && (
269
+ <span className="text-2xs font-mono text-text-4">{fmtDollar(a.lastRunCost)}</span>
270
+ )}
271
+ </div>
272
+ </div>
273
+ );
274
+ }