@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,245 @@
|
|
|
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 { createServer } from 'net';
|
|
8
|
+
import { unlinkSync, chmodSync } from 'fs';
|
|
9
|
+
import { EventEmitter } from 'events';
|
|
10
|
+
import { IPC_VERSION, BUILD_ID, RpcErrorCode } from './types.js';
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// IpcServer
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
export class IpcServer extends EventEmitter {
|
|
15
|
+
server = null;
|
|
16
|
+
clients = new Map();
|
|
17
|
+
methods = new Map();
|
|
18
|
+
nextClientId = 1;
|
|
19
|
+
startedAt;
|
|
20
|
+
version;
|
|
21
|
+
statusProvider;
|
|
22
|
+
constructor(opts) {
|
|
23
|
+
super();
|
|
24
|
+
this.version = opts.version;
|
|
25
|
+
this.startedAt = new Date();
|
|
26
|
+
// Register built-in methods
|
|
27
|
+
this.registerMethod('hello', (params) => this.handleHello(params));
|
|
28
|
+
this.registerMethod('ping', () => this.handlePing());
|
|
29
|
+
this.registerMethod('status', () => this.handleStatus());
|
|
30
|
+
this.registerMethod('shutdown', (_params, client) => this.handleShutdown(client));
|
|
31
|
+
this.registerMethod('subscribe-events', (_params, client) => this.handleSubscribe(client));
|
|
32
|
+
}
|
|
33
|
+
/** Register a JSON-RPC method handler. */
|
|
34
|
+
registerMethod(method, handler) {
|
|
35
|
+
this.methods.set(method, handler);
|
|
36
|
+
}
|
|
37
|
+
/** Set a provider for live status data (wired after AgentConnection starts). */
|
|
38
|
+
setStatusProvider(fn) {
|
|
39
|
+
this.statusProvider = fn;
|
|
40
|
+
}
|
|
41
|
+
/** Start listening on the given Unix socket path. */
|
|
42
|
+
async listen(socketPath) {
|
|
43
|
+
// Remove stale socket file if present
|
|
44
|
+
try {
|
|
45
|
+
unlinkSync(socketPath);
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
if (err.code !== 'ENOENT')
|
|
49
|
+
throw err;
|
|
50
|
+
}
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
this.server = createServer((socket) => this.onConnection(socket));
|
|
53
|
+
this.server.on('error', (err) => {
|
|
54
|
+
reject(err);
|
|
55
|
+
});
|
|
56
|
+
this.server.listen(socketPath, () => {
|
|
57
|
+
// Set socket permissions to owner-only
|
|
58
|
+
try {
|
|
59
|
+
chmodSync(socketPath, 0o600);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// Best effort — may fail on some systems
|
|
63
|
+
}
|
|
64
|
+
resolve();
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/** Gracefully close the server and all client connections. */
|
|
69
|
+
async close() {
|
|
70
|
+
// Notify subscribed clients
|
|
71
|
+
this.broadcast({
|
|
72
|
+
jsonrpc: '2.0',
|
|
73
|
+
method: 'event.daemonStatus',
|
|
74
|
+
params: { shutting_down: true },
|
|
75
|
+
});
|
|
76
|
+
// Close all client sockets
|
|
77
|
+
for (const client of this.clients.values()) {
|
|
78
|
+
client.socket.destroy();
|
|
79
|
+
}
|
|
80
|
+
this.clients.clear();
|
|
81
|
+
return new Promise((resolve) => {
|
|
82
|
+
if (this.server) {
|
|
83
|
+
this.server.close(() => resolve());
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
resolve();
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/** Get the number of connected clients. */
|
|
91
|
+
getClientCount() {
|
|
92
|
+
return this.clients.size;
|
|
93
|
+
}
|
|
94
|
+
/** Broadcast a JSON-RPC notification to all subscribed CLI clients. */
|
|
95
|
+
broadcast(notification) {
|
|
96
|
+
for (const client of this.clients.values()) {
|
|
97
|
+
if (client.subscribed) {
|
|
98
|
+
this.sendMessage(client.socket, notification);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** Send a JSON-RPC request to a specific client (for daemon→worker commands). */
|
|
103
|
+
sendRequest(clientId, method, params, id) {
|
|
104
|
+
const client = this.clients.get(clientId);
|
|
105
|
+
if (!client)
|
|
106
|
+
return false;
|
|
107
|
+
const request = { jsonrpc: '2.0', id, method, params };
|
|
108
|
+
this.sendMessage(client.socket, request);
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
// -----------------------------------------------------------------------
|
|
112
|
+
// Connection handling
|
|
113
|
+
// -----------------------------------------------------------------------
|
|
114
|
+
onConnection(socket) {
|
|
115
|
+
const clientId = `c${this.nextClientId++}`;
|
|
116
|
+
const client = {
|
|
117
|
+
id: clientId,
|
|
118
|
+
subscribed: false,
|
|
119
|
+
socket,
|
|
120
|
+
};
|
|
121
|
+
this.clients.set(clientId, client);
|
|
122
|
+
let buffer = '';
|
|
123
|
+
socket.on('data', (data) => {
|
|
124
|
+
buffer += data.toString();
|
|
125
|
+
let newlineIndex;
|
|
126
|
+
while ((newlineIndex = buffer.indexOf('\n')) !== -1) {
|
|
127
|
+
const line = buffer.slice(0, newlineIndex);
|
|
128
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
129
|
+
if (line.trim()) {
|
|
130
|
+
this.handleLine(line, client);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
socket.on('close', () => {
|
|
135
|
+
this.clients.delete(clientId);
|
|
136
|
+
this.emit('client-disconnected', client);
|
|
137
|
+
});
|
|
138
|
+
socket.on('error', () => {
|
|
139
|
+
this.clients.delete(clientId);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
async handleLine(line, client) {
|
|
143
|
+
let msg;
|
|
144
|
+
try {
|
|
145
|
+
msg = JSON.parse(line);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
this.sendError(client.socket, null, RpcErrorCode.PARSE_ERROR, 'Parse error');
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
// Ignore responses (we don't expect them from clients in this direction, but workers may ack)
|
|
152
|
+
if ('result' in msg || 'error' in msg) {
|
|
153
|
+
this.emit('response', msg, client);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
// Must have a method
|
|
157
|
+
if (!('method' in msg) || typeof msg.method !== 'string') {
|
|
158
|
+
this.sendError(client.socket, msg.id ?? null, RpcErrorCode.INVALID_REQUEST, 'Invalid request');
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const handler = this.methods.get(msg.method);
|
|
162
|
+
if (!handler) {
|
|
163
|
+
if ('id' in msg && msg.id != null) {
|
|
164
|
+
this.sendError(client.socket, msg.id, RpcErrorCode.METHOD_NOT_FOUND, `Method not found: ${msg.method}`);
|
|
165
|
+
}
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const params = ('params' in msg ? msg.params : {});
|
|
169
|
+
try {
|
|
170
|
+
const result = await handler(params, client);
|
|
171
|
+
// Only send response if it's a request (has id), not a notification
|
|
172
|
+
if ('id' in msg && msg.id != null) {
|
|
173
|
+
const response = { jsonrpc: '2.0', id: msg.id, result };
|
|
174
|
+
this.sendMessage(client.socket, response);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
if ('id' in msg && msg.id != null) {
|
|
179
|
+
const code = err.rpcCode ?? RpcErrorCode.INVALID_PARAMS;
|
|
180
|
+
this.sendError(client.socket, msg.id, code, err.message ?? 'Internal error');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// -----------------------------------------------------------------------
|
|
185
|
+
// Built-in method handlers
|
|
186
|
+
// -----------------------------------------------------------------------
|
|
187
|
+
handleHello(_params) {
|
|
188
|
+
// hello always succeeds — client decides based on version fields
|
|
189
|
+
return {
|
|
190
|
+
daemonVersion: this.version,
|
|
191
|
+
daemonIpcVersion: IPC_VERSION,
|
|
192
|
+
daemonBuildId: BUILD_ID,
|
|
193
|
+
daemonPid: process.pid,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
handlePing() {
|
|
197
|
+
const uptimeMs = Date.now() - this.startedAt.getTime();
|
|
198
|
+
return {
|
|
199
|
+
version: this.version,
|
|
200
|
+
ipcVersion: IPC_VERSION,
|
|
201
|
+
buildId: BUILD_ID,
|
|
202
|
+
uptime: Math.floor(uptimeMs / 1000),
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
handleStatus() {
|
|
206
|
+
if (this.statusProvider)
|
|
207
|
+
return this.statusProvider();
|
|
208
|
+
const uptimeMs = Date.now() - this.startedAt.getTime();
|
|
209
|
+
return {
|
|
210
|
+
version: this.version,
|
|
211
|
+
pid: process.pid,
|
|
212
|
+
uptime: Math.floor(uptimeMs / 1000),
|
|
213
|
+
connectionState: 'disconnected',
|
|
214
|
+
peerCount: 0,
|
|
215
|
+
activeSessions: 0,
|
|
216
|
+
managedRepos: 0,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
handleShutdown(_client) {
|
|
220
|
+
// Schedule shutdown on next tick so the response gets sent first
|
|
221
|
+
process.nextTick(() => this.emit('shutdown-requested'));
|
|
222
|
+
return { ok: true };
|
|
223
|
+
}
|
|
224
|
+
handleSubscribe(client) {
|
|
225
|
+
client.subscribed = true;
|
|
226
|
+
return { subscribed: true };
|
|
227
|
+
}
|
|
228
|
+
// -----------------------------------------------------------------------
|
|
229
|
+
// Wire helpers
|
|
230
|
+
// -----------------------------------------------------------------------
|
|
231
|
+
sendMessage(socket, msg) {
|
|
232
|
+
if (!socket.destroyed) {
|
|
233
|
+
socket.write(JSON.stringify(msg) + '\n');
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
sendError(socket, id, code, message) {
|
|
237
|
+
const response = {
|
|
238
|
+
jsonrpc: '2.0',
|
|
239
|
+
id: id ?? 0,
|
|
240
|
+
error: { code, message },
|
|
241
|
+
};
|
|
242
|
+
this.sendMessage(socket, response);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=ipcServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ipcServer.js","sourceRoot":"","sources":["../../src/service/ipcServer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAA4B,MAAM,KAAK,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAWtC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAuBjE,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,MAAM,OAAO,SAAU,SAAQ,YAAY;IACjC,MAAM,GAAkB,IAAI,CAAC;IAC7B,OAAO,GAAG,IAAI,GAAG,EAAqB,CAAC;IACvC,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAC;IAC3C,YAAY,GAAG,CAAC,CAAC;IACjB,SAAS,CAAO;IAChB,OAAO,CAAS;IAChB,cAAc,CAAsB;IAE5C,YAAY,IAAyB;QACnC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QAE5B,4BAA4B;QAC5B,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,MAAgC,CAAC,CAAC,CAAC;QAC7F,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;QACrD,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;QACzD,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;QAClF,IAAI,CAAC,cAAc,CAAC,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7F,CAAC;IAED,0CAA0C;IAC1C,cAAc,CAAC,MAAc,EAAE,OAAsB;QACnD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,CAAC;IAED,gFAAgF;IAChF,iBAAiB,CAAC,EAAsB;QACtC,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC;IAC3B,CAAC;IAED,qDAAqD;IACrD,KAAK,CAAC,MAAM,CAAC,UAAkB;QAC7B,sCAAsC;QACtC,IAAI,CAAC;YACH,UAAU,CAAC,UAAU,CAAC,CAAC;QACzB,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,GAAG,CAAC;QACvC,CAAC;QAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;YAElE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC9B,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,GAAG,EAAE;gBAClC,uCAAuC;gBACvC,IAAI,CAAC;oBACH,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;gBAC/B,CAAC;gBAAC,MAAM,CAAC;oBACP,yCAAyC;gBAC3C,CAAC;gBACD,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,8DAA8D;IAC9D,KAAK,CAAC,KAAK;QACT,4BAA4B;QAC5B,IAAI,CAAC,SAAS,CAAC;YACb,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,oBAAoB;YAC5B,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE;SAChC,CAAC,CAAC;QAEH,2BAA2B;QAC3B,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAC3C,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAC1B,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAErB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YACrC,CAAC;iBAAM,CAAC;gBACN,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,2CAA2C;IAC3C,cAAc;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED,uEAAuE;IACvE,SAAS,CAAC,YAAiC;QACzC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAC3C,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;gBACtB,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;IACH,CAAC;IAED,iFAAiF;IACjF,WAAW,CAAC,QAAgB,EAAE,MAAc,EAAE,MAA+B,EAAE,EAAmB;QAChG,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC1B,MAAM,OAAO,GAAmB,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QACvE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,0EAA0E;IAC1E,sBAAsB;IACtB,0EAA0E;IAElE,YAAY,CAAC,MAAc;QACjC,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;QAC3C,MAAM,MAAM,GAAc;YACxB,EAAE,EAAE,QAAQ;YACZ,UAAU,EAAE,KAAK;YACjB,MAAM;SACP,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAEnC,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC1B,IAAI,YAAoB,CAAC;YACzB,OAAO,CAAC,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;gBACpD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;gBAC3C,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;gBACxC,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;oBAChB,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBAChC,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACtB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACtB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,IAAY,EAAE,MAAiB;QACtD,IAAI,GAAmB,CAAC;QACxB,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;YAC7E,OAAO;QACT,CAAC;QAED,8FAA8F;QAC9F,IAAI,QAAQ,IAAI,GAAG,IAAI,OAAO,IAAI,GAAG,EAAE,CAAC;YACtC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;YACnC,OAAO;QACT,CAAC;QAED,qBAAqB;QACrB,IAAI,CAAC,CAAC,QAAQ,IAAI,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACzD,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAG,GAAW,CAAC,EAAE,IAAI,IAAI,EAAE,YAAY,CAAC,eAAe,EAAE,iBAAiB,CAAC,CAAC;YACxG,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,IAAI,IAAI,GAAG,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;gBAClC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAAE,YAAY,CAAC,gBAAgB,EAAE,qBAAqB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YAC1G,CAAC;YACD,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAA4B,CAAC;QAE9E,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAC7C,oEAAoE;YACpE,IAAI,IAAI,IAAI,GAAG,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;gBAClC,MAAM,QAAQ,GAAoB,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC;gBACzE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAI,IAAI,IAAI,GAAG,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;gBAClC,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,IAAI,YAAY,CAAC,cAAc,CAAC;gBACxD,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,IAAI,gBAAgB,CAAC,CAAC;YAC/E,CAAC;QACH,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,2BAA2B;IAC3B,0EAA0E;IAElE,WAAW,CAAC,OAAoB;QACtC,iEAAiE;QACjE,OAAO;YACL,aAAa,EAAE,IAAI,CAAC,OAAO;YAC3B,gBAAgB,EAAE,WAAW;YAC7B,aAAa,EAAE,QAAQ;YACvB,SAAS,EAAE,OAAO,CAAC,GAAG;SACvB,CAAC;IACJ,CAAC;IAEO,UAAU;QAChB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QACvD,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,UAAU,EAAE,WAAW;YACvB,OAAO,EAAE,QAAQ;YACjB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;SACpC,CAAC;IACJ,CAAC;IAEO,YAAY;QAClB,IAAI,IAAI,CAAC,cAAc;YAAE,OAAO,IAAI,CAAC,cAAc,EAAE,CAAC;QACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QACvD,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;YACnC,eAAe,EAAE,cAAc;YAC/B,SAAS,EAAE,CAAC;YACZ,cAAc,EAAE,CAAC;YACjB,YAAY,EAAE,CAAC;SAChB,CAAC;IACJ,CAAC;IAEO,cAAc,CAAC,OAAkB;QACvC,iEAAiE;QACjE,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC;QACxD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAEO,eAAe,CAAC,MAAiB;QACvC,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC;QACzB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IAC9B,CAAC;IAED,0EAA0E;IAC1E,eAAe;IACf,0EAA0E;IAElE,WAAW,CAAC,MAAc,EAAE,GAAmB;QACrD,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YACtB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAEO,SAAS,CAAC,MAAc,EAAE,EAA0B,EAAE,IAAY,EAAE,OAAe;QACzF,MAAM,QAAQ,GAAoB;YAChC,OAAO,EAAE,KAAK;YACd,EAAE,EAAE,EAAE,IAAI,CAAC;YACX,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;SACzB,CAAC;QACF,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACrC,CAAC;CACF"}
|
|
@@ -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.1';
|
|
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"}
|