@sumicom/quicksave 0.6.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/ai/cardBuilder.d.ts +27 -0
  2. package/dist/ai/cardBuilder.d.ts.map +1 -1
  3. package/dist/ai/cardBuilder.js +69 -0
  4. package/dist/ai/cardBuilder.js.map +1 -1
  5. package/dist/ai/claudeCliProvider.d.ts +1 -0
  6. package/dist/ai/claudeCliProvider.d.ts.map +1 -1
  7. package/dist/ai/claudeCliProvider.js +168 -35
  8. package/dist/ai/claudeCliProvider.js.map +1 -1
  9. package/dist/ai/claudeSdkProvider.d.ts.map +1 -1
  10. package/dist/ai/claudeSdkProvider.js +17 -6
  11. package/dist/ai/claudeSdkProvider.js.map +1 -1
  12. package/dist/ai/commitSummary.d.ts.map +1 -1
  13. package/dist/ai/commitSummary.js +37 -9
  14. package/dist/ai/commitSummary.js.map +1 -1
  15. package/dist/ai/commitSummaryCli.d.ts +67 -0
  16. package/dist/ai/commitSummaryCli.d.ts.map +1 -0
  17. package/dist/ai/commitSummaryCli.js +416 -0
  18. package/dist/ai/commitSummaryCli.js.map +1 -0
  19. package/dist/ai/commitSummaryStore.d.ts +53 -0
  20. package/dist/ai/commitSummaryStore.d.ts.map +1 -0
  21. package/dist/ai/commitSummaryStore.js +136 -0
  22. package/dist/ai/commitSummaryStore.js.map +1 -0
  23. package/dist/ai/provider.d.ts +13 -2
  24. package/dist/ai/provider.d.ts.map +1 -1
  25. package/dist/ai/sessionManager.d.ts +32 -3
  26. package/dist/ai/sessionManager.d.ts.map +1 -1
  27. package/dist/ai/sessionManager.js +229 -36
  28. package/dist/ai/sessionManager.js.map +1 -1
  29. package/dist/ai/sessionRegistry.d.ts +2 -0
  30. package/dist/ai/sessionRegistry.d.ts.map +1 -1
  31. package/dist/ai/sessionRegistry.js +9 -0
  32. package/dist/ai/sessionRegistry.js.map +1 -1
  33. package/dist/config.d.ts +4 -0
  34. package/dist/config.d.ts.map +1 -1
  35. package/dist/config.js +15 -5
  36. package/dist/config.js.map +1 -1
  37. package/dist/connection/connection.d.ts +0 -12
  38. package/dist/connection/connection.d.ts.map +1 -1
  39. package/dist/connection/connection.js +1 -44
  40. package/dist/connection/connection.js.map +1 -1
  41. package/dist/connection/pubsub.d.ts +5 -5
  42. package/dist/connection/pubsub.d.ts.map +1 -1
  43. package/dist/connection/pubsub.js +5 -7
  44. package/dist/connection/pubsub.js.map +1 -1
  45. package/dist/handlers/messageHandler.d.ts +32 -2
  46. package/dist/handlers/messageHandler.d.ts.map +1 -1
  47. package/dist/handlers/messageHandler.js +395 -176
  48. package/dist/handlers/messageHandler.js.map +1 -1
  49. package/dist/index.js +3 -3
  50. package/dist/index.js.map +1 -1
  51. package/dist/messageBus/busServerTransport.d.ts +29 -0
  52. package/dist/messageBus/busServerTransport.d.ts.map +1 -0
  53. package/dist/messageBus/busServerTransport.js +54 -0
  54. package/dist/messageBus/busServerTransport.js.map +1 -0
  55. package/dist/service/ipcClient.js +1 -1
  56. package/dist/service/pushClient.d.ts +69 -0
  57. package/dist/service/pushClient.d.ts.map +1 -0
  58. package/dist/service/pushClient.js +119 -0
  59. package/dist/service/pushClient.js.map +1 -0
  60. package/dist/service/run.d.ts.map +1 -1
  61. package/dist/service/run.js +280 -36
  62. package/dist/service/run.js.map +1 -1
  63. package/dist/service/types.d.ts +2 -0
  64. package/dist/service/types.d.ts.map +1 -1
  65. package/dist/service/types.js +13 -8
  66. package/dist/service/types.js.map +1 -1
  67. package/dist/storage/eventStore.d.ts +65 -0
  68. package/dist/storage/eventStore.d.ts.map +1 -0
  69. package/dist/storage/eventStore.js +122 -0
  70. package/dist/storage/eventStore.js.map +1 -0
  71. package/package.json +6 -2
