groove-dev 0.8.2 → 0.8.3

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/cli",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
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,7 +1,23 @@
1
1
  // GROOVE CLI — HTTP client for daemon communication
2
2
  // FSL-1.1-Apache-2.0 — see LICENSE
3
3
 
4
- const BASE_URL = process.env.GROOVE_URL || 'http://localhost:31415';
4
+ import { existsSync, readFileSync } from 'fs';
5
+ import { resolve } from 'path';
6
+
7
+ function getBaseUrl() {
8
+ if (process.env.GROOVE_URL) return process.env.GROOVE_URL;
9
+ // Read actual port from daemon's port file (supports auto-port rotation)
10
+ try {
11
+ const portFile = resolve(process.cwd(), '.groove', 'daemon.port');
12
+ if (existsSync(portFile)) {
13
+ const port = readFileSync(portFile, 'utf8').trim();
14
+ if (port) return `http://localhost:${port}`;
15
+ }
16
+ } catch { /* fallback */ }
17
+ return 'http://localhost:31415';
18
+ }
19
+
20
+ const BASE_URL = getBaseUrl();
5
21
 
6
22
  export async function apiCall(method, path, body) {
7
23
  const url = `${BASE_URL}${path}`;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/daemon",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
4
4
  "description": "GROOVE daemon — agent orchestration engine",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -140,19 +140,29 @@ export class Daemon {
140
140
  try { unlinkSync(this.pidFile); } catch { /* ignore */ }
141
141
  }
142
142
 
143
- // Check if port is in use by something else
144
- const portFree = await new Promise((res) => {
143
+ // Auto-find an open port if the default is taken
144
+ const checkPort = (port) => new Promise((res) => {
145
145
  const tester = createNetServer();
146
146
  tester.once('error', () => res(false));
147
147
  tester.once('listening', () => { tester.close(); res(true); });
148
- tester.listen(this.port, '127.0.0.1');
148
+ tester.listen(port, '127.0.0.1');
149
149
  }).catch(() => false);
150
150
 
151
- if (!portFree) {
152
- console.error(`\n Port ${this.port} is in use by another application.`);
153
- console.error(` Try a different port: groove start --port 31416`);
154
- console.error(` Or stop whatever is using port ${this.port}\n`);
155
- process.exit(1);
151
+ if (!(await checkPort(this.port))) {
152
+ const originalPort = this.port;
153
+ // Try next 10 ports
154
+ let found = false;
155
+ for (let i = 1; i <= 10; i++) {
156
+ if (await checkPort(this.port + i)) {
157
+ this.port = this.port + i;
158
+ found = true;
159
+ break;
160
+ }
161
+ }
162
+ if (!found) {
163
+ console.error(`\n Ports ${originalPort}-${originalPort + 10} are all in use. Free one and try again.\n`);
164
+ process.exit(1);
165
+ }
156
166
  }
157
167
 
158
168
  // Restore persisted state
@@ -162,6 +172,8 @@ export class Daemon {
162
172
  return new Promise((resolvePromise) => {
163
173
  this.server.listen(this.port, '127.0.0.1', () => {
164
174
  writeFileSync(this.pidFile, String(process.pid));
175
+ // Write actual port so CLI can find us (supports auto-port rotation)
176
+ writeFileSync(resolve(this.grooveDir, 'daemon.port'), String(this.port));
165
177
 
166
178
  printWelcome(this.port);
167
179
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/gui",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
4
4
  "description": "GROOVE GUI — visual agent control plane",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "groove-dev",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
4
4
  "description": "Open-source agent orchestration layer for AI coding tools. GUI dashboard, multi-agent coordination, zero cold-start (Journalist), infinite sessions (adaptive context rotation), AI Project Manager, Quick Launch. Works with Claude Code, Codex, Gemini CLI, Aider, Ollama.",
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.8.2",
3
+ "version": "0.8.3",
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,7 +1,23 @@
1
1
  // GROOVE CLI — HTTP client for daemon communication
2
2
  // FSL-1.1-Apache-2.0 — see LICENSE
3
3
 
4
- const BASE_URL = process.env.GROOVE_URL || 'http://localhost:31415';
4
+ import { existsSync, readFileSync } from 'fs';
5
+ import { resolve } from 'path';
6
+
7
+ function getBaseUrl() {
8
+ if (process.env.GROOVE_URL) return process.env.GROOVE_URL;
9
+ // Read actual port from daemon's port file (supports auto-port rotation)
10
+ try {
11
+ const portFile = resolve(process.cwd(), '.groove', 'daemon.port');
12
+ if (existsSync(portFile)) {
13
+ const port = readFileSync(portFile, 'utf8').trim();
14
+ if (port) return `http://localhost:${port}`;
15
+ }
16
+ } catch { /* fallback */ }
17
+ return 'http://localhost:31415';
18
+ }
19
+
20
+ const BASE_URL = getBaseUrl();
5
21
 
6
22
  export async function apiCall(method, path, body) {
7
23
  const url = `${BASE_URL}${path}`;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/daemon",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
4
4
  "description": "GROOVE daemon — agent orchestration engine",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -140,19 +140,29 @@ export class Daemon {
140
140
  try { unlinkSync(this.pidFile); } catch { /* ignore */ }
141
141
  }
142
142
 
143
- // Check if port is in use by something else
144
- const portFree = await new Promise((res) => {
143
+ // Auto-find an open port if the default is taken
144
+ const checkPort = (port) => new Promise((res) => {
145
145
  const tester = createNetServer();
146
146
  tester.once('error', () => res(false));
147
147
  tester.once('listening', () => { tester.close(); res(true); });
148
- tester.listen(this.port, '127.0.0.1');
148
+ tester.listen(port, '127.0.0.1');
149
149
  }).catch(() => false);
150
150
 
151
- if (!portFree) {
152
- console.error(`\n Port ${this.port} is in use by another application.`);
153
- console.error(` Try a different port: groove start --port 31416`);
154
- console.error(` Or stop whatever is using port ${this.port}\n`);
155
- process.exit(1);
151
+ if (!(await checkPort(this.port))) {
152
+ const originalPort = this.port;
153
+ // Try next 10 ports
154
+ let found = false;
155
+ for (let i = 1; i <= 10; i++) {
156
+ if (await checkPort(this.port + i)) {
157
+ this.port = this.port + i;
158
+ found = true;
159
+ break;
160
+ }
161
+ }
162
+ if (!found) {
163
+ console.error(`\n Ports ${originalPort}-${originalPort + 10} are all in use. Free one and try again.\n`);
164
+ process.exit(1);
165
+ }
156
166
  }
157
167
 
158
168
  // Restore persisted state
@@ -162,6 +172,8 @@ export class Daemon {
162
172
  return new Promise((resolvePromise) => {
163
173
  this.server.listen(this.port, '127.0.0.1', () => {
164
174
  writeFileSync(this.pidFile, String(process.pid));
175
+ // Write actual port so CLI can find us (supports auto-port rotation)
176
+ writeFileSync(resolve(this.grooveDir, 'daemon.port'), String(this.port));
165
177
 
166
178
  printWelcome(this.port);
167
179
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/gui",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
4
4
  "description": "GROOVE GUI — visual agent control plane",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",