groove-dev 0.27.71 → 0.27.72
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 +28 -20
- package/node_modules/@groove-dev/daemon/src/providers/claude-code.js +2 -0
- package/node_modules/@groove-dev/daemon/src/providers/codex.js +1 -0
- package/node_modules/@groove-dev/daemon/src/providers/index.js +3 -3
- package/node_modules/@groove-dev/gui/dist/assets/{index-BK6tvmxx.js → index-CHSXqfwy.js} +21 -21
- package/node_modules/@groove-dev/gui/dist/index.html +1 -1
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/node_modules/@groove-dev/gui/src/components/editor/file-tree.jsx +11 -0
- package/node_modules/@groove-dev/gui/src/stores/groove.js +5 -2
- package/node_modules/@groove-dev/gui/src/views/editor.jsx +10 -2
- 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 +28 -20
- package/packages/daemon/src/providers/claude-code.js +2 -0
- package/packages/daemon/src/providers/codex.js +1 -0
- package/packages/daemon/src/providers/index.js +3 -3
- package/packages/gui/dist/assets/{index-BK6tvmxx.js → index-CHSXqfwy.js} +21 -21
- package/packages/gui/dist/index.html +1 -1
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/components/editor/file-tree.jsx +11 -0
- package/packages/gui/src/stores/groove.js +5 -2
- package/packages/gui/src/views/editor.jsx +10 -2
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
3
3
|
|
|
4
4
|
import express from 'express';
|
|
5
|
-
import { resolve, dirname, join, sep, relative } from 'path';
|
|
5
|
+
import { resolve, dirname, join, sep, relative, isAbsolute } from 'path';
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
7
|
import { existsSync, readFileSync, readdirSync, statSync, writeFileSync, mkdirSync, unlinkSync, renameSync, rmSync, createReadStream, copyFileSync, realpathSync } from 'fs';
|
|
8
8
|
import { spawn, execFile, execFileSync } from 'child_process';
|
|
@@ -611,6 +611,7 @@ export function createApi(app, daemon) {
|
|
|
611
611
|
|
|
612
612
|
const proc = spawn('npm', ['install', '-g', pkg], {
|
|
613
613
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
614
|
+
shell: true,
|
|
614
615
|
env: { ...process.env, NODE_ENV: undefined },
|
|
615
616
|
});
|
|
616
617
|
|
|
@@ -719,6 +720,7 @@ export function createApi(app, daemon) {
|
|
|
719
720
|
|
|
720
721
|
const proc = spawn('codex', ['login'], {
|
|
721
722
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
723
|
+
shell: true,
|
|
722
724
|
});
|
|
723
725
|
let stdout = '';
|
|
724
726
|
let stderr = '';
|
|
@@ -763,7 +765,7 @@ export function createApi(app, daemon) {
|
|
|
763
765
|
if (customPath.length > 500) {
|
|
764
766
|
return res.status(400).json({ error: 'Path too long' });
|
|
765
767
|
}
|
|
766
|
-
if (!customPath
|
|
768
|
+
if (!isAbsolute(customPath)) {
|
|
767
769
|
return res.status(400).json({ error: 'Path must be absolute' });
|
|
768
770
|
}
|
|
769
771
|
|
|
@@ -830,6 +832,7 @@ export function createApi(app, daemon) {
|
|
|
830
832
|
encoding: 'utf8',
|
|
831
833
|
timeout: 5000,
|
|
832
834
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
835
|
+
shell: true,
|
|
833
836
|
}).trim();
|
|
834
837
|
} catch (err) {
|
|
835
838
|
version = null;
|
|
@@ -1033,7 +1036,7 @@ export function createApi(app, daemon) {
|
|
|
1033
1036
|
}
|
|
1034
1037
|
try {
|
|
1035
1038
|
daemon.setProjectDir(dirPath);
|
|
1036
|
-
|
|
1039
|
+
editorRootOverride = null;
|
|
1037
1040
|
res.json({ projectDir: daemon.projectDir, recentProjects: daemon.config.recentProjects || [] });
|
|
1038
1041
|
} catch (err) {
|
|
1039
1042
|
res.status(400).json({ error: err.message });
|
|
@@ -2660,12 +2663,13 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
2660
2663
|
return LANG_MAP[ext] || 'text';
|
|
2661
2664
|
}
|
|
2662
2665
|
|
|
2663
|
-
const IGNORED_NAMES = new Set(['.
|
|
2666
|
+
const IGNORED_NAMES = new Set(['.DS_Store', '__pycache__']);
|
|
2664
2667
|
|
|
2665
|
-
// Editor root directory —
|
|
2666
|
-
|
|
2668
|
+
// Editor root directory — always tracks daemon.projectDir unless explicitly
|
|
2669
|
+
// overridden via POST /api/files/root. Reset on project-dir change.
|
|
2670
|
+
let editorRootOverride = null;
|
|
2667
2671
|
|
|
2668
|
-
function getEditorRoot() { return
|
|
2672
|
+
function getEditorRoot() { return editorRootOverride || daemon.projectDir; }
|
|
2669
2673
|
|
|
2670
2674
|
function validateFilePath(relPath, projectDir) {
|
|
2671
2675
|
if (!relPath || typeof relPath !== 'string') return { error: 'path is required' };
|
|
@@ -2689,13 +2693,12 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
2689
2693
|
|
|
2690
2694
|
// Get/set the editor working directory
|
|
2691
2695
|
app.get('/api/files/root', (req, res) => {
|
|
2692
|
-
res.json({ root:
|
|
2696
|
+
res.json({ root: getEditorRoot() });
|
|
2693
2697
|
});
|
|
2694
2698
|
|
|
2695
2699
|
app.post('/api/files/root', (req, res) => {
|
|
2696
2700
|
const { root } = req.body || {};
|
|
2697
2701
|
if (!root || typeof root !== 'string') return res.status(400).json({ error: 'root path is required' });
|
|
2698
|
-
// Must be absolute and exist
|
|
2699
2702
|
if (!root.startsWith('/')) return res.status(400).json({ error: 'root must be an absolute path' });
|
|
2700
2703
|
if (root.includes('\0') || root.includes('..')) return res.status(400).json({ error: 'Invalid path' });
|
|
2701
2704
|
if (!existsSync(root)) return res.status(404).json({ error: 'Directory not found' });
|
|
@@ -2703,9 +2706,9 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
2703
2706
|
const stat = statSync(root);
|
|
2704
2707
|
if (!stat.isDirectory()) return res.status(400).json({ error: 'Path is not a directory' });
|
|
2705
2708
|
} catch { return res.status(400).json({ error: 'Cannot access directory' }); }
|
|
2706
|
-
|
|
2709
|
+
editorRootOverride = root;
|
|
2707
2710
|
daemon.audit.log('editor.root.set', { root });
|
|
2708
|
-
res.json({ ok: true, root:
|
|
2711
|
+
res.json({ ok: true, root: getEditorRoot() });
|
|
2709
2712
|
});
|
|
2710
2713
|
|
|
2711
2714
|
// File tree — returns dirs + files for a given path
|
|
@@ -2730,18 +2733,22 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
2730
2733
|
const raw = readdirSync(fullPath, { withFileTypes: true });
|
|
2731
2734
|
const entries = [];
|
|
2732
2735
|
|
|
2733
|
-
|
|
2734
|
-
|
|
2736
|
+
const dirs = raw.filter((e) => {
|
|
2737
|
+
if (e.name === '.DS_Store') return false;
|
|
2735
2738
|
if (e.isDirectory()) return true;
|
|
2736
|
-
if (e.isSymbolicLink()) {
|
|
2739
|
+
if (e.isSymbolicLink()) {
|
|
2740
|
+
try { return statSync(resolve(fullPath, e.name)).isDirectory(); }
|
|
2741
|
+
catch { return true; }
|
|
2742
|
+
}
|
|
2737
2743
|
return false;
|
|
2738
|
-
};
|
|
2739
|
-
const dirs = raw.filter((e) => isDir(e) && !IGNORED_NAMES.has(e.name) && !e.name.startsWith('.'))
|
|
2740
|
-
.sort((a, b) => a.name.localeCompare(b.name));
|
|
2744
|
+
}).sort((a, b) => a.name.localeCompare(b.name));
|
|
2741
2745
|
const files = raw.filter((e) => {
|
|
2742
|
-
if (e.name
|
|
2746
|
+
if (e.name === '.DS_Store') return false;
|
|
2743
2747
|
if (e.isFile()) return true;
|
|
2744
|
-
if (e.isSymbolicLink()) {
|
|
2748
|
+
if (e.isSymbolicLink()) {
|
|
2749
|
+
try { return statSync(resolve(fullPath, e.name)).isFile(); }
|
|
2750
|
+
catch { return false; }
|
|
2751
|
+
}
|
|
2745
2752
|
return false;
|
|
2746
2753
|
}).sort((a, b) => a.name.localeCompare(b.name));
|
|
2747
2754
|
|
|
@@ -2751,7 +2758,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
2751
2758
|
let hasChildren = false;
|
|
2752
2759
|
try {
|
|
2753
2760
|
const children = readdirSync(childFull, { withFileTypes: true });
|
|
2754
|
-
hasChildren = children.some((c) =>
|
|
2761
|
+
hasChildren = children.some((c) => c.name !== '.DS_Store');
|
|
2755
2762
|
} catch { /* unreadable */ }
|
|
2756
2763
|
entries.push({ name: d.name, type: 'dir', path: childPath, hasChildren });
|
|
2757
2764
|
}
|
|
@@ -4077,6 +4084,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4077
4084
|
|
|
4078
4085
|
const proc = spawn('npm', ['install', '-g', pkg], {
|
|
4079
4086
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
4087
|
+
shell: true,
|
|
4080
4088
|
env: { ...process.env, NODE_ENV: undefined },
|
|
4081
4089
|
});
|
|
4082
4090
|
|
|
@@ -336,6 +336,7 @@ export class ClaudeCodeProvider extends Provider {
|
|
|
336
336
|
const child = cpSpawn('claude', ['auth', 'login', '--claudeai'], {
|
|
337
337
|
detached: true,
|
|
338
338
|
stdio: 'ignore',
|
|
339
|
+
shell: true,
|
|
339
340
|
});
|
|
340
341
|
child.unref();
|
|
341
342
|
return { pid: child.pid };
|
|
@@ -359,6 +360,7 @@ export class ClaudeCodeProvider extends Provider {
|
|
|
359
360
|
return new Promise((resolve) => {
|
|
360
361
|
const child = cpSpawn('claude', ['auth', 'login', '--claudeai'], {
|
|
361
362
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
363
|
+
shell: true,
|
|
362
364
|
});
|
|
363
365
|
let stdout = '';
|
|
364
366
|
let stderr = '';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
3
3
|
|
|
4
4
|
import { execSync } from 'child_process';
|
|
5
|
-
import { dirname as pathDirname } from 'path';
|
|
5
|
+
import { dirname as pathDirname, delimiter as pathDelimiter } from 'path';
|
|
6
6
|
import { ClaudeCodeProvider } from './claude-code.js';
|
|
7
7
|
import { CodexProvider } from './codex.js';
|
|
8
8
|
import { GeminiProvider } from './gemini.js';
|
|
@@ -26,10 +26,10 @@ function _augmentPathWithCustomPaths() {
|
|
|
26
26
|
for (const p of Object.values(_providerPaths)) {
|
|
27
27
|
if (p && typeof p === 'string') {
|
|
28
28
|
const dir = pathDirname(p);
|
|
29
|
-
if (dir && !cur.split(
|
|
29
|
+
if (dir && !cur.split(pathDelimiter).includes(dir)) dirs.push(dir);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
if (dirs.length) process.env.PATH = [...dirs, cur].join(
|
|
32
|
+
if (dirs.length) process.env.PATH = [...dirs, cur].join(pathDelimiter);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export function getProviderPath(id) {
|