@m2015agg/git-skill 0.1.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 (112) hide show
  1. package/dist/commands/approve.d.ts +2 -0
  2. package/dist/commands/approve.js +56 -0
  3. package/dist/commands/approve.js.map +1 -0
  4. package/dist/commands/blame.d.ts +2 -0
  5. package/dist/commands/blame.js +139 -0
  6. package/dist/commands/blame.js.map +1 -0
  7. package/dist/commands/capture.d.ts +2 -0
  8. package/dist/commands/capture.js +68 -0
  9. package/dist/commands/capture.js.map +1 -0
  10. package/dist/commands/coupling.d.ts +2 -0
  11. package/dist/commands/coupling.js +48 -0
  12. package/dist/commands/coupling.js.map +1 -0
  13. package/dist/commands/cron.d.ts +2 -0
  14. package/dist/commands/cron.js +70 -0
  15. package/dist/commands/cron.js.map +1 -0
  16. package/dist/commands/decisions.d.ts +2 -0
  17. package/dist/commands/decisions.js +62 -0
  18. package/dist/commands/decisions.js.map +1 -0
  19. package/dist/commands/diff-summary.d.ts +2 -0
  20. package/dist/commands/diff-summary.js +151 -0
  21. package/dist/commands/diff-summary.js.map +1 -0
  22. package/dist/commands/docs.d.ts +3 -0
  23. package/dist/commands/docs.js +38 -0
  24. package/dist/commands/docs.js.map +1 -0
  25. package/dist/commands/doctor.d.ts +2 -0
  26. package/dist/commands/doctor.js +60 -0
  27. package/dist/commands/doctor.js.map +1 -0
  28. package/dist/commands/embed.d.ts +2 -0
  29. package/dist/commands/embed.js +81 -0
  30. package/dist/commands/embed.js.map +1 -0
  31. package/dist/commands/enrich.d.ts +2 -0
  32. package/dist/commands/enrich.js +148 -0
  33. package/dist/commands/enrich.js.map +1 -0
  34. package/dist/commands/experts.d.ts +2 -0
  35. package/dist/commands/experts.js +55 -0
  36. package/dist/commands/experts.js.map +1 -0
  37. package/dist/commands/hotspots.d.ts +2 -0
  38. package/dist/commands/hotspots.js +46 -0
  39. package/dist/commands/hotspots.js.map +1 -0
  40. package/dist/commands/init.d.ts +2 -0
  41. package/dist/commands/init.js +91 -0
  42. package/dist/commands/init.js.map +1 -0
  43. package/dist/commands/install.d.ts +2 -0
  44. package/dist/commands/install.js +59 -0
  45. package/dist/commands/install.js.map +1 -0
  46. package/dist/commands/metric.d.ts +2 -0
  47. package/dist/commands/metric.js +26 -0
  48. package/dist/commands/metric.js.map +1 -0
  49. package/dist/commands/regression.d.ts +2 -0
  50. package/dist/commands/regression.js +166 -0
  51. package/dist/commands/regression.js.map +1 -0
  52. package/dist/commands/release-notes.d.ts +2 -0
  53. package/dist/commands/release-notes.js +244 -0
  54. package/dist/commands/release-notes.js.map +1 -0
  55. package/dist/commands/search.d.ts +2 -0
  56. package/dist/commands/search.js +93 -0
  57. package/dist/commands/search.js.map +1 -0
  58. package/dist/commands/snapshot.d.ts +6 -0
  59. package/dist/commands/snapshot.js +154 -0
  60. package/dist/commands/snapshot.js.map +1 -0
  61. package/dist/commands/timeline.d.ts +2 -0
  62. package/dist/commands/timeline.js +78 -0
  63. package/dist/commands/timeline.js.map +1 -0
  64. package/dist/commands/trends.d.ts +2 -0
  65. package/dist/commands/trends.js +92 -0
  66. package/dist/commands/trends.js.map +1 -0
  67. package/dist/commands/uninstall.d.ts +2 -0
  68. package/dist/commands/uninstall.js +79 -0
  69. package/dist/commands/uninstall.js.map +1 -0
  70. package/dist/commands/update.d.ts +2 -0
  71. package/dist/commands/update.js +59 -0
  72. package/dist/commands/update.js.map +1 -0
  73. package/dist/commands/why.d.ts +2 -0
  74. package/dist/commands/why.js +111 -0
  75. package/dist/commands/why.js.map +1 -0
  76. package/dist/index.d.ts +2 -0
  77. package/dist/index.js +65 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/templates/walkthrough.d.ts +1 -0
  80. package/dist/templates/walkthrough.js +13 -0
  81. package/dist/templates/walkthrough.js.map +1 -0
  82. package/dist/util/analytics.d.ts +32 -0
  83. package/dist/util/analytics.js +308 -0
  84. package/dist/util/analytics.js.map +1 -0
  85. package/dist/util/claude-md.d.ts +2 -0
  86. package/dist/util/claude-md.js +41 -0
  87. package/dist/util/claude-md.js.map +1 -0
  88. package/dist/util/config.d.ts +21 -0
  89. package/dist/util/config.js +26 -0
  90. package/dist/util/config.js.map +1 -0
  91. package/dist/util/db.d.ts +3 -0
  92. package/dist/util/db.js +183 -0
  93. package/dist/util/db.js.map +1 -0
  94. package/dist/util/detect.d.ts +2 -0
  95. package/dist/util/detect.js +14 -0
  96. package/dist/util/detect.js.map +1 -0
  97. package/dist/util/embedding.d.ts +6 -0
  98. package/dist/util/embedding.js +48 -0
  99. package/dist/util/embedding.js.map +1 -0
  100. package/dist/util/git.d.ts +45 -0
  101. package/dist/util/git.js +191 -0
  102. package/dist/util/git.js.map +1 -0
  103. package/dist/util/hooks.d.ts +3 -0
  104. package/dist/util/hooks.js +43 -0
  105. package/dist/util/hooks.js.map +1 -0
  106. package/dist/util/metrics.d.ts +2 -0
  107. package/dist/util/metrics.js +42 -0
  108. package/dist/util/metrics.js.map +1 -0
  109. package/dist/util/search-hybrid.d.ts +10 -0
  110. package/dist/util/search-hybrid.js +33 -0
  111. package/dist/util/search-hybrid.js.map +1 -0
  112. package/package.json +35 -0
