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
@@ -1,379 +0,0 @@
1
- // FSL-1.1-Apache-2.0 — see LICENSE
2
- import { useState, useRef, useEffect } from 'react';
3
- import { Send, Loader2, MessageSquare, HelpCircle, ArrowRight, Paperclip, Square, FileCode, Terminal as TerminalIcon, X } from 'lucide-react';
4
- import { useGrooveStore } from '../../stores/groove';
5
- import { cn } from '../../lib/cn';
6
- import { ThinkingIndicator } from '../ui/thinking-indicator';
7
- import { TableTree } from '../ui/table-tree';
8
- import { timeAgo } from '../../lib/format';
9
-
10
- const EMPTY = [];
11
-
12
- function parseSegments(text) {
13
- const lines = text.split('\n');
14
- const segments = [];
15
- let i = 0;
16
- let textLines = [];
17
- while (i < lines.length) {
18
- const line = lines[i];
19
- if (line.includes('|') && i + 1 < lines.length && /^\|?\s*[-:]+/.test(lines[i + 1])) {
20
- if (textLines.length > 0) {
21
- segments.push({ type: 'text', content: textLines.join('\n') });
22
- textLines = [];
23
- }
24
- const headers = line.split('|').map((c) => c.trim()).filter(Boolean);
25
- i += 2;
26
- const rows = [];
27
- while (i < lines.length && lines[i].includes('|')) {
28
- rows.push(lines[i].split('|').map((c) => c.trim()).filter(Boolean));
29
- i++;
30
- }
31
- segments.push({ type: 'table', headers, rows });
32
- } else {
33
- textLines.push(line);
34
- i++;
35
- }
36
- }
37
- if (textLines.length > 0) segments.push({ type: 'text', content: textLines.join('\n') });
38
- return segments;
39
- }
40
-
41
- function highlightKeeper(text) {
42
- const parts = text.split(/(\[(?:save|append|update|delete|view|doc|link|read|instruct)\]|#[\w/.-]+)/gi);
43
- return parts.map((part, i) => {
44
- if (/^\[(?:save|append|update|delete|view|doc|link|read|instruct)\]$/i.test(part)) {
45
- return <span key={i} className="px-1 py-0.5 rounded bg-accent/15 text-accent font-semibold font-mono text-2xs">{part}</span>;
46
- }
47
- if (/^#[\w/.-]+$/.test(part)) {
48
- return <span key={i} className="text-accent font-medium">{part}</span>;
49
- }
50
- return part;
51
- });
52
- }
53
-
54
- function FormattedText({ text }) {
55
- if (!text) return null;
56
- const segments = parseSegments(text);
57
- return (
58
- <>
59
- {segments.map((seg, idx) => {
60
- if (seg.type === 'table') {
61
- return <TableTree key={idx} headers={seg.headers} rows={seg.rows} />;
62
- }
63
- const parts = seg.content.split(/(```[\s\S]*?```|`[^`]+`)/g);
64
- return (
65
- <span key={idx}>
66
- {parts.map((part, i) => {
67
- if (part.startsWith('```') && part.endsWith('```')) {
68
- const code = part.slice(3, -3).replace(/^\w+\n/, '');
69
- return <pre key={i} className="my-2 p-3 rounded-md bg-surface-0 text-xs font-mono text-text-1 overflow-x-auto whitespace-pre-wrap">{code}</pre>;
70
- }
71
- if (part.startsWith('`') && part.endsWith('`')) {
72
- return <code key={i} className="px-1.5 py-0.5 rounded bg-surface-0 text-xs font-mono text-accent">{part.slice(1, -1)}</code>;
73
- }
74
- return <span key={i}>{part.split(/(\*\*[^*]+\*\*)/g).map((s, j) =>
75
- s.startsWith('**') && s.endsWith('**')
76
- ? <strong key={j} className="font-semibold text-text-0">{s.slice(2, -2)}</strong>
77
- : <span key={j}>{highlightKeeper(s)}</span>
78
- )}</span>;
79
- })}
80
- </span>
81
- );
82
- })}
83
- </>
84
- );
85
- }
86
-
87
- function UserMessage({ msg }) {
88
- return (
89
- <div className="flex justify-end">
90
- <div className="max-w-[85%]">
91
- {msg.isQuery && (
92
- <div className="flex items-center gap-1 justify-end mb-1">
93
- <HelpCircle size={10} className="text-info" />
94
- <span className="text-2xs text-info font-sans">Query</span>
95
- </div>
96
- )}
97
- <div className={cn(
98
- 'px-3 py-2 rounded-xl rounded-br-sm',
99
- msg.isQuery ? 'bg-info/10 border border-info/15' : 'bg-accent/10 border border-accent/15',
100
- )}>
101
- <p className="text-xs text-text-0 font-sans whitespace-pre-wrap break-words leading-relaxed">
102
- <FormattedText text={msg.text} />
103
- </p>
104
- </div>
105
- <div className="text-2xs text-text-4 font-sans mt-0.5 text-right">{timeAgo(msg.timestamp)}</div>
106
- </div>
107
- </div>
108
- );
109
- }
110
-
111
- function AgentMessage({ msg, agent }) {
112
- return (
113
- <div>
114
- <div className="text-2xs text-text-3 font-sans mb-0.5 font-medium">{agent?.name}</div>
115
- <div className="border-l-2 border-accent/40 pl-3 py-0.5">
116
- <div className="text-xs text-text-1 font-sans whitespace-pre-wrap break-words leading-relaxed">
117
- <FormattedText text={msg.text} />
118
- </div>
119
- </div>
120
- <div className="text-2xs text-text-4 font-sans mt-0.5">{timeAgo(msg.timestamp)}</div>
121
- </div>
122
- );
123
- }
124
-
125
- function SystemMessage({ msg }) {
126
- return (
127
- <div className="flex justify-center py-1">
128
- <div className="flex items-center gap-1.5 px-3 py-1 rounded-full bg-surface-4/50">
129
- <ArrowRight size={10} className="text-text-4" />
130
- <span className="text-2xs text-text-3 font-sans">{msg.text}</span>
131
- </div>
132
- </div>
133
- );
134
- }
135
-
136
- function TypingIndicator() {
137
- return (
138
- <div className="border-l-2 border-accent/40 pl-3 py-2">
139
- <div className="flex items-center gap-1">
140
- <span className="w-1.5 h-1.5 rounded-full bg-text-3 animate-pulse" style={{ animationDelay: '0ms' }} />
141
- <span className="w-1.5 h-1.5 rounded-full bg-text-3 animate-pulse" style={{ animationDelay: '150ms' }} />
142
- <span className="w-1.5 h-1.5 rounded-full bg-text-3 animate-pulse" style={{ animationDelay: '300ms' }} />
143
- </div>
144
- </div>
145
- );
146
- }
147
-
148
- function SnippetTag({ snippet, onRemove }) {
149
- const isCode = snippet.type === 'code';
150
- const Icon = isCode ? FileCode : TerminalIcon;
151
- const lines = snippet.code.split('\n').length;
152
- let label;
153
- if (isCode && snippet.filePath) {
154
- const fileName = snippet.filePath.split('/').pop();
155
- label = `${fileName}:${snippet.lineStart}-${snippet.lineEnd}`;
156
- } else {
157
- label = `${isCode ? '' : 'Terminal · '}${lines} line${lines !== 1 ? 's' : ''}`;
158
- }
159
- return (
160
- <div className="flex items-center gap-1.5 px-2 py-1 rounded-md bg-accent/10 border border-accent/20 text-accent">
161
- <Icon size={11} className="flex-shrink-0" />
162
- <span className="text-2xs font-sans font-medium truncate max-w-[160px]">{label}</span>
163
- {snippet.instruction && (
164
- <span className="text-2xs text-accent/60 truncate max-w-[100px]">· {snippet.instruction}</span>
165
- )}
166
- <button onClick={onRemove} className="p-0.5 rounded hover:bg-accent/20 cursor-pointer flex-shrink-0">
167
- <X size={9} />
168
- </button>
169
- </div>
170
- );
171
- }
172
-
173
- export function AgentChat({ agent }) {
174
- const chatHistory = useGrooveStore((s) => s.chatHistory[agent.id]) || EMPTY;
175
- const activityLog = useGrooveStore((s) => s.activityLog[agent.id]) || EMPTY;
176
- const instructAgent = useGrooveStore((s) => s.instructAgent);
177
- const isThinking = useGrooveStore((s) => s.thinkingAgents?.has(agent.id));
178
-
179
- const pendingSnippet = useGrooveStore((s) => s.editorPendingSnippet);
180
- const clearSnippet = useGrooveStore((s) => s.clearSnippet);
181
-
182
- const storeInput = useGrooveStore((s) => s.chatInputs[agent.id] || '');
183
- const setStoreInput = (val) => useGrooveStore.setState((s) => ({ chatInputs: { ...s.chatInputs, [agent.id]: val } }));
184
- const input = storeInput;
185
- const setInput = setStoreInput;
186
- const [sending, setSending] = useState(false);
187
- const [attachedFiles, setAttachedFiles] = useState([]);
188
- const scrollRef = useRef(null);
189
- const inputRef = useRef(null);
190
- const fileInputRef = useRef(null);
191
- const isAtBottomRef = useRef(true);
192
-
193
- useEffect(() => {
194
- if (pendingSnippet) inputRef.current?.focus();
195
- }, [pendingSnippet]);
196
-
197
- useEffect(() => {
198
- const el = scrollRef.current;
199
- if (!el) return;
200
- function handleScroll() {
201
- isAtBottomRef.current = el.scrollHeight - el.scrollTop - el.clientHeight < 60;
202
- }
203
- el.addEventListener('scroll', handleScroll);
204
- return () => el.removeEventListener('scroll', handleScroll);
205
- }, []);
206
-
207
- useEffect(() => {
208
- if (isAtBottomRef.current && scrollRef.current) {
209
- scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
210
- }
211
- }, [chatHistory.length, activityLog.length, sending, isThinking]);
212
-
213
- function handleFileSelect(e) {
214
- const files = Array.from(e.target.files || []);
215
- if (files.length === 0) return;
216
- // Use webkitRelativePath or name — files from input have path info
217
- const paths = files.map((f) => f.name);
218
- setAttachedFiles((prev) => [...prev, ...paths]);
219
- // Also add file paths to the prompt so the agent knows about them
220
- const pathList = files.map((f) => f.name).join(', ');
221
- setInput((prev) => prev + (prev ? '\n' : '') + `[Attached files: ${pathList}]`);
222
- e.target.value = '';
223
- }
224
-
225
- async function handleSend() {
226
- const text = input.trim();
227
- if ((!text && !pendingSnippet) || sending) return;
228
- const parts = [];
229
- if (text) parts.push(text);
230
- if (pendingSnippet) {
231
- const s = pendingSnippet;
232
- if (s.type === 'code' && s.filePath) {
233
- if (s.instruction && !text) parts.push(s.instruction);
234
- parts.push(`File: ${s.filePath} (lines ${s.lineStart}-${s.lineEnd})`);
235
- parts.push('```\n' + s.code + '\n```');
236
- } else if (s.code) {
237
- parts.push('```\n' + s.code + '\n```');
238
- }
239
- }
240
- const message = parts.join('\n\n');
241
- setInput('');
242
- setAttachedFiles([]);
243
- clearSnippet();
244
- setSending(true);
245
- isAtBottomRef.current = true;
246
- requestAnimationFrame(() => {
247
- if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
248
- });
249
- try {
250
- await instructAgent(agent.id, message);
251
- } catch { /* toast handles */ }
252
- setSending(false);
253
- inputRef.current?.focus();
254
- }
255
-
256
- function onKeyDown(e) {
257
- if (e.key === 'Enter' && !e.shiftKey) {
258
- e.preventDefault();
259
- handleSend();
260
- }
261
- }
262
-
263
- const isAlive = agent.status === 'running' || agent.status === 'starting';
264
-
265
- // Build merged timeline
266
- const recentActivity = activityLog.slice(-8).map((a, i) => ({
267
- from: 'agent', text: a.text, timestamp: a.timestamp, key: `act-${i}`,
268
- }));
269
- const messages = chatHistory.length > 0 ? chatHistory : recentActivity;
270
-
271
- return (
272
- <div className="flex flex-col h-full">
273
- {/* Messages */}
274
- <div ref={scrollRef} className="flex-1 overflow-y-auto px-3 py-3 space-y-3">
275
- {messages.length === 0 && (
276
- <div className="flex flex-col items-center justify-center h-full text-center py-12">
277
- <div className="w-12 h-12 rounded-full bg-accent/8 flex items-center justify-center mb-4">
278
- <MessageSquare size={20} className="text-accent" />
279
- </div>
280
- <p className="text-sm font-medium text-text-1 font-sans">
281
- {isAlive ? 'Agent is running' : 'Agent finished'}
282
- </p>
283
- <p className="text-xs text-text-3 font-sans mt-1 max-w-[240px]">
284
- {isAlive
285
- ? 'Send a message to guide this agent. Use the stop button to interrupt.'
286
- : 'Reply to continue the conversation — a new session starts with full context.'}
287
- </p>
288
- </div>
289
- )}
290
- {messages.map((msg, i) => {
291
- if (msg.from === 'user') return <UserMessage key={msg.key || i} msg={msg} />;
292
- if (msg.from === 'system') return <SystemMessage key={msg.key || i} msg={msg} />;
293
- return <AgentMessage key={msg.key || i} msg={msg} agent={agent} />;
294
- })}
295
- {(sending || isThinking) && <ThinkingIndicator className="ml-8 py-1" />}
296
- </div>
297
-
298
- {/* ── Input area ──────────────────────────────────── */}
299
- <div className="border-t border-border-subtle px-3 py-2 bg-surface-1">
300
- {pendingSnippet && (
301
- <div className="mb-1.5">
302
- <SnippetTag snippet={pendingSnippet} onRemove={clearSnippet} />
303
- </div>
304
- )}
305
- {input && /\[(?:save|append|update|delete|view|doc|link|read|instruct)\]/i.test(input) && (() => {
306
- const cmdMatch = input.match(/\[(save|append|update|delete|view|doc|link|read|instruct)\]/i);
307
- const tags = (input.match(/#[\w/.-]+/g) || []);
308
- return (
309
- <div className="flex items-center gap-1.5 px-3 py-1 mb-1.5 rounded-md bg-accent/5 border border-accent/10">
310
- <span className="px-1.5 py-0.5 rounded bg-accent/15 text-accent font-semibold font-mono text-2xs">{cmdMatch[0]}</span>
311
- {tags.map((tag, i) => <span key={i} className="text-accent font-medium text-2xs">{tag}</span>)}
312
- <span className="text-2xs text-text-4 ml-auto">memory command</span>
313
- </div>
314
- );
315
- })()}
316
- <div className="flex items-end gap-1.5">
317
- <input
318
- ref={fileInputRef}
319
- type="file"
320
- multiple
321
- accept=".pdf,.png,.jpg,.jpeg,.gif,.svg,.csv,.txt,.md,.json,.yaml,.yml,.docx,.pptx,.xlsx"
322
- onChange={handleFileSelect}
323
- className="hidden"
324
- />
325
- <button
326
- onClick={() => fileInputRef.current?.click()}
327
- className="w-8 h-8 flex items-center justify-center rounded-lg text-text-4 hover:text-text-1 hover:bg-surface-3 transition-colors cursor-pointer flex-shrink-0"
328
- title="Attach file"
329
- >
330
- <Paperclip size={14} />
331
- </button>
332
- <div className="flex-1">
333
- <textarea
334
- ref={inputRef}
335
- value={input}
336
- onChange={(e) => setInput(e.target.value)}
337
- onKeyDown={onKeyDown}
338
- placeholder={pendingSnippet ? 'Add a message (optional)...' : isAlive ? 'Instruct this agent...' : 'Continue conversation...'}
339
- rows={1}
340
- className={cn(
341
- 'w-full resize-none rounded-lg px-3 py-1.5 text-xs',
342
- 'bg-surface-0 border font-sans',
343
- 'placeholder:text-text-4',
344
- 'focus:outline-none focus:ring-1',
345
- 'min-h-[32px] max-h-[120px]',
346
- 'border-border focus:ring-accent/40',
347
- input && /\[(?:save|append|update|delete|view|doc|link|read|instruct)\]/i.test(input)
348
- ? 'text-accent'
349
- : 'text-text-0',
350
- )}
351
- />
352
- </div>
353
- {isAlive && (
354
- <button
355
- onClick={() => useGrooveStore.getState().stopAgent(agent.id)}
356
- title="Stop agent"
357
- className="w-8 h-8 flex items-center justify-center rounded-lg transition-all cursor-pointer bg-danger/80 text-white hover:bg-danger flex-shrink-0"
358
- >
359
- <Square size={12} fill="currentColor" />
360
- </button>
361
- )}
362
- <button
363
- onClick={handleSend}
364
- disabled={(!input.trim() && !pendingSnippet) || sending}
365
- className={cn(
366
- 'w-8 h-8 flex items-center justify-center rounded-lg transition-all cursor-pointer flex-shrink-0',
367
- 'disabled:opacity-20 disabled:cursor-not-allowed',
368
- (input.trim() || pendingSnippet)
369
- ? 'bg-accent/15 text-accent hover:bg-accent/25 border border-accent/25'
370
- : 'bg-surface-4 text-text-4',
371
- )}
372
- >
373
- {sending ? <Loader2 size={14} className="animate-spin" /> : <Send size={14} />}
374
- </button>
375
- </div>
376
- </div>
377
- </div>
378
- );
379
- }
@@ -1,6 +0,0 @@
1
- // FSL-1.1-Apache-2.0 — see LICENSE
2
- import { PreviewWorkspace } from '../components/preview/preview-workspace';
3
-
4
- export default function PreviewView() {
5
- return <PreviewWorkspace />;
6
- }