@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.
Files changed (76) 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 +2 -0
  18. package/dist/connection/connection.d.ts.map +1 -1
  19. package/dist/connection/connection.js +14 -5
  20. package/dist/connection/connection.js.map +1 -1
  21. package/dist/connection/relay.d.ts +2 -1
  22. package/dist/connection/relay.d.ts.map +1 -1
  23. package/dist/connection/relay.js +9 -7
  24. package/dist/connection/relay.js.map +1 -1
  25. package/dist/git/operations.d.ts +8 -1
  26. package/dist/git/operations.d.ts.map +1 -1
  27. package/dist/git/operations.js +71 -4
  28. package/dist/git/operations.js.map +1 -1
  29. package/dist/handlers/messageHandler.d.ts +18 -1
  30. package/dist/handlers/messageHandler.d.ts.map +1 -1
  31. package/dist/handlers/messageHandler.js +231 -11
  32. package/dist/handlers/messageHandler.js.map +1 -1
  33. package/dist/handlers/messageHandler.test.js +1 -1
  34. package/dist/index.js +228 -94
  35. package/dist/index.js.map +1 -1
  36. package/dist/service/ensureDaemon.d.ts +23 -0
  37. package/dist/service/ensureDaemon.d.ts.map +1 -0
  38. package/dist/service/ensureDaemon.js +143 -0
  39. package/dist/service/ensureDaemon.js.map +1 -0
  40. package/dist/service/index.d.ts +8 -0
  41. package/dist/service/index.d.ts.map +1 -0
  42. package/dist/service/index.js +8 -0
  43. package/dist/service/index.js.map +1 -0
  44. package/dist/service/ipc.test.d.ts +2 -0
  45. package/dist/service/ipc.test.d.ts.map +1 -0
  46. package/dist/service/ipc.test.js +140 -0
  47. package/dist/service/ipc.test.js.map +1 -0
  48. package/dist/service/ipcClient.d.ts +36 -0
  49. package/dist/service/ipcClient.d.ts.map +1 -0
  50. package/dist/service/ipcClient.js +167 -0
  51. package/dist/service/ipcClient.js.map +1 -0
  52. package/dist/service/ipcServer.d.ts +53 -0
  53. package/dist/service/ipcServer.d.ts.map +1 -0
  54. package/dist/service/ipcServer.js +245 -0
  55. package/dist/service/ipcServer.js.map +1 -0
  56. package/dist/service/run.d.ts +13 -0
  57. package/dist/service/run.d.ts.map +1 -0
  58. package/dist/service/run.js +292 -0
  59. package/dist/service/run.js.map +1 -0
  60. package/dist/service/singleton.d.ts +31 -0
  61. package/dist/service/singleton.d.ts.map +1 -0
  62. package/dist/service/singleton.js +96 -0
  63. package/dist/service/singleton.js.map +1 -0
  64. package/dist/service/singleton.test.d.ts +2 -0
  65. package/dist/service/singleton.test.d.ts.map +1 -0
  66. package/dist/service/singleton.test.js +39 -0
  67. package/dist/service/singleton.test.js.map +1 -0
  68. package/dist/service/stateStore.d.ts +11 -0
  69. package/dist/service/stateStore.d.ts.map +1 -0
  70. package/dist/service/stateStore.js +35 -0
  71. package/dist/service/stateStore.js.map +1 -0
  72. package/dist/service/types.d.ts +111 -0
  73. package/dist/service/types.d.ts.map +1 -0
  74. package/dist/service/types.js +76 -0
  75. package/dist/service/types.js.map +1 -0
  76. 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"}