groove-dev 0.22.4 → 0.22.6
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.
- package/node_modules/@groove-dev/gui/dist/assets/index-DHaSTu1c.css +1 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-DZxQV2hQ.js +574 -0
- package/node_modules/@groove-dev/gui/dist/index.html +2 -2
- package/node_modules/@groove-dev/gui/src/components/agents/agent-feed.jsx +182 -26
- package/node_modules/@groove-dev/gui/src/components/editor/code-editor.jsx +3 -2
- package/node_modules/@groove-dev/gui/src/components/editor/file-tree.jsx +296 -22
- package/package.json +1 -1
- package/packages/gui/dist/assets/index-DHaSTu1c.css +1 -0
- package/packages/gui/dist/assets/index-DZxQV2hQ.js +574 -0
- package/packages/gui/dist/index.html +2 -2
- package/packages/gui/src/components/agents/agent-feed.jsx +182 -26
- package/packages/gui/src/components/editor/code-editor.jsx +3 -2
- package/packages/gui/src/components/editor/file-tree.jsx +296 -22
- package/node_modules/@groove-dev/gui/dist/assets/index-BDyGhxDd.css +0 -1
- package/node_modules/@groove-dev/gui/dist/assets/index-BHDZqhzW.js +0 -562
- package/packages/gui/dist/assets/index-BDyGhxDd.css +0 -1
- package/packages/gui/dist/assets/index-BHDZqhzW.js +0 -562
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<link rel="icon" type="image/png" href="/favicon.png" />
|
|
7
7
|
<title>Groove GUI</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-DZxQV2hQ.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/vendor-C0HXlhrU.js">
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/reactflow-BQPfi37R.js">
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/codemirror-BBL3i_JW.js">
|
|
12
12
|
<link rel="modulepreload" crossorigin href="/assets/xterm--7_ns2zW.js">
|
|
13
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
13
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DHaSTu1c.css">
|
|
14
14
|
</head>
|
|
15
15
|
<body>
|
|
16
16
|
<div id="root"></div>
|
|
@@ -38,29 +38,162 @@ function activityMeta(text) {
|
|
|
38
38
|
return { icon: Code2, color: 'text-text-3', label: 'Activity' };
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
// ──
|
|
41
|
+
// ── Inline formatting (bold, code) ───────────────────────────
|
|
42
|
+
function InlineFormat({ text }) {
|
|
43
|
+
if (!text) return null;
|
|
44
|
+
return text.split(/(\*\*[^*]+\*\*|`[^`]+`)/g).map((part, i) => {
|
|
45
|
+
if (part.startsWith('**') && part.endsWith('**'))
|
|
46
|
+
return <strong key={i} className="font-semibold text-text-0">{part.slice(2, -2)}</strong>;
|
|
47
|
+
if (part.startsWith('`') && part.endsWith('`'))
|
|
48
|
+
return <code key={i} className="px-1 py-px rounded bg-accent/8 text-[11px] font-mono text-accent">{part.slice(1, -1)}</code>;
|
|
49
|
+
return <span key={i}>{part}</span>;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ── Structured message renderer ──────────────────────────────
|
|
54
|
+
// Parses agent output into sections: headers, bullets, code blocks, paragraphs
|
|
55
|
+
function StructuredMessage({ text }) {
|
|
56
|
+
if (!text) return null;
|
|
57
|
+
|
|
58
|
+
const blocks = [];
|
|
59
|
+
const lines = text.split('\n');
|
|
60
|
+
let i = 0;
|
|
61
|
+
|
|
62
|
+
while (i < lines.length) {
|
|
63
|
+
const line = lines[i];
|
|
64
|
+
|
|
65
|
+
// Code block
|
|
66
|
+
if (line.trimStart().startsWith('```')) {
|
|
67
|
+
const codeLines = [];
|
|
68
|
+
const lang = line.trim().slice(3);
|
|
69
|
+
i++;
|
|
70
|
+
while (i < lines.length && !lines[i].trimStart().startsWith('```')) {
|
|
71
|
+
codeLines.push(lines[i]);
|
|
72
|
+
i++;
|
|
73
|
+
}
|
|
74
|
+
i++; // skip closing ```
|
|
75
|
+
blocks.push({ type: 'code', content: codeLines.join('\n'), lang });
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Header (## or **Header:** at start of line)
|
|
80
|
+
if (/^#{1,3}\s/.test(line) || /^\*\*[^*]+:\*\*\s*$/.test(line.trim())) {
|
|
81
|
+
const heading = line.replace(/^#+\s*/, '').replace(/^\*\*/, '').replace(/:\*\*\s*$/, ':').trim();
|
|
82
|
+
blocks.push({ type: 'heading', content: heading });
|
|
83
|
+
i++;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Bullet / dash list item
|
|
88
|
+
if (/^\s*[-*]\s/.test(line)) {
|
|
89
|
+
const items = [];
|
|
90
|
+
while (i < lines.length && /^\s*[-*]\s/.test(lines[i])) {
|
|
91
|
+
items.push(lines[i].replace(/^\s*[-*]\s+/, '').trim());
|
|
92
|
+
i++;
|
|
93
|
+
}
|
|
94
|
+
blocks.push({ type: 'list', items });
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Numbered list
|
|
99
|
+
if (/^\s*\d+[\.)]\s/.test(line)) {
|
|
100
|
+
const items = [];
|
|
101
|
+
while (i < lines.length && /^\s*\d+[\.)]\s/.test(lines[i])) {
|
|
102
|
+
items.push(lines[i].replace(/^\s*\d+[\.)]\s+/, '').trim());
|
|
103
|
+
i++;
|
|
104
|
+
}
|
|
105
|
+
blocks.push({ type: 'numbered', items });
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Empty line — skip
|
|
110
|
+
if (!line.trim()) { i++; continue; }
|
|
111
|
+
|
|
112
|
+
// Note/warning line
|
|
113
|
+
if (/^(Note|Warning|Important|IMPORTANT|TODO):/i.test(line.trim())) {
|
|
114
|
+
blocks.push({ type: 'note', content: line.trim() });
|
|
115
|
+
i++;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Regular paragraph — collect consecutive non-empty lines
|
|
120
|
+
const paraLines = [];
|
|
121
|
+
while (i < lines.length && lines[i].trim() && !/^#{1,3}\s/.test(lines[i]) && !/^\s*[-*]\s/.test(lines[i]) && !/^\s*\d+[\.)]\s/.test(lines[i]) && !lines[i].trimStart().startsWith('```')) {
|
|
122
|
+
paraLines.push(lines[i].trim());
|
|
123
|
+
i++;
|
|
124
|
+
}
|
|
125
|
+
if (paraLines.length > 0) {
|
|
126
|
+
blocks.push({ type: 'para', content: paraLines.join(' ') });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<div className="space-y-2">
|
|
132
|
+
{blocks.map((block, idx) => {
|
|
133
|
+
switch (block.type) {
|
|
134
|
+
case 'heading':
|
|
135
|
+
return (
|
|
136
|
+
<div key={idx} className="flex items-center gap-1.5 pt-1.5 first:pt-0">
|
|
137
|
+
<div className="w-1 h-3.5 rounded-full bg-accent/40 flex-shrink-0" />
|
|
138
|
+
<span className="text-[12px] font-semibold text-text-0 font-sans"><InlineFormat text={block.content} /></span>
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
case 'list':
|
|
142
|
+
return (
|
|
143
|
+
<div key={idx} className="space-y-1 pl-2">
|
|
144
|
+
{block.items.map((item, j) => (
|
|
145
|
+
<div key={j} className="flex gap-2 text-[12px] text-text-2 font-sans leading-relaxed">
|
|
146
|
+
<span className="text-accent/50 mt-0.5 flex-shrink-0">-</span>
|
|
147
|
+
<span className="min-w-0"><InlineFormat text={item} /></span>
|
|
148
|
+
</div>
|
|
149
|
+
))}
|
|
150
|
+
</div>
|
|
151
|
+
);
|
|
152
|
+
case 'numbered':
|
|
153
|
+
return (
|
|
154
|
+
<div key={idx} className="space-y-1 pl-2">
|
|
155
|
+
{block.items.map((item, j) => (
|
|
156
|
+
<div key={j} className="flex gap-2 text-[12px] text-text-2 font-sans leading-relaxed">
|
|
157
|
+
<span className="text-text-4 font-mono w-4 text-right flex-shrink-0">{j + 1}.</span>
|
|
158
|
+
<span className="min-w-0"><InlineFormat text={item} /></span>
|
|
159
|
+
</div>
|
|
160
|
+
))}
|
|
161
|
+
</div>
|
|
162
|
+
);
|
|
163
|
+
case 'code':
|
|
164
|
+
return (
|
|
165
|
+
<pre key={idx} className="p-2.5 rounded-md bg-[#0d1117] text-[11px] font-mono text-[#c9d1d9] overflow-x-auto whitespace-pre-wrap border border-white/[0.06] leading-relaxed">
|
|
166
|
+
{block.content}
|
|
167
|
+
</pre>
|
|
168
|
+
);
|
|
169
|
+
case 'note':
|
|
170
|
+
return (
|
|
171
|
+
<div key={idx} className="flex items-start gap-1.5 px-2.5 py-1.5 rounded-md bg-warning/6 border border-warning/12">
|
|
172
|
+
<AlertCircle size={10} className="text-warning mt-0.5 flex-shrink-0" />
|
|
173
|
+
<span className="text-[11px] text-warning/80 font-sans"><InlineFormat text={block.content} /></span>
|
|
174
|
+
</div>
|
|
175
|
+
);
|
|
176
|
+
case 'para':
|
|
177
|
+
default:
|
|
178
|
+
return <p key={idx} className="text-[12px] text-text-2 font-sans leading-relaxed"><InlineFormat text={block.content} /></p>;
|
|
179
|
+
}
|
|
180
|
+
})}
|
|
181
|
+
</div>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Simple inline formatting for user messages
|
|
42
186
|
function FormattedText({ text }) {
|
|
43
187
|
if (!text) return null;
|
|
44
|
-
const parts = text.split(/(```[\s\S]
|
|
188
|
+
const parts = text.split(/(```[\s\S]*?```)/g);
|
|
45
189
|
return (
|
|
46
190
|
<span>
|
|
47
191
|
{parts.map((part, i) => {
|
|
48
192
|
if (part.startsWith('```') && part.endsWith('```')) {
|
|
49
193
|
const code = part.slice(3, -3).replace(/^\w+\n/, '');
|
|
50
|
-
return
|
|
51
|
-
<pre key={i} className="my-2.5 p-3.5 rounded-lg bg-[#0d1117] text-[12px] font-mono text-[#c9d1d9] overflow-x-auto whitespace-pre-wrap border border-white/[0.06] leading-relaxed">
|
|
52
|
-
{code}
|
|
53
|
-
</pre>
|
|
54
|
-
);
|
|
194
|
+
return <pre key={i} className="my-1.5 p-2 rounded-md bg-[#0d1117] text-[11px] font-mono text-[#c9d1d9] overflow-x-auto whitespace-pre-wrap border border-white/[0.06]">{code}</pre>;
|
|
55
195
|
}
|
|
56
|
-
|
|
57
|
-
return <code key={i} className="px-1.5 py-0.5 rounded bg-accent/8 text-[12px] font-mono text-accent border border-accent/10">{part.slice(1, -1)}</code>;
|
|
58
|
-
}
|
|
59
|
-
return <span key={i}>{part.split(/(\*\*[^*]+\*\*)/g).map((s, j) =>
|
|
60
|
-
s.startsWith('**') && s.endsWith('**')
|
|
61
|
-
? <strong key={j} className="font-semibold text-text-0">{s.slice(2, -2)}</strong>
|
|
62
|
-
: s
|
|
63
|
-
)}</span>;
|
|
196
|
+
return <span key={i}><InlineFormat text={part} /></span>;
|
|
64
197
|
})}
|
|
65
198
|
</span>
|
|
66
199
|
);
|
|
@@ -71,8 +204,8 @@ function FormattedText({ text }) {
|
|
|
71
204
|
function UserMessage({ msg }) {
|
|
72
205
|
const isQuery = msg.isQuery;
|
|
73
206
|
return (
|
|
74
|
-
<div className="flex justify-end pl-
|
|
75
|
-
<div className="max-w-[
|
|
207
|
+
<div className="flex justify-end pl-8">
|
|
208
|
+
<div className="max-w-[90%]">
|
|
76
209
|
{isQuery && (
|
|
77
210
|
<div className="flex items-center justify-end gap-1 mb-1">
|
|
78
211
|
<HelpCircle size={9} className="text-info" />
|
|
@@ -80,24 +213,27 @@ function UserMessage({ msg }) {
|
|
|
80
213
|
</div>
|
|
81
214
|
)}
|
|
82
215
|
<div className={cn(
|
|
83
|
-
'px-
|
|
216
|
+
'px-3.5 py-2.5 rounded-2xl rounded-br-md',
|
|
84
217
|
isQuery
|
|
85
218
|
? 'bg-info/10 border border-info/15'
|
|
86
219
|
: 'bg-accent/10 border border-accent/15',
|
|
87
220
|
)}>
|
|
88
|
-
<div className="text-[
|
|
221
|
+
<div className="text-[12px] font-sans whitespace-pre-wrap break-words leading-relaxed text-text-0">
|
|
89
222
|
<FormattedText text={msg.text} />
|
|
90
223
|
</div>
|
|
91
224
|
</div>
|
|
92
|
-
<div className="text-[10px] text-text-4 font-sans mt-1
|
|
225
|
+
<div className="text-[10px] text-text-4 font-sans mt-1 text-right">{timeAgo(msg.timestamp)}</div>
|
|
93
226
|
</div>
|
|
94
227
|
</div>
|
|
95
228
|
);
|
|
96
229
|
}
|
|
97
230
|
|
|
98
231
|
function AgentMessage({ msg, agent }) {
|
|
232
|
+
const [collapsed, setCollapsed] = useState(msg.text?.length > 600);
|
|
233
|
+
const isLong = msg.text?.length > 600;
|
|
234
|
+
|
|
99
235
|
return (
|
|
100
|
-
<div className="pr-
|
|
236
|
+
<div className="pr-2">
|
|
101
237
|
<div className="flex items-center gap-2 mb-1.5">
|
|
102
238
|
<div className="w-5 h-5 rounded-md bg-accent/12 flex items-center justify-center flex-shrink-0">
|
|
103
239
|
<Code2 size={10} className="text-accent" />
|
|
@@ -105,12 +241,32 @@ function AgentMessage({ msg, agent }) {
|
|
|
105
241
|
<span className="text-2xs font-semibold text-text-1 font-sans">{agent?.name || 'Agent'}</span>
|
|
106
242
|
<span className="text-2xs text-text-4 font-sans">{agent?.role}</span>
|
|
107
243
|
</div>
|
|
108
|
-
<div className=
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
244
|
+
<div className={cn(
|
|
245
|
+
'ml-7 px-3.5 py-3 rounded-xl bg-surface-2/40 border border-border-subtle/50 overflow-hidden',
|
|
246
|
+
collapsed && 'max-h-[200px] relative',
|
|
247
|
+
)}>
|
|
248
|
+
<StructuredMessage text={collapsed ? msg.text.slice(0, 600) : msg.text} />
|
|
249
|
+
{collapsed && (
|
|
250
|
+
<div className="absolute bottom-0 left-0 right-0 h-16 bg-gradient-to-t from-surface-2/90 to-transparent flex items-end justify-center pb-2">
|
|
251
|
+
<button
|
|
252
|
+
onClick={() => setCollapsed(false)}
|
|
253
|
+
className="flex items-center gap-1 px-3 py-1 rounded-full bg-surface-3 border border-border-subtle text-2xs text-text-2 font-sans hover:text-text-0 cursor-pointer transition-colors"
|
|
254
|
+
>
|
|
255
|
+
<ChevronDown size={10} />
|
|
256
|
+
Show full response
|
|
257
|
+
</button>
|
|
258
|
+
</div>
|
|
259
|
+
)}
|
|
112
260
|
</div>
|
|
113
|
-
|
|
261
|
+
{isLong && !collapsed && (
|
|
262
|
+
<button
|
|
263
|
+
onClick={() => setCollapsed(true)}
|
|
264
|
+
className="ml-7 mt-1 text-[10px] text-text-4 hover:text-text-2 font-sans cursor-pointer"
|
|
265
|
+
>
|
|
266
|
+
Collapse
|
|
267
|
+
</button>
|
|
268
|
+
)}
|
|
269
|
+
<div className="text-[10px] text-text-4 font-sans mt-1 ml-7">{timeAgo(msg.timestamp)}</div>
|
|
114
270
|
</div>
|
|
115
271
|
);
|
|
116
272
|
}
|
|
@@ -26,7 +26,8 @@ const LANGS = {
|
|
|
26
26
|
|
|
27
27
|
// Custom theme overrides to match our design tokens
|
|
28
28
|
const grooveTheme = EditorView.theme({
|
|
29
|
-
'&': { backgroundColor: '#24282f', color: '#bcc2cd', fontFamily: 'var(--font-mono)', fontSize: '13px' },
|
|
29
|
+
'&': { backgroundColor: '#24282f', color: '#bcc2cd', fontFamily: 'var(--font-mono)', fontSize: '13px', height: '100%' },
|
|
30
|
+
'.cm-scroller': { overflow: 'auto' },
|
|
30
31
|
'.cm-content': { caretColor: '#33afbc' },
|
|
31
32
|
'.cm-cursor': { borderLeftColor: '#33afbc' },
|
|
32
33
|
'.cm-gutters': { backgroundColor: '#24282f', borderRight: '1px solid #2c313a', color: '#505862' },
|
|
@@ -103,5 +104,5 @@ export function CodeEditor({ content, language, onChange, onSave }) {
|
|
|
103
104
|
view.dispatch({ effects: langCompartment.current.reconfigure(langExt()) });
|
|
104
105
|
}, [language]);
|
|
105
106
|
|
|
106
|
-
return <div ref={containerRef} className="w-full h-full" />;
|
|
107
|
+
return <div ref={containerRef} className="w-full h-full overflow-hidden" />;
|
|
107
108
|
}
|