@sumicom/quicksave 0.4.0 → 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.
- 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.map +1 -1
- package/dist/connection/relay.js +2 -0
- 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 +138 -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 @@
|
|
|
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 @@
|
|
|
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"}
|