@@ -13,15 +13,20 @@ import { fileURLToPath } from 'url';
13
13
  // ---------------------------------------------------------------------------
14
14
  /** Bumped only on IPC protocol breaking changes. */
15
15
  export const IPC_VERSION = 1;
16
+ /**
17
+ * True when this process was launched via the dev-daemon loader
18
+ * (`dev-marker.mjs` sets this before any app code runs). This is the single
19
+ * source of truth for "am I a dev-mode process" — we don't parse BUILD_ID or
20
+ * NODE_ENV, both of which have silently broken dev detection in the past.
21
+ */
22
+ const IS_DEV = globalThis.__QUICKSAVE_DEV__ === true;
16
23
  /**
17
24
  * 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.
25
+ * In dev mode, hashes source file mtimes so the value only changes when code
26
+ * actually changes — avoids spurious daemon restarts.
20
27
  */
21
- const _PLACEHOLDER = '41525c7e5f3f';
22
- export const BUILD_ID = _PLACEHOLDER === '__BUILD' + '_ID__'
23
- ? devBuildId()
24
- : _PLACEHOLDER;
28
+ const _PLACEHOLDER = '83cf9e5eabeb';
29
+ export const BUILD_ID = IS_DEV ? devBuildId() : _PLACEHOLDER;
25
30
  function devBuildId() {
26
31
  try {
27
32
  const srcDir = resolve(dirname(fileURLToPath(import.meta.url)), '..');
@@ -70,8 +75,8 @@ export function shouldRestartDaemon(daemon, cli) {
70
75
  }
71
76
  return { action: 'ok' };
72
77
  }
73
- function isDev() {
74
- return BUILD_ID.startsWith('dev-') || process.env.NODE_ENV === 'development';
78
+ export function isDev() {
79
+ return IS_DEV;
75
80
  }
76
81
  /**
77
82
  * Debug CLI commands are enabled by default in dev mode.
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/service/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/service/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Event store — append-only SQLite log of session activity.
3
+ *
4
+ * Storage: ~/.quicksave/state/quicksave.db
5
+ *
6
+ * Schema:
7
+ * events (id, time, session_id, cwd, type, data)
8
+ * Indexes on (session_id, time), (type, time), (time).
9
+ *
10
+ * Intended as a long-lived audit/analytics log. Derived stats (cumulative
11
+ * tokens, cost, last prompt time) are computed via aggregate queries.
12
+ */
13
+ export type EventType = 'prompt_sent' | 'turn_ended' | 'permission_requested' | 'permission_resolved' | 'session_cancelled';
14
+ export interface EventRecord {
15
+ id: number;
16
+ time: number;
17
+ sessionId: string | null;
18
+ cwd: string | null;
19
+ type: EventType;
20
+ data: unknown;
21
+ }
22
+ export interface SessionStats {
23
+ turnCount: number;
24
+ totalInputTokens: number;
25
+ totalOutputTokens: number;
26
+ totalCostUsd: number;
27
+ lastPromptAt: number | null;
28
+ lastTurnEndedAt: number | null;
29
+ }
30
+ export interface LastTurnInfo {
31
+ time: number;
32
+ inputTokens: number;
33
+ outputTokens: number;
34
+ cacheCreationTokens: number;
35
+ cacheReadTokens: number;
36
+ costUsd: number;
37
+ /** Category-level context-window breakdown from the provider. Shape mirrors
38
+ * `ContextUsageBreakdown` in @sumicom/quicksave-shared. Present only when
39
+ * the CLI answered `get_context_usage` successfully at turn end. */
40
+ contextUsage?: unknown;
41
+ }
42
+ export declare class EventStore {
43
+ private db;
44
+ private insertStmt;
45
+ private statsStmt;
46
+ private lastPromptStmt;
47
+ private sessionEventsStmt;
48
+ private lastTurnStmt;
49
+ constructor(dbPath: string);
50
+ record(params: {
51
+ type: EventType;
52
+ sessionId?: string | null;
53
+ cwd?: string | null;
54
+ data?: unknown;
55
+ time?: number;
56
+ }): void;
57
+ getSessionStats(sessionId: string): SessionStats;
58
+ getSessionEvents(sessionId: string, limit?: number, offset?: number): EventRecord[];
59
+ getLastTurn(sessionId: string): LastTurnInfo | null;
60
+ close(): void;
61
+ }
62
+ export declare function getEventStore(): EventStore;
63
+ /** Reset the singleton — only for tests. */
64
+ export declare function resetEventStore(): void;
65
+ //# sourceMappingURL=eventStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eventStore.d.ts","sourceRoot":"","sources":["../../src/storage/eventStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,MAAM,MAAM,SAAS,GACjB,aAAa,GACb,YAAY,GACZ,sBAAsB,GACtB,qBAAqB,GACrB,mBAAmB,CAAC;AAExB,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB;;wEAEoE;IACpE,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAWD,qBAAa,UAAU;IACrB,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,cAAc,CAAqB;IAC3C,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,YAAY,CAAqB;gBAE7B,MAAM,EAAE,MAAM;IAkD1B,MAAM,CAAC,MAAM,EAAE;QACb,IAAI,EAAE,SAAS,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GAAG,IAAI;IAMR,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY;IAmBhD,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,SAAM,EAAE,MAAM,SAAI,GAAG,WAAW,EAAE;IAK3E,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAenD,KAAK,IAAI,IAAI;CAGd;AAeD,wBAAgB,aAAa,IAAI,UAAU,CAK1C;AAED,4CAA4C;AAC5C,wBAAgB,eAAe,IAAI,IAAI,CAGtC"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Event store — append-only SQLite log of session activity.
3
+ *
4
+ * Storage: ~/.quicksave/state/quicksave.db
5
+ *
6
+ * Schema:
7
+ * events (id, time, session_id, cwd, type, data)
8
+ * Indexes on (session_id, time), (type, time), (time).
9
+ *
10
+ * Intended as a long-lived audit/analytics log. Derived stats (cumulative
11
+ * tokens, cost, last prompt time) are computed via aggregate queries.
12
+ */
13
+ import Database from 'better-sqlite3';
14
+ import { mkdirSync, existsSync } from 'fs';
15
+ import { join, dirname } from 'path';
16
+ import { getStateDir } from '../service/singleton.js';
17
+ export class EventStore {
18
+ db;
19
+ insertStmt;
20
+ statsStmt;
21
+ lastPromptStmt;
22
+ sessionEventsStmt;
23
+ lastTurnStmt;
24
+ constructor(dbPath) {
25
+ const dir = dirname(dbPath);
26
+ if (!existsSync(dir))
27
+ mkdirSync(dir, { recursive: true });
28
+ this.db = new Database(dbPath);
29
+ this.db.pragma('journal_mode = WAL');
30
+ this.db.pragma('synchronous = NORMAL');
31
+ this.db.exec(`
32
+ CREATE TABLE IF NOT EXISTS events (
33
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
34
+ time INTEGER NOT NULL,
35
+ session_id TEXT,
36
+ cwd TEXT,
37
+ type TEXT NOT NULL,
38
+ data TEXT
39
+ );
40
+ CREATE INDEX IF NOT EXISTS idx_events_session_time ON events(session_id, time);
41
+ CREATE INDEX IF NOT EXISTS idx_events_type_time ON events(type, time);
42
+ CREATE INDEX IF NOT EXISTS idx_events_time ON events(time);
43
+ `);
44
+ this.insertStmt = this.db.prepare('INSERT INTO events (time, session_id, cwd, type, data) VALUES (?, ?, ?, ?, ?)');
45
+ this.statsStmt = this.db.prepare(`
46
+ SELECT
47
+ COUNT(*) AS turnCount,
48
+ COALESCE(SUM(CAST(json_extract(data, '$.inputTokens') AS INTEGER)), 0) AS totalInputTokens,
49
+ COALESCE(SUM(CAST(json_extract(data, '$.outputTokens') AS INTEGER)), 0) AS totalOutputTokens,
50
+ COALESCE(SUM(CAST(json_extract(data, '$.costUsd') AS REAL)), 0) AS totalCostUsd,
51
+ MAX(time) AS lastTurnEndedAt
52
+ FROM events
53
+ WHERE session_id = ? AND type = 'turn_ended'
54
+ `);
55
+ this.lastPromptStmt = this.db.prepare(`SELECT MAX(time) AS lastPromptAt FROM events WHERE session_id = ? AND type = 'prompt_sent'`);
56
+ this.sessionEventsStmt = this.db.prepare(`SELECT id, time, session_id, cwd, type, data FROM events WHERE session_id = ? ORDER BY time ASC, id ASC LIMIT ? OFFSET ?`);
57
+ this.lastTurnStmt = this.db.prepare(`SELECT time, data FROM events WHERE session_id = ? AND type = 'turn_ended' ORDER BY time DESC, id DESC LIMIT 1`);
58
+ }
59
+ record(params) {
60
+ const time = params.time ?? Date.now();
61
+ const data = params.data === undefined ? null : JSON.stringify(params.data);
62
+ this.insertStmt.run(time, params.sessionId ?? null, params.cwd ?? null, params.type, data);
63
+ }
64
+ getSessionStats(sessionId) {
65
+ const turnRow = this.statsStmt.get(sessionId);
66
+ const promptRow = this.lastPromptStmt.get(sessionId);
67
+ return {
68
+ turnCount: turnRow.turnCount,
69
+ totalInputTokens: turnRow.totalInputTokens,
70
+ totalOutputTokens: turnRow.totalOutputTokens,
71
+ totalCostUsd: turnRow.totalCostUsd,
72
+ lastPromptAt: promptRow.lastPromptAt,
73
+ lastTurnEndedAt: turnRow.lastTurnEndedAt,
74
+ };
75
+ }
76
+ getSessionEvents(sessionId, limit = 500, offset = 0) {
77
+ const rows = this.sessionEventsStmt.all(sessionId, limit, offset);
78
+ return rows.map(rowToRecord);
79
+ }
80
+ getLastTurn(sessionId) {
81
+ const row = this.lastTurnStmt.get(sessionId);
82
+ if (!row)
83
+ return null;
84
+ const data = row.data ? JSON.parse(row.data) : {};
85
+ return {
86
+ time: row.time,
87
+ inputTokens: Number(data.inputTokens ?? 0),
88
+ outputTokens: Number(data.outputTokens ?? 0),
89
+ cacheCreationTokens: Number(data.cacheCreationTokens ?? 0),
90
+ cacheReadTokens: Number(data.cacheReadTokens ?? 0),
91
+ costUsd: Number(data.costUsd ?? 0),
92
+ contextUsage: data.contextUsage ?? undefined,
93
+ };
94
+ }
95
+ close() {
96
+ this.db.close();
97
+ }
98
+ }
99
+ function rowToRecord(row) {
100
+ return {
101
+ id: row.id,
102
+ time: row.time,
103
+ sessionId: row.session_id,
104
+ cwd: row.cwd,
105
+ type: row.type,
106
+ data: row.data ? JSON.parse(row.data) : null,
107
+ };
108
+ }
109
+ let instance = null;
110
+ export function getEventStore() {
111
+ if (!instance) {
112
+ instance = new EventStore(join(getStateDir(), 'quicksave.db'));
113
+ }
114
+ return instance;
115
+ }
116
+ /** Reset the singleton — only for tests. */
117
+ export function resetEventStore() {
118
+ if (instance)
119
+ instance.close();
120
+ instance = null;
121
+ }
122
+ //# sourceMappingURL=eventStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eventStore.js","sourceRoot":"","sources":["../../src/storage/eventStore.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.6.3",
3
+ "version": "0.7.0",
4
4
  "description": "Quicksave agent - remote git control CLI",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,14 +34,18 @@
34
34
  "@anthropic-ai/sdk": "^0.71.2",
35
35
  "@modelcontextprotocol/sdk": "^1.29.0",
36
36
  "@openai/codex-sdk": "^0.120.0",
37
+ "better-sqlite3": "^12.9.0",
37
38
  "commander": "^12.0.0",
38
39
  "qrcode-terminal": "^0.12.0",
39
40
  "simple-git": "^3.22.0",
41
+ "tweetnacl": "^1.0.3",
40
42
  "ws": "^8.16.0",
41
43
  "zod": "^4.3.6",
42
- "@sumicom/quicksave-shared": "0.6.3"
44
+ "@sumicom/quicksave-shared": "0.7.0",
45
+ "@sumicom/quicksave-message-bus": "0.7.0"
43
46
  },
44
47
  "devDependencies": {
48
+ "@types/better-sqlite3": "^7.6.13",
45
49
  "@types/node": "^20.11.0",
46
50
  "@types/ws": "^8.5.10",
47
51
  "@vitest/coverage-v8": "^1.6.1",