@@ -0,0 +1,244 @@
1
+ import { Command } from "commander";
2
+ import { join } from "path";
3
+ import { execSync } from "child_process";
4
+ import { openDb, hasDb } from "../util/db.js";
5
+ function inferCategory(message) {
6
+ const lower = message.toLowerCase();
7
+ if (lower.startsWith("fix") || lower.includes("bug") || lower.includes("revert"))
8
+ return "bugfix";
9
+ if (lower.startsWith("feat") || lower.startsWith("add") || lower.includes("add "))
10
+ return "feature";
11
+ if (lower.startsWith("refactor") || lower.startsWith("perf") || lower.startsWith("perf:"))
12
+ return "refactor";
13
+ if (lower.startsWith("docs") || lower.startsWith("doc"))
14
+ return "docs";
15
+ if (lower.startsWith("test") || lower.startsWith("chore") || lower.startsWith("ci") || lower.startsWith("build"))
16
+ return "chore";
17
+ return "other";
18
+ }
19
+ function getCategory(commit, enrichment) {
20
+ if (enrichment?.category) {
21
+ const cat = enrichment.category.toLowerCase();
22
+ if (cat === "bugfix" || cat === "bug" || cat === "fix")
23
+ return "bugfix";
24
+ if (cat === "feature" || cat === "feat")
25
+ return "feature";
26
+ if (cat === "refactor")
27
+ return "refactor";
28
+ if (cat === "docs" || cat === "doc")
29
+ return "docs";
30
+ if (cat === "chore" || cat === "test" || cat === "ci" || cat === "build" || cat === "style")
31
+ return "chore";
32
+ return cat;
33
+ }
34
+ return inferCategory(commit.message);
35
+ }
36
+ export function releaseNotesCommand() {
37
+ return new Command("release-notes")
38
+ .description("Generate aggregated release notes from git history data")
39
+ .argument("<range>", "Git range (e.g. v1.0..v1.1 or HEAD~10..HEAD)")
40
+ .option("--json", "Output as JSON")
41
+ .action((range, opts) => {
42
+ const historyDir = join(process.cwd(), ".git-history");
43
+ if (!hasDb(historyDir)) {
44
+ process.stdout.write("No .git-history/ database found. Run `git-skill snapshot` first.\n");
45
+ process.exit(1);
46
+ }
47
+ // Resolve hashes in range via git
48
+ let rangeHashes = [];
49
+ try {
50
+ rangeHashes = execSync(`git rev-list ${range}`, {
51
+ cwd: process.cwd(),
52
+ encoding: "utf-8",
53
+ timeout: 10000,
54
+ })
55
+ .trim()
56
+ .split("\n")
57
+ .filter(Boolean);
58
+ }
59
+ catch {
60
+ process.stdout.write(`Error: could not resolve range "${range}"\n`);
61
+ process.exit(1);
62
+ }
63
+ if (rangeHashes.length === 0) {
64
+ process.stdout.write(`No commits found in range "${range}"\n`);
65
+ return;
66
+ }
67
+ const db = openDb(historyDir);
68
+ try {
69
+ const placeholders = rangeHashes.map(() => "?").join(",");
70
+ const commits = db
71
+ .prepare(`SELECT hash, message, author, timestamp, insertions, deletions, files_changed
72
+ FROM commits WHERE hash IN (${placeholders})
73
+ ORDER BY timestamp DESC`)
74
+ .all(...rangeHashes);
75
+ const enrichments = db
76
+ .prepare(`SELECT commit_hash, intent, category FROM enrichments WHERE commit_hash IN (${placeholders})`)
77
+ .all(...rangeHashes);
78
+ const enrichmentMap = new Map();
79
+ for (const e of enrichments)
80
+ enrichmentMap.set(e.commit_hash, e);
81
+ const files = db
82
+ .prepare(`SELECT file_path, status, COUNT(*) as commit_count,
83
+ SUM(insertions) as total_insertions, SUM(deletions) as total_deletions
84
+ FROM commit_files WHERE commit_hash IN (${placeholders})
85
+ GROUP BY file_path
86
+ ORDER BY commit_count DESC`)
87
+ .all(...rangeHashes);
88
+ const decisions = db
89
+ .prepare(`SELECT commit_hash, type, impact_score, files_affected
90
+ FROM decision_points WHERE commit_hash IN (${placeholders})
91
+ ORDER BY impact_score DESC`)
92
+ .all(...rangeHashes);
93
+ const metrics = db
94
+ .prepare(`SELECT metric_name, value, captured_at FROM metric_values
95
+ WHERE commit_hash IN (${placeholders})
96
+ ORDER BY captured_at DESC`)
97
+ .all(...rangeHashes);
98
+ // Group commits by category
99
+ const grouped = {
100
+ feature: [],
101
+ bugfix: [],
102
+ refactor: [],
103
+ docs: [],
104
+ chore: [],
105
+ other: [],
106
+ };
107
+ for (const commit of commits) {
108
+ const enrichment = enrichmentMap.get(commit.hash);
109
+ const category = getCategory(commit, enrichment);
110
+ if (grouped[category]) {
111
+ grouped[category].push(commit);
112
+ }
113
+ else {
114
+ grouped.other.push(commit);
115
+ }
116
+ }
117
+ // Compute file impact
118
+ const newFiles = files.filter((f) => f.status === "A");
119
+ const deletedFiles = files.filter((f) => f.status === "D");
120
+ const mostChanged = files.slice(0, 5);
121
+ // Total churn stats
122
+ const totalInsertions = commits.reduce((sum, c) => sum + c.insertions, 0);
123
+ const totalDeletions = commits.reduce((sum, c) => sum + c.deletions, 0);
124
+ if (opts.json) {
125
+ process.stdout.write(JSON.stringify({
126
+ range,
127
+ commits: commits.length,
128
+ summary: {
129
+ features: grouped.feature.length,
130
+ bugfixes: grouped.bugfix.length,
131
+ refactors: grouped.refactor.length,
132
+ docs: grouped.docs.length,
133
+ chores: grouped.chore.length,
134
+ other: grouped.other.length,
135
+ total_insertions: totalInsertions,
136
+ total_deletions: totalDeletions,
137
+ },
138
+ grouped,
139
+ file_impact: {
140
+ most_changed: mostChanged,
141
+ new_files: newFiles.length,
142
+ deleted_files: deletedFiles.length,
143
+ },
144
+ architecture_changes: decisions.filter((d) => d.type === "architecture_change" || d.type === "big_refactor"),
145
+ health: metrics.slice(0, 20),
146
+ }, null, 2) + "\n");
147
+ return;
148
+ }
149
+ // Markdown output
150
+ const lines = [];
151
+ lines.push(`# Release Notes: ${range}`);
152
+ lines.push("");
153
+ lines.push("## Summary");
154
+ lines.push("");
155
+ lines.push(`- **${commits.length}** commits in this range`);
156
+ lines.push(`- **+${totalInsertions}** insertions, **-${totalDeletions}** deletions`);
157
+ lines.push(`- ${grouped.feature.length} feature${grouped.feature.length !== 1 ? "s" : ""}, ${grouped.bugfix.length} fix${grouped.bugfix.length !== 1 ? "es" : ""}, ${grouped.refactor.length} refactor${grouped.refactor.length !== 1 ? "s" : ""}`);
158
+ lines.push("");
159
+ if (grouped.feature.length > 0) {
160
+ lines.push("## Features");
161
+ lines.push("");
162
+ for (const c of grouped.feature) {
163
+ const e = enrichmentMap.get(c.hash);
164
+ const desc = e?.intent ?? c.message;
165
+ lines.push(`- **${c.hash.slice(0, 7)}** ${desc}`);
166
+ }
167
+ lines.push("");
168
+ }
169
+ if (grouped.bugfix.length > 0) {
170
+ lines.push("## Fixes");
171
+ lines.push("");
172
+ for (const c of grouped.bugfix) {
173
+ const e = enrichmentMap.get(c.hash);
174
+ const desc = e?.intent ?? c.message;
175
+ lines.push(`- **${c.hash.slice(0, 7)}** ${desc}`);
176
+ }
177
+ lines.push("");
178
+ }
179
+ const archChanges = decisions.filter((d) => d.type === "architecture_change" || d.type === "big_refactor");
180
+ if (archChanges.length > 0 || grouped.refactor.length > 0) {
181
+ lines.push("## Architecture Changes");
182
+ lines.push("");
183
+ for (const d of archChanges) {
184
+ const c = commits.find((x) => x.hash === d.commit_hash);
185
+ if (c) {
186
+ lines.push(`- **${c.hash.slice(0, 7)}** [${d.type}] ${c.message} (impact: ${d.impact_score.toFixed(2)})`);
187
+ }
188
+ }
189
+ for (const c of grouped.refactor) {
190
+ if (!archChanges.find((d) => d.commit_hash === c.hash)) {
191
+ const e = enrichmentMap.get(c.hash);
192
+ const desc = e?.intent ?? c.message;
193
+ lines.push(`- **${c.hash.slice(0, 7)}** ${desc}`);
194
+ }
195
+ }
196
+ lines.push("");
197
+ }
198
+ if (files.length > 0) {
199
+ lines.push("## File Impact");
200
+ lines.push("");
201
+ if (newFiles.length > 0) {
202
+ lines.push(`**New files:** ${newFiles.length}`);
203
+ for (const f of newFiles.slice(0, 5)) {
204
+ lines.push(` - \`${f.file_path}\``);
205
+ }
206
+ if (newFiles.length > 5)
207
+ lines.push(` - ... and ${newFiles.length - 5} more`);
208
+ }
209
+ if (deletedFiles.length > 0) {
210
+ lines.push(`**Deleted files:** ${deletedFiles.length}`);
211
+ for (const f of deletedFiles.slice(0, 3)) {
212
+ lines.push(` - \`${f.file_path}\``);
213
+ }
214
+ }
215
+ if (mostChanged.length > 0) {
216
+ lines.push(`**Most changed files:**`);
217
+ for (const f of mostChanged) {
218
+ lines.push(` - \`${f.file_path}\` (${f.commit_count} commits, +${f.total_insertions} -${f.total_deletions})`);
219
+ }
220
+ }
221
+ lines.push("");
222
+ }
223
+ if (metrics.length > 0) {
224
+ // Show latest value per metric
225
+ const latestMetrics = new Map();
226
+ for (const m of metrics) {
227
+ if (!latestMetrics.has(m.metric_name))
228
+ latestMetrics.set(m.metric_name, m);
229
+ }
230
+ lines.push("## Health Report");
231
+ lines.push("");
232
+ for (const [name, m] of latestMetrics) {
233
+ lines.push(`- **${name}**: ${m.value}`);
234
+ }
235
+ lines.push("");
236
+ }
237
+ process.stdout.write(lines.join("\n") + "\n");
238
+ }
239
+ finally {
240
+ db.close();
241
+ }
242
+ });
243
+ }
244
+ //# sourceMappingURL=release-notes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release-notes.js","sourceRoot":"","sources":["../../src/commands/release-notes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function searchCommand(): Command;
@@ -0,0 +1,93 @@
1
+ import { Command } from "commander";
2
+ import { join } from "path";
3
+ import { openDb, hasDb } from "../util/db.js";
4
+ import { searchBM25 } from "../util/search-hybrid.js";
5
+ function write(msg) {
6
+ process.stdout.write(msg);
7
+ }
8
+ export function searchCommand() {
9
+ return new Command("search")
10
+ .description("Search git history using BM25 full-text search")
11
+ .argument("<query>", "Search query")
12
+ .option("--limit <n>", "Maximum results", "20")
13
+ .option("--json", "Output as JSON")
14
+ .option("--since <date>", "Only show results from commits after this date")
15
+ .option("--until <date>", "Only show results from commits before this date")
16
+ .action((query, opts) => {
17
+ const cwd = process.cwd();
18
+ const historyDir = join(cwd, ".git-history");
19
+ if (!hasDb(historyDir)) {
20
+ write("No .git-history/ database found. Run `git-skill snapshot` first.\n");
21
+ process.exit(1);
22
+ }
23
+ const db = openDb(historyDir);
24
+ try {
25
+ const limit = parseInt(opts.limit, 10) || 20;
26
+ let results = searchBM25(db, query, limit);
27
+ // Filter by date if --since or --until provided
28
+ if ((opts.since || opts.until) && results.length > 0) {
29
+ const hashes = [...new Set(results.map(r => r.hash))];
30
+ const placeholders = hashes.map(() => "?").join(",");
31
+ let dateFilter = `SELECT hash FROM commits WHERE hash IN (${placeholders})`;
32
+ const params = [...hashes];
33
+ if (opts.since) {
34
+ dateFilter += " AND timestamp >= ?";
35
+ params.push(opts.since);
36
+ }
37
+ if (opts.until) {
38
+ dateFilter += " AND timestamp <= ?";
39
+ params.push(opts.until);
40
+ }
41
+ const matchingHashes = new Set(db.prepare(dateFilter).all(...params).map(r => r.hash));
42
+ results = results.filter(r => matchingHashes.has(r.hash));
43
+ }
44
+ if (opts.json) {
45
+ write(JSON.stringify(results, null, 2) + "\n");
46
+ return;
47
+ }
48
+ if (results.length === 0) {
49
+ write(`No results found for "${query}".\n`);
50
+ return;
51
+ }
52
+ // Group by commit hash for text output
53
+ const commitResults = results.filter(r => r.type === "commit");
54
+ const fileResults = results.filter(r => r.type === "file");
55
+ // Collect unique commit hashes to enrich with metadata
56
+ const allHashes = [...new Set(results.map(r => r.hash))];
57
+ const commitMeta = new Map();
58
+ if (allHashes.length > 0) {
59
+ const placeholders = allHashes.map(() => "?").join(",");
60
+ const rows = db.prepare(`SELECT hash, author, timestamp, message FROM commits WHERE hash IN (${placeholders})`).all(...allHashes);
61
+ for (const row of rows) {
62
+ commitMeta.set(row.hash, row);
63
+ }
64
+ }
65
+ write(`\nSearch results for "${query}" (${results.length} match${results.length !== 1 ? "es" : ""})\n`);
66
+ write("─".repeat(60) + "\n");
67
+ if (commitResults.length > 0) {
68
+ write("\nCommits:\n");
69
+ for (const r of commitResults) {
70
+ const meta = commitMeta.get(r.hash);
71
+ const shortHash = r.hash.slice(0, 7);
72
+ const date = meta ? meta.timestamp.slice(0, 10) : "";
73
+ const author = meta ? meta.author : "";
74
+ write(` ${shortHash} ${r.message || meta?.message || ""} (${author}, ${date})\n`);
75
+ }
76
+ }
77
+ if (fileResults.length > 0) {
78
+ write("\nFiles:\n");
79
+ for (const r of fileResults) {
80
+ const meta = commitMeta.get(r.hash);
81
+ const shortHash = r.hash.slice(0, 7);
82
+ const date = meta ? meta.timestamp.slice(0, 10) : "";
83
+ write(` ${shortHash} ${r.path} [${r.detail}] (${date})\n`);
84
+ }
85
+ }
86
+ write("\n");
87
+ }
88
+ finally {
89
+ db.close();
90
+ }
91
+ });
92
+ }
93
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ interface SnapshotOptions {
2
+ force?: boolean;
3
+ cwd?: string;
4
+ }
5
+ export declare function snapshotCommand(opts?: SnapshotOptions): Promise<void>;
6
+ export {};
@@ -0,0 +1,154 @@
1
+ import { mkdirSync, existsSync } from "fs";
2
+ import { join } from "path";
3
+ import { openDb } from "../util/db.js";
4
+ import { getLog, getDiffTree, getBranches, getTags } from "../util/git.js";
5
+ import { runAllAnalytics } from "../util/analytics.js";
6
+ import { computeBuiltinMetrics } from "../util/metrics.js";
7
+ export async function snapshotCommand(opts = {}) {
8
+ const cwd = opts.cwd ?? process.cwd();
9
+ const historyDir = join(cwd, ".git-history");
10
+ // Create .git-history if it doesn't exist
11
+ if (!existsSync(historyDir)) {
12
+ mkdirSync(historyDir, { recursive: true });
13
+ }
14
+ const db = openDb(historyDir);
15
+ // --force: wipe all data before backfilling
16
+ if (opts.force) {
17
+ process.stdout.write("Force mode: clearing all data...\n");
18
+ db.exec(`
19
+ DELETE FROM commits;
20
+ DELETE FROM commit_files;
21
+ DELETE FROM branches;
22
+ DELETE FROM tags;
23
+ DELETE FROM history_fts;
24
+ `);
25
+ }
26
+ // Phase 1: Backfill commits
27
+ process.stdout.write("Phase 1: Indexing commits...\n");
28
+ const allCommits = getLog(cwd);
29
+ process.stdout.write(` Found ${allCommits.length} commits in git log\n`);
30
+ // Check which hashes are already stored
31
+ const existingHashes = new Set(db.prepare("SELECT hash FROM commits").all().map((r) => r.hash));
32
+ const newCommits = allCommits.filter((c) => !existingHashes.has(c.hash));
33
+ process.stdout.write(` ${newCommits.length} new commits to index\n`);
34
+ if (newCommits.length > 0) {
35
+ const insertCommit = db.prepare(`
36
+ INSERT OR IGNORE INTO commits
37
+ (hash, message, author, email, timestamp, branch, parent_hash, merge_commit, insertions, deletions, files_changed)
38
+ VALUES
39
+ (@hash, @message, @author, @email, @timestamp, @branch, @parentHash, @mergeCommit, @insertions, @deletions, @filesChanged)
40
+ `);
41
+ const insertFile = db.prepare(`
42
+ INSERT INTO commit_files (commit_hash, file_path, status, insertions, deletions, old_path)
43
+ VALUES (@commitHash, @filePath, @status, @insertions, @deletions, @oldPath)
44
+ `);
45
+ const insertMany = db.transaction(() => {
46
+ for (const commit of newCommits) {
47
+ insertCommit.run({
48
+ hash: commit.hash,
49
+ message: commit.message,
50
+ author: commit.author,
51
+ email: commit.email,
52
+ timestamp: commit.timestamp,
53
+ branch: commit.branch,
54
+ parentHash: commit.parentHash,
55
+ mergeCommit: commit.mergeCommit ? 1 : 0,
56
+ insertions: commit.insertions,
57
+ deletions: commit.deletions,
58
+ filesChanged: commit.filesChanged,
59
+ });
60
+ const files = getDiffTree(cwd, commit.hash);
61
+ for (const file of files) {
62
+ insertFile.run({
63
+ commitHash: commit.hash,
64
+ filePath: file.path,
65
+ status: file.status,
66
+ insertions: file.insertions,
67
+ deletions: file.deletions,
68
+ oldPath: file.oldPath ?? null,
69
+ });
70
+ }
71
+ }
72
+ });
73
+ insertMany();
74
+ process.stdout.write(` Indexed ${newCommits.length} commits with their files\n`);
75
+ }
76
+ // Phase 2: Branches
77
+ process.stdout.write("Phase 2: Indexing branches...\n");
78
+ const branches = getBranches(cwd);
79
+ const insertBranch = db.prepare(`
80
+ INSERT OR REPLACE INTO branches (name, head_hash, is_active)
81
+ VALUES (@name, @headHash, @isActive)
82
+ `);
83
+ const syncBranches = db.transaction(() => {
84
+ db.exec("DELETE FROM branches");
85
+ for (const branch of branches) {
86
+ insertBranch.run({
87
+ name: branch.name,
88
+ headHash: branch.headHash,
89
+ isActive: branch.isActive ? 1 : 0,
90
+ });
91
+ }
92
+ });
93
+ syncBranches();
94
+ process.stdout.write(` Indexed ${branches.length} branches\n`);
95
+ // Phase 3: Tags
96
+ process.stdout.write("Phase 3: Indexing tags...\n");
97
+ const tags = getTags(cwd);
98
+ const insertTag = db.prepare(`
99
+ INSERT OR REPLACE INTO tags (name, hash, timestamp, message)
100
+ VALUES (@name, @hash, @timestamp, @message)
101
+ `);
102
+ const syncTags = db.transaction(() => {
103
+ db.exec("DELETE FROM tags");
104
+ for (const tag of tags) {
105
+ insertTag.run({
106
+ name: tag.name,
107
+ hash: tag.hash,
108
+ timestamp: tag.timestamp,
109
+ message: tag.message,
110
+ });
111
+ }
112
+ });
113
+ syncTags();
114
+ process.stdout.write(` Indexed ${tags.length} tags\n`);
115
+ // Phase 4: FTS rebuild
116
+ process.stdout.write("Phase 4: Rebuilding FTS index...\n");
117
+ const rebuildFts = db.transaction(() => {
118
+ db.exec("DELETE FROM history_fts");
119
+ // Insert commits into FTS
120
+ const commitRows = db
121
+ .prepare("SELECT hash, message FROM commits")
122
+ .all();
123
+ const ftsInsert = db.prepare(`
124
+ INSERT INTO history_fts (hash, type, path, message, detail)
125
+ VALUES (?, ?, ?, ?, ?)
126
+ `);
127
+ for (const row of commitRows) {
128
+ ftsInsert.run(row.hash, "commit", "", row.message, "");
129
+ }
130
+ // Insert commit files into FTS
131
+ const fileRows = db
132
+ .prepare("SELECT commit_hash, file_path, status FROM commit_files")
133
+ .all();
134
+ for (const row of fileRows) {
135
+ ftsInsert.run(row.commit_hash, "file", row.file_path, "", row.status);
136
+ }
137
+ });
138
+ rebuildFts();
139
+ const ftsCount = db.prepare("SELECT COUNT(*) as c FROM history_fts").get().c;
140
+ process.stdout.write(` FTS index has ${ftsCount} entries\n`);
141
+ // Phase 5: Analytics
142
+ process.stdout.write("Phase 5: Running analytics...\n");
143
+ runAllAnalytics(db);
144
+ process.stdout.write(" Analytics complete\n");
145
+ // Phase 6: Built-in metrics
146
+ process.stdout.write("Phase 6: Computing built-in metrics...\n");
147
+ computeBuiltinMetrics(db);
148
+ process.stdout.write(" Metrics complete\n");
149
+ // Store last_snapshot timestamp
150
+ db.prepare("INSERT OR REPLACE INTO schema_meta (key, value) VALUES ('last_snapshot', ?)").run(new Date().toISOString());
151
+ db.close();
152
+ process.stdout.write("Snapshot complete.\n");
153
+ }
154
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/commands/snapshot.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function timelineCommand(): Command;
@@ -0,0 +1,78 @@
1
+ import { Command } from "commander";
2
+ import { openDb } from "../util/db.js";
3
+ import { join } from "path";
4
+ export function timelineCommand() {
5
+ return new Command("timeline")
6
+ .description("Show chronological commits for a file or directory")
7
+ .argument("<path>", "File path or directory (end with / for directory)")
8
+ .option("--limit <n>", "Max results", "50")
9
+ .option("--json", "Output as JSON")
10
+ .option("--since <date>", "Only commits after this date (ISO 8601)")
11
+ .option("--until <date>", "Only commits before this date (ISO 8601)")
12
+ .action((filePath, opts) => {
13
+ const historyDir = join(process.cwd(), ".git-history");
14
+ const db = openDb(historyDir);
15
+ try {
16
+ const isDir = filePath.endsWith("/");
17
+ const limit = parseInt(opts.limit, 10);
18
+ let whereClauses = ["1=1"];
19
+ const params = [];
20
+ if (isDir) {
21
+ whereClauses.push("cf.file_path LIKE ?");
22
+ params.push(`${filePath}%`);
23
+ }
24
+ else {
25
+ whereClauses.push("cf.file_path = ?");
26
+ params.push(filePath);
27
+ }
28
+ if (opts.since) {
29
+ whereClauses.push("c.timestamp >= ?");
30
+ params.push(opts.since);
31
+ }
32
+ if (opts.until) {
33
+ whereClauses.push("c.timestamp <= ?");
34
+ params.push(opts.until);
35
+ }
36
+ params.push(limit);
37
+ const sql = `
38
+ SELECT
39
+ c.hash,
40
+ c.timestamp,
41
+ c.message,
42
+ c.author,
43
+ cf.file_path,
44
+ cf.status,
45
+ cf.insertions,
46
+ cf.deletions
47
+ FROM commit_files cf
48
+ JOIN commits c ON cf.commit_hash = c.hash
49
+ WHERE ${whereClauses.join(" AND ")}
50
+ ORDER BY c.timestamp ASC
51
+ LIMIT ?
52
+ `;
53
+ const rows = db.prepare(sql).all(...params);
54
+ if (opts.json) {
55
+ process.stdout.write(JSON.stringify(rows, null, 2) + "\n");
56
+ return;
57
+ }
58
+ if (rows.length === 0) {
59
+ process.stdout.write(`No commits found for: ${filePath}\n`);
60
+ return;
61
+ }
62
+ process.stdout.write(`Timeline for: ${filePath}\n`);
63
+ process.stdout.write(`${"─".repeat(80)}\n`);
64
+ for (const row of rows) {
65
+ const date = row.timestamp.slice(0, 10);
66
+ const hash = row.hash.slice(0, 7);
67
+ const ins = `+${row.insertions}`;
68
+ const del = `-${row.deletions}`;
69
+ process.stdout.write(`${date} ${hash} [${row.status}] ${ins}/${del} ${row.file_path}\n`);
70
+ process.stdout.write(` ${row.message}\n`);
71
+ }
72
+ }
73
+ finally {
74
+ db.close();
75
+ }
76
+ });
77
+ }
78
+ //# sourceMappingURL=timeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline.js","sourceRoot":"","sources":["../../src/commands/timeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function trendsCommand(): Command;