@sumicom/quicksave 0.3.1 → 0.5.0

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 (81) hide show
  1. package/dist/ai/claudeCodeService.d.ts +89 -0
  2. package/dist/ai/claudeCodeService.d.ts.map +1 -0
  3. package/dist/ai/claudeCodeService.js +602 -0
  4. package/dist/ai/claudeCodeService.js.map +1 -0
  5. package/dist/ai/sessionStore.d.ts +31 -0
  6. package/dist/ai/sessionStore.d.ts.map +1 -0
  7. package/dist/ai/sessionStore.js +72 -0
  8. package/dist/ai/sessionStore.js.map +1 -0
  9. package/dist/ai/sessionStore.test.d.ts +2 -0
  10. package/dist/ai/sessionStore.test.d.ts.map +1 -0
  11. package/dist/ai/sessionStore.test.js +99 -0
  12. package/dist/ai/sessionStore.test.js.map +1 -0
  13. package/dist/config.d.ts +7 -0
  14. package/dist/config.d.ts.map +1 -1
  15. package/dist/config.js +39 -0
  16. package/dist/config.js.map +1 -1
  17. package/dist/connection/connection.d.ts +16 -17
  18. package/dist/connection/connection.d.ts.map +1 -1
  19. package/dist/connection/connection.js +72 -57
  20. package/dist/connection/connection.js.map +1 -1
  21. package/dist/connection/{signaling.d.ts → relay.d.ts} +3 -5
  22. package/dist/connection/relay.d.ts.map +1 -0
  23. package/dist/connection/{signaling.js → relay.js} +18 -19
  24. package/dist/connection/relay.js.map +1 -0
  25. package/dist/git/operations.d.ts +27 -1
  26. package/dist/git/operations.d.ts.map +1 -1
  27. package/dist/git/operations.js +113 -4
  28. package/dist/git/operations.js.map +1 -1
  29. package/dist/git/operations.test.js +69 -1
  30. package/dist/git/operations.test.js.map +1 -1
  31. package/dist/handlers/messageHandler.d.ts +31 -4
  32. package/dist/handlers/messageHandler.d.ts.map +1 -1
  33. package/dist/handlers/messageHandler.js +491 -62
  34. package/dist/handlers/messageHandler.js.map +1 -1
  35. package/dist/handlers/messageHandler.test.js +130 -2
  36. package/dist/handlers/messageHandler.test.js.map +1 -1
  37. package/dist/index.js +229 -89
  38. package/dist/index.js.map +1 -1
  39. package/dist/service/ensureDaemon.d.ts +23 -0
  40. package/dist/service/ensureDaemon.d.ts.map +1 -0
  41. package/dist/service/ensureDaemon.js +138 -0
  42. package/dist/service/ensureDaemon.js.map +1 -0
  43. package/dist/service/index.d.ts +8 -0
  44. package/dist/service/index.d.ts.map +1 -0
  45. package/dist/service/index.js +8 -0
  46. package/dist/service/index.js.map +1 -0
  47. package/dist/service/ipc.test.d.ts +2 -0
  48. package/dist/service/ipc.test.d.ts.map +1 -0
  49. package/dist/service/ipc.test.js +140 -0
  50. package/dist/service/ipc.test.js.map +1 -0
  51. package/dist/service/ipcClient.d.ts +36 -0
  52. package/dist/service/ipcClient.d.ts.map +1 -0
  53. package/dist/service/ipcClient.js +167 -0
  54. package/dist/service/ipcClient.js.map +1 -0
  55. package/dist/service/ipcServer.d.ts +53 -0
  56. package/dist/service/ipcServer.d.ts.map +1 -0
  57. package/dist/service/ipcServer.js +245 -0
  58. package/dist/service/ipcServer.js.map +1 -0
  59. package/dist/service/run.d.ts +13 -0
  60. package/dist/service/run.d.ts.map +1 -0
  61. package/dist/service/run.js +292 -0
  62. package/dist/service/run.js.map +1 -0
  63. package/dist/service/singleton.d.ts +31 -0
  64. package/dist/service/singleton.d.ts.map +1 -0
  65. package/dist/service/singleton.js +96 -0
  66. package/dist/service/singleton.js.map +1 -0
  67. package/dist/service/singleton.test.d.ts +2 -0
  68. package/dist/service/singleton.test.d.ts.map +1 -0
  69. package/dist/service/singleton.test.js +39 -0
  70. package/dist/service/singleton.test.js.map +1 -0
  71. package/dist/service/stateStore.d.ts +11 -0
  72. package/dist/service/stateStore.d.ts.map +1 -0
  73. package/dist/service/stateStore.js +35 -0
  74. package/dist/service/stateStore.js.map +1 -0
  75. package/dist/service/types.d.ts +111 -0
  76. package/dist/service/types.d.ts.map +1 -0
  77. package/dist/service/types.js +76 -0
  78. package/dist/service/types.js.map +1 -0
  79. package/package.json +3 -2
  80. package/dist/connection/signaling.d.ts.map +0 -1
  81. package/dist/connection/signaling.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipcServer.js","sourceRoot":"","sources":["../../src/service/ipcServer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Daemon entrypoint — `quicksave service run`.
