@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,96 @@
1
+ /**
2
+ * Singleton lock for ensuring exactly one daemon per user.
3
+ *
4
+ * Uses an exclusive lock file at ~/.quicksave/run/service.lock.
5
+ * The lock is held via an open file descriptor — if the process crashes,
6
+ * the OS releases the lock automatically.
7
+ */
8
+ import { openSync, closeSync, mkdirSync, existsSync, unlinkSync, constants } from 'fs';
9
+ import { join } from 'path';
10
+ import { homedir } from 'os';
11
+ const QUICKSAVE_DIR = join(homedir(), '.quicksave');
12
+ const RUN_DIR = join(QUICKSAVE_DIR, 'run');
13
+ const LOCK_FILE = join(RUN_DIR, 'service.lock');
14
+ const SOCKET_PATH = join(RUN_DIR, 'service.sock');
15
+ export function getRunDir() {
16
+ return RUN_DIR;
17
+ }
18
+ export function getSocketPath() {
19
+ return SOCKET_PATH;
20
+ }
21
+ export function getLockPath() {
22
+ return LOCK_FILE;
23
+ }
24
+ export function getStateDir() {
25
+ return join(QUICKSAVE_DIR, 'state');
26
+ }
27
+ export function getSessionsDir() {
28
+ return join(getStateDir(), 'sessions');
29
+ }
30
+ export function getLogsDir() {
31
+ return join(QUICKSAVE_DIR, 'logs');
32
+ }
33
+ /**
34
+ * Ensure all required directories exist.
35
+ */
36
+ export function ensureDirectories() {
37
+ for (const dir of [RUN_DIR, getStateDir(), getSessionsDir(), getLogsDir()]) {
38
+ if (!existsSync(dir)) {
39
+ mkdirSync(dir, { recursive: true });
40
+ }
41
+ }
42
+ }
43
+ /**
44
+ * Try to acquire the singleton lock.
45
+ * Returns a release function on success, or null if the lock is held by another process.
46
+ */
47
+ export function acquireLock() {
48
+ ensureDirectories();
49
+ try {
50
+ const fd = openSync(LOCK_FILE, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL, 0o600);
51
+ return () => {
52
+ try {
53
+ closeSync(fd);
54
+ unlinkSync(LOCK_FILE);
55
+ }
56
+ catch {
57
+ // Best-effort cleanup
58
+ }
59
+ };
60
+ }
61
+ catch (err) {
62
+ if (err.code === 'EEXIST') {
63
+ return null;
64
+ }
65
+ throw err;
66
+ }
67
+ }
68
+ /**
69
+ * Remove stale runtime files (lock, socket) when we detect a dead daemon.
70
+ */
71
+ export function cleanStaleRuntime() {
72
+ for (const file of [LOCK_FILE, SOCKET_PATH]) {
73
+ try {
74
+ unlinkSync(file);
75
+ }
76
+ catch (err) {
77
+ if (err.code !== 'ENOENT') {
78
+ // Ignore missing files, rethrow anything else
79
+ throw err;
80
+ }
81
+ }
82
+ }
83
+ }
84
+ /**
85
+ * Check if a PID is alive.
86
+ */
87
+ export function isProcessAlive(pid) {
88
+ try {
89
+ process.kill(pid, 0);
90
+ return true;
91
+ }
92
+ catch {
93
+ return false;
94
+ }
95
+ }
96
+ //# sourceMappingURL=singleton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"singleton.js","sourceRoot":"","sources":["../../src/service/singleton.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=singleton.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"singleton.test.d.ts","sourceRoot":"","sources":["../../src/service/singleton.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,39 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { isProcessAlive } from './singleton.js';
3
+ import { shouldRestartDaemon, IPC_VERSION, BUILD_ID } from './types.js';
4
+ describe('isProcessAlive', () => {
5
+ it('returns true for the current process', () => {
6
+ expect(isProcessAlive(process.pid)).toBe(true);
7
+ });
8
+ it('returns false for a non-existent PID', () => {
9
+ // PID 99999999 is extremely unlikely to exist
10
+ expect(isProcessAlive(99999999)).toBe(false);
11
+ });
12
+ });
13
+ describe('shouldRestartDaemon', () => {
14
+ const makeDaemon = (overrides = {}) => ({
15
+ daemonVersion: '0.5.1',
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"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Service daemon IPC protocol types.
3
+ *
4
+ * Wire format: JSON-RPC 2.0 over newline-delimited Unix domain socket.
5
+ * Each JSON-RPC message is terminated by '\n'.
6
+ */
7
+ /** Bumped only on IPC protocol breaking changes. */
8
+ export declare const IPC_VERSION = 1;
9
+ export declare const BUILD_ID: string;
10
+ export interface JsonRpcRequest {
11
+ jsonrpc: '2.0';
12
+ id: number | string;
13
+ method: string;
14
+ params?: Record<string, unknown>;
15
+ }
16
+ export interface JsonRpcNotification {
17
+ jsonrpc: '2.0';
18
+ method: string;
19
+ params?: Record<string, unknown>;
20
+ }
21
+ export interface JsonRpcResponse {
22
+ jsonrpc: '2.0';
23
+ id: number | string;
24
+ result?: unknown;
25
+ error?: JsonRpcError;
26
+ }
27
+ export interface JsonRpcError {
28
+ code: number;
29
+ message: string;
30
+ data?: unknown;
31
+ }
32
+ export type JsonRpcMessage = JsonRpcRequest | JsonRpcNotification | JsonRpcResponse;
33
+ export declare const RpcErrorCode: {
34
+ readonly PARSE_ERROR: -32700;
35
+ readonly INVALID_REQUEST: -32600;
36
+ readonly METHOD_NOT_FOUND: -32601;
37
+ readonly INVALID_PARAMS: -32602;
38
+ readonly SESSION_NOT_FOUND: -32002;
39
+ readonly SESSION_NOT_ACTIVE: -32003;
40
+ readonly WORKER_DISCONNECTED: -32004;
41
+ readonly PERMISSION_TIMEOUT: -32005;
42
+ readonly DAEMON_SHUTTING_DOWN: -32006;
43
+ };
44
+ export interface HelloParams {
45
+ role: 'cli' | 'worker';
46
+ version: string;
47
+ ipcVersion: number;
48
+ buildId: string;
49
+ sessionId?: string;
50
+ workerPid?: number;
51
+ }
52
+ export interface HelloResult {
53
+ daemonVersion: string;
54
+ daemonIpcVersion: number;
55
+ daemonBuildId: string;
56
+ daemonPid: number;
57
+ }
58
+ export interface PingResult {
59
+ version: string;
60
+ ipcVersion: number;
61
+ buildId: string;
62
+ uptime: number;
63
+ }
64
+ export interface StatusResult {
65
+ version: string;
66
+ pid: number;
67
+ uptime: number;
68
+ connectionState: 'connected' | 'connecting' | 'disconnected';
69
+ peerCount: number;
70
+ activeSessions: number;
71
+ managedRepos: number;
72
+ }
73
+ export interface ServiceState {
74
+ pid: number;
75
+ version: string;
76
+ ipcVersion: number;
77
+ buildId: string;
78
+ startedAt: string;
79
+ lastHeartbeatAt: string;
80
+ socketPath: string;
81
+ agentId: string;
82
+ publicKey: string;
83
+ signalingServer: string;
84
+ connectionState: 'connected' | 'connecting' | 'disconnected';
85
+ peerCount: number;
86
+ }
87
+ export interface PairingInfoResult {
88
+ agentId: string;
89
+ publicKey: string;
90
+ pairingUrl: string;
91
+ connectionState: 'connected' | 'connecting' | 'disconnected';
92
+ peerCount: number;
93
+ }
94
+ export interface RepoInfo {
95
+ path: string;
96
+ name: string;
97
+ valid: boolean;
98
+ currentBranch?: string;
99
+ }
100
+ export type DaemonCheckResult = {
101
+ action: 'restart';
102
+ } | {
103
+ action: 'warn_outdated';
104
+ } | {
105
+ action: 'ok';
106
+ };
107
+ export declare function shouldRestartDaemon(daemon: HelloResult, cli: {
108
+ ipcVersion: number;
109
+ buildId: string;
110
+ }): DaemonCheckResult;
111
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/service/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Service daemon IPC protocol types.
3
+ *
4
+ * Wire format: JSON-RPC 2.0 over newline-delimited Unix domain socket.
5
+ * Each JSON-RPC message is terminated by '\n'.
6
+ */
7
+ import { createHash } from 'crypto';
8
+ import { readdirSync, statSync } from 'fs';
9
+ import { resolve, dirname } from 'path';
10
+ import { fileURLToPath } from 'url';
11
+ // ---------------------------------------------------------------------------
12
+ // Version constants
13
+ // ---------------------------------------------------------------------------
14
+ /** Bumped only on IPC protocol breaking changes. */
15
+ export const IPC_VERSION = 1;
16
+ /**
17
+ * Build output content hash, replaced by the bundler at production build time.
18
+ * In dev mode (placeholder unreplaced), hashes source file mtimes so the
19
+ * value only changes when code actually changes — avoids spurious daemon restarts.
20
+ */
21
+ const _PLACEHOLDER = '__BUILD_ID__';
22
+ export const BUILD_ID = _PLACEHOLDER === '__BUILD' + '_ID__'
23
+ ? devBuildId()
24
+ : _PLACEHOLDER;
25
+ function devBuildId() {
26
+ try {
27
+ const srcDir = resolve(dirname(fileURLToPath(import.meta.url)), '..');
28
+ const hash = createHash('md5');
29
+ (function walk(dir) {
30
+ for (const e of readdirSync(dir, { withFileTypes: true })) {
31
+ if (e.name.startsWith('.') || e.name === 'node_modules')
32
+ continue;
33
+ const p = resolve(dir, e.name);
34
+ if (e.isDirectory())
35
+ walk(p);
36
+ else if (e.name.endsWith('.ts'))
37
+ hash.update(`${p}:${statSync(p).mtimeMs}`);
38
+ }
39
+ })(srcDir);
40
+ return 'dev-' + hash.digest('hex').slice(0, 12);
41
+ }
42
+ catch {
43
+ return 'dev';
44
+ }
45
+ }
46
+ // ---------------------------------------------------------------------------
47
+ // Error codes
48
+ // ---------------------------------------------------------------------------
49
+ export const RpcErrorCode = {
50
+ // Standard JSON-RPC 2.0
51
+ PARSE_ERROR: -32700,
52
+ INVALID_REQUEST: -32600,
53
+ METHOD_NOT_FOUND: -32601,
54
+ INVALID_PARAMS: -32602,
55
+ // Application-specific
56
+ SESSION_NOT_FOUND: -32002,
57
+ SESSION_NOT_ACTIVE: -32003,
58
+ WORKER_DISCONNECTED: -32004,
59
+ PERMISSION_TIMEOUT: -32005,
60
+ DAEMON_SHUTTING_DOWN: -32006,
61
+ };
62
+ export function shouldRestartDaemon(daemon, cli) {
63
+ if (daemon.daemonIpcVersion !== cli.ipcVersion) {
64
+ return daemon.daemonIpcVersion < cli.ipcVersion
65
+ ? { action: 'restart' }
66
+ : { action: 'warn_outdated' };
67
+ }
68
+ if (isDev() && daemon.daemonBuildId !== cli.buildId) {
69
+ return { action: 'restart' };
70
+ }
71
+ return { action: 'ok' };
72
+ }
73
+ function isDev() {
74
+ return BUILD_ID.startsWith('dev-') || process.env.NODE_ENV === 'development';
75
+ }
76
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/service/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sumicom/quicksave",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "description": "Quicksave agent - remote git control CLI",
5
5
  "repository": {
6
6
  "type": "git",
@@ -30,12 +30,13 @@
30
30
  "quicksave": "./dist/index.js"
31
31
  },
32
32
  "dependencies": {
33
+ "@anthropic-ai/claude-agent-sdk": "^0.2.91",
33
34
  "@anthropic-ai/sdk": "^0.71.2",
34
35
  "commander": "^12.0.0",
35
36
  "qrcode-terminal": "^0.12.0",
36
37
  "simple-git": "^3.22.0",
37
38
  "ws": "^8.16.0",
38
- "@sumicom/quicksave-shared": "0.4.0"
39
+ "@sumicom/quicksave-shared": "0.5.1"
39
40
  },
40
41
  "devDependencies": {
41
42
  "@types/node": "^20.11.0",