@lumenflow/host 5.0.2

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 (47) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +19 -0
  3. package/dist/enrollment/index.d.ts +10 -0
  4. package/dist/enrollment/index.d.ts.map +1 -0
  5. package/dist/enrollment/index.js +11 -0
  6. package/dist/enrollment/index.js.map +1 -0
  7. package/dist/enrollment/phone-device.d.ts +73 -0
  8. package/dist/enrollment/phone-device.d.ts.map +1 -0
  9. package/dist/enrollment/phone-device.js +198 -0
  10. package/dist/enrollment/phone-device.js.map +1 -0
  11. package/dist/git/git-adapter.d.ts +452 -0
  12. package/dist/git/git-adapter.d.ts.map +1 -0
  13. package/dist/git/git-adapter.js +778 -0
  14. package/dist/git/git-adapter.js.map +1 -0
  15. package/dist/git/git-context-constants.d.ts +43 -0
  16. package/dist/git/git-context-constants.d.ts.map +1 -0
  17. package/dist/git/git-context-constants.js +45 -0
  18. package/dist/git/git-context-constants.js.map +1 -0
  19. package/dist/git/git-context-extractor.d.ts +102 -0
  20. package/dist/git/git-context-extractor.d.ts.map +1 -0
  21. package/dist/git/git-context-extractor.js +568 -0
  22. package/dist/git/git-context-extractor.js.map +1 -0
  23. package/dist/git/git-staged-validator.d.ts +33 -0
  24. package/dist/git/git-staged-validator.d.ts.map +1 -0
  25. package/dist/git/git-staged-validator.js +52 -0
  26. package/dist/git/git-staged-validator.js.map +1 -0
  27. package/dist/git/git-validator.ports.d.ts +114 -0
  28. package/dist/git/git-validator.ports.d.ts.map +1 -0
  29. package/dist/git/git-validator.ports.js +4 -0
  30. package/dist/git/git-validator.ports.js.map +1 -0
  31. package/dist/git/index.d.ts +12 -0
  32. package/dist/git/index.d.ts.map +1 -0
  33. package/dist/git/index.js +14 -0
  34. package/dist/git/index.js.map +1 -0
  35. package/dist/index.d.ts +16 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +18 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/workspace-config/index.d.ts +10 -0
  40. package/dist/workspace-config/index.d.ts.map +1 -0
  41. package/dist/workspace-config/index.js +12 -0
  42. package/dist/workspace-config/index.js.map +1 -0
  43. package/dist/workspace-config/lumenflow-config.d.ts +75 -0
  44. package/dist/workspace-config/lumenflow-config.d.ts.map +1 -0
  45. package/dist/workspace-config/lumenflow-config.js +212 -0
  46. package/dist/workspace-config/lumenflow-config.js.map +1 -0
  47. package/package.json +65 -0
