@sumicom/quicksave 0.4.0 → 0.5.1
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/dist/ai/claudeCodeService.d.ts +89 -0
- package/dist/ai/claudeCodeService.d.ts.map +1 -0
- package/dist/ai/claudeCodeService.js +602 -0
- package/dist/ai/claudeCodeService.js.map +1 -0
- package/dist/ai/sessionStore.d.ts +31 -0
- package/dist/ai/sessionStore.d.ts.map +1 -0
- package/dist/ai/sessionStore.js +72 -0
- package/dist/ai/sessionStore.js.map +1 -0
- package/dist/ai/sessionStore.test.d.ts +2 -0
- package/dist/ai/sessionStore.test.d.ts.map +1 -0
- package/dist/ai/sessionStore.test.js +99 -0
- package/dist/ai/sessionStore.test.js.map +1 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +39 -0
- package/dist/config.js.map +1 -1
- package/dist/connection/connection.d.ts +2 -0
- package/dist/connection/connection.d.ts.map +1 -1
- package/dist/connection/connection.js +14 -5
- package/dist/connection/connection.js.map +1 -1
- package/dist/connection/relay.d.ts +2 -1
- package/dist/connection/relay.d.ts.map +1 -1
- package/dist/connection/relay.js +9 -7
- package/dist/connection/relay.js.map +1 -1
- package/dist/git/operations.d.ts +8 -1
- package/dist/git/operations.d.ts.map +1 -1
- package/dist/git/operations.js +71 -4
- package/dist/git/operations.js.map +1 -1
- package/dist/handlers/messageHandler.d.ts +18 -1
- package/dist/handlers/messageHandler.d.ts.map +1 -1
- package/dist/handlers/messageHandler.js +231 -11
- package/dist/handlers/messageHandler.js.map +1 -1
- package/dist/handlers/messageHandler.test.js +1 -1
- package/dist/index.js +228 -94
- package/dist/index.js.map +1 -1
- package/dist/service/ensureDaemon.d.ts +23 -0
- package/dist/service/ensureDaemon.d.ts.map +1 -0
- package/dist/service/ensureDaemon.js +143 -0
- package/dist/service/ensureDaemon.js.map +1 -0
- package/dist/service/index.d.ts +8 -0
- package/dist/service/index.d.ts.map +1 -0
- package/dist/service/index.js +8 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/ipc.test.d.ts +2 -0
- package/dist/service/ipc.test.d.ts.map +1 -0
- package/dist/service/ipc.test.js +140 -0
- package/dist/service/ipc.test.js.map +1 -0
- package/dist/service/ipcClient.d.ts +36 -0
- package/dist/service/ipcClient.d.ts.map +1 -0
- package/dist/service/ipcClient.js +167 -0
- package/dist/service/ipcClient.js.map +1 -0
- package/dist/service/ipcServer.d.ts +53 -0
- package/dist/service/ipcServer.d.ts.map +1 -0
- package/dist/service/ipcServer.js +245 -0
- package/dist/service/ipcServer.js.map +1 -0
- package/dist/service/run.d.ts +13 -0
- package/dist/service/run.d.ts.map +1 -0
- package/dist/service/run.js +292 -0
- package/dist/service/run.js.map +1 -0
- package/dist/service/singleton.d.ts +31 -0
- package/dist/service/singleton.d.ts.map +1 -0
- package/dist/service/singleton.js +96 -0
- package/dist/service/singleton.js.map +1 -0
- package/dist/service/singleton.test.d.ts +2 -0
- package/dist/service/singleton.test.d.ts.map +1 -0
- package/dist/service/singleton.test.js +39 -0
- package/dist/service/singleton.test.js.map +1 -0
- package/dist/service/stateStore.d.ts +11 -0
- package/dist/service/stateStore.d.ts.map +1 -0
- package/dist/service/stateStore.js +35 -0
- package/dist/service/stateStore.js.map +1 -0
- package/dist/service/types.d.ts +111 -0
- package/dist/service/types.d.ts.map +1 -0
- package/dist/service/types.js +76 -0
- package/dist/service/types.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ensureDaemon — connect to an existing daemon or auto-start one.
|
|
3
|
+
*
|
|
4
|
+
* Flow:
|
|
5
|
+
* 1. Read service.json for socket path. Quick pre-check: if PID is dead, skip to step 4.
|
|
6
|
+
* 2. Connect to socket, send hello (both liveness check and version exchange).
|
|
7
|
+
* 3. Inspect HelloResult for version compatibility. If compatible, attach.
|
|
8
|
+
* If restart needed, proceed to step 4.
|
|
9
|
+
* 4. If stale or version mismatch, remove stale runtime files and start a new daemon.
|
|
10
|
+
* 5. If lock acquisition fails, retry attach with backoff (up to 3 attempts, 500ms base delay).
|
|
11
|
+
*/
|
|
12
|
+
import { fork } from 'child_process';
|
|
13
|
+
import { openSync, mkdirSync } from 'fs';
|
|
14
|
+
import { join, resolve } from 'path';
|
|
15
|
+
import { fileURLToPath } from 'url';
|
|
16
|
+
import { IpcClient } from './ipcClient.js';
|
|
17
|
+
import { readServiceState } from './stateStore.js';
|
|
18
|
+
import { isProcessAlive, cleanStaleRuntime, getRunDir } from './singleton.js';
|
|
19
|
+
import { shouldRestartDaemon, IPC_VERSION, BUILD_ID } from './types.js';
|
|
20
|
+
const MAX_ATTACH_RETRIES = 3;
|
|
21
|
+
const BASE_RETRY_DELAY_MS = 500;
|
|
22
|
+
const DAEMON_READY_TIMEOUT_MS = 10_000;
|
|
23
|
+
const DAEMON_READY_POLL_MS = 200;
|
|
24
|
+
/**
|
|
25
|
+
* Ensure the daemon is running and return a connected IPC client.
|
|
26
|
+
* Auto-starts a new daemon if needed.
|
|
27
|
+
*/
|
|
28
|
+
export async function ensureDaemon() {
|
|
29
|
+
for (let attempt = 0; attempt <= MAX_ATTACH_RETRIES; attempt++) {
|
|
30
|
+
// Step 1: Read service.json
|
|
31
|
+
const state = readServiceState();
|
|
32
|
+
if (state) {
|
|
33
|
+
// Quick pre-check: is the PID alive?
|
|
34
|
+
if (!isProcessAlive(state.pid)) {
|
|
35
|
+
cleanStaleRuntime();
|
|
36
|
+
return startAndConnect();
|
|
37
|
+
}
|
|
38
|
+
// Step 2: Try connecting
|
|
39
|
+
try {
|
|
40
|
+
const client = new IpcClient();
|
|
41
|
+
const hello = await client.connect(state.socketPath);
|
|
42
|
+
// Step 3: Check version compatibility
|
|
43
|
+
const check = shouldRestartDaemon(hello, { ipcVersion: IPC_VERSION, buildId: BUILD_ID });
|
|
44
|
+
if (check.action === 'ok') {
|
|
45
|
+
return { client, hello };
|
|
46
|
+
}
|
|
47
|
+
if (check.action === 'warn_outdated') {
|
|
48
|
+
console.warn('Warning: CLI is outdated. Please update quicksave.');
|
|
49
|
+
return { client, hello };
|
|
50
|
+
}
|
|
51
|
+
// action === 'restart'
|
|
52
|
+
client.close();
|
|
53
|
+
await requestShutdownAndWait(state.socketPath);
|
|
54
|
+
cleanStaleRuntime();
|
|
55
|
+
return startAndConnect();
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Connection failed — daemon might be stale or starting
|
|
59
|
+
if (attempt < MAX_ATTACH_RETRIES) {
|
|
60
|
+
await sleep(BASE_RETRY_DELAY_MS * (attempt + 1));
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
// Last attempt — clean up and start fresh
|
|
64
|
+
cleanStaleRuntime();
|
|
65
|
+
return startAndConnect();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
// No service.json — start a new daemon
|
|
70
|
+
return startAndConnect();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Should not reach here, but just in case
|
|
74
|
+
throw new Error('Failed to connect to daemon after retries');
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Spawn a new daemon process in detached mode and wait for it to be ready.
|
|
78
|
+
*/
|
|
79
|
+
async function startAndConnect() {
|
|
80
|
+
spawnDaemon();
|
|
81
|
+
return waitForDaemon();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Spawn `quicksave service run` as a detached background process.
|
|
85
|
+
*/
|
|
86
|
+
function spawnDaemon() {
|
|
87
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
88
|
+
const isTs = thisFile.endsWith('.ts');
|
|
89
|
+
const entryPath = resolve(thisFile, isTs ? '../../index.ts' : '../../index.js');
|
|
90
|
+
// Ensure run directory exists before opening log file (daemon hasn't started yet)
|
|
91
|
+
const runDir = getRunDir();
|
|
92
|
+
mkdirSync(runDir, { recursive: true });
|
|
93
|
+
const logFd = openSync(join(runDir, 'daemon.log'), 'a');
|
|
94
|
+
const child = fork(entryPath, ['service', 'run'], {
|
|
95
|
+
detached: true,
|
|
96
|
+
stdio: ['ignore', logFd, logFd, 'ipc'],
|
|
97
|
+
execArgv: isTs ? ['--import', 'tsx'] : [],
|
|
98
|
+
});
|
|
99
|
+
// Disconnect IPC so parent can exit immediately
|
|
100
|
+
child.disconnect();
|
|
101
|
+
child.unref();
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Poll until the daemon is ready (service.json exists and IPC responds).
|
|
105
|
+
*/
|
|
106
|
+
async function waitForDaemon() {
|
|
107
|
+
const deadline = Date.now() + DAEMON_READY_TIMEOUT_MS;
|
|
108
|
+
while (Date.now() < deadline) {
|
|
109
|
+
const state = readServiceState();
|
|
110
|
+
if (state && isProcessAlive(state.pid)) {
|
|
111
|
+
try {
|
|
112
|
+
const client = new IpcClient();
|
|
113
|
+
const hello = await client.connect(state.socketPath);
|
|
114
|
+
return { client, hello };
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Not ready yet
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
await sleep(DAEMON_READY_POLL_MS);
|
|
121
|
+
}
|
|
122
|
+
throw new Error('Timed out waiting for daemon to start');
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Send shutdown to the daemon and wait for the process to exit.
|
|
126
|
+
*/
|
|
127
|
+
async function requestShutdownAndWait(socketPath) {
|
|
128
|
+
try {
|
|
129
|
+
const client = new IpcClient();
|
|
130
|
+
await client.connect(socketPath);
|
|
131
|
+
await client.request('shutdown');
|
|
132
|
+
client.close();
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// If we can't connect, the daemon is already gone
|
|
136
|
+
}
|
|
137
|
+
// Wait briefly for the process to exit
|
|
138
|
+
await sleep(500);
|
|
139
|
+
}
|
|
140
|
+
function sleep(ms) {
|
|
141
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=ensureDaemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensureDaemon.js","sourceRoot":"","sources":["../../src/service/ensureDaemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGxE,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAC7B,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAChC,MAAM,uBAAuB,GAAG,MAAM,CAAC;AACvC,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAOjC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,kBAAkB,EAAE,OAAO,EAAE,EAAE,CAAC;QAC/D,4BAA4B;QAC5B,MAAM,KAAK,GAAG,gBAAgB,EAAE,CAAC;QAEjC,IAAI,KAAK,EAAE,CAAC;YACV,qCAAqC;YACrC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC/B,iBAAiB,EAAE,CAAC;gBACpB,OAAO,eAAe,EAAE,CAAC;YAC3B,CAAC;YAED,yBAAyB;YACzB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;gBAC/B,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;gBAErD,sCAAsC;gBACtC,MAAM,KAAK,GAAG,mBAAmB,CAAC,KAAK,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;gBAEzF,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;oBAC1B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;gBAC3B,CAAC;gBAED,IAAI,KAAK,CAAC,MAAM,KAAK,eAAe,EAAE,CAAC;oBACrC,OAAO,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC;oBACnE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;gBAC3B,CAAC;gBAED,uBAAuB;gBACvB,MAAM,CAAC,KAAK,EAAE,CAAC;gBACf,MAAM,sBAAsB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;gBAC/C,iBAAiB,EAAE,CAAC;gBACpB,OAAO,eAAe,EAAE,CAAC;YAC3B,CAAC;YAAC,MAAM,CAAC;gBACP,wDAAwD;gBACxD,IAAI,OAAO,GAAG,kBAAkB,EAAE,CAAC;oBACjC,MAAM,KAAK,CAAC,mBAAmB,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;oBACjD,SAAS;gBACX,CAAC;gBACD,0CAA0C;gBAC1C,iBAAiB,EAAE,CAAC;gBACpB,OAAO,eAAe,EAAE,CAAC;YAC3B,CAAC;QACH,CAAC;aAAM,CAAC;YACN,uCAAuC;YACvC,OAAO,eAAe,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,0CAA0C;IAC1C,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;AAC/D,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,eAAe;IAC5B,WAAW,EAAE,CAAC;IACd,OAAO,aAAa,EAAE,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,SAAS,WAAW;IAClB,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAEhF,kFAAkF;IAClF,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,GAAG,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE;QAChD,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;QACtC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;KAC1C,CAAC,CAAC;IAEH,gDAAgD;IAChD,KAAK,CAAC,UAAU,EAAE,CAAC;IACnB,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,aAAa;IAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,uBAAuB,CAAC;IAEtD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,gBAAgB,EAAE,CAAC;QACjC,IAAI,KAAK,IAAI,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YACvC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;gBAC/B,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;gBACrD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;YAC3B,CAAC;YAAC,MAAM,CAAC;gBACP,gBAAgB;YAClB,CAAC;QACH,CAAC;QACD,MAAM,KAAK,CAAC,oBAAoB,CAAC,CAAC;IACpC,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;AAC3D,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,sBAAsB,CAAC,UAAkB;IACtD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC/B,MAAM,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACjC,MAAM,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACjC,MAAM,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,kDAAkD;IACpD,CAAC;IAED,uCAAuC;IACvC,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;AACnB,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { runDaemon } from './run.js';
|
|
2
|
+
export { ensureDaemon } from './ensureDaemon.js';
|
|
3
|
+
export { IpcClient, IpcDisconnectedError, RpcError } from './ipcClient.js';
|
|
4
|
+
export { IpcServer } from './ipcServer.js';
|
|
5
|
+
export { readServiceState, writeServiceState, removeServiceState } from './stateStore.js';
|
|
6
|
+
export { acquireLock, cleanStaleRuntime, isProcessAlive, getSocketPath, getRunDir, getStateDir, getSessionsDir, getLogsDir, ensureDirectories, } from './singleton.js';
|
|
7
|
+
export * from './types.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/service/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1F,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,SAAS,EACT,WAAW,EACX,cAAc,EACd,UAAU,EACV,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { runDaemon } from './run.js';
|
|
2
|
+
export { ensureDaemon } from './ensureDaemon.js';
|
|
3
|
+
export { IpcClient, IpcDisconnectedError, RpcError } from './ipcClient.js';
|
|
4
|
+
export { IpcServer } from './ipcServer.js';
|
|
5
|
+
export { readServiceState, writeServiceState, removeServiceState } from './stateStore.js';
|
|
6
|
+
export { acquireLock, cleanStaleRuntime, isProcessAlive, getSocketPath, getRunDir, getStateDir, getSessionsDir, getLogsDir, ensureDirectories, } from './singleton.js';
|
|
7
|
+
export * from './types.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/service/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1F,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,SAAS,EACT,WAAW,EACX,cAAc,EACd,UAAU,EACV,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ipc.test.d.ts","sourceRoot":"","sources":["../../src/service/ipc.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { tmpdir } from 'os';
|
|
4
|
+
import { mkdtempSync, rmSync } from 'fs';
|
|
5
|
+
import { IpcServer } from './ipcServer.js';
|
|
6
|
+
import { IpcClient } from './ipcClient.js';
|
|
7
|
+
function makeTmpDir() {
|
|
8
|
+
return mkdtempSync(join(tmpdir(), 'qs-ipc-test-'));
|
|
9
|
+
}
|
|
10
|
+
describe('IPC Server + Client', () => {
|
|
11
|
+
let tmpDir;
|
|
12
|
+
let server;
|
|
13
|
+
const clients = [];
|
|
14
|
+
afterEach(async () => {
|
|
15
|
+
for (const c of clients)
|
|
16
|
+
c.close();
|
|
17
|
+
clients.length = 0;
|
|
18
|
+
if (server)
|
|
19
|
+
await server.close();
|
|
20
|
+
if (tmpDir) {
|
|
21
|
+
try {
|
|
22
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
23
|
+
}
|
|
24
|
+
catch { /* ignore */ }
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
function socketPath() {
|
|
28
|
+
tmpDir = makeTmpDir();
|
|
29
|
+
return join(tmpDir, 'test.sock');
|
|
30
|
+
}
|
|
31
|
+
async function createServer() {
|
|
32
|
+
const sock = socketPath();
|
|
33
|
+
server = new IpcServer({ version: '0.5.1' });
|
|
34
|
+
await server.listen(sock);
|
|
35
|
+
return sock;
|
|
36
|
+
}
|
|
37
|
+
async function createClient(sock) {
|
|
38
|
+
const client = new IpcClient();
|
|
39
|
+
const hello = await client.connect(sock);
|
|
40
|
+
clients.push(client);
|
|
41
|
+
return { client, hello };
|
|
42
|
+
}
|
|
43
|
+
it('hello handshake returns daemon version info', async () => {
|
|
44
|
+
const sock = await createServer();
|
|
45
|
+
const { hello } = await createClient(sock);
|
|
46
|
+
expect(hello.daemonVersion).toBe('0.5.1');
|
|
47
|
+
expect(hello.daemonIpcVersion).toBe(1);
|
|
48
|
+
expect(hello.daemonPid).toBe(process.pid);
|
|
49
|
+
expect(typeof hello.daemonBuildId).toBe('string');
|
|
50
|
+
});
|
|
51
|
+
it('ping returns uptime and version', async () => {
|
|
52
|
+
const sock = await createServer();
|
|
53
|
+
const { client } = await createClient(sock);
|
|
54
|
+
const result = await client.request('ping');
|
|
55
|
+
expect(result.version).toBe('0.5.1');
|
|
56
|
+
expect(result.ipcVersion).toBe(1);
|
|
57
|
+
expect(typeof result.uptime).toBe('number');
|
|
58
|
+
expect(result.uptime).toBeGreaterThanOrEqual(0);
|
|
59
|
+
});
|
|
60
|
+
it('status returns daemon status summary', async () => {
|
|
61
|
+
const sock = await createServer();
|
|
62
|
+
const { client } = await createClient(sock);
|
|
63
|
+
const result = await client.request('status');
|
|
64
|
+
expect(result.pid).toBe(process.pid);
|
|
65
|
+
expect(result.version).toBe('0.5.1');
|
|
66
|
+
expect(typeof result.uptime).toBe('number');
|
|
67
|
+
expect(result.connectionState).toBe('disconnected');
|
|
68
|
+
expect(result.peerCount).toBe(0);
|
|
69
|
+
});
|
|
70
|
+
it('unknown method returns error', async () => {
|
|
71
|
+
const sock = await createServer();
|
|
72
|
+
const { client } = await createClient(sock);
|
|
73
|
+
await expect(client.request('nonexistent')).rejects.toThrow('Method not found');
|
|
74
|
+
});
|
|
75
|
+
it('custom method handler works', async () => {
|
|
76
|
+
const sock = await createServer();
|
|
77
|
+
server.registerMethod('echo', (params) => ({ echoed: params }));
|
|
78
|
+
const { client } = await createClient(sock);
|
|
79
|
+
const result = await client.request('echo', { message: 'hello' });
|
|
80
|
+
expect(result.echoed).toEqual({ message: 'hello' });
|
|
81
|
+
});
|
|
82
|
+
it('multiple clients can connect', async () => {
|
|
83
|
+
const sock = await createServer();
|
|
84
|
+
const { client: c1 } = await createClient(sock);
|
|
85
|
+
const { client: c2 } = await createClient(sock);
|
|
86
|
+
const r1 = await c1.request('ping');
|
|
87
|
+
const r2 = await c2.request('ping');
|
|
88
|
+
expect(r1.version).toBe('0.5.1');
|
|
89
|
+
expect(r2.version).toBe('0.5.1');
|
|
90
|
+
expect(server.getClientCount()).toBe(2);
|
|
91
|
+
});
|
|
92
|
+
it('subscribe-events enables notifications', async () => {
|
|
93
|
+
const sock = await createServer();
|
|
94
|
+
const { client } = await createClient(sock);
|
|
95
|
+
const received = [];
|
|
96
|
+
client.onNotification((method, params) => {
|
|
97
|
+
received.push({ method, params });
|
|
98
|
+
});
|
|
99
|
+
await client.request('subscribe-events');
|
|
100
|
+
// Broadcast a notification
|
|
101
|
+
server.broadcast({
|
|
102
|
+
jsonrpc: '2.0',
|
|
103
|
+
method: 'event.test',
|
|
104
|
+
params: { foo: 'bar' },
|
|
105
|
+
});
|
|
106
|
+
// Give the event a moment to arrive
|
|
107
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
108
|
+
expect(received.length).toBe(1);
|
|
109
|
+
expect(received[0].method).toBe('event.test');
|
|
110
|
+
expect(received[0].params).toEqual({ foo: 'bar' });
|
|
111
|
+
});
|
|
112
|
+
it('shutdown request triggers shutdown event', async () => {
|
|
113
|
+
const sock = await createServer();
|
|
114
|
+
const { client } = await createClient(sock);
|
|
115
|
+
let shutdownRequested = false;
|
|
116
|
+
server.on('shutdown-requested', () => {
|
|
117
|
+
shutdownRequested = true;
|
|
118
|
+
});
|
|
119
|
+
const result = await client.request('shutdown');
|
|
120
|
+
expect(result.ok).toBe(true);
|
|
121
|
+
// Wait for nextTick
|
|
122
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
123
|
+
expect(shutdownRequested).toBe(true);
|
|
124
|
+
});
|
|
125
|
+
it('client disconnect is detected by server', async () => {
|
|
126
|
+
const sock = await createServer();
|
|
127
|
+
const { client } = await createClient(sock);
|
|
128
|
+
expect(server.getClientCount()).toBe(1);
|
|
129
|
+
let disconnected = false;
|
|
130
|
+
server.on('client-disconnected', () => {
|
|
131
|
+
disconnected = true;
|
|
132
|
+
});
|
|
133
|
+
client.close();
|
|
134
|
+
// Wait for the close event to propagate
|
|
135
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
136
|
+
expect(server.getClientCount()).toBe(0);
|
|
137
|
+
expect(disconnected).toBe(true);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
//# sourceMappingURL=ipc.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ipc.test.js","sourceRoot":"","sources":["../../src/service/ipc.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IPC client — connects to the daemon's Unix domain socket
|
|
3
|
+
* and speaks JSON-RPC 2.0 over newline-delimited transport.
|
|
4
|
+
*
|
|
5
|
+
* Used by CLI attach clients and (later) session workers.
|
|
6
|
+
*/
|
|
7
|
+
import type { HelloResult } from './types.js';
|
|
8
|
+
export declare class IpcClient {
|
|
9
|
+
private socket;
|
|
10
|
+
private nextId;
|
|
11
|
+
private pending;
|
|
12
|
+
private notificationHandler?;
|
|
13
|
+
private buffer;
|
|
14
|
+
/** Connect to the daemon socket and perform the hello handshake. */
|
|
15
|
+
connect(socketPath: string): Promise<HelloResult>;
|
|
16
|
+
/** Send a JSON-RPC request and wait for the response. */
|
|
17
|
+
request<T = unknown>(method: string, params?: Record<string, unknown>, timeoutMs?: number): Promise<T>;
|
|
18
|
+
/** Send a JSON-RPC notification (fire-and-forget, no response expected). */
|
|
19
|
+
notify(method: string, params?: Record<string, unknown>): void;
|
|
20
|
+
/** Register a handler for server-pushed notifications. */
|
|
21
|
+
onNotification(handler: (method: string, params: Record<string, unknown>) => void): void;
|
|
22
|
+
/** Close the connection. */
|
|
23
|
+
close(): void;
|
|
24
|
+
get isConnected(): boolean;
|
|
25
|
+
private setupDataHandler;
|
|
26
|
+
private handleLine;
|
|
27
|
+
}
|
|
28
|
+
export declare class IpcDisconnectedError extends Error {
|
|
29
|
+
code: string;
|
|
30
|
+
constructor(message: string);
|
|
31
|
+
}
|
|
32
|
+
export declare class RpcError extends Error {
|
|
33
|
+
rpcCode: number;
|
|
34
|
+
constructor(message: string, rpcCode: number);
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=ipcClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ipcClient.d.ts","sourceRoot":"","sources":["../../src/service/ipcClient.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAIV,WAAW,EACZ,MAAM,YAAY,CAAC;AAYpB,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,OAAO,CAA8C;IAC7D,OAAO,CAAC,mBAAmB,CAAC,CAA4D;IACxF,OAAO,CAAC,MAAM,CAAM;IAEpB,oEAAoE;IAC9D,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAuCvD,yDAAyD;IACnD,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC;IA6B5G,4EAA4E;IAC5E,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAY9D,0DAA0D;IAC1D,cAAc,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,IAAI;IAIxF,4BAA4B;IAC5B,KAAK,IAAI,IAAI;IAOb,IAAI,WAAW,IAAI,OAAO,CAEzB;IAMD,OAAO,CAAC,gBAAgB;IAcxB,OAAO,CAAC,UAAU;CA8BnB;AAMD,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,IAAI,SAAsB;gBACd,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,QAAS,SAAQ,KAAK;IAGxB,OAAO,EAAE,MAAM;gBADtB,OAAO,EAAE,MAAM,EACR,OAAO,EAAE,MAAM;CAKzB"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IPC client — connects to the daemon's Unix domain socket
|
|
3
|
+
* and speaks JSON-RPC 2.0 over newline-delimited transport.
|
|
4
|
+
*
|
|
5
|
+
* Used by CLI attach clients and (later) session workers.
|
|
6
|
+
*/
|
|
7
|
+
import { connect } from 'net';
|
|
8
|
+
import { IPC_VERSION, BUILD_ID } from './types.js';
|
|
9
|
+
// Package version — matches package.json
|
|
10
|
+
const PACKAGE_VERSION = '0.5.1';
|
|
11
|
+
export class IpcClient {
|
|
12
|
+
socket = null;
|
|
13
|
+
nextId = 1;
|
|
14
|
+
pending = new Map();
|
|
15
|
+
notificationHandler;
|
|
16
|
+
buffer = '';
|
|
17
|
+
/** Connect to the daemon socket and perform the hello handshake. */
|
|
18
|
+
async connect(socketPath) {
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
const socket = connect(socketPath);
|
|
21
|
+
let connected = false;
|
|
22
|
+
socket.on('connect', () => {
|
|
23
|
+
connected = true;
|
|
24
|
+
this.socket = socket;
|
|
25
|
+
this.setupDataHandler(socket);
|
|
26
|
+
// Perform hello handshake
|
|
27
|
+
this.request('hello', {
|
|
28
|
+
role: 'cli',
|
|
29
|
+
version: PACKAGE_VERSION,
|
|
30
|
+
ipcVersion: IPC_VERSION,
|
|
31
|
+
buildId: BUILD_ID,
|
|
32
|
+
})
|
|
33
|
+
.then(resolve)
|
|
34
|
+
.catch(reject);
|
|
35
|
+
});
|
|
36
|
+
socket.on('error', (err) => {
|
|
37
|
+
if (!connected) {
|
|
38
|
+
reject(err);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
socket.on('close', () => {
|
|
42
|
+
// Reject all pending requests
|
|
43
|
+
for (const [, pending] of this.pending) {
|
|
44
|
+
clearTimeout(pending.timer);
|
|
45
|
+
pending.reject(new IpcDisconnectedError('IPC connection closed'));
|
|
46
|
+
}
|
|
47
|
+
this.pending.clear();
|
|
48
|
+
this.socket = null;
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/** Send a JSON-RPC request and wait for the response. */
|
|
53
|
+
async request(method, params, timeoutMs = 10_000) {
|
|
54
|
+
if (!this.socket) {
|
|
55
|
+
throw new IpcDisconnectedError('Not connected');
|
|
56
|
+
}
|
|
57
|
+
const id = this.nextId++;
|
|
58
|
+
const request = {
|
|
59
|
+
jsonrpc: '2.0',
|
|
60
|
+
id,
|
|
61
|
+
method,
|
|
62
|
+
params: params ?? {},
|
|
63
|
+
};
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
const timer = setTimeout(() => {
|
|
66
|
+
this.pending.delete(id);
|
|
67
|
+
reject(new Error(`RPC timeout: ${method}`));
|
|
68
|
+
}, timeoutMs);
|
|
69
|
+
this.pending.set(id, {
|
|
70
|
+
resolve: resolve,
|
|
71
|
+
reject,
|
|
72
|
+
timer,
|
|
73
|
+
});
|
|
74
|
+
this.socket.write(JSON.stringify(request) + '\n');
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/** Send a JSON-RPC notification (fire-and-forget, no response expected). */
|
|
78
|
+
notify(method, params) {
|
|
79
|
+
if (!this.socket)
|
|
80
|
+
return;
|
|
81
|
+
const notification = {
|
|
82
|
+
jsonrpc: '2.0',
|
|
83
|
+
method,
|
|
84
|
+
params: params ?? {},
|
|
85
|
+
};
|
|
86
|
+
this.socket.write(JSON.stringify(notification) + '\n');
|
|
87
|
+
}
|
|
88
|
+
/** Register a handler for server-pushed notifications. */
|
|
89
|
+
onNotification(handler) {
|
|
90
|
+
this.notificationHandler = handler;
|
|
91
|
+
}
|
|
92
|
+
/** Close the connection. */
|
|
93
|
+
close() {
|
|
94
|
+
if (this.socket) {
|
|
95
|
+
this.socket.destroy();
|
|
96
|
+
this.socket = null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
get isConnected() {
|
|
100
|
+
return this.socket !== null && !this.socket.destroyed;
|
|
101
|
+
}
|
|
102
|
+
// -----------------------------------------------------------------------
|
|
103
|
+
// Data parsing
|
|
104
|
+
// -----------------------------------------------------------------------
|
|
105
|
+
setupDataHandler(socket) {
|
|
106
|
+
socket.on('data', (data) => {
|
|
107
|
+
this.buffer += data.toString();
|
|
108
|
+
let newlineIndex;
|
|
109
|
+
while ((newlineIndex = this.buffer.indexOf('\n')) !== -1) {
|
|
110
|
+
const line = this.buffer.slice(0, newlineIndex);
|
|
111
|
+
this.buffer = this.buffer.slice(newlineIndex + 1);
|
|
112
|
+
if (line.trim()) {
|
|
113
|
+
this.handleLine(line);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
handleLine(line) {
|
|
119
|
+
let msg;
|
|
120
|
+
try {
|
|
121
|
+
msg = JSON.parse(line);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return; // Ignore malformed messages
|
|
125
|
+
}
|
|
126
|
+
// JSON-RPC response (has id + result/error)
|
|
127
|
+
if (msg.id != null && ('result' in msg || 'error' in msg)) {
|
|
128
|
+
const pending = this.pending.get(msg.id);
|
|
129
|
+
if (pending) {
|
|
130
|
+
this.pending.delete(msg.id);
|
|
131
|
+
clearTimeout(pending.timer);
|
|
132
|
+
if (msg.error) {
|
|
133
|
+
const err = new RpcError(msg.error.message, msg.error.code);
|
|
134
|
+
pending.reject(err);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
pending.resolve(msg.result);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
// JSON-RPC notification (has method, no id)
|
|
143
|
+
if (msg.method && msg.id == null) {
|
|
144
|
+
this.notificationHandler?.(msg.method, msg.params ?? {});
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
// Custom errors
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
export class IpcDisconnectedError extends Error {
|
|
153
|
+
code = 'IPC_DISCONNECTED';
|
|
154
|
+
constructor(message) {
|
|
155
|
+
super(message);
|
|
156
|
+
this.name = 'IpcDisconnectedError';
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
export class RpcError extends Error {
|
|
160
|
+
rpcCode;
|
|
161
|
+
constructor(message, rpcCode) {
|
|
162
|
+
super(message);
|
|
163
|
+
this.rpcCode = rpcCode;
|
|
164
|
+
this.name = 'RpcError';
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=ipcClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ipcClient.js","sourceRoot":"","sources":["../../src/service/ipcClient.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAe,MAAM,KAAK,CAAC;AAO3C,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEnD,yCAAyC;AACzC,MAAM,eAAe,GAAG,OAAO,CAAC;AAQhC,MAAM,OAAO,SAAS;IACZ,MAAM,GAAkB,IAAI,CAAC;IAC7B,MAAM,GAAG,CAAC,CAAC;IACX,OAAO,GAAG,IAAI,GAAG,EAAmC,CAAC;IACrD,mBAAmB,CAA6D;IAChF,MAAM,GAAG,EAAE,CAAC;IAEpB,oEAAoE;IACpE,KAAK,CAAC,OAAO,CAAC,UAAkB;QAC9B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;YACnC,IAAI,SAAS,GAAG,KAAK,CAAC;YAEtB,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;gBACxB,SAAS,GAAG,IAAI,CAAC;gBACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;gBACrB,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;gBAE9B,0BAA0B;gBAC1B,IAAI,CAAC,OAAO,CAAc,OAAO,EAAE;oBACjC,IAAI,EAAE,KAAK;oBACX,OAAO,EAAE,eAAe;oBACxB,UAAU,EAAE,WAAW;oBACvB,OAAO,EAAE,QAAQ;iBACI,CAAC;qBACrB,IAAI,CAAC,OAAO,CAAC;qBACb,KAAK,CAAC,MAAM,CAAC,CAAC;YACnB,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACzB,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,MAAM,CAAC,GAAG,CAAC,CAAC;gBACd,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;gBACtB,8BAA8B;gBAC9B,KAAK,MAAM,CAAC,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;oBACvC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;oBAC5B,OAAO,CAAC,MAAM,CAAC,IAAI,oBAAoB,CAAC,uBAAuB,CAAC,CAAC,CAAC;gBACpE,CAAC;gBACD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;gBACrB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YACrB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,yDAAyD;IACzD,KAAK,CAAC,OAAO,CAAc,MAAc,EAAE,MAAgC,EAAE,SAAS,GAAG,MAAM;QAC7F,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,oBAAoB,CAAC,eAAe,CAAC,CAAC;QAClD,CAAC;QAED,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACzB,MAAM,OAAO,GAAmB;YAC9B,OAAO,EAAE,KAAK;YACd,EAAE;YACF,MAAM;YACN,MAAM,EAAE,MAAM,IAAI,EAAE;SACrB,CAAC;QAEF,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACxC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACxB,MAAM,CAAC,IAAI,KAAK,CAAC,gBAAgB,MAAM,EAAE,CAAC,CAAC,CAAC;YAC9C,CAAC,EAAE,SAAS,CAAC,CAAC;YAEd,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE;gBACnB,OAAO,EAAE,OAAoC;gBAC7C,MAAM;gBACN,KAAK;aACN,CAAC,CAAC;YAEH,IAAI,CAAC,MAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,4EAA4E;IAC5E,MAAM,CAAC,MAAc,EAAE,MAAgC;QACrD,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QAEzB,MAAM,YAAY,GAAwB;YACxC,OAAO,EAAE,KAAK;YACd,MAAM;YACN,MAAM,EAAE,MAAM,IAAI,EAAE;SACrB,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC;IACzD,CAAC;IAED,0DAA0D;IAC1D,cAAc,CAAC,OAAkE;QAC/E,IAAI,CAAC,mBAAmB,GAAG,OAAO,CAAC;IACrC,CAAC;IAED,4BAA4B;IAC5B,KAAK;QACH,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACtB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACrB,CAAC;IACH,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;IACxD,CAAC;IAED,0EAA0E;IAC1E,eAAe;IACf,0EAA0E;IAElE,gBAAgB,CAAC,MAAc;QACrC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC/B,IAAI,YAAoB,CAAC;YACzB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;gBACzD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;gBAChD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;gBAClD,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;oBAChB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBACxB,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,UAAU,CAAC,IAAY;QAC7B,IAAI,GAAQ,CAAC;QACb,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,4BAA4B;QACtC,CAAC;QAED,4CAA4C;QAC5C,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC,QAAQ,IAAI,GAAG,IAAI,OAAO,IAAI,GAAG,CAAC,EAAE,CAAC;YAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACzC,IAAI,OAAO,EAAE,CAAC;gBACZ,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC5B,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAC5B,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;oBACd,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBAC5D,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACtB,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAC9B,CAAC;YACH,CAAC;YACD,OAAO;QACT,CAAC;QAED,4CAA4C;QAC5C,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;YACjC,IAAI,CAAC,mBAAmB,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;YACzD,OAAO;QACT,CAAC;IACH,CAAC;CACF;AAED,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,IAAI,GAAG,kBAAkB,CAAC;IAC1B,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED,MAAM,OAAO,QAAS,SAAQ,KAAK;IAGxB;IAFT,YACE,OAAe,EACR,OAAe;QAEtB,KAAK,CAAC,OAAO,CAAC,CAAC;QAFR,YAAO,GAAP,OAAO,CAAQ;QAGtB,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IPC server — JSON-RPC 2.0 over newline-delimited Unix domain socket.
|
|
3
|
+
*
|
|
4
|
+
* The daemon creates this server on startup. CLI clients and session workers
|
|
5
|
+
* connect to it as JSON-RPC clients.
|
|
6
|
+
*/
|
|
7
|
+
import { type Socket } from 'net';
|
|
8
|
+
import { EventEmitter } from 'events';
|
|
9
|
+
import type { JsonRpcNotification, StatusResult } from './types.js';
|
|
10
|
+
export interface IpcClient {
|
|
11
|
+
id: string;
|
|
12
|
+
role?: 'cli' | 'worker';
|
|
13
|
+
sessionId?: string;
|
|
14
|
+
subscribed: boolean;
|
|
15
|
+
socket: Socket;
|
|
16
|
+
}
|
|
17
|
+
export type MethodHandler = (params: Record<string, unknown>, client: IpcClient) => Promise<unknown> | unknown;
|
|
18
|
+
export declare class IpcServer extends EventEmitter {
|
|
19
|
+
private server;
|
|
20
|
+
private clients;
|
|
21
|
+
private methods;
|
|
22
|
+
private nextClientId;
|
|
23
|
+
private startedAt;
|
|
24
|
+
private version;
|
|
25
|
+
private statusProvider?;
|
|
26
|
+
constructor(opts: {
|
|
27
|
+
version: string;
|
|
28
|
+
});
|
|
29
|
+
/** Register a JSON-RPC method handler. */
|
|
30
|
+
registerMethod(method: string, handler: MethodHandler): void;
|
|
31
|
+
/** Set a provider for live status data (wired after AgentConnection starts). */
|
|
32
|
+
setStatusProvider(fn: () => StatusResult): void;
|
|
33
|
+
/** Start listening on the given Unix socket path. */
|
|
34
|
+
listen(socketPath: string): Promise<void>;
|
|
35
|
+
/** Gracefully close the server and all client connections. */
|
|
36
|
+
close(): Promise<void>;
|
|
37
|
+
/** Get the number of connected clients. */
|
|
38
|
+
getClientCount(): number;
|
|
39
|
+
/** Broadcast a JSON-RPC notification to all subscribed CLI clients. */
|
|
40
|
+
broadcast(notification: JsonRpcNotification): void;
|
|
41
|
+
/** Send a JSON-RPC request to a specific client (for daemon→worker commands). */
|
|
42
|
+
sendRequest(clientId: string, method: string, params: Record<string, unknown>, id: number | string): boolean;
|
|
43
|
+
private onConnection;
|
|
44
|
+
private handleLine;
|
|
45
|
+
private handleHello;
|
|
46
|
+
private handlePing;
|
|
47
|
+
private handleStatus;
|
|
48
|
+
private handleShutdown;
|
|
49
|
+
private handleSubscribe;
|
|
50
|
+
private sendMessage;
|
|
51
|
+
private sendError;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=ipcServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ipcServer.d.ts","sourceRoot":"","sources":["../../src/service/ipcServer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAA6B,KAAK,MAAM,EAAE,MAAM,KAAK,CAAC;AAE7D,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAGV,mBAAmB,EAKnB,YAAY,EACb,MAAM,YAAY,CAAC;AAOpB,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAMD,MAAM,MAAM,aAAa,GAAG,CAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,MAAM,EAAE,SAAS,KACd,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;AAMhC,qBAAa,SAAU,SAAQ,YAAY;IACzC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAC,CAAqB;gBAEhC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE;IAarC,0CAA0C;IAC1C,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI;IAI5D,gFAAgF;IAChF,iBAAiB,CAAC,EAAE,EAAE,MAAM,YAAY,GAAG,IAAI;IAI/C,qDAAqD;IAC/C,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA2B/C,8DAA8D;IACxD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAuB5B,2CAA2C;IAC3C,cAAc,IAAI,MAAM;IAIxB,uEAAuE;IACvE,SAAS,CAAC,YAAY,EAAE,mBAAmB,GAAG,IAAI;IAQlD,iFAAiF;IACjF,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO;IAY5G,OAAO,CAAC,YAAY;YAiCN,UAAU;IAkDxB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,SAAS;CAQlB"}
|