groove-dev 0.27.186 → 0.27.187

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.
@@ -6,7 +6,7 @@
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <link rel="icon" type="image/png" href="/favicon.png" />
8
8
  <title>Groove GUI</title>
9
- <script type="module" crossorigin src="/assets/index-DOOaCFRS.js"></script>
9
+ <script type="module" crossorigin src="/assets/index-DyI84i9Y.js"></script>
10
10
  <link rel="modulepreload" crossorigin href="/assets/vendor-26L3JoZv.js">
11
11
  <link rel="modulepreload" crossorigin href="/assets/reactflow-DoBZjiHE.js">
12
12
  <link rel="modulepreload" crossorigin href="/assets/codemirror-BYKpdS2W.js">
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/gui",
3
- "version": "0.27.186",
3
+ "version": "0.27.187",
4
4
  "description": "GROOVE GUI — visual agent control plane",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -385,9 +385,28 @@ function InnerChatMessage({ msg, agent }) {
385
385
  );
386
386
  }
387
387
 
388
+ // Single-quote a value for safe use inside the shell command we inject.
389
+ function shq(s) {
390
+ return `'${String(s).replace(/'/g, `'\\''`)}'`;
391
+ }
392
+
393
+ // Build a `tail -f` that actually resolves. Agents usually write a log path
394
+ // relative to wherever they ran it — often a bare filename several directories
395
+ // deep — but the terminal opens in a different cwd, so a naive `tail -f name`
396
+ // fails. Absolute paths are used as-is; anything else is resolved against the
397
+ // agent's working directory, falling back to a `find` by basename when the file
398
+ // sits below that directory.
399
+ function tailCommand(path, workdir) {
400
+ if (/^[/~]/.test(path) || !workdir) return `tail -f ${shq(path)}`;
401
+ const base = path.split('/').pop();
402
+ return `cd ${shq(workdir)} 2>/dev/null; `
403
+ + `if [ -f ${shq(path)} ]; then tail -f ${shq(path)}; `
404
+ + `else tail -f "$(find . -name ${shq(base)} -type f 2>/dev/null | head -1)"; fi`;
405
+ }
406
+
388
407
  // One-click "tail" chips for any log paths the agent mentioned — saves asking
389
408
  // "what's the log file?" and hand-copying it into a terminal.
390
- function LogChips({ text }) {
409
+ function LogChips({ text, workdir }) {
391
410
  const runInTerminal = useGrooveStore((s) => s.runInTerminal);
392
411
  const paths = useMemo(() => extractLogPaths(text), [text]);
393
412
  if (paths.length === 0) return null;
@@ -397,7 +416,7 @@ function LogChips({ text }) {
397
416
  {paths.map((path) => (
398
417
  <button
399
418
  key={path}
400
- onClick={() => runInTerminal(`tail -f ${path}`)}
419
+ onClick={() => runInTerminal(tailCommand(path, workdir))}
401
420
  title={`tail -f ${path}`}
402
421
  className="inline-flex items-center gap-1.5 px-2 py-0.5 rounded-md bg-accent/10 hover:bg-accent/20 text-accent text-[11px] font-medium font-sans cursor-pointer transition-colors max-w-full"
403
422
  >
@@ -430,7 +449,7 @@ function AgentMessage({ msg, agent, answeredTo }) {
430
449
  <div className={cn('pl-3.5 py-1 border-l', answeredTo ? 'border-indigo/50' : 'border-accent')}>
431
450
  <StructuredMessage text={collapsed ? msg.text.slice(0, 600) + '...' : msg.text} />
432
451
  </div>
433
- <LogChips text={msg.text} />
452
+ <LogChips text={msg.text} workdir={agent?.workingDir} />
434
453
  {collapsed && (
435
454
  <button
436
455
  onClick={() => setCollapsed(false)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "groove-dev",
3
- "version": "0.27.186",
3
+ "version": "0.27.187",
4
4
  "description": "Open-source agent orchestration layer — the AI company OS. Local model agent engine (GGUF/Ollama/llama-server), HuggingFace model browser, MCP integrations (Slack, Gmail, Stripe, 15+), agent scheduling (cron), business roles (CMO, CFO, EA). GUI dashboard, multi-agent coordination, zero cold-start, infinite sessions. Works with Claude Code, Codex, Gemini CLI, Ollama, any local model.",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "author": "Groove Dev <hello@groovedev.ai> (https://groovedev.ai)",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/cli",
3
- "version": "0.27.186",
3
+ "version": "0.27.187",
4
4
  "description": "GROOVE CLI — manage AI coding agents from your terminal",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/daemon",
3
- "version": "0.27.186",
3
+ "version": "0.27.187",
4
4
  "description": "GROOVE daemon — agent orchestration engine",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -94,3 +94,19 @@ export function watchInstructions(port = 31415, agentName = 'YOUR_NAME') {
94
94
  '- Do not poll or sleep-loop waiting yourself — set the watch and end the turn. That is the whole point.',
95
95
  ];
96
96
  }
97
+
98
+ // Log-path convention. The GUI turns log paths in a message into a one-click
99
+ // "tail" button; a bare or relative filename can't be located reliably (there
100
+ // may be several with the same name in different directories), so agents must
101
+ // give the absolute path.
102
+ export function logFileInstructions() {
103
+ return [
104
+ '## Mentioning Log Files',
105
+ '',
106
+ 'When you start a process that writes to a log the user may want to watch, state the',
107
+ "log's ABSOLUTE path — e.g. `Logging to /home/you/project/runs/train.log` — not a bare",
108
+ 'or relative filename. The GUI turns that path into a one-click "tail" button for the',
109
+ 'user; a bare name like `train.log` cannot be located reliably (several files may share',
110
+ 'it), so always resolve it to a full path first (`realpath` / `readlink -f` if unsure).',
111
+ ];
112
+ }
@@ -4,7 +4,7 @@
4
4
  import { writeFileSync, readFileSync, existsSync, readdirSync, statSync } from 'fs';
5
5
  import { resolve, dirname, basename } from 'path';
6
6
  import { escapeMd } from './validate.js';
7
- import { innerChatInstructions, watchInstructions } from './innerchat-docs.js';
7
+ import { innerChatInstructions, watchInstructions, logFileInstructions } from './innerchat-docs.js';
8
8
 
9
9
  const GROOVE_SECTION_START = '<!-- GROOVE:START -->';
10
10
  const GROOVE_SECTION_END = '<!-- GROOVE:END -->';
@@ -561,7 +561,7 @@ export class Introducer {
561
561
  // compaction — the spawn prompt alone can scroll out of a long session.
562
562
  _innerChatSection() {
563
563
  const port = this.daemon.port || 31415;
564
- return [...innerChatInstructions(port), '', ...watchInstructions(port)];
564
+ return [...innerChatInstructions(port), '', ...watchInstructions(port), '', ...logFileInstructions()];
565
565
  }
566
566
 
567
567
  writeRegistryFile(projectDir) {
@@ -10,7 +10,7 @@ import { LocalProvider } from './providers/local.js';
10
10
  import { OllamaProvider } from './providers/ollama.js';
11
11
  import { AgentLoop } from './agent-loop.js';
12
12
  import { validateAgentConfig } from './validate.js';
13
- import { innerChatInstructions, watchInstructions } from './innerchat-docs.js';
13
+ import { innerChatInstructions, watchInstructions, logFileInstructions } from './innerchat-docs.js';
14
14
 
15
15
  const __dirname = dirname(fileURLToPath(import.meta.url));
16
16
  const SLIDES_ENGINE_SRC = resolve(__dirname, '../templates/groove-slides.cjs');
@@ -1174,6 +1174,8 @@ For normal file edits within your scope, proceed without review.
1174
1174
  ...innerChatInstructions(port, agent.name),
1175
1175
  '',
1176
1176
  ...watchInstructions(port, agent.name),
1177
+ '',
1178
+ ...logFileInstructions(),
1177
1179
  ].join('\n') + '\n\n';
1178
1180
  if (spawnConfig.prompt.startsWith('# Handoff Brief')) {
1179
1181
  spawnConfig.prompt += '\n\n' + capabilities.trim();