@@ -0,0 +1,568 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+ /**
4
+ * Git Context Extractor Module (WU-1190)
5
+ *
6
+ * Extracts git history insights for LLM context enrichment:
7
+ * - Co-occurrence: files frequently changed together
8
+ * - Ownership: primary contributors to file/directory
9
+ * - Churn: change frequency metrics (hotspots)
10
+ *
11
+ * These signals help the LLM understand codebase relationships
12
+ * without algorithmic clustering - the LLM interprets the patterns.
13
+ */
14
+ import { execSync } from 'node:child_process';
15
+ import { SHA1_HEX_LENGTH, GIT_COMMAND_TIMEOUT_MS, GIT_MAX_BUFFER_BYTES, GIT_DEFAULT_MAX_COMMITS, GIT_DEFAULT_MAX_RESULTS, GIT_MIN_COMMIT_COUNT, GIT_MIN_CO_OCCURRENCE_COUNT, GIT_MAX_TOP_LEVEL_DIRS, GIT_SUMMARY_ITEM_LIMIT, CHARS_PER_TOKEN, GIT_DEFAULT_MAX_SUMMARY_TOKENS, GIT_TRUNCATION_PADDING, SECTION_HEADER_LINE_COUNT, } from './git-context-constants.js';
16
+ // Constants
17
+ const DEFAULT_EXCLUDE_PATTERNS = ['*.lock', '*.yaml', '*.yml', '*.json', '*.md', 'pnpm-lock.yaml'];
18
+ // Pre-compiled regex patterns for performance
19
+ // Note: Using atomic groups or possessive quantifiers isn't supported in JS,
20
+ // so some patterns are implemented as functions to avoid backtracking
21
+ const NUMSTAT_LINE_REGEX = /^(\d+|-)\t(\d+|-)\t(.+)$/;
22
+ const DANGEROUS_CHARS_REGEX = /[;&|`$]/;
23
+ /**
24
+ * Parse shortlog line: " 10\tName <email>"
25
+ * Manual parsing to avoid slow regex backtracking
26
+ */
27
+ function parseShortlogFormat(line) {
28
+ // Skip leading whitespace
29
+ let i = 0;
30
+ while (i < line.length && (line.charAt(i) === ' ' || line.charAt(i) === '\t')) {
31
+ i++;
32
+ }
33
+ // Parse digits
34
+ const digitStart = i;
35
+ while (i < line.length && line.charAt(i) >= '0' && line.charAt(i) <= '9') {
36
+ i++;
37
+ }
38
+ if (i === digitStart)
39
+ return null; // No digits found
40
+ const count = parseInt(line.slice(digitStart, i), 10);
41
+ // Skip whitespace after digits
42
+ while (i < line.length && (line.charAt(i) === ' ' || line.charAt(i) === '\t')) {
43
+ i++;
44
+ }
45
+ // Rest is the name
46
+ const name = line.slice(i).trim();
47
+ if (!name)
48
+ return null;
49
+ return { count, name };
50
+ }
51
+ /**
52
+ * Check if a string is a git commit hash (40 hex chars)
53
+ * Uses character-by-character check to avoid slow regex backtracking
54
+ */
55
+ function isCommitHash(str) {
56
+ if (str.length !== SHA1_HEX_LENGTH)
57
+ return false;
58
+ for (const char of str) {
59
+ if (!((char >= '0' && char <= '9') || (char >= 'a' && char <= 'f'))) {
60
+ return false;
61
+ }
62
+ }
63
+ return true;
64
+ }
65
+ const SOURCE_FILE_EXCLUDE_PATTERNS = [
66
+ /\.lock$/,
67
+ /lock\.ya?ml$/,
68
+ /package-lock\.json$/,
69
+ /yarn\.lock$/,
70
+ /\.gitignore$/,
71
+ /\.env/,
72
+ /node_modules/,
73
+ /dist\//,
74
+ /build\//,
75
+ /\.min\./,
76
+ ];
77
+ /**
78
+ * Execute a git command safely, returning empty string on error.
79
+ *
80
+ * SECURITY: Commands are constructed from static arguments (no user input) to prevent injection.
81
+ * The args array is joined into a command string for execSync.
82
+ * All callers pass only internally-constructed arguments.
83
+ */
84
+ function safeGitExec(args, cwd) {
85
+ try {
86
+ // Join args into a command string
87
+ // SECURITY: all args are constructed internally (no user input)
88
+ const cmd = ['git', ...args].join(' ');
89
+ // SECURITY: execSync is safe here because:
90
+ // 1. 'git' is a fixed command from PATH (trusted)
91
+ // 2. args are internally constructed, not from user input
92
+ // 3. cwd is validated by the caller (projectRoot from CLI)
93
+ const result = execSync(cmd, {
94
+ cwd,
95
+ encoding: 'utf-8',
96
+ maxBuffer: GIT_MAX_BUFFER_BYTES,
97
+ timeout: GIT_COMMAND_TIMEOUT_MS,
98
+ });
99
+ return result;
100
+ }
101
+ catch {
102
+ return '';
103
+ }
104
+ }
105
+ /**
106
+ * Check if commit count indicates limited history
107
+ */
108
+ function hasLimitedCommitCount(projectRoot) {
109
+ const commitCountStr = safeGitExec(['rev-list', '--count', 'HEAD'], projectRoot).trim();
110
+ const count = parseInt(commitCountStr, 10) || 0;
111
+ return { limited: count < GIT_MIN_COMMIT_COUNT, count };
112
+ }
113
+ /**
114
+ * Extract complete git context from a repository
115
+ */
116
+ export function extractGitContext(projectRoot, options = {}) {
117
+ const result = {
118
+ coOccurrences: [],
119
+ ownership: [],
120
+ churn: [],
121
+ hasLimitedHistory: false,
122
+ };
123
+ try {
124
+ // Check if this is a git repo using execSync directly
125
+ // SECURITY: This is a static command with no user input
126
+ // eslint-disable-next-line sonarjs/no-os-command-from-path -- git resolved from PATH; workflow tooling requires git
127
+ execSync('git rev-parse --is-inside-work-tree', {
128
+ cwd: projectRoot,
129
+ encoding: 'utf-8',
130
+ });
131
+ const { limited, count } = hasLimitedCommitCount(projectRoot);
132
+ if (limited) {
133
+ result.hasLimitedHistory = true;
134
+ result.error = `Repository has fewer than ${GIT_MIN_COMMIT_COUNT} commits (found ${count})`;
135
+ return result;
136
+ }
137
+ // Extract co-occurrences
138
+ result.coOccurrences = getFileCoOccurrence(projectRoot, {
139
+ maxCommits: options.maxCommits ?? GIT_DEFAULT_MAX_COMMITS,
140
+ since: options.since,
141
+ });
142
+ // Get top-level directories for ownership analysis
143
+ const topDirs = getTopLevelDirs(projectRoot);
144
+ result.ownership = getOwnershipSignals(projectRoot, topDirs);
145
+ // Extract churn metrics
146
+ result.churn = getChurnMetrics(projectRoot, {
147
+ maxCommits: options.maxCommits ?? GIT_DEFAULT_MAX_COMMITS,
148
+ since: options.since,
149
+ });
150
+ }
151
+ catch (error) {
152
+ handleExtractionError(result, error);
153
+ }
154
+ return result;
155
+ }
156
+ /**
157
+ * Handle extraction errors and set appropriate error messages
158
+ */
159
+ function handleExtractionError(result, error) {
160
+ result.hasLimitedHistory = true;
161
+ if (error instanceof Error) {
162
+ if (error.message.includes('not a git repository')) {
163
+ result.error = 'not a git repository';
164
+ }
165
+ else if (error.message.includes('does not have UnsafeAny commits')) {
166
+ result.error = 'no commits in repository';
167
+ }
168
+ else {
169
+ result.error = error.message;
170
+ }
171
+ }
172
+ }
173
+ /**
174
+ * Get top-level directories for ownership analysis
175
+ */
176
+ function getTopLevelDirs(projectRoot) {
177
+ const output = safeGitExec(['ls-tree', '-d', '--name-only', 'HEAD'], projectRoot);
178
+ return output
179
+ .split('\n')
180
+ .filter((d) => d.trim() && !d.startsWith('.'))
181
+ .slice(0, GIT_MAX_TOP_LEVEL_DIRS);
182
+ }
183
+ /**
184
+ * Parse git log output into commits with their files
185
+ */
186
+ function parseCommitsFromLog(output) {
187
+ const commits = [];
188
+ let currentFiles = [];
189
+ for (const line of output.split('\n')) {
190
+ const trimmed = line.trim();
191
+ if (!trimmed) {
192
+ if (currentFiles.length > 0) {
193
+ commits.push([...currentFiles]);
194
+ currentFiles = [];
195
+ }
196
+ continue;
197
+ }
198
+ // Skip commit hashes (40 hex chars)
199
+ if (isCommitHash(trimmed)) {
200
+ if (currentFiles.length > 0) {
201
+ commits.push([...currentFiles]);
202
+ currentFiles = [];
203
+ }
204
+ continue;
205
+ }
206
+ // Only track source files
207
+ if (isSourceFile(trimmed)) {
208
+ currentFiles.push(trimmed);
209
+ }
210
+ }
211
+ if (currentFiles.length > 0) {
212
+ commits.push(currentFiles);
213
+ }
214
+ return commits;
215
+ }
216
+ /**
217
+ * Count file pair co-occurrences from commits
218
+ */
219
+ function countFilePairs(commits) {
220
+ const pairCounts = new Map();
221
+ for (const files of commits) {
222
+ if (files.length < 2)
223
+ continue;
224
+ // Generate all pairs
225
+ for (let i = 0; i < files.length; i++) {
226
+ for (let j = i + 1; j < files.length; j++) {
227
+ const fileA = files[i];
228
+ const fileB = files[j];
229
+ if (!fileA || !fileB)
230
+ continue;
231
+ const pair = [fileA, fileB]
232
+ .slice()
233
+ .sort((a, b) => a.localeCompare(b))
234
+ .join('::');
235
+ pairCounts.set(pair, (pairCounts.get(pair) ?? 0) + 1);
236
+ }
237
+ }
238
+ }
239
+ return pairCounts;
240
+ }
241
+ /**
242
+ * Extract file co-occurrence patterns from git history
243
+ */
244
+ export function getFileCoOccurrence(projectRoot, options = {}) {
245
+ const maxCommits = options.maxCommits ?? GIT_DEFAULT_MAX_COMMITS;
246
+ const maxResults = options.maxResults ?? GIT_DEFAULT_MAX_RESULTS;
247
+ // Build git log args array (safe - no user input in paths)
248
+ const args = ['log', `-n`, String(maxCommits)];
249
+ if (options.since) {
250
+ args.push(`--since=${options.since}`);
251
+ }
252
+ args.push('--name-only', '--pretty=format:%H', '--diff-filter=ACMRT');
253
+ const output = safeGitExec(args, projectRoot);
254
+ if (!output.trim()) {
255
+ return [];
256
+ }
257
+ const commits = parseCommitsFromLog(output);
258
+ const pairCounts = countFilePairs(commits);
259
+ // Convert to array and filter
260
+ const coOccurrences = [];
261
+ for (const [pair, count] of pairCounts.entries()) {
262
+ if (count >= GIT_MIN_CO_OCCURRENCE_COUNT) {
263
+ const [file1, file2] = pair.split('::');
264
+ if (!file1 || !file2)
265
+ continue;
266
+ coOccurrences.push({ file1, file2, count });
267
+ }
268
+ }
269
+ // Sort by count descending and limit results (use toSorted to avoid mutation)
270
+ return coOccurrences
271
+ .slice()
272
+ .sort((a, b) => b.count - a.count)
273
+ .slice(0, maxResults);
274
+ }
275
+ /**
276
+ * Check if a file is a source file (not config, lock, etc.)
277
+ */
278
+ function isSourceFile(filePath) {
279
+ return !SOURCE_FILE_EXCLUDE_PATTERNS.some((pattern) => pattern.test(filePath));
280
+ }
281
+ /**
282
+ * Parse a single contributor line from shortlog output
283
+ */
284
+ function parseShortlogLine(line) {
285
+ const result = parseShortlogFormat(line);
286
+ if (!result)
287
+ return null;
288
+ return {
289
+ count: result.count,
290
+ name: result.name,
291
+ };
292
+ }
293
+ /**
294
+ * Extract ownership signal for a single path
295
+ */
296
+ function extractOwnershipForPath(projectRoot, targetPath) {
297
+ // Validate path doesn't contain dangerous characters
298
+ if (DANGEROUS_CHARS_REGEX.test(targetPath)) {
299
+ return {
300
+ path: targetPath,
301
+ primaryOwner: null,
302
+ contributors: [],
303
+ commitCount: 0,
304
+ };
305
+ }
306
+ // Use array form for safety
307
+ const args = ['shortlog', '-sne', '--all', '--', targetPath];
308
+ const output = safeGitExec(args, projectRoot);
309
+ if (!output.trim()) {
310
+ return {
311
+ path: targetPath,
312
+ primaryOwner: null,
313
+ contributors: [],
314
+ commitCount: 0,
315
+ };
316
+ }
317
+ // Parse shortlog output
318
+ const contributors = [];
319
+ let totalCommits = 0;
320
+ for (const line of output.split('\n')) {
321
+ const parsed = parseShortlogLine(line);
322
+ if (parsed) {
323
+ contributors.push(parsed);
324
+ totalCommits += parsed.count;
325
+ }
326
+ }
327
+ // Sort by commit count descending (use toSorted to avoid mutation)
328
+ const sorted = contributors.slice().sort((a, b) => b.count - a.count);
329
+ return {
330
+ path: targetPath,
331
+ primaryOwner: sorted[0]?.name ?? null,
332
+ contributors: sorted.map((c) => c.name),
333
+ commitCount: totalCommits,
334
+ };
335
+ }
336
+ /**
337
+ * Extract ownership signals for specified paths.
338
+ * Note: paths are validated internally and not derived from user input.
339
+ */
340
+ export function getOwnershipSignals(projectRoot, paths) {
341
+ return paths.map((path) => extractOwnershipForPath(projectRoot, path));
342
+ }
343
+ /**
344
+ * Parse a single numstat line from git log output
345
+ */
346
+ function parseNumstatLine(line) {
347
+ const match = NUMSTAT_LINE_REGEX.exec(line);
348
+ if (!match)
349
+ return null;
350
+ const additions = match[1];
351
+ const deletions = match[2];
352
+ const filePath = match[3];
353
+ if (!additions || !deletions || !filePath)
354
+ return null;
355
+ return {
356
+ additions: additions === '-' ? 0 : parseInt(additions, 10),
357
+ deletions: deletions === '-' ? 0 : parseInt(deletions, 10),
358
+ filePath,
359
+ };
360
+ }
361
+ /**
362
+ * Check if a file matches UnsafeAny exclude pattern using simple glob matching
363
+ */
364
+ function matchesExcludePattern(filePath, patterns) {
365
+ return patterns.some((pattern) => {
366
+ // Simple glob matching using a state machine approach
367
+ // Avoids control characters and dynamic regex construction
368
+ return globMatch(filePath, pattern);
369
+ });
370
+ }
371
+ /**
372
+ * Simple glob matching without regex
373
+ * Supports * (match UnsafeAny) and ? (match single char)
374
+ */
375
+ function globMatch(str, pattern) {
376
+ let si = 0; // string index
377
+ let pi = 0; // pattern index
378
+ let starIdx = -1;
379
+ let matchIdx = 0;
380
+ while (si < str.length) {
381
+ if (pi < pattern.length && (pattern[pi] === '?' || pattern[pi] === str[si])) {
382
+ // Character match or ? wildcard
383
+ si++;
384
+ pi++;
385
+ }
386
+ else if (pi < pattern.length && pattern[pi] === '*') {
387
+ // Star found, mark position
388
+ starIdx = pi;
389
+ matchIdx = si;
390
+ pi++;
391
+ }
392
+ else if (starIdx !== -1) {
393
+ // Mismatch after star, backtrack
394
+ pi = starIdx + 1;
395
+ matchIdx++;
396
+ si = matchIdx;
397
+ }
398
+ else {
399
+ // Mismatch without star
400
+ return false;
401
+ }
402
+ }
403
+ // Skip trailing stars
404
+ while (pi < pattern.length && pattern[pi] === '*') {
405
+ pi++;
406
+ }
407
+ return pi === pattern.length;
408
+ }
409
+ /**
410
+ * Aggregate file statistics from numstat output
411
+ */
412
+ function aggregateFileStats(output, excludePatterns) {
413
+ const fileStats = new Map();
414
+ for (const line of output.split('\n')) {
415
+ const trimmed = line.trim();
416
+ if (!trimmed)
417
+ continue;
418
+ const parsed = parseNumstatLine(trimmed);
419
+ if (!parsed)
420
+ continue;
421
+ // Skip excluded patterns
422
+ if (matchesExcludePattern(parsed.filePath, excludePatterns))
423
+ continue;
424
+ // Skip non-source files
425
+ if (!isSourceFile(parsed.filePath))
426
+ continue;
427
+ const existing = fileStats.get(parsed.filePath) ?? { additions: 0, deletions: 0, commits: 0 };
428
+ fileStats.set(parsed.filePath, {
429
+ additions: existing.additions + parsed.additions,
430
+ deletions: existing.deletions + parsed.deletions,
431
+ commits: existing.commits + 1,
432
+ });
433
+ }
434
+ return fileStats;
435
+ }
436
+ /**
437
+ * Extract churn metrics for the repository
438
+ */
439
+ export function getChurnMetrics(projectRoot, options = {}) {
440
+ const maxCommits = options.maxCommits ?? GIT_DEFAULT_MAX_COMMITS;
441
+ const maxResults = options.maxResults ?? GIT_DEFAULT_MAX_RESULTS;
442
+ const excludePatterns = options.excludePatterns ?? DEFAULT_EXCLUDE_PATTERNS;
443
+ // Build git log args array
444
+ const args = ['log', `-n`, String(maxCommits)];
445
+ if (options.since) {
446
+ args.push(`--since=${options.since}`);
447
+ }
448
+ args.push('--numstat', '--pretty=format:');
449
+ let output;
450
+ try {
451
+ /// SECURITY: all args are constructed internally (no user input)
452
+ const cmd = ['git', ...args].join(' ');
453
+ output = execSync(cmd, {
454
+ cwd: projectRoot,
455
+ encoding: 'utf-8',
456
+ maxBuffer: GIT_MAX_BUFFER_BYTES,
457
+ timeout: GIT_COMMAND_TIMEOUT_MS,
458
+ });
459
+ }
460
+ catch {
461
+ return [];
462
+ }
463
+ if (!output.trim()) {
464
+ return [];
465
+ }
466
+ const fileStats = aggregateFileStats(output, excludePatterns);
467
+ // Convert to array with churn scores
468
+ const metrics = [];
469
+ for (const [filePath, stats] of fileStats.entries()) {
470
+ metrics.push({
471
+ filePath,
472
+ additions: stats.additions,
473
+ deletions: stats.deletions,
474
+ churnScore: stats.additions + stats.deletions,
475
+ commitCount: stats.commits,
476
+ });
477
+ }
478
+ // Sort by churn score descending and limit results (use toSorted to avoid mutation)
479
+ return metrics
480
+ .slice()
481
+ .sort((a, b) => b.churnScore - a.churnScore)
482
+ .slice(0, maxResults);
483
+ }
484
+ /**
485
+ * Build co-occurrence section for summary
486
+ */
487
+ function buildCoOccurrenceSection(coOccurrences) {
488
+ const lines = ['## Co-occurrence Patterns', 'Files frequently changed together:'];
489
+ for (const co of coOccurrences.slice(0, GIT_SUMMARY_ITEM_LIMIT)) {
490
+ lines.push(`- ${co.file1} <-> ${co.file2} (${co.count} commits)`);
491
+ }
492
+ return lines.join('\n');
493
+ }
494
+ /**
495
+ * Build ownership section for summary
496
+ */
497
+ function buildOwnershipSection(ownership) {
498
+ const lines = ['## Ownership Signals', 'Primary contributors by area:'];
499
+ for (const own of ownership.filter((o) => o.primaryOwner)) {
500
+ const ownerName = own.primaryOwner?.split(' <')[0] ?? 'unknown';
501
+ lines.push(`- ${own.path}: ${ownerName} (${own.commitCount} commits)`);
502
+ }
503
+ return lines.join('\n');
504
+ }
505
+ /**
506
+ * Build churn section for summary
507
+ */
508
+ function buildChurnSection(churn) {
509
+ const lines = ['## Churn Hotspots', 'High-change files (potential complexity):'];
510
+ for (const ch of churn.slice(0, GIT_SUMMARY_ITEM_LIMIT)) {
511
+ lines.push(`- ${ch.filePath}: ${ch.churnScore} lines changed across ${ch.commitCount} commits`);
512
+ }
513
+ return lines.join('\n');
514
+ }
515
+ /**
516
+ * Truncate a section to fit within character limit
517
+ */
518
+ function truncateSection(section, maxChars) {
519
+ if (section.length <= maxChars)
520
+ return section;
521
+ const lines = section.split('\n');
522
+ const header = lines.slice(0, SECTION_HEADER_LINE_COUNT).join('\n');
523
+ const items = lines.slice(SECTION_HEADER_LINE_COUNT);
524
+ const availableChars = maxChars - header.length - GIT_TRUNCATION_PADDING;
525
+ const truncatedItems = [];
526
+ let currentChars = 0;
527
+ for (const item of items) {
528
+ if (currentChars + item.length > availableChars)
529
+ break;
530
+ truncatedItems.push(item);
531
+ currentChars += item.length + 1;
532
+ }
533
+ return [header, ...truncatedItems, '(truncated)'].join('\n');
534
+ }
535
+ /**
536
+ * Summarize git context for LLM prompt inclusion
537
+ *
538
+ * Produces a token-efficient summary that fits within specified limits.
539
+ */
540
+ export function summarizeGitContext(context, options = {}) {
541
+ const maxTokens = options.maxTokens ?? GIT_DEFAULT_MAX_SUMMARY_TOKENS;
542
+ const maxChars = maxTokens * CHARS_PER_TOKEN;
543
+ // Handle limited history case
544
+ if (context.hasLimitedHistory) {
545
+ return context.error
546
+ ? `Git history analysis limited: ${context.error}`
547
+ : 'Git history analysis limited due to sparse commit history.';
548
+ }
549
+ const sections = [];
550
+ if (context.coOccurrences.length > 0) {
551
+ sections.push(buildCoOccurrenceSection(context.coOccurrences));
552
+ }
553
+ if (context.ownership.length > 0) {
554
+ sections.push(buildOwnershipSection(context.ownership));
555
+ }
556
+ if (context.churn.length > 0) {
557
+ sections.push(buildChurnSection(context.churn));
558
+ }
559
+ let result = sections.join('\n\n');
560
+ // Truncate if needed
561
+ if (result.length > maxChars && sections.length > 0) {
562
+ const charsPerSection = Math.floor(maxChars / sections.length) - GIT_TRUNCATION_PADDING;
563
+ const truncatedSections = sections.map((s) => truncateSection(s, charsPerSection));
564
+ result = truncatedSections.join('\n\n');
565
+ }
566
+ return result || 'Git history analysis limited due to sparse commit history.';
567
+ }
568
+ //# sourceMappingURL=git-context-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-context-extractor.js","sourceRoot":"","sources":["../../src/git/git-context-extractor.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,yCAAyC;AAEzC;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAuF9C,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACpB,2BAA2B,EAC3B,sBAAsB,EACtB,sBAAsB,EACtB,eAAe,EACf,8BAA8B,EAC9B,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AAEpC,YAAY;AACZ,MAAM,wBAAwB,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC;AAEnG,8CAA8C;AAC9C,6EAA6E;AAC7E,sEAAsE;AACtE,MAAM,kBAAkB,GAAG,0BAA0B,CAAC;AACtD,MAAM,qBAAqB,GAAG,SAAS,CAAC;AAExC;;;GAGG;AACH,SAAS,mBAAmB,CAAC,IAAY;IACvC,0BAA0B;IAC1B,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;QAC9E,CAAC,EAAE,CAAC;IACN,CAAC;IAED,eAAe;IACf,MAAM,UAAU,GAAG,CAAC,CAAC;IACrB,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC;QACzE,CAAC,EAAE,CAAC;IACN,CAAC;IACD,IAAI,CAAC,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC,CAAC,kBAAkB;IAErD,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEtD,+BAA+B;IAC/B,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;QAC9E,CAAC,EAAE,CAAC;IACN,CAAC;IAED,mBAAmB;IACnB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAClC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,SAAS,YAAY,CAAC,GAAW;IAC/B,IAAI,GAAG,CAAC,MAAM,KAAK,eAAe;QAAE,OAAO,KAAK,CAAC;IACjD,KAAK,MAAM,IAAI,IAAI,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC;YACpE,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AACD,MAAM,4BAA4B,GAAG;IACnC,SAAS;IACT,cAAc;IACd,qBAAqB;IACrB,aAAa;IACb,cAAc;IACd,OAAO;IACP,cAAc;IACd,QAAQ;IACR,SAAS;IACT,SAAS;CACV,CAAC;AAEF;;;;;;GAMG;AACH,SAAS,WAAW,CAAC,IAAc,EAAE,GAAW;IAC9C,IAAI,CAAC;QACH,kCAAkC;QAClC,gEAAgE;QAChE,MAAM,GAAG,GAAG,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACvC,2CAA2C;QAC3C,kDAAkD;QAClD,0DAA0D;QAC1D,2DAA2D;QAE3D,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE;YAC3B,GAAG;YACH,QAAQ,EAAE,OAAO;YACjB,SAAS,EAAE,oBAAoB;YAC/B,OAAO,EAAE,sBAAsB;SAChC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAAC,WAAmB;IAChD,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC;IACxF,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IAChD,OAAO,EAAE,OAAO,EAAE,KAAK,GAAG,oBAAoB,EAAE,KAAK,EAAE,CAAC;AAC1D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,WAAmB,EACnB,UAA6B,EAAE;IAE/B,MAAM,MAAM,GAAe;QACzB,aAAa,EAAE,EAAE;QACjB,SAAS,EAAE,EAAE;QACb,KAAK,EAAE,EAAE;QACT,iBAAiB,EAAE,KAAK;KACzB,CAAC;IAEF,IAAI,CAAC;QACH,sDAAsD;QACtD,wDAAwD;QAExD,oHAAoH;QACpH,QAAQ,CAAC,qCAAqC,EAAE;YAC9C,GAAG,EAAE,WAAW;YAChB,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QAEH,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,qBAAqB,CAAC,WAAW,CAAC,CAAC;QAC9D,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,CAAC,iBAAiB,GAAG,IAAI,CAAC;YAChC,MAAM,CAAC,KAAK,GAAG,6BAA6B,oBAAoB,mBAAmB,KAAK,GAAG,CAAC;YAC5F,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,yBAAyB;QACzB,MAAM,CAAC,aAAa,GAAG,mBAAmB,CAAC,WAAW,EAAE;YACtD,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,uBAAuB;YACzD,KAAK,EAAE,OAAO,CAAC,KAAK;SACrB,CAAC,CAAC;QAEH,mDAAmD;QACnD,MAAM,OAAO,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;QAC7C,MAAM,CAAC,SAAS,GAAG,mBAAmB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAE7D,wBAAwB;QACxB,MAAM,CAAC,KAAK,GAAG,eAAe,CAAC,WAAW,EAAE;YAC1C,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,uBAAuB;YACzD,KAAK,EAAE,OAAO,CAAC,KAAK;SACrB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,qBAAqB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAAC,MAAkB,EAAE,KAAc;IAC/D,MAAM,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAChC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC;YACnD,MAAM,CAAC,KAAK,GAAG,sBAAsB,CAAC;QACxC,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,iCAAiC,CAAC,EAAE,CAAC;YACrE,MAAM,CAAC,KAAK,GAAG,0BAA0B,CAAC;QAC5C,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC;QAC/B,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,WAAmB;IAC1C,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC;IAClF,OAAO,MAAM;SACV,KAAK,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;SAC7C,KAAK,CAAC,CAAC,EAAE,sBAAsB,CAAC,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,SAAS,mBAAmB,CAAC,MAAc;IACzC,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,IAAI,YAAY,GAAa,EAAE,CAAC;IAEhC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC;gBAChC,YAAY,GAAG,EAAE,CAAC;YACpB,CAAC;YACD,SAAS;QACX,CAAC;QACD,oCAAoC;QACpC,IAAI,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1B,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC;gBAChC,YAAY,GAAG,EAAE,CAAC;YACpB,CAAC;YACD,SAAS;QACX,CAAC;QACD,0BAA0B;QAC1B,IAAI,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1B,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IACD,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC7B,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,OAAmB;IACzC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE7C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QAE/B,qBAAqB;QACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACvB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACvB,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK;oBAAE,SAAS;gBAC/B,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC;qBACxB,KAAK,EAAE;qBACP,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;qBAClC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACd,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,WAAmB,EACnB,UAA+B,EAAE;IAEjC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,uBAAuB,CAAC;IACjE,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,uBAAuB,CAAC;IAEjE,2DAA2D;IAC3D,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IAC/C,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC,IAAI,CAAC,WAAW,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,oBAAoB,EAAE,qBAAqB,CAAC,CAAC;IAEtE,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAE9C,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACnB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,OAAO,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,UAAU,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAE3C,8BAA8B;IAC9B,MAAM,aAAa,GAAmB,EAAE,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;QACjD,IAAI,KAAK,IAAI,2BAA2B,EAAE,CAAC;YACzC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK;gBAAE,SAAS;YAC/B,aAAa,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IAED,8EAA8E;IAC9E,OAAO,aAAa;SACjB,KAAK,EAAE;SACP,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;SACjC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,QAAgB;IACpC,OAAO,CAAC,4BAA4B,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AACjF,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,IAAY;IACrC,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,IAAI,EAAE,MAAM,CAAC,IAAI;KAClB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,uBAAuB,CAAC,WAAmB,EAAE,UAAkB;IACtE,qDAAqD;IACrD,IAAI,qBAAqB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3C,OAAO;YACL,IAAI,EAAE,UAAU;YAChB,YAAY,EAAE,IAAI;YAClB,YAAY,EAAE,EAAE;YAChB,WAAW,EAAE,CAAC;SACf,CAAC;IACJ,CAAC;IAED,4BAA4B;IAC5B,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAE9C,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACnB,OAAO;YACL,IAAI,EAAE,UAAU;YAChB,YAAY,EAAE,IAAI;YAClB,YAAY,EAAE,EAAE;YAChB,WAAW,EAAE,CAAC;SACf,CAAC;IACJ,CAAC;IAED,wBAAwB;IACxB,MAAM,YAAY,GAAsC,EAAE,CAAC;IAC3D,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,MAAM,EAAE,CAAC;YACX,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC1B,YAAY,IAAI,MAAM,CAAC,KAAK,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,mEAAmE;IACnE,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAEtE,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,IAAI;QACrC,YAAY,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACvC,WAAW,EAAE,YAAY;KAC1B,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAAmB,EAAE,KAAe;IACtE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,uBAAuB,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;AACzE,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CACvB,IAAY;IAEZ,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IACvD,OAAO;QACL,SAAS,EAAE,SAAS,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC;QAC1D,SAAS,EAAE,SAAS,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC;QAC1D,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAAC,QAAgB,EAAE,QAAkB;IACjE,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;QAC/B,sDAAsD;QACtD,2DAA2D;QAC3D,OAAO,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,SAAS,SAAS,CAAC,GAAW,EAAE,OAAe;IAC7C,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,eAAe;IAC3B,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,gBAAgB;IAC5B,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC;IACjB,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,OAAO,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;QACvB,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,GAAG,IAAI,OAAO,CAAC,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YAC5E,gCAAgC;YAChC,EAAE,EAAE,CAAC;YACL,EAAE,EAAE,CAAC;QACP,CAAC;aAAM,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC;YACtD,4BAA4B;YAC5B,OAAO,GAAG,EAAE,CAAC;YACb,QAAQ,GAAG,EAAE,CAAC;YACd,EAAE,EAAE,CAAC;QACP,CAAC;aAAM,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC;YAC1B,iCAAiC;YACjC,EAAE,GAAG,OAAO,GAAG,CAAC,CAAC;YACjB,QAAQ,EAAE,CAAC;YACX,EAAE,GAAG,QAAQ,CAAC;QAChB,CAAC;aAAM,CAAC;YACN,wBAAwB;YACxB,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,sBAAsB;IACtB,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC;QAClD,EAAE,EAAE,CAAC;IACP,CAAC;IAED,OAAO,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CACzB,MAAc,EACd,eAAyB;IAEzB,MAAM,SAAS,GAAG,IAAI,GAAG,EAAqE,CAAC;IAE/F,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO;YAAE,SAAS;QAEvB,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM;YAAE,SAAS;QAEtB,yBAAyB;QACzB,IAAI,qBAAqB,CAAC,MAAM,CAAC,QAAQ,EAAE,eAAe,CAAC;YAAE,SAAS;QAEtE,wBAAwB;QACxB,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC;YAAE,SAAS;QAE7C,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;QAC9F,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE;YAC7B,SAAS,EAAE,QAAQ,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS;YAChD,SAAS,EAAE,QAAQ,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS;YAChD,OAAO,EAAE,QAAQ,CAAC,OAAO,GAAG,CAAC;SAC9B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,WAAmB,EAAE,UAAwB,EAAE;IAC7E,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,uBAAuB,CAAC;IACjE,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,uBAAuB,CAAC;IACjE,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,wBAAwB,CAAC;IAE5E,2BAA2B;IAC3B,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IAC/C,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC,IAAI,CAAC,WAAW,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;IAE3C,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,iEAAiE;QACjE,MAAM,GAAG,GAAG,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEvC,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE;YACrB,GAAG,EAAE,WAAW;YAChB,QAAQ,EAAE,OAAO;YACjB,SAAS,EAAE,oBAAoB;YAC/B,OAAO,EAAE,sBAAsB;SAChC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACnB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,SAAS,GAAG,kBAAkB,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAE9D,qCAAqC;IACrC,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,KAAK,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC;YACX,QAAQ;YACR,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,UAAU,EAAE,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS;YAC7C,WAAW,EAAE,KAAK,CAAC,OAAO;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,oFAAoF;IACpF,OAAO,OAAO;SACX,KAAK,EAAE;SACP,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC;SAC3C,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,SAAS,wBAAwB,CAAC,aAA6B;IAC7D,MAAM,KAAK,GAAG,CAAC,2BAA2B,EAAE,oCAAoC,CAAC,CAAC;IAClF,KAAK,MAAM,EAAE,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,sBAAsB,CAAC,EAAE,CAAC;QAChE,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,KAAK,WAAW,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAAC,SAA4B;IACzD,MAAM,KAAK,GAAG,CAAC,sBAAsB,EAAE,+BAA+B,CAAC,CAAC;IACxE,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC;QAC1D,MAAM,SAAS,GAAG,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;QAChE,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,KAAK,SAAS,KAAK,GAAG,CAAC,WAAW,WAAW,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,KAAoB;IAC7C,MAAM,KAAK,GAAG,CAAC,mBAAmB,EAAE,2CAA2C,CAAC,CAAC;IACjF,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,sBAAsB,CAAC,EAAE,CAAC;QACxD,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,QAAQ,KAAK,EAAE,CAAC,UAAU,yBAAyB,EAAE,CAAC,WAAW,UAAU,CAAC,CAAC;IAClG,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,OAAe,EAAE,QAAgB;IACxD,IAAI,OAAO,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO,OAAO,CAAC;IAE/C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,yBAAyB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpE,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACrD,MAAM,cAAc,GAAG,QAAQ,GAAG,MAAM,CAAC,MAAM,GAAG,sBAAsB,CAAC;IACzE,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,YAAY,GAAG,IAAI,CAAC,MAAM,GAAG,cAAc;YAAE,MAAM;QACvD,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,YAAY,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,CAAC,MAAM,EAAE,GAAG,cAAc,EAAE,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC/D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAmB,EAAE,UAA4B,EAAE;IACrF,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,8BAA8B,CAAC;IACtE,MAAM,QAAQ,GAAG,SAAS,GAAG,eAAe,CAAC;IAE7C,8BAA8B;IAC9B,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;QAC9B,OAAO,OAAO,CAAC,KAAK;YAClB,CAAC,CAAC,iCAAiC,OAAO,CAAC,KAAK,EAAE;YAClD,CAAC,CAAC,4DAA4D,CAAC;IACnE,CAAC;IAED,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrC,QAAQ,CAAC,IAAI,CAAC,wBAAwB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;IACjE,CAAC;IAED,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,QAAQ,CAAC,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,IAAI,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAEnC,qBAAqB;IACrB,IAAI,MAAM,CAAC,MAAM,GAAG,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpD,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,sBAAsB,CAAC;QACxF,MAAM,iBAAiB,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC;QACnF,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1C,CAAC;IAED,OAAO,MAAM,IAAI,4DAA4D,CAAC;AAChF,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Git Staged Files Validator
3
+ *
4
+ * Centralized validation for staged files requirement.
5
+ * Extracted from duplicate implementations in wu-block and wu-unblock (WU-1341).
6
+ *
7
+ * Used in --no-auto mode to enforce that required files are staged before commit.
8
+ *
9
+ * @module git-staged-validator
10
+ */
11
+ /**
12
+ * Ensure all required paths are staged in git index
13
+ *
14
+ * Validates that specified files/directories are staged for commit.
15
+ * Supports exact path matching and directory prefix matching.
16
+ *
17
+ * @param {Array<string|null|undefined>} paths - Paths to check (null/undefined values filtered out)
18
+ * @throws {Error} If UnsafeAny required paths are not staged
19
+ * @returns {Array<string>} List of all staged files
20
+ *
21
+ * @example
22
+ * // All files staged - success
23
+ * ensureStaged(['<configured-doc-file>', 'tools/script.js']);
24
+ *
25
+ * // Directory prefix - matches all files under directory
26
+ * ensureStaged(['<configured-doc-root>/']);
27
+ *
28
+ * // Missing files - throws error
29
+ * ensureStaged(['<configured-doc-file-1>', '<configured-doc-file-2>']);
30
+ * // Error: Stage updates for: <configured-doc-file-2>
31
+ */
32
+ export declare function ensureStaged(paths: Array<string | null | undefined>): string[];
33
+ //# sourceMappingURL=git-staged-validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-staged-validator.d.ts","sourceRoot":"","sources":["../../src/git/git-staged-validator.ts"],"names":[],"mappings":"AAMA;;;;;;;;;GASG;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,YAkBnE"}
@@ -0,0 +1,52 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+ import { getGitForCwd } from './git-adapter.js';
4
+ import { die } from '@lumenflow/kernel/primitives/error-handler';
5
+ /**
6
+ * Git Staged Files Validator
7
+ *
8
+ * Centralized validation for staged files requirement.
9
+ * Extracted from duplicate implementations in wu-block and wu-unblock (WU-1341).
10
+ *
11
+ * Used in --no-auto mode to enforce that required files are staged before commit.
12
+ *
13
+ * @module git-staged-validator
14
+ */
15
+ /**
16
+ * Ensure all required paths are staged in git index
17
+ *
18
+ * Validates that specified files/directories are staged for commit.
19
+ * Supports exact path matching and directory prefix matching.
20
+ *
21
+ * @param {Array<string|null|undefined>} paths - Paths to check (null/undefined values filtered out)
22
+ * @throws {Error} If UnsafeAny required paths are not staged
23
+ * @returns {Array<string>} List of all staged files
24
+ *
25
+ * @example
26
+ * // All files staged - success
27
+ * ensureStaged(['<configured-doc-file>', 'tools/script.js']);
28
+ *
29
+ * // Directory prefix - matches all files under directory
30
+ * ensureStaged(['<configured-doc-root>/']);
31
+ *
32
+ * // Missing files - throws error
33
+ * ensureStaged(['<configured-doc-file-1>', '<configured-doc-file-2>']);
34
+ * // Error: Stage updates for: <configured-doc-file-2>
35
+ */
36
+ export function ensureStaged(paths) {
37
+ const git = getGitForCwd();
38
+ const raw = git.run('git diff --cached --name-only');
39
+ const staged = raw ? raw.split(/\r?\n/).filter((s) => Boolean(s)) : [];
40
+ // Filter out null/undefined and check each path
41
+ const normalizedPaths = paths.filter((p) => typeof p === 'string' && p.length > 0);
42
+ const missing = normalizedPaths.filter((p) => {
43
+ // Normalize path: remove trailing slash for directory checks
44
+ const pathToCheck = p.endsWith('/') ? p.slice(0, -1) : p;
45
+ return !staged.some((name) => name === pathToCheck || name.startsWith(`${pathToCheck}/`));
46
+ });
47
+ if (missing.length) {
48
+ die(`Stage updates for: ${missing.join(', ')}`);
49
+ }
50
+ return staged;
51
+ }
52
+ //# sourceMappingURL=git-staged-validator.js.map