groove-dev 0.27.66 → 0.27.67

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 (49) hide show
  1. package/node_modules/@groove-dev/cli/package.json +1 -1
  2. package/node_modules/@groove-dev/daemon/package.json +1 -1
  3. package/node_modules/@groove-dev/daemon/src/api.js +12 -31
  4. package/node_modules/@groove-dev/daemon/src/tunnel-manager.js +25 -2
  5. package/node_modules/@groove-dev/gui/dist/assets/index-MPNqazCA.js +8614 -0
  6. package/node_modules/@groove-dev/gui/dist/assets/index-YeunozTU.css +1 -0
  7. package/node_modules/@groove-dev/gui/dist/index.html +2 -2
  8. package/node_modules/@groove-dev/gui/package.json +1 -1
  9. package/node_modules/@groove-dev/gui/src/app.jsx +5 -1
  10. package/node_modules/@groove-dev/gui/src/components/agents/agent-config.jsx +3 -1
  11. package/node_modules/@groove-dev/gui/src/components/agents/folder-browser.jsx +5 -4
  12. package/node_modules/@groove-dev/gui/src/components/layout/app-shell.jsx +1 -2
  13. package/node_modules/@groove-dev/gui/src/components/layout/breadcrumb-bar.jsx +1 -9
  14. package/node_modules/@groove-dev/gui/src/components/layout/project-picker.jsx +3 -1
  15. package/node_modules/@groove-dev/gui/src/components/layout/welcome-splash.jsx +132 -0
  16. package/node_modules/@groove-dev/gui/src/components/onboarding/setup-wizard.jsx +3 -1
  17. package/node_modules/@groove-dev/gui/src/components/pro/upgrade-modal.jsx +1 -2
  18. package/node_modules/@groove-dev/gui/src/components/settings/server-dialog.jsx +2 -0
  19. package/node_modules/@groove-dev/gui/src/components/settings/ssh-wizard.jsx +3 -0
  20. package/node_modules/@groove-dev/gui/src/stores/groove.js +10 -2
  21. package/node_modules/@groove-dev/gui/src/views/agents.jsx +14 -1
  22. package/node_modules/@groove-dev/gui/src/views/settings.jsx +3 -1
  23. package/package.json +1 -1
  24. package/packages/cli/package.json +1 -1
  25. package/packages/daemon/package.json +1 -1
  26. package/packages/daemon/src/api.js +12 -31
  27. package/packages/daemon/src/tunnel-manager.js +25 -2
  28. package/packages/gui/dist/assets/index-MPNqazCA.js +8614 -0
  29. package/packages/gui/dist/assets/index-YeunozTU.css +1 -0
  30. package/packages/gui/dist/index.html +2 -2
  31. package/packages/gui/package.json +1 -1
  32. package/packages/gui/src/app.jsx +5 -1
  33. package/packages/gui/src/components/agents/agent-config.jsx +3 -1
  34. package/packages/gui/src/components/agents/folder-browser.jsx +5 -4
  35. package/packages/gui/src/components/layout/app-shell.jsx +1 -2
  36. package/packages/gui/src/components/layout/breadcrumb-bar.jsx +1 -9
  37. package/packages/gui/src/components/layout/project-picker.jsx +3 -1
  38. package/packages/gui/src/components/layout/welcome-splash.jsx +132 -0
  39. package/packages/gui/src/components/onboarding/setup-wizard.jsx +3 -1
  40. package/packages/gui/src/components/pro/upgrade-modal.jsx +1 -2
  41. package/packages/gui/src/components/settings/server-dialog.jsx +2 -0
  42. package/packages/gui/src/components/settings/ssh-wizard.jsx +3 -0
  43. package/packages/gui/src/stores/groove.js +10 -2
  44. package/packages/gui/src/views/agents.jsx +14 -1
  45. package/packages/gui/src/views/settings.jsx +3 -1
  46. package/node_modules/@groove-dev/gui/dist/assets/index-BvvSZvQz.js +0 -8614
  47. package/node_modules/@groove-dev/gui/dist/assets/index-DFp5IOnd.css +0 -1
  48. package/packages/gui/dist/assets/index-BvvSZvQz.js +0 -8614
  49. package/packages/gui/dist/assets/index-DFp5IOnd.css +0 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/cli",
3
- "version": "0.27.66",
3
+ "version": "0.27.67",
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.66",
3
+ "version": "0.27.67",
4
4
  "description": "GROOVE daemon — agent orchestration engine",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -744,6 +744,7 @@ export function createApi(app, daemon) {
744
744
  port: daemon.port,
745
745
  projectDir: daemon.projectDir,
746
746
  edition: sub.active ? 'pro' : 'community',
747
+ homedir: homedir(),
747
748
  });
748
749
  });
749
750
 
@@ -763,6 +764,7 @@ export function createApi(app, daemon) {
763
764
  }
