@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
@@ -0,0 +1,416 @@
1
+ import { spawn } from 'child_process';
2
+ import { getClaudeBin } from './claudeCliProvider.js';
3
+ export class CommitSummaryCliError extends Error {
4
+ errorCode;
5
+ constructor(message, errorCode) {
6
+ super(message);
7
+ this.errorCode = errorCode;
8
+ this.name = 'CommitSummaryCliError';
9
+ }
10
+ }
11
+ const DEFAULT_TIMEOUT_MS = 120_000;
12
+ const ALLOWED_TOOLS = [
13
+ 'Read',
14
+ 'Grep',
15
+ 'Glob',
16
+ 'Bash(git diff:*)',
17
+ 'Bash(git log:*)',
18
+ 'Bash(git status:*)',
19
+ 'Bash(git show:*)',
20
+ 'Bash(git blame:*)',
21
+ ].join(',');
22
+ export class CommitSummaryCliService {
23
+ timeoutMs;
24
+ constructor(timeoutMs = DEFAULT_TIMEOUT_MS) {
25
+ this.timeoutMs = timeoutMs;
26
+ }
27
+ async generateSummary(options) {
28
+ const { repoPath, model, attribution = true, onProgress, onSpawn } = options;
29
+ const prompt = this.buildPrompt(options);
30
+ const bin = getClaudeBin();
31
+ // stream-json + --verbose lets us observe tool_use / partial assistant
32
+ // text events as they arrive, so we can emit progress updates. The final
33
+ // `result` event still carries the full JSON payload with token usage.
34
+ const args = [
35
+ '-p',
36
+ prompt,
37
+ '--output-format', 'stream-json',
38
+ '--verbose',
39
+ '--allowedTools', ALLOWED_TOOLS,
40
+ '--no-session-persistence',
41
+ ];
42
+ if (model) {
43
+ args.push('--model', model);
44
+ }
45
+ const final = await this.spawnAndCollect(bin, args, repoPath, onProgress, onSpawn);
46
+ const { summary, description } = this.extractCommitMessage(final.result);
47
+ const finalDescription = attribution
48
+ ? appendAttribution(description)
49
+ : description;
50
+ return {
51
+ summary,
52
+ description: finalDescription,
53
+ tokenUsage: final.tokenUsage,
54
+ };
55
+ }
56
+ spawnAndCollect(bin, args, cwd, onProgress, onSpawn) {
57
+ return new Promise((resolve, reject) => {
58
+ let child;
59
+ try {
60
+ child = spawn(bin, args, {
61
+ cwd,
62
+ env: { ...process.env },
63
+ stdio: ['ignore', 'pipe', 'pipe'],
64
+ });
65
+ }
66
+ catch (err) {
67
+ reject(mapSpawnError(err));
68
+ return;
69
+ }
70
+ onSpawn?.(child);
71
+ let stdoutBuf = '';
72
+ let stderr = '';
73
+ let settled = false;
74
+ let finalResult;
75
+ let finalTokenUsage;
76
+ let toolCount = 0;
77
+ const timer = setTimeout(() => {
78
+ if (settled)
79
+ return;
80
+ settled = true;
81
+ try {
82
+ child.kill('SIGTERM');
83
+ }
84
+ catch { /* ignore */ }
85
+ reject(new CommitSummaryCliError(`Claude CLI timed out after ${Math.round(this.timeoutMs / 1000)}s`, 'CLI_TIMEOUT'));
86
+ }, this.timeoutMs);
87
+ child.stdout?.on('data', (chunk) => {
88
+ stdoutBuf += chunk.toString('utf8');
89
+ // Process complete lines; keep the trailing partial line in the buffer.
90
+ let newlineIdx;
91
+ while ((newlineIdx = stdoutBuf.indexOf('\n')) !== -1) {
92
+ const line = stdoutBuf.slice(0, newlineIdx).trim();
93
+ stdoutBuf = stdoutBuf.slice(newlineIdx + 1);
94
+ if (!line)
95
+ continue;
96
+ let event;
97
+ try {
98
+ event = JSON.parse(line);
99
+ }
100
+ catch {
101
+ continue; // not a JSON line, skip
102
+ }
103
+ const parsed = interpretStreamEvent(event);
104
+ if (parsed?.kind === 'progress' && onProgress) {
105
+ if (parsed.toolCountDelta) {
106
+ toolCount += parsed.toolCountDelta;
107
+ onProgress({ ...parsed.progress, toolCount });
108
+ }
109
+ else {
110
+ onProgress({ ...parsed.progress, toolCount });
111
+ }
112
+ }
113
+ else if (parsed?.kind === 'result') {
114
+ finalResult = parsed.result;
115
+ finalTokenUsage = parsed.tokenUsage;
116
+ }
117
+ else if (parsed?.kind === 'error') {
118
+ if (settled)
119
+ return;
120
+ settled = true;
121
+ clearTimeout(timer);
122
+ try {
123
+ child.kill('SIGTERM');
124
+ }
125
+ catch { /* ignore */ }
126
+ reject(classifyCliFailure(parsed.message, null));
127
+ return;
128
+ }
129
+ }
130
+ });
131
+ child.stderr?.on('data', (chunk) => { stderr += chunk.toString('utf8'); });
132
+ child.on('error', (err) => {
133
+ if (settled)
134
+ return;
135
+ settled = true;
136
+ clearTimeout(timer);
137
+ reject(mapSpawnError(err));
138
+ });
139
+ child.on('close', (code, signal) => {
140
+ if (settled)
141
+ return;
142
+ settled = true;
143
+ clearTimeout(timer);
144
+ if (signal === 'SIGTERM' && code === null) {
145
+ reject(new CommitSummaryCliError('Generation was cancelled', 'CLI_ERROR'));
146
+ return;
147
+ }
148
+ if (code !== 0) {
149
+ const hint = stderr.trim() || stdoutBuf.trim() || `exit code ${code}`;
150
+ reject(classifyCliFailure(hint, code));
151
+ return;
152
+ }
153
+ if (!finalResult) {
154
+ reject(new CommitSummaryCliError('Claude CLI produced no result event', 'CLI_PARSE_ERROR'));
155
+ return;
156
+ }
157
+ onProgress?.({ phase: 'finalizing' });
158
+ resolve({ result: finalResult, tokenUsage: finalTokenUsage });
159
+ });
160
+ });
161
+ }
162
+ extractCommitMessage(result) {
163
+ // Models often wrap or surround the JSON with markdown fences and chatter.
164
+ // Try every plausible candidate (whole text, fence bodies, balanced
165
+ // brace blocks scanned right-to-left) and return the first that parses.
166
+ for (const candidate of jsonCandidates(result)) {
167
+ const parsed = tryParseCommitJson(candidate);
168
+ if (parsed)
169
+ return parsed;
170
+ }
171
+ throw new CommitSummaryCliError('Could not extract {summary, description} from Claude CLI output', 'CLI_PARSE_ERROR');
172
+ }
173
+ buildPrompt(opts) {
174
+ const sections = [
175
+ 'You are generating a git commit message for staged changes in this repository.',
176
+ '',
177
+ 'Steps:',
178
+ '1. Run `git diff --cached --name-only` to see which files changed; then `git diff --cached` for content.',
179
+ '2. If staged changes touch a function, type, or component that is referenced elsewhere, briefly inspect call sites (Grep + Read) to understand intent.',
180
+ '3. Inspect recent commits to match the project\'s style (`git log --oneline -20`).',
181
+ '4. Your VERY LAST line of output must be a single JSON object — no markdown fences, no commentary after it:',
182
+ ' {"summary": "<header line, ≤72 chars>", "description": "<body explaining the why>"}',
183
+ '',
184
+ 'Default format — Conventional Commits v1.0.0:',
185
+ ' <type>(<scope>): <subject>',
186
+ '',
187
+ ' [body]',
188
+ '',
189
+ ' [footers]',
190
+ '',
191
+ 'Type (required): one of feat, fix, docs, refactor, chore, test, style, perf, ci, build.',
192
+ ' - feat: user-visible new capability - fix: user-visible bug fix',
193
+ ' - refactor: behavior-preserving code change - perf: measurable perf improvement',
194
+ ' - test/docs/style/chore/ci/build: as named',
195
+ '',
196
+ 'Scope (optional, recommended): a single short noun naming the area of the codebase touched.',
197
+ ' - Infer it from the staged file paths\' common prefix (top-level dir, package, or module name).',
198
+ ' - If staged changes span multiple unrelated areas, OMIT the scope rather than inventing an umbrella term.',
199
+ ' - Lowercase, hyphenated; no commas, no slashes.',
200
+ '',
201
+ 'Subject (required, in `summary`):',
202
+ ' - ≤72 chars including the `<type>(<scope>): ` prefix.',
203
+ ' - Imperative present tense ("add X", not "added X" / "adds X").',
204
+ ' - No trailing period. Lowercase first word after the colon (unless it is a proper noun).',
205
+ ' - Describe WHAT and WHY in one breath; details go in the body.',
206
+ '',
207
+ 'Body (in `description`, separated from header by a blank line in the rendered commit):',
208
+ ' - Wrap each line at ≤72 chars. Use `\\n` for line breaks inside the JSON string.',
209
+ ' - Use blank lines between paragraphs. Use `- ` bullets when listing multiple distinct aspects.',
210
+ ' - Required when: behavior changes, multiple modules touched, motivation non-obvious, or migration steps needed.',
211
+ ' - Omit `description` ONLY for truly trivial changes (typo fix, dependency bump, single-line tweak).',
212
+ '',
213
+ 'Footer (append to `description` after a blank line, one trailer per line):',
214
+ ' - `BREAKING CHANGE: <what broke and how to migrate>` for any breaking API/behavior change.',
215
+ ' - Issue refs like `Refs: #123` / `Closes: #123` when the staged changes resolve a tracked issue.',
216
+ '',
217
+ 'Hard constraints:',
218
+ ' - Do NOT wrap the JSON in markdown fences. Do NOT write anything after the JSON object.',
219
+ ' - Do NOT invent issue numbers, ticket IDs, or co-author trailers — only include footers backed by evidence in the diff or context.',
220
+ ];
221
+ if (opts.conventions) {
222
+ sections.push('', 'Project commit conventions (these OVERRIDE the defaults above where they conflict — e.g. allowed scope vocabulary, custom types, subject length):', opts.conventions);
223
+ }
224
+ if (opts.recentCommits?.length) {
225
+ sections.push('', 'Recent commits (match this style):', ...opts.recentCommits.map((m) => `- ${m}`));
226
+ }
227
+ if (opts.branchName) {
228
+ sections.push('', `Branch: ${opts.branchName}`);
229
+ }
230
+ if (opts.context) {
231
+ sections.push('', `User context: ${opts.context}`);
232
+ }
233
+ return sections.join('\n');
234
+ }
235
+ }
236
+ /**
237
+ * Interpret a single stream-json envelope into a progress update or the final
238
+ * result. The CLI emits envelopes of several shapes; we read the ones we need
239
+ * and ignore the rest (tolerant of CLI version drift).
240
+ */
241
+ function interpretStreamEvent(event) {
242
+ if (!event || typeof event !== 'object')
243
+ return null;
244
+ const e = event;
245
+ // Terminal result envelope: `{ type: 'result', result: string, usage, is_error }`
246
+ if (e.type === 'result') {
247
+ if (e.is_error) {
248
+ const msg = typeof e.result === 'string' ? e.result : 'Claude CLI reported an error';
249
+ return { kind: 'error', message: msg };
250
+ }
251
+ const result = typeof e.result === 'string' ? e.result : '';
252
+ if (!result)
253
+ return null;
254
+ return { kind: 'result', result, tokenUsage: extractTokenUsage(e.usage) };
255
+ }
256
+ // System init — the CLI is spinning up tools.
257
+ if (e.type === 'system') {
258
+ if (e.subtype === 'init') {
259
+ return { kind: 'progress', progress: { phase: 'preparing' } };
260
+ }
261
+ return null;
262
+ }
263
+ // Assistant turn — wraps a raw Anthropic API message under `message`.
264
+ if (e.type === 'assistant') {
265
+ const msg = e.message;
266
+ const content = msg?.content;
267
+ if (!Array.isArray(content))
268
+ return null;
269
+ let toolName;
270
+ let text;
271
+ let toolCountDelta = 0;
272
+ for (const block of content) {
273
+ if (!block || typeof block !== 'object')
274
+ continue;
275
+ const b = block;
276
+ if (b.type === 'tool_use') {
277
+ toolName = typeof b.name === 'string' ? b.name : toolName;
278
+ toolCountDelta += 1;
279
+ }
280
+ else if (b.type === 'text') {
281
+ const t = typeof b.text === 'string' ? b.text : undefined;
282
+ if (t)
283
+ text = text ? `${text}${t}` : t;
284
+ }
285
+ }
286
+ if (toolName) {
287
+ return {
288
+ kind: 'progress',
289
+ progress: { phase: 'inspecting', lastToolName: toolName },
290
+ toolCountDelta,
291
+ };
292
+ }
293
+ if (text) {
294
+ const snippet = text.length > 200 ? `${text.slice(0, 200)}…` : text;
295
+ return { kind: 'progress', progress: { phase: 'generating', partialText: snippet } };
296
+ }
297
+ return null;
298
+ }
299
+ return null;
300
+ }
301
+ /**
302
+ * Yield JSON candidate strings to try, in priority order:
303
+ * 1. The trimmed whole text.
304
+ * 2. Each ```...``` fence body (last fence first — LLMs usually put the
305
+ * "real answer" fence at the end of any preamble).
306
+ * 3. Every balanced {...} block scanned right-to-left, ignoring braces
307
+ * inside JSON string literals.
308
+ *
309
+ * Yields lazily so callers can stop at the first parsable candidate.
310
+ */
311
+ function* jsonCandidates(raw) {
312
+ const trimmed = raw.trim();
313
+ if (!trimmed)
314
+ return;
315
+ yield trimmed;
316
+ // Pull each fence body. We accept ```json, ```JSON, or bare ```.
317
+ const fenceBodies = [];
318
+ const fenceRe = /```(?:[a-zA-Z]+)?\s*\n?([\s\S]*?)```/g;
319
+ let m;
320
+ while ((m = fenceRe.exec(trimmed)) !== null) {
321
+ const body = m[1].trim();
322
+ if (body)
323
+ fenceBodies.push(body);
324
+ }
325
+ for (let i = fenceBodies.length - 1; i >= 0; i--) {
326
+ yield fenceBodies[i];
327
+ }
328
+ // Walk right-to-left, finding balanced {...} blocks. We respect JSON string
329
+ // literals so a `}` inside `"foo}"` doesn't throw off the brace count.
330
+ for (const block of balancedBraceBlocks(trimmed)) {
331
+ yield block;
332
+ }
333
+ }
334
+ function* balancedBraceBlocks(text) {
335
+ const braces = [];
336
+ let inString = false;
337
+ let escape = false;
338
+ for (let i = 0; i < text.length; i++) {
339
+ const c = text[i];
340
+ if (escape) {
341
+ escape = false;
342
+ continue;
343
+ }
344
+ if (c === '\\') {
345
+ escape = true;
346
+ continue;
347
+ }
348
+ if (c === '"') {
349
+ inString = !inString;
350
+ continue;
351
+ }
352
+ if (inString)
353
+ continue;
354
+ if (c === '{' || c === '}')
355
+ braces.push({ idx: i, kind: c });
356
+ }
357
+ const pairs = [];
358
+ const stack = [];
359
+ for (const b of braces) {
360
+ if (b.kind === '{')
361
+ stack.push(b.idx);
362
+ else if (stack.length > 0) {
363
+ const open = stack.pop();
364
+ pairs.push([open, b.idx]);
365
+ }
366
+ }
367
+ // Sort by close index descending — rightmost (likely final) JSON first.
368
+ pairs.sort((a, b) => b[1] - a[1]);
369
+ for (const [open, close] of pairs) {
370
+ yield text.slice(open, close + 1);
371
+ }
372
+ }
373
+ function tryParseCommitJson(text) {
374
+ try {
375
+ const obj = JSON.parse(text);
376
+ if (obj && typeof obj.summary === 'string' && obj.summary.trim()) {
377
+ const description = typeof obj.description === 'string' && obj.description.trim()
378
+ ? obj.description.trim()
379
+ : undefined;
380
+ return { summary: obj.summary.trim(), description };
381
+ }
382
+ }
383
+ catch { /* fall through */ }
384
+ return null;
385
+ }
386
+ function appendAttribution(description) {
387
+ const trailer = 'Commit-message-by: Quicksave AI <save@quicksave.dev>';
388
+ return description ? `${description}\n\n${trailer}` : trailer;
389
+ }
390
+ function extractTokenUsage(usage) {
391
+ if (!usage || typeof usage !== 'object')
392
+ return undefined;
393
+ const u = usage;
394
+ const inputTokens = Number(u.input_tokens) || 0;
395
+ const outputTokens = Number(u.output_tokens) || 0;
396
+ if (!inputTokens && !outputTokens)
397
+ return undefined;
398
+ return { inputTokens, outputTokens };
399
+ }
400
+ function mapSpawnError(err) {
401
+ const msg = err instanceof Error ? err.message : String(err);
402
+ if (err?.code === 'ENOENT') {
403
+ return new CommitSummaryCliError('Claude CLI binary not found. Install with: npm install -g @anthropic-ai/claude-code', 'NO_CLI_BINARY');
404
+ }
405
+ return new CommitSummaryCliError(`Failed to spawn Claude CLI: ${msg}`, 'CLI_ERROR');
406
+ }
407
+ function classifyCliFailure(hint, _exitCode) {
408
+ const lower = hint.toLowerCase();
409
+ if (lower.includes('not authenticated') || lower.includes('please log in') || lower.includes('login') || lower.includes('api key')) {
410
+ return new CommitSummaryCliError('Claude CLI is not authenticated. Run `claude` once to log in.', 'NO_CLI_AUTH');
411
+ }
412
+ return new CommitSummaryCliError(hint, 'CLI_ERROR');
413
+ }
414
+ // Exposed for testing
415
+ export const __testing = { interpretStreamEvent, jsonCandidates };
416
+ //# sourceMappingURL=commitSummaryCli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commitSummaryCli.js","sourceRoot":"","sources":["../../src/ai/commitSummaryCli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * CommitSummaryStateStore — agent-owned per-repo state for AI commit summary
3
+ * generation.
4
+ *
5
+ * The state lives on the agent (not the PWA) so that:
6
+ * • Long-running agentic generations (Claude CLI can take ~2 minutes) survive
7
+ * PWA reloads and reconnections.
8
+ * • Multiple PWAs/tabs see the same pending suggestion and can apply or
9
+ * dismiss it cooperatively.
10
+ *
11
+ * State is keyed by repoPath. Emits `state-updated` (full state snapshot) any
12
+ * time a state mutation happens — the daemon wires this to `connection.broadcast`
13
+ * so all connected peers observe the change.
14
+ */
15
+ import { EventEmitter } from 'events';
16
+ import type { CommitSummaryProgress, CommitSummaryState, CommitSummarySource, ClaudeModel, TokenUsage, GenerateCommitSummaryErrorCode } from '@sumicom/quicksave-shared';
17
+ export interface CommitSummaryStoreEvents {
18
+ 'state-updated': (state: CommitSummaryState) => void;
19
+ }
20
+ export declare interface CommitSummaryStateStore {
21
+ on<E extends keyof CommitSummaryStoreEvents>(event: E, listener: CommitSummaryStoreEvents[E]): this;
22
+ emit<E extends keyof CommitSummaryStoreEvents>(event: E, ...args: Parameters<CommitSummaryStoreEvents[E]>): boolean;
23
+ }
24
+ export declare class CommitSummaryStateStore extends EventEmitter {
25
+ private states;
26
+ private active;
27
+ get(repoPath: string): CommitSummaryState;
28
+ /** Is a generation currently in flight for this repo? */
29
+ isGenerating(repoPath: string): boolean;
30
+ /** Returns the abort token for the active generation, if any. The caller
31
+ * can use this token later to ensure they're not clobbering a newer run. */
32
+ activeToken(repoPath: string): symbol | undefined;
33
+ /**
34
+ * Mark generation as started and register an abort callback. Returns the
35
+ * opaque token that services can check before writing results — if the
36
+ * token no longer matches, a newer kickoff has superseded this one.
37
+ */
38
+ startGenerating(repoPath: string, source: CommitSummarySource, model: ClaudeModel | undefined, onAbort: () => void): symbol;
39
+ updateProgress(repoPath: string, token: symbol, progress: Partial<CommitSummaryProgress>): void;
40
+ setResult(repoPath: string, token: symbol, result: {
41
+ summary: string;
42
+ description?: string;
43
+ tokenUsage?: TokenUsage;
44
+ cached?: boolean;
45
+ }): void;
46
+ setError(repoPath: string, token: symbol, error: string, errorCode?: GenerateCommitSummaryErrorCode): void;
47
+ /** Reset the state to idle. If a generation is in-flight, abort it first. */
48
+ clear(repoPath: string): CommitSummaryState;
49
+ /** Snapshot every tracked repo state (debugging / introspection). */
50
+ snapshot(): CommitSummaryState[];
51
+ private writeState;
52
+ }
53
+ //# sourceMappingURL=commitSummaryStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commitSummaryStore.d.ts","sourceRoot":"","sources":["../../src/ai/commitSummaryStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EACV,qBAAqB,EACrB,kBAAkB,EAElB,mBAAmB,EACnB,WAAW,EACX,UAAU,EACV,8BAA8B,EAC/B,MAAM,2BAA2B,CAAC;AAOnC,MAAM,WAAW,wBAAwB;IACvC,eAAe,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACtD;AAED,MAAM,CAAC,OAAO,WAAW,uBAAuB;IAC9C,EAAE,CAAC,CAAC,SAAS,MAAM,wBAAwB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,wBAAwB,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IACpG,IAAI,CAAC,CAAC,SAAS,MAAM,wBAAwB,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;CACrH;AAED,qBAAa,uBAAwB,SAAQ,YAAY;IACvD,OAAO,CAAC,MAAM,CAAyC;IACvD,OAAO,CAAC,MAAM,CAAuC;IAErD,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB;IAIzC,yDAAyD;IACzD,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIvC;iFAC6E;IAC7E,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIjD;;;;OAIG;IACH,eAAe,CACb,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,mBAAmB,EAC3B,KAAK,EAAE,WAAW,GAAG,SAAS,EAC9B,OAAO,EAAE,MAAM,IAAI,GAClB,MAAM;IAsBT,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG,IAAI;IAgB/F,SAAS,CACP,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,UAAU,CAAC;QACxB,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,GACA,IAAI;IAmBP,QAAQ,CACN,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,8BAA8B,GACzC,IAAI;IAiBP,6EAA6E;IAC7E,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB;IAW3C,qEAAqE;IACrE,QAAQ,IAAI,kBAAkB,EAAE;IAIhC,OAAO,CAAC,UAAU;CAInB"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * CommitSummaryStateStore — agent-owned per-repo state for AI commit summary
3
+ * generation.
4
+ *
5
+ * The state lives on the agent (not the PWA) so that:
6
+ * • Long-running agentic generations (Claude CLI can take ~2 minutes) survive
7
+ * PWA reloads and reconnections.
8
+ * • Multiple PWAs/tabs see the same pending suggestion and can apply or
9
+ * dismiss it cooperatively.
10
+ *
11
+ * State is keyed by repoPath. Emits `state-updated` (full state snapshot) any
12
+ * time a state mutation happens — the daemon wires this to `connection.broadcast`
13
+ * so all connected peers observe the change.
14
+ */
15
+ import { EventEmitter } from 'events';
16
+ export class CommitSummaryStateStore extends EventEmitter {
17
+ states = new Map();
18
+ active = new Map();
19
+ get(repoPath) {
20
+ return this.states.get(repoPath) ?? idleState(repoPath);
21
+ }
22
+ /** Is a generation currently in flight for this repo? */
23
+ isGenerating(repoPath) {
24
+ return this.states.get(repoPath)?.status === 'generating';
25
+ }
26
+ /** Returns the abort token for the active generation, if any. The caller
27
+ * can use this token later to ensure they're not clobbering a newer run. */
28
+ activeToken(repoPath) {
29
+ return this.active.get(repoPath)?.token;
30
+ }
31
+ /**
32
+ * Mark generation as started and register an abort callback. Returns the
33
+ * opaque token that services can check before writing results — if the
34
+ * token no longer matches, a newer kickoff has superseded this one.
35
+ */
36
+ startGenerating(repoPath, source, model, onAbort) {
37
+ // Abort any prior active generation for the same repo
38
+ const prev = this.active.get(repoPath);
39
+ if (prev) {
40
+ try {
41
+ prev.abort();
42
+ }
43
+ catch { /* ignore */ }
44
+ }
45
+ const token = Symbol(`commit-summary:${repoPath}`);
46
+ this.active.set(repoPath, { abort: onAbort, token });
47
+ const next = {
48
+ repoPath,
49
+ status: 'generating',
50
+ startedAt: Date.now(),
51
+ source,
52
+ model,
53
+ progress: { phase: 'preparing', elapsedMs: 0 },
54
+ };
55
+ this.writeState(next);
56
+ return token;
57
+ }
58
+ updateProgress(repoPath, token, progress) {
59
+ if (this.active.get(repoPath)?.token !== token)
60
+ return; // stale
61
+ const prev = this.states.get(repoPath);
62
+ if (!prev || prev.status !== 'generating')
63
+ return;
64
+ const elapsedMs = prev.startedAt ? Date.now() - prev.startedAt : undefined;
65
+ const merged = {
66
+ phase: progress.phase ?? prev.progress?.phase ?? 'generating',
67
+ elapsedMs,
68
+ toolCount: progress.toolCount ?? prev.progress?.toolCount,
69
+ lastToolName: progress.lastToolName ?? prev.progress?.lastToolName,
70
+ partialText: progress.partialText ?? prev.progress?.partialText,
71
+ };
72
+ this.writeState({ ...prev, progress: merged });
73
+ }
74
+ setResult(repoPath, token, result) {
75
+ if (this.active.get(repoPath)?.token !== token)
76
+ return; // stale
77
+ this.active.delete(repoPath);
78
+ const prev = this.states.get(repoPath);
79
+ const next = {
80
+ repoPath,
81
+ status: 'ready',
82
+ startedAt: prev?.startedAt,
83
+ completedAt: Date.now(),
84
+ source: prev?.source,
85
+ model: prev?.model,
86
+ summary: result.summary,
87
+ description: result.description,
88
+ tokenUsage: result.tokenUsage,
89
+ cached: result.cached,
90
+ };
91
+ this.writeState(next);
92
+ }
93
+ setError(repoPath, token, error, errorCode) {
94
+ if (this.active.get(repoPath)?.token !== token)
95
+ return; // stale
96
+ this.active.delete(repoPath);
97
+ const prev = this.states.get(repoPath);
98
+ const next = {
99
+ repoPath,
100
+ status: 'error',
101
+ startedAt: prev?.startedAt,
102
+ completedAt: Date.now(),
103
+ source: prev?.source,
104
+ model: prev?.model,
105
+ error,
106
+ errorCode,
107
+ };
108
+ this.writeState(next);
109
+ }
110
+ /** Reset the state to idle. If a generation is in-flight, abort it first. */
111
+ clear(repoPath) {
112
+ const active = this.active.get(repoPath);
113
+ if (active) {
114
+ try {
115
+ active.abort();
116
+ }
117
+ catch { /* ignore */ }
118
+ this.active.delete(repoPath);
119
+ }
120
+ const next = idleState(repoPath);
121
+ this.writeState(next);
122
+ return next;
123
+ }
124
+ /** Snapshot every tracked repo state (debugging / introspection). */
125
+ snapshot() {
126
+ return Array.from(this.states.values());
127
+ }
128
+ writeState(state) {
129
+ this.states.set(state.repoPath, state);
130
+ this.emit('state-updated', state);
131
+ }
132
+ }
133
+ function idleState(repoPath) {
134
+ return { repoPath, status: 'idle' };
135
+ }
136
+ //# sourceMappingURL=commitSummaryStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commitSummaryStore.js","sourceRoot":"","sources":["../../src/ai/commitSummaryStore.ts"],"names":[],"mappings":"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"}