3
+ *
4
+ * Boot sequence:
5
+ * 1. Acquire singleton lock.
6
+ * 2. Start IPC server on Unix socket.
7
+ * 3. Load config and managed repos.
8
+ * 4. Start AgentConnection (signaling + message handler).
9
+ * 5. Persist ready state to service.json.
10
+ * 6. Run heartbeat loop.
11
+ */
12
+ export declare function runDaemon(): Promise<void>;
13
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/service/run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAuBH,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CA6L/C"}
@@ -0,0 +1,292 @@
1
+ /**
2
+ * Daemon entrypoint — `quicksave service run`.
3
+ *
4
+ * Boot sequence:
5
+ * 1. Acquire singleton lock.
6
+ * 2. Start IPC server on Unix socket.
7
+ * 3. Load config and managed repos.
8
+ * 4. Start AgentConnection (signaling + message handler).
9
+ * 5. Persist ready state to service.json.
10
+ * 6. Run heartbeat loop.
11
+ */
12
+ import { basename } from 'path';
13
+ import { hostname } from 'os';
14
+ import { getOrCreateConfig, getManagedRepos, getManagedCodingPaths, addManagedRepo, removeManagedRepo } from '../config.js';
15
+ import { AgentConnection } from '../connection/connection.js';
16
+ import { MessageHandler } from '../handlers/messageHandler.js';
17
+ import { GitOperations } from '../git/operations.js';
18
+ import { IpcServer } from './ipcServer.js';
19
+ import { acquireLock, ensureDirectories, getSocketPath, cleanStaleRuntime, } from './singleton.js';
20
+ import { writeServiceState, removeServiceState } from './stateStore.js';
21
+ import { IPC_VERSION, BUILD_ID } from './types.js';
22
+ import { createMessage } from '@sumicom/quicksave-shared';
23
+ const HEARTBEAT_INTERVAL_MS = 30_000;
24
+ const PACKAGE_VERSION = '0.5.0';
25
+ export async function runDaemon() {
26
+ ensureDirectories();
27
+ // Prevent unhandled rejections from silently killing the daemon
28
+ process.on('unhandledRejection', (reason) => {
29
+ console.error('Unhandled rejection in daemon:', reason);
30
+ });
31
+ // 1. Acquire singleton lock
32
+ const releaseLock = acquireLock();
33
+ if (!releaseLock) {
34
+ console.error('Another daemon is already running. Use `quicksave service status` to check.');
35
+ process.exit(1);
36
+ }
37
+ const socketPath = getSocketPath();
38
+ let heartbeatTimer = null;
39
+ let shuttingDown = false;
40
+ // 2. Start IPC server
41
+ const ipcServer = new IpcServer({ version: PACKAGE_VERSION });
42
+ try {
43
+ await ipcServer.listen(socketPath);
44
+ }
45
+ catch (err) {
46
+ console.error('Failed to start IPC server:', err);
47
+ releaseLock();
48
+ process.exit(1);
49
+ }
50
+ // 3. Load config and managed repos
51
+ const config = getOrCreateConfig('wss://signal.quicksave.dev');
52
+ const repoPaths = getManagedRepos();
53
+ const codingPaths = getManagedCodingPaths();
54
+ const validRepos = await validateRepos(repoPaths);
55
+ console.log(`Managed repos: ${validRepos.length} valid of ${repoPaths.length} configured`);
56
+ // 4. Start AgentConnection
57
+ const connection = new AgentConnection({
58
+ signalingServer: config.signalingServer,
59
+ agentId: config.agentId,
60
+ keyPair: config.keyPair,
61
+ });
62
+ const messageHandler = new MessageHandler(validRepos, config.license, codingPaths);
63
+ // Pub/sub: ClaudeCodeService emits events → broadcast to all connected PWA peers
64
+ const claudeService = messageHandler.getClaudeService();
65
+ claudeService.on('stream', (event) => {
66
+ connection.broadcast(createMessage('claude:stream', event));
67
+ });
68
+ claudeService.on('stream:end', (result) => {
69
+ connection.broadcast(createMessage('claude:stream:end', result));
70
+ });
71
+ claudeService.on('user-input-request', (request) => {
72
+ connection.broadcast(createMessage('claude:user-input-request', request));
73
+ });
74
+ claudeService.on('user-input-resolved', (info) => {
75
+ connection.broadcast(createMessage('claude:user-input-resolved', info));
76
+ });
77
+ claudeService.on('session-updated', (info) => {
78
+ connection.broadcast(createMessage('claude:session-updated', info));
79
+ });
80
+ // Wire: incoming PWA messages → MessageHandler → response back to PWA
81
+ connection.on('message', async (message, peerAddress) => {
82
+ try {
83
+ const response = await messageHandler.handleMessage(message, peerAddress);
84
+ connection.send(response, peerAddress);
85
+ }
86
+ catch (error) {
87
+ console.error('Failed to handle message:', error);
88
+ }
89
+ });
90
+ // 5. Register IPC methods and status provider BEFORE writing service state,
91
+ // so methods are available as soon as clients can discover the daemon.
92
+ const startedAt = new Date().toISOString();
93
+ const serviceState = {
94
+ pid: process.pid,
95
+ version: PACKAGE_VERSION,
96
+ ipcVersion: IPC_VERSION,
97
+ buildId: BUILD_ID,
98
+ startedAt,
99
+ lastHeartbeatAt: startedAt,
100
+ socketPath,
101
+ agentId: config.agentId,
102
+ publicKey: config.keyPair.publicKey,
103
+ signalingServer: config.signalingServer,
104
+ connectionState: 'disconnected',
105
+ peerCount: 0,
106
+ };
107
+ ipcServer.setStatusProvider(() => {
108
+ const uptimeMs = Date.now() - new Date(startedAt).getTime();
109
+ return {
110
+ version: PACKAGE_VERSION,
111
+ pid: process.pid,
112
+ uptime: Math.floor(uptimeMs / 1000),
113
+ connectionState: serviceState.connectionState,
114
+ peerCount: connection.getPeerCount(),
115
+ activeSessions: messageHandler.getActiveSessionCount(),
116
+ managedRepos: getManagedRepos().length,
117
+ };
118
+ });
119
+ registerDaemonMethods(ipcServer, connection, messageHandler, config);
120
+ // Wire peer events
121
+ connection.on('connected', (peerAddress) => {
122
+ const peerKey = peerAddress.replace('pwa:', '');
123
+ console.log(`+ PWA connected: ${peerKey.slice(0, 12)}... (${connection.getPeerCount()} peers)`);
124
+ serviceState.peerCount = connection.getPeerCount();
125
+ serviceState.connectionState = 'connected';
126
+ writeServiceState(serviceState);
127
+ ipcServer.broadcast({
128
+ jsonrpc: '2.0',
129
+ method: 'event.peerConnected',
130
+ params: { peerId: peerKey.slice(0, 12), peerCount: connection.getPeerCount() },
131
+ });
132
+ });
133
+ connection.on('disconnected', (peerAddress) => {
134
+ const peerKey = peerAddress.replace('pwa:', '');
135
+ messageHandler.removeClient(peerAddress);
136
+ console.log(`- PWA disconnected: ${peerKey.slice(0, 12)}... (${connection.getPeerCount()} peers)`);
137
+ serviceState.peerCount = connection.getPeerCount();
138
+ if (!connection.hasPeers())
139
+ serviceState.connectionState = 'disconnected';
140
+ writeServiceState(serviceState);
141
+ ipcServer.broadcast({
142
+ jsonrpc: '2.0',
143
+ method: 'event.peerDisconnected',
144
+ params: { peerId: peerKey.slice(0, 12), peerCount: connection.getPeerCount() },
145
+ });
146
+ });
147
+ connection.on('error', (error) => {
148
+ console.error('Connection error:', error.message);
149
+ });
150
+ // Persist ready state — daemon becomes discoverable by CLI clients
151
+ writeServiceState(serviceState);
152
+ // Start signaling connection (may be slow — all IPC methods already registered above)
153
+ try {
154
+ await connection.start();
155
+ console.log('Signaling connection established');
156
+ }
157
+ catch (error) {
158
+ console.error('Failed to start signaling connection:', error);
159
+ // Daemon continues running — will retry on reconnect
160
+ }
161
+ // 6. Heartbeat loop
162
+ heartbeatTimer = setInterval(() => {
163
+ serviceState.lastHeartbeatAt = new Date().toISOString();
164
+ serviceState.peerCount = connection.getPeerCount();
165
+ writeServiceState(serviceState);
166
+ }, HEARTBEAT_INTERVAL_MS);
167
+ console.log(`Quicksave daemon started (pid: ${process.pid})`);
168
+ console.log(` IPC socket: ${socketPath}`);
169
+ console.log(` Agent ID: ${config.agentId}`);
170
+ // Shutdown handler
171
+ const shutdown = async () => {
172
+ if (shuttingDown)
173
+ return;
174
+ shuttingDown = true;
175
+ console.log('Daemon shutting down...');
176
+ if (heartbeatTimer) {
177
+ clearInterval(heartbeatTimer);
178
+ heartbeatTimer = null;
179
+ }
180
+ messageHandler.cleanup();
181
+ connection.disconnect();
182
+ await ipcServer.close();
183
+ removeServiceState();
184
+ cleanStaleRuntime();
185
+ releaseLock();
186
+ process.exit(0);
187
+ };
188
+ ipcServer.on('shutdown-requested', shutdown);
189
+ process.on('SIGINT', shutdown);
190
+ process.on('SIGTERM', shutdown);
191
+ }
192
+ // ---------------------------------------------------------------------------
193
+ // IPC method registration
194
+ // ---------------------------------------------------------------------------
195
+ function registerDaemonMethods(ipcServer, connection, messageHandler, config) {
196
+ // get-pairing-info
197
+ ipcServer.registerMethod('get-pairing-info', () => {
198
+ const pairingUrl = `https://quicksave.dev/connect?id=${config.agentId}&pk=${encodeURIComponent(config.keyPair.publicKey)}&name=${encodeURIComponent(hostname())}`;
199
+ return {
200
+ agentId: config.agentId,
201
+ publicKey: config.keyPair.publicKey,
202
+ pairingUrl,
203
+ connectionState: connection.hasPeers() ? 'connected' : 'disconnected',
204
+ peerCount: connection.getPeerCount(),
205
+ };
206
+ });
207
+ // list-repos
208
+ ipcServer.registerMethod('list-repos', async () => {
209
+ const paths = getManagedRepos();
210
+ const repos = [];
211
+ for (const path of paths) {
212
+ const git = new GitOperations(path);
213
+ const valid = await git.isValidRepo();
214
+ let currentBranch;
215
+ if (valid) {
216
+ try {
217
+ const branches = await git.getBranches();
218
+ currentBranch = branches.current;
219
+ }
220
+ catch { /* ignore */ }
221
+ }
222
+ repos.push({ path, name: basename(path), valid, currentBranch });
223
+ }
224
+ return { repos };
225
+ });
226
+ // add-repo
227
+ ipcServer.registerMethod('add-repo', async (params) => {
228
+ const path = params.path;
229
+ if (!path)
230
+ throw Object.assign(new Error('Missing path'), { rpcCode: -32602 });
231
+ const git = new GitOperations(path);
232
+ const valid = await git.isValidRepo();
233
+ if (!valid) {
234
+ throw Object.assign(new Error(`Not a valid git repository: ${path}`), { rpcCode: -32602 });
235
+ }
236
+ addManagedRepo(path);
237
+ const rootPath = await git.getGitRoot();
238
+ const branches = await git.getBranches();
239
+ const repo = { path: rootPath, name: basename(rootPath), valid: true, currentBranch: branches.current };
240
+ // Update running message handler so PWA can use the repo immediately
241
+ messageHandler.addRepo({ path: rootPath, name: basename(rootPath), currentBranch: branches.current });
242
+ ipcServer.broadcast({
243
+ jsonrpc: '2.0',
244
+ method: 'event.repoAdded',
245
+ params: { repo },
246
+ });
247
+ return { added: true, repo };
248
+ });
249
+ // remove-repo
250
+ ipcServer.registerMethod('remove-repo', (params) => {
251
+ const path = params.path;
252
+ if (!path)
253
+ throw Object.assign(new Error('Missing path'), { rpcCode: -32602 });
254
+ removeManagedRepo(path);
255
+ messageHandler.removeRepo(path);
256
+ ipcServer.broadcast({
257
+ jsonrpc: '2.0',
258
+ method: 'event.repoRemoved',
259
+ params: { path },
260
+ });
261
+ return { removed: true };
262
+ });
263
+ // restart
264
+ ipcServer.registerMethod('restart', () => {
265
+ process.nextTick(() => ipcServer.emit('shutdown-requested'));
266
+ return { ok: true };
267
+ });
268
+ }
269
+ // ---------------------------------------------------------------------------
270
+ // Repo validation helper
271
+ // ---------------------------------------------------------------------------
272
+ async function validateRepos(paths) {
273
+ const repos = [];
274
+ for (const repoPath of paths) {
275
+ const git = new GitOperations(repoPath);
276
+ const valid = await git.isValidRepo();
277
+ if (!valid) {
278
+ console.warn(` Skipping invalid repo: ${repoPath}`);
279
+ continue;
280
+ }
281
+ try {
282
+ const rootPath = await git.getGitRoot();
283
+ const { current: currentBranch } = await git.getBranches();
284
+ repos.push({ path: rootPath, name: basename(rootPath), currentBranch });
285
+ }
286
+ catch (err) {
287
+ console.warn(` Failed to read repo: ${repoPath}`, err);
288
+ }
289
+ }
290
+ return repos;
291
+ }
292
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/service/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Singleton lock for ensuring exactly one daemon per user.
3
+ *
4
+ * Uses an exclusive lock file at ~/.quicksave/run/service.lock.
5
+ * The lock is held via an open file descriptor — if the process crashes,
6
+ * the OS releases the lock automatically.
7
+ */
8
+ export declare function getRunDir(): string;
9
+ export declare function getSocketPath(): string;
10
+ export declare function getLockPath(): string;
11
+ export declare function getStateDir(): string;
12
+ export declare function getSessionsDir(): string;
13
+ export declare function getLogsDir(): string;
14
+ /**
15
+ * Ensure all required directories exist.
16
+ */
17
+ export declare function ensureDirectories(): void;
18
+ /**
19
+ * Try to acquire the singleton lock.
20
+ * Returns a release function on success, or null if the lock is held by another process.
21
+ */
22
+ export declare function acquireLock(): (() => void) | null;
23
+ /**
24
+ * Remove stale runtime files (lock, socket) when we detect a dead daemon.
25
+ */
26
+ export declare function cleanStaleRuntime(): void;
27
+ /**
28
+ * Check if a PID is alive.
29
+ */
30
+ export declare function isProcessAlive(pid: number): boolean;
31
+ //# sourceMappingURL=singleton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"singleton.d.ts","sourceRoot":"","sources":["../../src/service/singleton.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAWH,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAMxC;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAmBjD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAWxC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOnD"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Singleton lock for ensuring exactly one daemon per user.
3
+ *
4
+ * Uses an exclusive lock file at ~/.quicksave/run/service.lock.
5
+ * The lock is held via an open file descriptor — if the process crashes,
6
+ * the OS releases the lock automatically.
7
+ */
8
+ import { openSync, closeSync, mkdirSync, existsSync, unlinkSync, constants } from 'fs';
9
+ import { join } from 'path';
10
+ import { homedir } from 'os';
11
+ const QUICKSAVE_DIR = join(homedir(), '.quicksave');
12
+ const RUN_DIR = join(QUICKSAVE_DIR, 'run');
13
+ const LOCK_FILE = join(RUN_DIR, 'service.lock');
14
+ const SOCKET_PATH = join(RUN_DIR, 'service.sock');
15
+ export function getRunDir() {
16
+ return RUN_DIR;
17
+ }
18
+ export function getSocketPath() {
19
+ return SOCKET_PATH;
20
+ }
21
+ export function getLockPath() {
22
+ return LOCK_FILE;
23
+ }
24
+ export function getStateDir() {
25
+ return join(QUICKSAVE_DIR, 'state');
26
+ }
27
+ export function getSessionsDir() {
28
+ return join(getStateDir(), 'sessions');
29
+ }
30
+ export function getLogsDir() {
31
+ return join(QUICKSAVE_DIR, 'logs');
32
+ }
33
+ /**
34
+ * Ensure all required directories exist.
35
+ */
36
+ export function ensureDirectories() {
37
+ for (const dir of [RUN_DIR, getStateDir(), getSessionsDir(), getLogsDir()]) {
38
+ if (!existsSync(dir)) {
39
+ mkdirSync(dir, { recursive: true });
40
+ }
41
+ }
42
+ }
43
+ /**
44
+ * Try to acquire the singleton lock.
45
+ * Returns a release function on success, or null if the lock is held by another process.
46
+ */
47
+ export function acquireLock() {
48
+ ensureDirectories();
49
+ try {
50
+ const fd = openSync(LOCK_FILE, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL, 0o600);
51
+ return () => {
52
+ try {
53
+ closeSync(fd);
54
+ unlinkSync(LOCK_FILE);
55
+ }
56
+ catch {
57
+ // Best-effort cleanup
58
+ }
59
+ };
60
+ }
61
+ catch (err) {
62
+ if (err.code === 'EEXIST') {
63
+ return null;
64
+ }
65
+ throw err;
66
+ }
67
+ }
68
+ /**
69
+ * Remove stale runtime files (lock, socket) when we detect a dead daemon.
70
+ */
71
+ export function cleanStaleRuntime() {
72
+ for (const file of [LOCK_FILE, SOCKET_PATH]) {
73
+ try {
74
+ unlinkSync(file);
75
+ }
76
+ catch (err) {
77
+ if (err.code !== 'ENOENT') {
78
+ // Ignore missing files, rethrow anything else
79
+ throw err;
80
+ }
81
+ }
82
+ }
83
+ }
84
+ /**
85
+ * Check if a PID is alive.
86
+ */
87
+ export function isProcessAlive(pid) {
88
+ try {
89
+ process.kill(pid, 0);
90
+ return true;
91
+ }
92
+ catch {
93
+ return false;
94
+ }
95
+ }
96
+ //# sourceMappingURL=singleton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"singleton.js","sourceRoot":"","sources":["../../src/service/singleton.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=singleton.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"singleton.test.d.ts","sourceRoot":"","sources":["../../src/service/singleton.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,39 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { isProcessAlive } from './singleton.js';
3
+ import { shouldRestartDaemon, IPC_VERSION, BUILD_ID } from './types.js';
4
+ describe('isProcessAlive', () => {
5
+ it('returns true for the current process', () => {
6
+ expect(isProcessAlive(process.pid)).toBe(true);
7
+ });
8
+ it('returns false for a non-existent PID', () => {
9
+ // PID 99999999 is extremely unlikely to exist
10
+ expect(isProcessAlive(99999999)).toBe(false);
11
+ });
12
+ });
13
+ describe('shouldRestartDaemon', () => {
14
+ const makeDaemon = (overrides = {}) => ({
15
+ daemonVersion: '0.5.0',
16
+ daemonIpcVersion: IPC_VERSION,
17
+ daemonBuildId: BUILD_ID,
18
+ daemonPid: 12345,
19
+ ...overrides,
20
+ });
21
+ it('returns ok when versions match', () => {
22
+ const result = shouldRestartDaemon(makeDaemon(), { ipcVersion: IPC_VERSION, buildId: BUILD_ID });
23
+ expect(result.action).toBe('ok');
24
+ });
25
+ it('returns restart when daemon ipcVersion is lower', () => {
26
+ const result = shouldRestartDaemon(makeDaemon({ daemonIpcVersion: 0 }), { ipcVersion: IPC_VERSION, buildId: BUILD_ID });
27
+ expect(result.action).toBe('restart');
28
+ });
29
+ it('returns warn_outdated when CLI ipcVersion is lower', () => {
30
+ const result = shouldRestartDaemon(makeDaemon({ daemonIpcVersion: 99 }), { ipcVersion: IPC_VERSION, buildId: BUILD_ID });
31
+ expect(result.action).toBe('warn_outdated');
32
+ });
33
+ it('returns restart when buildId differs in dev mode', () => {
34
+ // In dev mode, BUILD_ID starts with 'dev-' so isDev() returns true
35
+ const result = shouldRestartDaemon(makeDaemon({ daemonBuildId: 'dev-aaa111bbb222' }), { ipcVersion: IPC_VERSION, buildId: 'dev-ccc333ddd444' });
36
+ expect(result.action).toBe('restart');
37
+ });
38
+ });
39
+ //# sourceMappingURL=singleton.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"singleton.test.js","sourceRoot":"","sources":["../../src/service/singleton.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGxE,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,8CAA8C;QAC9C,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,MAAM,UAAU,GAAG,CAAC,YAAkC,EAAE,EAAe,EAAE,CAAC,CAAC;QACzE,aAAa,EAAE,OAAO;QACtB,gBAAgB,EAAE,WAAW;QAC7B,aAAa,EAAE,QAAQ;QACvB,SAAS,EAAE,KAAK;QAChB,GAAG,SAAS;KACb,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,MAAM,GAAG,mBAAmB,CAChC,UAAU,EAAE,EACZ,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,CAC/C,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,MAAM,GAAG,mBAAmB,CAChC,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC,EACnC,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,CAC/C,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,MAAM,GAAG,mBAAmB,CAChC,UAAU,CAAC,EAAE,gBAAgB,EAAE,EAAE,EAAE,CAAC,EACpC,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,CAC/C,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,mEAAmE;QACnE,MAAM,MAAM,GAAG,mBAAmB,CAChC,UAAU,CAAC,EAAE,aAAa,EAAE,kBAAkB,EAAE,CAAC,EACjD,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,kBAAkB,EAAE,CACzD,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Persistence for service.json — the daemon's externally-visible state file.
3
+ *
4
+ * Written by the daemon, read by CLI clients for quick pre-checks
5
+ * before attempting IPC connection.
6
+ */
7
+ import type { ServiceState } from './types.js';
8
+ export declare function readServiceState(): ServiceState | null;
9
+ export declare function writeServiceState(state: ServiceState): void;
10
+ export declare function removeServiceState(): void;
11
+ //# sourceMappingURL=stateStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stateStore.d.ts","sourceRoot":"","sources":["../../src/service/stateStore.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK/C,wBAAgB,gBAAgB,IAAI,YAAY,GAAG,IAAI,CAStD;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAE3D;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAMzC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Persistence for service.json — the daemon's externally-visible state file.
3
+ *
4
+ * Written by the daemon, read by CLI clients for quick pre-checks
5
+ * before attempting IPC connection.
6
+ */
7
+ import { readFileSync, writeFileSync, existsSync, unlinkSync } from 'fs';
8
+ import { join } from 'path';
9
+ import { getStateDir } from './singleton.js';
10
+ const SERVICE_JSON = () => join(getStateDir(), 'service.json');
11
+ export function readServiceState() {
12
+ try {
13
+ const path = SERVICE_JSON();
14
+ if (!existsSync(path))
15
+ return null;
16
+ const data = readFileSync(path, 'utf-8');
17
+ return JSON.parse(data);
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ export function writeServiceState(state) {
24
+ writeFileSync(SERVICE_JSON(), JSON.stringify(state, null, 2));
25
+ }
26
+ export function removeServiceState() {
27
+ try {
28
+ unlinkSync(SERVICE_JSON());
29
+ }
30
+ catch (err) {
31
+ if (err.code !== 'ENOENT')
32
+ throw err;
33
+ }
34
+ }
35
+ //# sourceMappingURL=stateStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stateStore.js","sourceRoot":"","sources":["../../src/service/stateStore.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACzE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,cAAc,CAAC,CAAC;AAE/D,MAAM,UAAU,gBAAgB;IAC9B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAC5B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAiB,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAmB;IACnD,aAAa,CAAC,YAAY,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,IAAI,CAAC;QACH,UAAU,CAAC,YAAY,EAAE,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,GAAG,CAAC;IACvC,CAAC;AACH,CAAC"}