764
765
  try {
765
766
  daemon.setProjectDir(dirPath);
767
+ editorRootDir = daemon.projectDir;
766
768
  res.json({ projectDir: daemon.projectDir, recentProjects: daemon.config.recentProjects || [] });
767
769
  } catch (err) {
768
770
  res.status(400).json({ error: err.message });
@@ -3635,11 +3637,11 @@ Keep responses concise. Help them think, don't lecture them about the system the
3635
3637
 
3636
3638
  // --- Tunnels (Remote Access) ---
3637
3639
 
3638
- app.get('/api/tunnels', proOnly, (req, res) => {
3640
+ app.get('/api/tunnels', (req, res) => {
3639
3641
  res.json(daemon.tunnelManager.getSaved());
3640
3642
  });
3641
3643
 
3642
- app.post('/api/tunnels', proOnly, (req, res) => {
3644
+ app.post('/api/tunnels', (req, res) => {
3643
3645
  try {
3644
3646
  const { name, host, user, port, sshKeyPath, autoStart, autoConnect } = req.body;
3645
3647
  if (!name || typeof name !== 'string') return res.status(400).json({ error: 'name is required (string)' });
@@ -3651,7 +3653,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
3651
3653
  }
3652
3654
  });
3653
3655
 
3654
- app.patch('/api/tunnels/:id', proOnly, (req, res) => {
3656
+ app.patch('/api/tunnels/:id', (req, res) => {
3655
3657
  try {
3656
3658
  const result = daemon.tunnelManager.update(req.params.id, req.body);
3657
3659
  res.json(result);
@@ -3660,7 +3662,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
3660
3662
  }
3661
3663
  });
3662
3664
 
3663
- app.delete('/api/tunnels/:id', proOnly, async (req, res) => {
3665
+ app.delete('/api/tunnels/:id', async (req, res) => {
3664
3666
  try {
3665
3667
  await daemon.tunnelManager.delete(req.params.id);
3666
3668
  res.json({ ok: true });
@@ -3669,7 +3671,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
3669
3671
  }
3670
3672
  });
3671
3673
 
3672
- app.post('/api/tunnels/:id/test', proOnly, async (req, res) => {
3674
+ app.post('/api/tunnels/:id/test', async (req, res) => {
3673
3675
  try {
3674
3676
  const result = await daemon.tunnelManager.test(req.params.id);
3675
3677
  res.json(result);
@@ -3678,7 +3680,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
3678
3680
  }
3679
3681
  });
3680
3682
 
3681
- app.post('/api/tunnels/:id/connect', proOnly, async (req, res) => {
3683
+ app.post('/api/tunnels/:id/connect', async (req, res) => {
3682
3684
  try {
3683
3685
  const opts = {};
3684
3686
  if (req.body?.skipTest && req.body?.testResult) {
@@ -3694,7 +3696,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
3694
3696
  }
3695
3697
  });
3696
3698
 
3697
- app.post('/api/tunnels/:id/disconnect', proOnly, async (req, res) => {
3699
+ app.post('/api/tunnels/:id/disconnect', async (req, res) => {
3698
3700
  try {
3699
3701
  await daemon.tunnelManager.disconnect(req.params.id);
3700
3702
  res.json({ ok: true });
@@ -3703,7 +3705,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
3703
3705
  }
3704
3706
  });
3705
3707
 
3706
- app.post('/api/tunnels/:id/install', proOnly, async (req, res) => {
3708
+ app.post('/api/tunnels/:id/install', async (req, res) => {
3707
3709
  try {
3708
3710
  const result = await daemon.tunnelManager.remoteInstall(req.params.id);
3709
3711
  res.json(result);
@@ -3712,7 +3714,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
3712
3714
  }
3713
3715
  });
3714
3716
 
3715
- app.post('/api/tunnels/:id/start', proOnly, async (req, res) => {
3717
+ app.post('/api/tunnels/:id/start', async (req, res) => {
3716
3718
  try {
3717
3719
  await daemon.tunnelManager.autoStart(req.params.id);
3718
3720
  res.json({ ok: true });
@@ -3721,7 +3723,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
3721
3723
  }
3722
3724
  });
3723
3725
 
3724
- app.get('/api/tunnels/:id/status', proOnly, (req, res) => {
3726
+ app.get('/api/tunnels/:id/status', (req, res) => {
3725
3727
  const s = daemon.tunnelManager.getStatus(req.params.id);
3726
3728
  if (!s) return res.status(404).json({ error: 'Remote not found' });
3727
3729
  res.json(s);
@@ -3869,27 +3871,6 @@ Keep responses concise. Help them think, don't lecture them about the system the
3869
3871
  res.json({ ok: true });
3870
3872
  });
3871
3873
 
3872
- // --- Project Directory ---
3873
-
3874
- app.post('/api/project-dir', async (req, res) => {
3875
- const { dir } = req.body;
3876
- if (!dir || typeof dir !== 'string') return res.status(400).json({ error: 'dir required' });
3877
- if (/[\0\n\r]/.test(dir)) return res.status(400).json({ error: 'Invalid characters in path' });
3878
- const { existsSync, statSync } = await import('fs');
3879
- const { resolve, isAbsolute } = await import('path');
3880
- const resolved = resolve(dir);
3881
- if (!isAbsolute(resolved)) return res.status(400).json({ error: 'Path must be absolute' });
3882
- if (!existsSync(resolved) || !statSync(resolved).isDirectory()) {
3883
- return res.status(400).json({ error: 'Directory does not exist' });
3884
- }
3885
- daemon.config.defaultWorkingDir = resolved;
3886
- const { saveConfig } = await import('./firstrun.js');
3887
- saveConfig(daemon.grooveDir, daemon.config);
3888
- daemon.broadcast({ type: 'config:updated', data: { defaultWorkingDir: resolved } });
3889
- daemon.audit.log('project.dir.change', { dir: resolved });
3890
- res.json({ ok: true, dir: resolved });
3891
- });
3892
-
3893
3874
  // --- Config ---
3894
3875
 
3895
3876
  app.get('/api/config', (req, res) => {
@@ -85,7 +85,7 @@ export class TunnelManager {
85
85
  }));
86
86
  }
87
87
 
88
- save({ name, host, user, port, sshKeyPath, autoStart, autoConnect }) {
88
+ save({ name, host, user, port, sshKeyPath, autoStart, autoConnect, projectDir }) {
89
89
  validateField(name, 'name');
90
90
  validateField(host, 'host');
91
91
  validateField(user, 'user');
@@ -104,6 +104,15 @@ export class TunnelManager {
104
104
  }
105
105
  }
106
106
 
107
+ if (projectDir) {
108
+ if (typeof projectDir !== 'string' || !projectDir.startsWith('/')) {
109
+ throw new Error('projectDir must be an absolute path');
110
+ }
111
+ if (/[;|&`$(){}[\]<>!#\n\r\\]/.test(projectDir)) {
112
+ throw new Error('Invalid characters in projectDir');
113
+ }
114
+ }
115
+
107
116
  const id = crypto.randomUUID().slice(0, 8);
108
117
  const entry = {
109
118
  id,
@@ -114,6 +123,7 @@ export class TunnelManager {
114
123
  sshKeyPath: sshKeyPath || null,
115
124
  autoStart: !!autoStart,
116
125
  autoConnect: !!autoConnect,
126
+ projectDir: projectDir ? projectDir.trim() : null,
117
127
  createdAt: new Date().toISOString(),
118
128
  };
119
129
 
@@ -163,6 +173,19 @@ export class TunnelManager {
163
173
  }
164
174
  if (config.autoStart !== undefined) merged.autoStart = !!config.autoStart;
165
175
  if (config.autoConnect !== undefined) merged.autoConnect = !!config.autoConnect;
176
+ if (config.projectDir !== undefined) {
177
+ if (config.projectDir) {
178
+ if (typeof config.projectDir !== 'string' || !config.projectDir.startsWith('/')) {
179
+ throw new Error('projectDir must be an absolute path');
180
+ }
181
+ if (/[;|&`$(){}[\]<>!#\n\r\\]/.test(config.projectDir)) {
182
+ throw new Error('Invalid characters in projectDir');
183
+ }
184
+ merged.projectDir = config.projectDir.trim();
185
+ } else {
186
+ merged.projectDir = null;
187
+ }
188
+ }
166
189
 
167
190
  this.saved.set(id, merged);
168
191
  this._save();
@@ -380,7 +403,7 @@ export class TunnelManager {
380
403
  '-o', 'ConnectTimeout=10',
381
404
  '-o', 'BatchMode=yes',
382
405
  target,
383
- `bash -lc 'nohup groove start > /tmp/groove-daemon.log 2>&1 < /dev/null & disown; sleep 5; curl -sf http://localhost:${REMOTE_PORT}/api/health > /dev/null && echo __DAEMON_OK__ || (echo __DAEMON_FAIL__; tail -20 /tmp/groove-daemon.log 2>/dev/null)'`,
406
+ `bash -lc '${config.projectDir ? `cd "${config.projectDir}" && ` : ''}nohup groove start > /tmp/groove-daemon.log 2>&1 < /dev/null & disown; sleep 5; curl -sf http://localhost:${REMOTE_PORT}/api/health > /dev/null && echo __DAEMON_OK__ || (echo __DAEMON_FAIL__; tail -20 /tmp/groove-daemon.log 2>/dev/null)'`,
384
407
  ], {
385
408
  encoding: 'utf8',
386
409
  timeout: 45000,