groove-dev 0.27.142 → 0.27.144
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/cli/package.json +1 -1
- package/node_modules/@groove-dev/daemon/package.json +1 -1
- package/node_modules/@groove-dev/daemon/src/api.js +1086 -6532
- package/node_modules/@groove-dev/daemon/src/gateways/manager.js +35 -1
- package/node_modules/@groove-dev/daemon/src/index.js +3 -0
- package/node_modules/@groove-dev/daemon/src/journalist.js +23 -13
- package/node_modules/@groove-dev/daemon/src/mlx-server.js +365 -0
- package/node_modules/@groove-dev/daemon/src/model-lab.js +308 -12
- package/node_modules/@groove-dev/daemon/src/pm.js +1 -1
- package/node_modules/@groove-dev/daemon/src/process.js +2 -2
- package/node_modules/@groove-dev/daemon/src/providers/local.js +36 -8
- package/node_modules/@groove-dev/daemon/src/registry.js +21 -5
- package/node_modules/@groove-dev/daemon/src/routes/agents.js +889 -0
- package/node_modules/@groove-dev/daemon/src/routes/coordination.js +318 -0
- package/node_modules/@groove-dev/daemon/src/routes/files.js +751 -0
- package/node_modules/@groove-dev/daemon/src/routes/integrations.js +485 -0
- package/node_modules/@groove-dev/daemon/src/routes/network.js +1784 -0
- package/node_modules/@groove-dev/daemon/src/routes/providers.js +755 -0
- package/node_modules/@groove-dev/daemon/src/routes/schedules.js +110 -0
- package/node_modules/@groove-dev/daemon/src/routes/teams.js +650 -0
- package/node_modules/@groove-dev/daemon/src/scheduler.js +456 -24
- package/node_modules/@groove-dev/daemon/src/teams.js +1 -1
- package/node_modules/@groove-dev/daemon/src/validate.js +38 -1
- package/node_modules/@groove-dev/daemon/templates/mlx-setup.json +12 -0
- package/node_modules/@groove-dev/daemon/templates/tgi-setup.json +1 -1
- package/node_modules/@groove-dev/daemon/templates/vllm-setup.json +1 -1
- package/node_modules/@groove-dev/daemon/test/introducer.test.js +3 -3
- package/node_modules/@groove-dev/daemon/test/journalist.test.js +7 -10
- package/node_modules/@groove-dev/daemon/test/registry.test.js +38 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-BcoF6_eF.js +1012 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-Dd7qhiEd.css +1 -0
- package/node_modules/@groove-dev/gui/dist/index.html +2 -2
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/{packages/gui/src/app.jsx → node_modules/@groove-dev/gui/src/App.jsx} +0 -2
- package/node_modules/@groove-dev/gui/src/app.css +35 -0
- package/node_modules/@groove-dev/gui/src/components/agents/agent-config.jsx +1 -128
- package/node_modules/@groove-dev/gui/src/components/agents/agent-feed.jsx +144 -31
- package/node_modules/@groove-dev/gui/src/components/agents/agent-node.jsx +8 -13
- package/node_modules/@groove-dev/gui/src/components/agents/code-review.jsx +159 -122
- package/node_modules/@groove-dev/gui/src/components/agents/diff-viewer.jsx +23 -23
- package/node_modules/@groove-dev/gui/src/components/agents/journalist-panel.jsx +1 -1
- package/node_modules/@groove-dev/gui/src/components/agents/spawn-wizard.jsx +2 -135
- package/node_modules/@groove-dev/gui/src/components/automations/automation-card.jsx +274 -0
- package/node_modules/@groove-dev/gui/src/components/automations/automation-wizard.jsx +1136 -0
- package/node_modules/@groove-dev/gui/src/components/dashboard/activity-feed.jsx +3 -3
- package/node_modules/@groove-dev/gui/src/components/dashboard/cache-ring.jsx +5 -5
- package/node_modules/@groove-dev/gui/src/components/dashboard/context-gauges.jsx +6 -8
- package/node_modules/@groove-dev/gui/src/components/dashboard/fleet-panel.jsx +8 -14
- package/node_modules/@groove-dev/gui/src/components/dashboard/intel-panel.jsx +238 -656
- package/node_modules/@groove-dev/gui/src/components/dashboard/kpi-card.jsx +3 -3
- package/node_modules/@groove-dev/gui/src/components/dashboard/routing-chart.jsx +3 -3
- package/node_modules/@groove-dev/gui/src/components/dashboard/team-burn-panel.jsx +1 -1
- package/node_modules/@groove-dev/gui/src/components/dashboard/token-chart.jsx +4 -4
- package/node_modules/@groove-dev/gui/src/components/editor/selection-menu.jsx +2 -0
- package/node_modules/@groove-dev/gui/src/components/lab/lab-assistant.jsx +316 -82
- package/node_modules/@groove-dev/gui/src/components/lab/metrics-panel.jsx +187 -32
- package/node_modules/@groove-dev/gui/src/components/lab/parameter-panel.jsx +195 -14
- package/node_modules/@groove-dev/gui/src/components/lab/runtime-config.jsx +286 -102
- package/node_modules/@groove-dev/gui/src/components/layout/activity-bar.jsx +2 -4
- package/node_modules/@groove-dev/gui/src/components/layout/terminal-panel.jsx +4 -2
- package/node_modules/@groove-dev/gui/src/components/layout/welcome-splash.jsx +137 -108
- package/node_modules/@groove-dev/gui/src/components/network/network-health.jsx +2 -2
- package/node_modules/@groove-dev/gui/src/components/network/performance-dashboard.jsx +4 -4
- package/node_modules/@groove-dev/gui/src/components/settings/ssh-wizard.jsx +81 -99
- package/node_modules/@groove-dev/gui/src/components/ui/sheet.jsx +5 -2
- package/node_modules/@groove-dev/gui/src/lib/cron.js +64 -0
- package/node_modules/@groove-dev/gui/src/lib/status.js +24 -24
- package/node_modules/@groove-dev/gui/src/lib/theme-hex.js +1 -0
- package/node_modules/@groove-dev/gui/src/stores/groove.js +34 -3144
- package/node_modules/@groove-dev/gui/src/stores/helpers.js +10 -0
- package/node_modules/@groove-dev/gui/src/stores/slices/agents-slice.js +452 -0
- package/node_modules/@groove-dev/gui/src/stores/slices/automations-slice.js +96 -0
- package/node_modules/@groove-dev/gui/src/stores/slices/chat-slice.js +227 -0
- package/node_modules/@groove-dev/gui/src/stores/slices/editor-slice.js +285 -0
- package/node_modules/@groove-dev/gui/src/stores/slices/marketplace-slice.js +461 -0
- package/node_modules/@groove-dev/gui/src/stores/slices/network-slice.js +361 -0
- package/node_modules/@groove-dev/gui/src/stores/slices/preview-slice.js +109 -0
- package/node_modules/@groove-dev/gui/src/stores/slices/providers-slice.js +897 -0
- package/node_modules/@groove-dev/gui/src/stores/slices/teams-slice.js +413 -0
- package/node_modules/@groove-dev/gui/src/stores/slices/ui-slice.js +98 -0
- package/node_modules/@groove-dev/gui/src/views/agents.jsx +5 -5
- package/node_modules/@groove-dev/gui/src/views/dashboard.jsx +12 -13
- package/node_modules/@groove-dev/gui/src/views/marketplace.jsx +191 -3
- package/node_modules/@groove-dev/gui/src/views/model-lab.jsx +17 -6
- package/node_modules/@groove-dev/gui/src/views/models.jsx +410 -509
- package/node_modules/@groove-dev/gui/src/views/network.jsx +3 -3
- package/node_modules/@groove-dev/gui/src/views/settings.jsx +81 -94
- package/node_modules/@groove-dev/gui/src/views/teams.jsx +40 -483
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/api.js +1086 -6532
- package/packages/daemon/src/gateways/manager.js +35 -1
- package/packages/daemon/src/index.js +3 -0
- package/packages/daemon/src/journalist.js +23 -13
- package/packages/daemon/src/mlx-server.js +365 -0
- package/packages/daemon/src/model-lab.js +308 -12
- package/packages/daemon/src/pm.js +1 -1
- package/packages/daemon/src/process.js +2 -2
- package/packages/daemon/src/providers/local.js +36 -8
- package/packages/daemon/src/registry.js +21 -5
- package/packages/daemon/src/routes/agents.js +889 -0
- package/packages/daemon/src/routes/coordination.js +318 -0
- package/packages/daemon/src/routes/files.js +751 -0
- package/packages/daemon/src/routes/integrations.js +485 -0
- package/packages/daemon/src/routes/network.js +1784 -0
- package/packages/daemon/src/routes/providers.js +755 -0
- package/packages/daemon/src/routes/schedules.js +110 -0
- package/packages/daemon/src/routes/teams.js +650 -0
- package/packages/daemon/src/scheduler.js +456 -24
- package/packages/daemon/src/teams.js +1 -1
- package/packages/daemon/src/validate.js +38 -1
- package/packages/daemon/templates/mlx-setup.json +12 -0
- package/packages/daemon/templates/tgi-setup.json +1 -1
- package/packages/daemon/templates/vllm-setup.json +1 -1
- package/packages/gui/dist/assets/index-BcoF6_eF.js +1012 -0
- package/packages/gui/dist/assets/index-Dd7qhiEd.css +1 -0
- package/packages/gui/dist/index.html +2 -2
- package/packages/gui/package.json +1 -1
- package/{node_modules/@groove-dev/gui/src/app.jsx → packages/gui/src/App.jsx} +0 -2
- package/packages/gui/src/app.css +35 -0
- package/packages/gui/src/components/agents/agent-config.jsx +1 -128
- package/packages/gui/src/components/agents/agent-feed.jsx +144 -31
- package/packages/gui/src/components/agents/agent-node.jsx +8 -13
- package/packages/gui/src/components/agents/code-review.jsx +159 -122
- package/packages/gui/src/components/agents/diff-viewer.jsx +23 -23
- package/packages/gui/src/components/agents/journalist-panel.jsx +1 -1
- package/packages/gui/src/components/agents/spawn-wizard.jsx +2 -135
- package/packages/gui/src/components/automations/automation-card.jsx +274 -0
- package/packages/gui/src/components/automations/automation-wizard.jsx +1136 -0
- package/packages/gui/src/components/dashboard/activity-feed.jsx +3 -3
- package/packages/gui/src/components/dashboard/cache-ring.jsx +5 -5
- package/packages/gui/src/components/dashboard/context-gauges.jsx +6 -8
- package/packages/gui/src/components/dashboard/fleet-panel.jsx +8 -14
- package/packages/gui/src/components/dashboard/intel-panel.jsx +238 -656
- package/packages/gui/src/components/dashboard/kpi-card.jsx +3 -3
- package/packages/gui/src/components/dashboard/routing-chart.jsx +3 -3
- package/packages/gui/src/components/dashboard/team-burn-panel.jsx +1 -1
- package/packages/gui/src/components/dashboard/token-chart.jsx +4 -4
- package/packages/gui/src/components/editor/selection-menu.jsx +2 -0
- package/packages/gui/src/components/lab/lab-assistant.jsx +316 -82
- package/packages/gui/src/components/lab/metrics-panel.jsx +187 -32
- package/packages/gui/src/components/lab/parameter-panel.jsx +195 -14
- package/packages/gui/src/components/lab/runtime-config.jsx +286 -102
- package/packages/gui/src/components/layout/activity-bar.jsx +2 -4
- package/packages/gui/src/components/layout/terminal-panel.jsx +4 -2
- package/packages/gui/src/components/layout/welcome-splash.jsx +137 -108
- package/packages/gui/src/components/network/network-health.jsx +2 -2
- package/packages/gui/src/components/network/performance-dashboard.jsx +4 -4
- package/packages/gui/src/components/settings/ssh-wizard.jsx +81 -99
- package/packages/gui/src/components/ui/sheet.jsx +5 -2
- package/packages/gui/src/lib/cron.js +64 -0
- package/packages/gui/src/lib/status.js +24 -24
- package/packages/gui/src/lib/theme-hex.js +1 -0
- package/packages/gui/src/stores/groove.js +34 -3144
- package/packages/gui/src/stores/helpers.js +10 -0
- package/packages/gui/src/stores/slices/agents-slice.js +452 -0
- package/packages/gui/src/stores/slices/automations-slice.js +96 -0
- package/packages/gui/src/stores/slices/chat-slice.js +227 -0
- package/packages/gui/src/stores/slices/editor-slice.js +285 -0
- package/packages/gui/src/stores/slices/marketplace-slice.js +461 -0
- package/packages/gui/src/stores/slices/network-slice.js +361 -0
- package/packages/gui/src/stores/slices/preview-slice.js +109 -0
- package/packages/gui/src/stores/slices/providers-slice.js +897 -0
- package/packages/gui/src/stores/slices/teams-slice.js +413 -0
- package/packages/gui/src/stores/slices/ui-slice.js +98 -0
- package/packages/gui/src/views/agents.jsx +5 -5
- package/packages/gui/src/views/dashboard.jsx +12 -13
- package/packages/gui/src/views/marketplace.jsx +191 -3
- package/packages/gui/src/views/model-lab.jsx +17 -6
- package/packages/gui/src/views/models.jsx +410 -509
- package/packages/gui/src/views/network.jsx +3 -3
- package/packages/gui/src/views/settings.jsx +81 -94
- package/packages/gui/src/views/teams.jsx +40 -483
- package/SECURITY_SWEEP.md +0 -228
- package/TRAINING_DATA_v4.md +0 -6
- package/node_modules/@groove-dev/gui/dist/assets/index-Bjd91ufV.js +0 -984
- package/node_modules/@groove-dev/gui/dist/assets/index-BqdwIFn4.css +0 -1
- package/node_modules/@groove-dev/gui/src/components/agents/agent-chat.jsx +0 -322
- package/node_modules/@groove-dev/gui/src/views/preview.jsx +0 -6
- package/node_modules/@groove-dev/gui/src/views/subscription-panel.jsx +0 -327
- package/packages/gui/dist/assets/index-Bjd91ufV.js +0 -984
- package/packages/gui/dist/assets/index-BqdwIFn4.css +0 -1
- package/packages/gui/src/components/agents/agent-chat.jsx +0 -322
- package/packages/gui/src/views/preview.jsx +0 -6
- package/packages/gui/src/views/subscription-panel.jsx +0 -327
- package/test.py +0 -571
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
FileEdit, Search, Terminal, CheckCircle2, AlertCircle,
|
|
6
6
|
RotateCw, Zap, Wrench, Eye, Code2, Bug,
|
|
7
7
|
ChevronDown, HelpCircle, Pencil, Paperclip, GripHorizontal,
|
|
8
|
+
FileCode, X,
|
|
8
9
|
} from 'lucide-react';
|
|
9
10
|
import { AnimatePresence, motion } from 'framer-motion';
|
|
10
11
|
import { useGrooveStore } from '../../stores/groove';
|
|
@@ -15,6 +16,18 @@ import { ThinkingIndicator } from '../ui/thinking-indicator';
|
|
|
15
16
|
import { TableTree } from '../ui/table-tree';
|
|
16
17
|
|
|
17
18
|
const EMPTY = [];
|
|
19
|
+
const KEEPER_RE = /(\[(?:save|append|update|delete|view|doc|link|read|instruct)\]|#[\w/.-]+)/gi;
|
|
20
|
+
const KEEPER_CMD_RE = /^\[(?:save|append|update|delete|view|doc|link|read|instruct)\]$/i;
|
|
21
|
+
const KEEPER_TAG_RE = /^#[\w/.-]+$/;
|
|
22
|
+
const KEEPER_DETECT_RE = /\[(?:save|append|update|delete|view|doc|link|read|instruct)\]|#[\w/.-]+/i;
|
|
23
|
+
|
|
24
|
+
function highlightKeeperInput(text) {
|
|
25
|
+
return text.split(KEEPER_RE).map((part, i) => {
|
|
26
|
+
if (KEEPER_CMD_RE.test(part)) return <span key={i} className="text-accent font-semibold">{part}</span>;
|
|
27
|
+
if (KEEPER_TAG_RE.test(part)) return <span key={i} className="text-accent">{part}</span>;
|
|
28
|
+
return <span key={i} className="text-text-0">{part}</span>;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
18
31
|
|
|
19
32
|
// ── Activity metadata ────────────────────────────────────────
|
|
20
33
|
function activityMeta(text) {
|
|
@@ -369,7 +382,7 @@ function StreamingBar({ agent }) {
|
|
|
369
382
|
<div className="flex items-center gap-3 px-4 h-8 border-b border-border-subtle bg-surface-1/80 flex-shrink-0">
|
|
370
383
|
<div className="flex items-center gap-2 flex-1 min-w-0">
|
|
371
384
|
<div className="relative flex items-center justify-center w-4 h-4">
|
|
372
|
-
<span className="absolute inset-0 rounded-full bg-accent/15 animate-ping
|
|
385
|
+
<span className="absolute inset-0 rounded-full bg-accent/15 animate-ping [animation-duration:2s]" />
|
|
373
386
|
<span className="relative w-1.5 h-1.5 rounded-full bg-accent" />
|
|
374
387
|
</div>
|
|
375
388
|
{isRecent ? (
|
|
@@ -432,8 +445,8 @@ function BootSequence({ agent }) {
|
|
|
432
445
|
{/* Agent identity */}
|
|
433
446
|
<div className="flex items-center gap-3 mb-5">
|
|
434
447
|
<div className="relative w-9 h-9">
|
|
435
|
-
<span className="absolute inset-0 rounded-full border-2 border-accent/20 animate-ping
|
|
436
|
-
<span className="absolute inset-0 rounded-full border-2 border-transparent border-t-accent animate-spin
|
|
448
|
+
<span className="absolute inset-0 rounded-full border-2 border-accent/20 animate-ping [animation-duration:2s]" />
|
|
449
|
+
<span className="absolute inset-0 rounded-full border-2 border-transparent border-t-accent animate-spin [animation-duration:1s]" />
|
|
437
450
|
<span className="absolute inset-[5px] rounded-full bg-accent/8" />
|
|
438
451
|
</div>
|
|
439
452
|
<div>
|
|
@@ -467,9 +480,9 @@ function BootSequence({ agent }) {
|
|
|
467
480
|
</span>
|
|
468
481
|
{isLast && visible && (
|
|
469
482
|
<span className="flex gap-0.5 ml-1">
|
|
470
|
-
<span className="w-1 h-1 rounded-full bg-accent animate-pulse
|
|
471
|
-
<span className="w-1 h-1 rounded-full bg-accent animate-pulse
|
|
472
|
-
<span className="w-1 h-1 rounded-full bg-accent animate-pulse
|
|
483
|
+
<span className="w-1 h-1 rounded-full bg-accent animate-pulse [animation-delay:0ms]" />
|
|
484
|
+
<span className="w-1 h-1 rounded-full bg-accent animate-pulse [animation-delay:200ms]" />
|
|
485
|
+
<span className="w-1 h-1 rounded-full bg-accent animate-pulse [animation-delay:400ms]" />
|
|
473
486
|
</span>
|
|
474
487
|
)}
|
|
475
488
|
</div>
|
|
@@ -480,6 +493,33 @@ function BootSequence({ agent }) {
|
|
|
480
493
|
);
|
|
481
494
|
}
|
|
482
495
|
|
|
496
|
+
// ── Snippet Tag ─────────────────────────────────────────────
|
|
497
|
+
|
|
498
|
+
function SnippetTag({ snippet, onRemove }) {
|
|
499
|
+
const isCode = snippet.type === 'code';
|
|
500
|
+
const Icon = isCode ? FileCode : Terminal;
|
|
501
|
+
const lines = snippet.code.split('\n').length;
|
|
502
|
+
let label;
|
|
503
|
+
if (isCode && snippet.filePath) {
|
|
504
|
+
const fileName = snippet.filePath.split('/').pop();
|
|
505
|
+
label = `${fileName}:${snippet.lineStart}-${snippet.lineEnd}`;
|
|
506
|
+
} else {
|
|
507
|
+
label = `${isCode ? '' : 'Terminal · '}${lines} line${lines !== 1 ? 's' : ''}`;
|
|
508
|
+
}
|
|
509
|
+
return (
|
|
510
|
+
<div className="flex items-center gap-1.5 px-2 py-1 rounded-md bg-accent/10 border border-accent/20 text-accent">
|
|
511
|
+
<Icon size={11} className="flex-shrink-0" />
|
|
512
|
+
<span className="text-2xs font-sans font-medium truncate max-w-[160px]">{label}</span>
|
|
513
|
+
{snippet.instruction && (
|
|
514
|
+
<span className="text-2xs text-accent/60 truncate max-w-[100px]">· {snippet.instruction}</span>
|
|
515
|
+
)}
|
|
516
|
+
<button onClick={onRemove} className="p-0.5 rounded hover:bg-accent/20 cursor-pointer flex-shrink-0">
|
|
517
|
+
<X size={9} />
|
|
518
|
+
</button>
|
|
519
|
+
</div>
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
|
|
483
523
|
// ── Main Feed ────────────────────────────────────────────────
|
|
484
524
|
|
|
485
525
|
export function AgentFeed({ agent }) {
|
|
@@ -495,8 +535,15 @@ export function AgentFeed({ agent }) {
|
|
|
495
535
|
const chatHistory = rawChatHistory.length > 0 ? rawChatHistory : cachedChatRef.current;
|
|
496
536
|
const activityLog = rawActivityLog.length > 0 ? rawActivityLog : cachedActivityRef.current;
|
|
497
537
|
|
|
538
|
+
const pendingSnippet = useGrooveStore((s) => s.editorPendingSnippet);
|
|
539
|
+
const clearSnippet = useGrooveStore((s) => s.clearSnippet);
|
|
540
|
+
|
|
498
541
|
const storeInput = useGrooveStore((s) => s.chatInputs[agent.id] || '');
|
|
499
|
-
const setStoreInput = (val) => useGrooveStore.setState((s) =>
|
|
542
|
+
const setStoreInput = (val) => useGrooveStore.setState((s) => {
|
|
543
|
+
const current = s.chatInputs[agent.id] || '';
|
|
544
|
+
const next = typeof val === 'function' ? val(current) : val;
|
|
545
|
+
return { chatInputs: { ...s.chatInputs, [agent.id]: next } };
|
|
546
|
+
});
|
|
500
547
|
const input = storeInput;
|
|
501
548
|
const setInput = setStoreInput;
|
|
502
549
|
const [mode, setMode] = useState('instruct'); // instruct | query
|
|
@@ -506,8 +553,13 @@ export function AgentFeed({ agent }) {
|
|
|
506
553
|
const scrollRef = useRef(null);
|
|
507
554
|
const inputRef = useRef(null);
|
|
508
555
|
const fileInputRef = useRef(null);
|
|
556
|
+
const highlightRef = useRef(null);
|
|
509
557
|
const isAtBottomRef = useRef(true);
|
|
510
558
|
|
|
559
|
+
useEffect(() => {
|
|
560
|
+
if (pendingSnippet) inputRef.current?.focus();
|
|
561
|
+
}, [pendingSnippet]);
|
|
562
|
+
|
|
511
563
|
useEffect(() => {
|
|
512
564
|
const el = scrollRef.current;
|
|
513
565
|
if (!el) return;
|
|
@@ -616,7 +668,7 @@ export function AgentFeed({ agent }) {
|
|
|
616
668
|
|
|
617
669
|
async function handleSend() {
|
|
618
670
|
const text = input.trim();
|
|
619
|
-
if (!text || sending) return;
|
|
671
|
+
if ((!text && !pendingSnippet) || sending) return;
|
|
620
672
|
|
|
621
673
|
if (text === '/rotate') {
|
|
622
674
|
const rotateAgent = useGrooveStore.getState().rotateAgent;
|
|
@@ -625,7 +677,22 @@ export function AgentFeed({ agent }) {
|
|
|
625
677
|
return;
|
|
626
678
|
}
|
|
627
679
|
|
|
680
|
+
const parts = [];
|
|
681
|
+
if (text) parts.push(text);
|
|
682
|
+
if (pendingSnippet) {
|
|
683
|
+
const s = pendingSnippet;
|
|
684
|
+
if (s.type === 'code' && s.filePath) {
|
|
685
|
+
if (s.instruction && !text) parts.push(s.instruction);
|
|
686
|
+
parts.push(`File: ${s.filePath} (lines ${s.lineStart}-${s.lineEnd})`);
|
|
687
|
+
parts.push('```\n' + s.code + '\n```');
|
|
688
|
+
} else if (s.code) {
|
|
689
|
+
parts.push('```\n' + s.code + '\n```');
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
const message = parts.join('\n\n');
|
|
693
|
+
|
|
628
694
|
setInput('');
|
|
695
|
+
clearSnippet();
|
|
629
696
|
setSending(true);
|
|
630
697
|
isAtBottomRef.current = true;
|
|
631
698
|
requestAnimationFrame(() => {
|
|
@@ -633,9 +700,9 @@ export function AgentFeed({ agent }) {
|
|
|
633
700
|
});
|
|
634
701
|
try {
|
|
635
702
|
if (mode === 'query') {
|
|
636
|
-
await queryAgent(agent.id,
|
|
703
|
+
await queryAgent(agent.id, message);
|
|
637
704
|
} else {
|
|
638
|
-
await instructAgent(agent.id,
|
|
705
|
+
await instructAgent(agent.id, message);
|
|
639
706
|
}
|
|
640
707
|
} catch { /* toast handles */ }
|
|
641
708
|
setSending(false);
|
|
@@ -707,6 +774,26 @@ export function AgentFeed({ agent }) {
|
|
|
707
774
|
</div>
|
|
708
775
|
|
|
709
776
|
<div className="px-4 pb-3">
|
|
777
|
+
{/* Snippet tag */}
|
|
778
|
+
{pendingSnippet && (
|
|
779
|
+
<div className="mb-2">
|
|
780
|
+
<SnippetTag snippet={pendingSnippet} onRemove={clearSnippet} />
|
|
781
|
+
</div>
|
|
782
|
+
)}
|
|
783
|
+
|
|
784
|
+
{/* Keeper command indicator */}
|
|
785
|
+
{input && /\[(?:save|append|update|delete|view|doc|link|read|instruct)\]/i.test(input) && (() => {
|
|
786
|
+
const cmdMatch = input.match(/\[(save|append|update|delete|view|doc|link|read|instruct)\]/i);
|
|
787
|
+
const tags = (input.match(/#[\w/.-]+/g) || []);
|
|
788
|
+
return (
|
|
789
|
+
<div className="flex items-center gap-1.5 px-3 py-1 mb-2 rounded-lg bg-accent/5 border border-accent/10">
|
|
790
|
+
<span className="px-1.5 py-0.5 rounded bg-accent/15 text-accent font-semibold font-mono text-[10px]">{cmdMatch[0]}</span>
|
|
791
|
+
{tags.map((tag, i) => <span key={i} className="text-accent font-medium text-[10px]">{tag}</span>)}
|
|
792
|
+
<span className="text-[10px] text-text-4 ml-auto">memory command</span>
|
|
793
|
+
</div>
|
|
794
|
+
);
|
|
795
|
+
})()}
|
|
796
|
+
|
|
710
797
|
{/* Mode pills */}
|
|
711
798
|
<div className="flex items-center gap-1 mb-2">
|
|
712
799
|
<button
|
|
@@ -757,42 +844,68 @@ export function AgentFeed({ agent }) {
|
|
|
757
844
|
>
|
|
758
845
|
<Paperclip size={14} />
|
|
759
846
|
</button>
|
|
760
|
-
<
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
'flex-1 resize-none px-3 py-2 text-[13px]',
|
|
771
|
-
'bg-transparent text-text-0 font-sans',
|
|
772
|
-
'placeholder:text-text-4',
|
|
773
|
-
'focus:outline-none',
|
|
847
|
+
<div className="flex-1 relative">
|
|
848
|
+
{input && KEEPER_DETECT_RE.test(input) && (
|
|
849
|
+
<div
|
|
850
|
+
ref={highlightRef}
|
|
851
|
+
aria-hidden
|
|
852
|
+
className="absolute inset-0 px-3 py-2 text-[13px] font-sans pointer-events-none whitespace-pre-wrap break-words overflow-y-hidden"
|
|
853
|
+
style={{ height: inputHeight }}
|
|
854
|
+
>
|
|
855
|
+
{highlightKeeperInput(input)}
|
|
856
|
+
</div>
|
|
774
857
|
)}
|
|
775
|
-
|
|
776
|
-
|
|
858
|
+
<textarea
|
|
859
|
+
ref={inputRef}
|
|
860
|
+
value={input}
|
|
861
|
+
onChange={(e) => setInput(e.target.value)}
|
|
862
|
+
onKeyDown={onKeyDown}
|
|
863
|
+
onScroll={(e) => { if (highlightRef.current) highlightRef.current.scrollTop = e.target.scrollTop; }}
|
|
864
|
+
onDragOver={(e) => e.preventDefault()}
|
|
865
|
+
onDrop={(e) => {
|
|
866
|
+
e.preventDefault();
|
|
867
|
+
if (e.dataTransfer?.files?.length) {
|
|
868
|
+
const dt = new DataTransfer();
|
|
869
|
+
for (const f of e.dataTransfer.files) dt.items.add(f);
|
|
870
|
+
fileInputRef.current.files = dt.files;
|
|
871
|
+
fileInputRef.current.dispatchEvent(new Event('change', { bubbles: true }));
|
|
872
|
+
}
|
|
873
|
+
}}
|
|
874
|
+
placeholder={pendingSnippet ? 'Add a message (optional)...'
|
|
875
|
+
: mode === 'query' ? 'Ask about this agent\'s work...'
|
|
876
|
+
: isAlive ? 'Send an instruction...' : 'Continue this session...'}
|
|
877
|
+
rows={1}
|
|
878
|
+
className={cn(
|
|
879
|
+
'w-full resize-none px-3 py-2 text-[13px]',
|
|
880
|
+
'bg-transparent font-sans relative z-10',
|
|
881
|
+
'placeholder:text-text-4',
|
|
882
|
+
'focus:outline-none',
|
|
883
|
+
input && KEEPER_DETECT_RE.test(input)
|
|
884
|
+
? 'text-transparent caret-text-0'
|
|
885
|
+
: 'text-text-0',
|
|
886
|
+
)}
|
|
887
|
+
style={{ height: inputHeight }}
|
|
888
|
+
/>
|
|
889
|
+
</div>
|
|
777
890
|
{isAlive && (
|
|
778
891
|
<button
|
|
779
892
|
onClick={() => useGrooveStore.getState().stopAgent(agent.id)}
|
|
780
893
|
title="Stop agent"
|
|
781
|
-
className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-
|
|
894
|
+
className="group w-9 h-9 flex items-center justify-center rounded-lg hover:bg-red-500/10 transition-colors cursor-pointer flex-shrink-0 mb-px"
|
|
782
895
|
>
|
|
783
896
|
<span className="relative flex items-center justify-center w-3.5 h-3.5">
|
|
784
|
-
<span className="absolute inset-0 rounded-full bg-
|
|
785
|
-
<span className="relative w-2.5 h-2.5 rounded-full bg-
|
|
897
|
+
<span className="absolute inset-0 rounded-full bg-accent/30 group-hover:bg-red-500/30 animate-ping [animation-duration:2s] transition-colors" />
|
|
898
|
+
<span className="relative w-2.5 h-2.5 rounded-full bg-accent group-hover:bg-red-500 transition-colors" />
|
|
786
899
|
</span>
|
|
787
900
|
</button>
|
|
788
901
|
)}
|
|
789
902
|
<button
|
|
790
903
|
onClick={handleSend}
|
|
791
|
-
disabled={!input.trim() || sending}
|
|
904
|
+
disabled={(!input.trim() && !pendingSnippet) || sending}
|
|
792
905
|
className={cn(
|
|
793
906
|
'w-9 h-9 flex items-center justify-center rounded-lg transition-all cursor-pointer flex-shrink-0 mb-px',
|
|
794
907
|
'disabled:opacity-15 disabled:cursor-not-allowed',
|
|
795
|
-
input.trim()
|
|
908
|
+
(input.trim() || pendingSnippet)
|
|
796
909
|
? mode === 'query'
|
|
797
910
|
? 'bg-info/15 text-info hover:bg-info/25 border border-info/25'
|
|
798
911
|
: 'bg-accent/15 text-accent hover:bg-accent/25 border border-accent/25'
|
|
@@ -8,7 +8,6 @@ import { fmtNum, fmtDollar, fmtUptime } from '../../lib/format';
|
|
|
8
8
|
|
|
9
9
|
const EMPTY = [];
|
|
10
10
|
const ERROR_RE = /error|crash|fail/i;
|
|
11
|
-
const BAR_BG = 'rgba(51, 175, 188, 0.15)';
|
|
12
11
|
const BAR_H = 'h-[2px]';
|
|
13
12
|
|
|
14
13
|
function shortModel(id) {
|
|
@@ -98,13 +97,9 @@ const AgentNode = memo(({ data, selected }) => {
|
|
|
98
97
|
|
|
99
98
|
{/* Scan line — running only */}
|
|
100
99
|
{isAlive && (
|
|
101
|
-
<div className="absolute inset-0 overflow-hidden pointer-events-none"
|
|
100
|
+
<div className="absolute inset-0 overflow-hidden pointer-events-none rounded-[3px]">
|
|
102
101
|
<div
|
|
103
|
-
className="absolute left-0 right-0 h-px"
|
|
104
|
-
style={{
|
|
105
|
-
background: 'linear-gradient(90deg, transparent 0%, rgba(97,175,239,0.25) 50%, transparent 100%)',
|
|
106
|
-
animation: 'node-scan 3s ease-in-out infinite',
|
|
107
|
-
}}
|
|
102
|
+
className="absolute left-0 right-0 h-px [background:linear-gradient(90deg,transparent_0%,rgba(97,175,239,0.25)_50%,transparent_100%)] [animation:node-scan_3s_ease-in-out_infinite]"
|
|
108
103
|
/>
|
|
109
104
|
</div>
|
|
110
105
|
)}
|
|
@@ -116,8 +111,8 @@ const AgentNode = memo(({ data, selected }) => {
|
|
|
116
111
|
<span className="absolute inset-0 rounded-sm" style={{ background: sColor }} />
|
|
117
112
|
{isAlive && (
|
|
118
113
|
<span
|
|
119
|
-
className="absolute inset-[-2px] rounded-sm"
|
|
120
|
-
style={{ background: sColor
|
|
114
|
+
className="absolute inset-[-2px] rounded-sm opacity-[0.15] [animation:node-pulse-bar_2s_ease-in-out_infinite]"
|
|
115
|
+
style={{ background: sColor }}
|
|
121
116
|
/>
|
|
122
117
|
)}
|
|
123
118
|
</span>
|
|
@@ -155,7 +150,7 @@ const AgentNode = memo(({ data, selected }) => {
|
|
|
155
150
|
</div>
|
|
156
151
|
|
|
157
152
|
{/* Context bar */}
|
|
158
|
-
<div className={`mt-1.5 ${BAR_H} rounded-sm overflow-hidden`}
|
|
153
|
+
<div className={`mt-1.5 ${BAR_H} rounded-sm overflow-hidden bg-[rgba(51,175,188,0.15)]`}>
|
|
159
154
|
<div
|
|
160
155
|
className="h-full rounded-sm transition-all duration-700"
|
|
161
156
|
style={{
|
|
@@ -185,7 +180,7 @@ const AgentNode = memo(({ data, selected }) => {
|
|
|
185
180
|
)}
|
|
186
181
|
</div>
|
|
187
182
|
<div className="flex items-center gap-2">
|
|
188
|
-
<div className={`flex-1 ${BAR_H} rounded-sm overflow-hidden`}
|
|
183
|
+
<div className={`flex-1 ${BAR_H} rounded-sm overflow-hidden bg-[rgba(51,175,188,0.15)]`}>
|
|
189
184
|
<div className="h-full rounded-sm transition-all duration-500" style={{ width: `${Math.max(contextPct, 1)}%`, background: ctxColor }} />
|
|
190
185
|
</div>
|
|
191
186
|
<span className="text-[9px] font-mono font-medium" style={{ color: ctxColor }}>{contextPct}%</span>
|
|
@@ -196,7 +191,7 @@ const AgentNode = memo(({ data, selected }) => {
|
|
|
196
191
|
<div className="px-3 pt-1 pb-1">
|
|
197
192
|
<span className="text-[9px] font-mono text-[#505862] uppercase tracking-wider">Quality</span>
|
|
198
193
|
<div className="flex items-center gap-2 mt-1">
|
|
199
|
-
<div className={`flex-1 ${BAR_H} rounded-sm overflow-hidden`}
|
|
194
|
+
<div className={`flex-1 ${BAR_H} rounded-sm overflow-hidden bg-[rgba(51,175,188,0.15)]`}>
|
|
200
195
|
<div className="h-full rounded-sm transition-all duration-500" style={{ width: `${qScore != null ? Math.max(qScore, 1) : 0}%`, background: qColor || '#505862' }} />
|
|
201
196
|
</div>
|
|
202
197
|
<span className="text-[9px] font-mono font-medium" style={{ color: qColor || '#505862' }}>{qScore != null ? qScore : '—'}</span>
|
|
@@ -207,7 +202,7 @@ const AgentNode = memo(({ data, selected }) => {
|
|
|
207
202
|
<div className="px-3 pt-1 pb-1">
|
|
208
203
|
<span className="text-[9px] font-mono text-[#505862] uppercase tracking-wider">Efficiency</span>
|
|
209
204
|
<div className="flex items-center gap-2 mt-1">
|
|
210
|
-
<div className={`flex-1 ${BAR_H} rounded-sm overflow-hidden`}
|
|
205
|
+
<div className={`flex-1 ${BAR_H} rounded-sm overflow-hidden bg-[rgba(51,175,188,0.15)]`}>
|
|
211
206
|
<div className="h-full rounded-sm transition-all duration-500" style={{ width: `${effPct != null ? Math.max(effPct, 1) : 0}%`, background: effColor || '#505862' }} />
|
|
212
207
|
</div>
|
|
213
208
|
<span className="text-[9px] font-mono font-medium" style={{ color: effColor || '#505862' }}>{effPct != null ? `${effPct}%` : '—'}</span>
|