groove-dev 0.8.1 → 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.
- package/node_modules/@groove-dev/cli/package.json +1 -1
- package/node_modules/@groove-dev/cli/src/client.js +17 -1
- package/node_modules/@groove-dev/daemon/package.json +1 -1
- package/node_modules/@groove-dev/daemon/src/index.js +38 -7
- package/node_modules/@groove-dev/gui/dist/assets/{index-BO95Rm1F.js → index-B5E3l1CX.js} +10 -10
- 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/AgentActions.jsx +4 -2
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/cli/src/client.js +17 -1
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/index.js +38 -7
- package/packages/gui/dist/assets/{index-BO95Rm1F.js → index-B5E3l1CX.js} +10 -10
- package/packages/gui/dist/index.html +1 -1
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/components/AgentActions.jsx +4 -2
|
@@ -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
|
-
|
|
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,7 +1,8 @@
|
|
|
1
1
|
// GROOVE Daemon — Entry Point
|
|
2
2
|
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
3
3
|
|
|
4
|
-
import { createServer } from 'http';
|
|
4
|
+
import { createServer as createHttpServer } from 'http';
|
|
5
|
+
import { createServer as createNetServer } from 'net';
|
|
5
6
|
import { resolve } from 'path';
|
|
6
7
|
import { readFileSync, writeFileSync, unlinkSync, existsSync, mkdirSync } from 'fs';
|
|
7
8
|
import express from 'express';
|
|
@@ -71,7 +72,7 @@ export class Daemon {
|
|
|
71
72
|
|
|
72
73
|
// HTTP + WebSocket server
|
|
73
74
|
this.app = express();
|
|
74
|
-
this.server =
|
|
75
|
+
this.server = createHttpServer(this.app);
|
|
75
76
|
this.wss = new WebSocketServer({
|
|
76
77
|
server: this.server,
|
|
77
78
|
maxPayload: 1024 * 1024, // 1MB max message
|
|
@@ -123,16 +124,44 @@ export class Daemon {
|
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
async start() {
|
|
126
|
-
//
|
|
127
|
+
// Kill any existing daemon on our port
|
|
127
128
|
if (existsSync(this.pidFile)) {
|
|
128
129
|
const existingPid = parseInt(readFileSync(this.pidFile, 'utf8'), 10);
|
|
129
130
|
try {
|
|
130
131
|
process.kill(existingPid, 0); // Signal 0 = check if alive
|
|
131
|
-
console.
|
|
132
|
-
process.
|
|
132
|
+
console.log(` Stopping previous daemon (PID ${existingPid})...`);
|
|
133
|
+
process.kill(existingPid, 'SIGTERM');
|
|
134
|
+
// Wait briefly for clean shutdown
|
|
135
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
136
|
+
try { process.kill(existingPid, 'SIGKILL'); } catch { /* already dead */ }
|
|
133
137
|
} catch {
|
|
134
|
-
// PID file is stale
|
|
135
|
-
|
|
138
|
+
// PID file is stale
|
|
139
|
+
}
|
|
140
|
+
try { unlinkSync(this.pidFile); } catch { /* ignore */ }
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Auto-find an open port if the default is taken
|
|
144
|
+
const checkPort = (port) => new Promise((res) => {
|
|
145
|
+
const tester = createNetServer();
|
|
146
|
+
tester.once('error', () => res(false));
|
|
147
|
+
tester.once('listening', () => { tester.close(); res(true); });
|
|
148
|
+
tester.listen(port, '127.0.0.1');
|
|
149
|
+
}).catch(() => false);
|
|
150
|
+
|
|
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);
|
|
136
165
|
}
|
|
137
166
|
}
|
|
138
167
|
|
|
@@ -143,6 +172,8 @@ export class Daemon {
|
|
|
143
172
|
return new Promise((resolvePromise) => {
|
|
144
173
|
this.server.listen(this.port, '127.0.0.1', () => {
|
|
145
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));
|
|
146
177
|
|
|
147
178
|
printWelcome(this.port);
|
|
148
179
|
|