@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,151 @@
1
+ import { Command } from "commander";
2
+ import { openDb } from "../util/db.js";
3
+ import { join } from "path";
4
+ import { execSync } from "child_process";
5
+ export function diffSummaryCommand() {
6
+ return new Command("diff-summary")
7
+ .description("LLM-friendly summary of a commit range")
8
+ .argument("<range>", "Commit range (e.g. v1.0..v1.1 or HEAD~10..HEAD)")
9
+ .option("--json", "Output as JSON")
10
+ .action((range, opts) => {
11
+ const historyDir = join(process.cwd(), ".git-history");
12
+ const db = openDb(historyDir);
13
+ try {
14
+ // Get hashes in range
15
+ let revListOutput;
16
+ try {
17
+ revListOutput = execSync(`git rev-list ${range}`, {
18
+ cwd: process.cwd(),
19
+ encoding: "utf-8",
20
+ });
21
+ }
22
+ catch {
23
+ process.stderr.write(`Could not resolve range: ${range}\n`);
24
+ process.exit(1);
25
+ }
26
+ const hashes = revListOutput
27
+ .split("\n")
28
+ .map((h) => h.trim())
29
+ .filter(Boolean);
30
+ if (hashes.length === 0) {
31
+ const empty = {
32
+ range,
33
+ commits: [],
34
+ authors: [],
35
+ added_files: [],
36
+ modified_files: [],
37
+ deleted_files: [],
38
+ total_insertions: 0,
39
+ total_deletions: 0,
40
+ decision_points: 0,
41
+ };
42
+ if (opts.json) {
43
+ process.stdout.write(JSON.stringify(empty, null, 2) + "\n");
44
+ }
45
+ else {
46
+ process.stdout.write(`No commits found in range: ${range}\n`);
47
+ }
48
+ return;
49
+ }
50
+ const placeholders = hashes.map(() => "?").join(",");
51
+ // Query commits
52
+ const commitRows = db
53
+ .prepare(`SELECT hash, author, timestamp, message, insertions, deletions
54
+ FROM commits
55
+ WHERE hash IN (${placeholders})
56
+ ORDER BY timestamp ASC`)
57
+ .all(...hashes);
58
+ // Query files
59
+ const fileRows = db
60
+ .prepare(`SELECT file_path, status, insertions, deletions
61
+ FROM commit_files
62
+ WHERE commit_hash IN (${placeholders})`)
63
+ .all(...hashes);
64
+ // Decision points in range
65
+ const dpRow = db
66
+ .prepare(`SELECT COUNT(*) AS cnt FROM decision_points WHERE commit_hash IN (${placeholders})`)
67
+ .get(...hashes);
68
+ // Compute stats
69
+ const authorSet = new Set();
70
+ let totalInsertions = 0;
71
+ let totalDeletions = 0;
72
+ for (const c of commitRows) {
73
+ authorSet.add(c.author);
74
+ totalInsertions += c.insertions ?? 0;
75
+ totalDeletions += c.deletions ?? 0;
76
+ }
77
+ const addedFiles = [];
78
+ const modifiedFiles = [];
79
+ const deletedFiles = [];
80
+ const seenFiles = new Set();
81
+ for (const f of fileRows) {
82
+ if (seenFiles.has(f.file_path))
83
+ continue;
84
+ seenFiles.add(f.file_path);
85
+ if (f.status === "A")
86
+ addedFiles.push(f.file_path);
87
+ else if (f.status === "D")
88
+ deletedFiles.push(f.file_path);
89
+ else
90
+ modifiedFiles.push(f.file_path);
91
+ }
92
+ const result = {
93
+ range,
94
+ commits: commitRows.map((c) => ({
95
+ hash: c.hash,
96
+ author: c.author,
97
+ timestamp: c.timestamp,
98
+ message: c.message,
99
+ })),
100
+ authors: [...authorSet],
101
+ added_files: addedFiles,
102
+ modified_files: modifiedFiles,
103
+ deleted_files: deletedFiles,
104
+ total_insertions: totalInsertions,
105
+ total_deletions: totalDeletions,
106
+ decision_points: dpRow?.cnt ?? 0,
107
+ };
108
+ if (opts.json) {
109
+ process.stdout.write(JSON.stringify(result, null, 2) + "\n");
110
+ return;
111
+ }
112
+ // Text output
113
+ process.stdout.write(`Diff Summary: ${range}\n`);
114
+ process.stdout.write(`${"─".repeat(80)}\n`);
115
+ process.stdout.write(`Commits: ${commitRows.length}\n`);
116
+ process.stdout.write(`Authors: ${[...authorSet].join(", ")}\n`);
117
+ process.stdout.write(`Insertions: +${totalInsertions}\n`);
118
+ process.stdout.write(`Deletions: -${totalDeletions}\n`);
119
+ process.stdout.write(`Decision pts: ${dpRow?.cnt ?? 0}\n`);
120
+ process.stdout.write(`\n`);
121
+ if (addedFiles.length > 0) {
122
+ process.stdout.write(`Added files (${addedFiles.length}):\n`);
123
+ for (const f of addedFiles)
124
+ process.stdout.write(` + ${f}\n`);
125
+ process.stdout.write(`\n`);
126
+ }
127
+ if (deletedFiles.length > 0) {
128
+ process.stdout.write(`Deleted files (${deletedFiles.length}):\n`);
129
+ for (const f of deletedFiles)
130
+ process.stdout.write(` - ${f}\n`);
131
+ process.stdout.write(`\n`);
132
+ }
133
+ if (modifiedFiles.length > 0) {
134
+ process.stdout.write(`Modified files (${modifiedFiles.length}):\n`);
135
+ for (const f of modifiedFiles)
136
+ process.stdout.write(` ~ ${f}\n`);
137
+ process.stdout.write(`\n`);
138
+ }
139
+ process.stdout.write(`Commits:\n`);
140
+ for (const c of commitRows) {
141
+ const date = c.timestamp.slice(0, 10);
142
+ const hash = c.hash.slice(0, 7);
143
+ process.stdout.write(` ${date} ${hash} ${c.message}\n`);
144
+ }
145
+ }
146
+ finally {
147
+ db.close();
148
+ }
149
+ });
150
+ }
151
+ //# sourceMappingURL=diff-summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-summary.js","sourceRoot":"","sources":["../../src/commands/diff-summary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function getSkillDoc(): string;
3
+ export declare function docsCommand(): Command;
@@ -0,0 +1,38 @@
1
+ import { Command } from "commander";
2
+ function write(msg) { process.stdout.write(msg); }
3
+ export function getSkillDoc() {
4
+ return `## git-skill (Git History Intelligence)
5
+
6
+ ### Quick Reference
7
+ | Command | Use For |
8
+ |---------|---------|
9
+ | \`git-skill search <query>\` | Search commit history |
10
+ | \`git-skill timeline <path>\` | File/directory evolution |
11
+ | \`git-skill blame <path>\` | Enhanced blame with enrichments |
12
+ | \`git-skill trends\` | Metric trends dashboard |
13
+ | \`git-skill hotspots\` | Files with most churn |
14
+ | \`git-skill coupling <path>\` | Co-changed file analysis |
15
+ | \`git-skill decisions\` | Major decision points |
16
+ | \`git-skill experts <path>\` | Who has most context |
17
+ | \`git-skill diff-summary <range>\` | Range summary |
18
+ | \`git-skill why <hash>\` | Commit intent/reasoning |
19
+ | \`git-skill regression\` | Change-point detection |
20
+ | \`git-skill doctor\` | Health check |
21
+
22
+ ### Write Commands (require confirmation)
23
+ | \`git-skill snapshot\` | Full re-index |
24
+ | \`git-skill enrich [range]\` | Backfill LLM enrichments |
25
+ | \`git-skill release-notes <range>\` | Generate release notes |
26
+ | \`git-skill embed\` | Generate embeddings |
27
+
28
+ ### Global Flags
29
+ - \`--json\` — structured output
30
+ - \`--limit N\` — cap results
31
+ - \`--since <date>\` / \`--until <date>\` — time filter`;
32
+ }
33
+ export function docsCommand() {
34
+ return new Command("docs")
35
+ .description("Output CLAUDE.md instruction snippet")
36
+ .action(() => { write(getSkillDoc() + "\n"); });
37
+ }
38
+ //# sourceMappingURL=docs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.js","sourceRoot":"","sources":["../../src/commands/docs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,SAAS,KAAK,CAAC,GAAW,IAAU,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAEhE,MAAM,UAAU,WAAW;IACzB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;wDA2B+C,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;SACvB,WAAW,CAAC,sCAAsC,CAAC;SACnD,MAAM,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function doctorCommand(): Command;
@@ -0,0 +1,60 @@
1
+ import { Command } from "commander";
2
+ import { join } from "path";
3
+ import { existsSync, readFileSync } from "fs";
4
+ import { isGitRepo } from "../util/git.js";
5
+ import { hasHook } from "../util/hooks.js";
6
+ import { hasDb, openDb } from "../util/db.js";
7
+ function write(msg) { process.stdout.write(msg); }
8
+ export function doctorCommand() {
9
+ return new Command("doctor")
10
+ .description("Health check — verify git-skill setup")
11
+ .option("--json", "Output as JSON")
12
+ .action((opts) => {
13
+ const cwd = process.cwd();
14
+ const checks = [];
15
+ // 1. Git repo
16
+ const isRepo = isGitRepo(cwd);
17
+ checks.push({ name: "git repo", status: isRepo ? "pass" : "fail", message: isRepo ? "Git repository detected" : "Not a git repository" });
18
+ // 2. Post-commit hook
19
+ const gitDir = join(cwd, ".git");
20
+ const hookOk = isRepo && hasHook(gitDir);
21
+ checks.push({ name: "post-commit hook", status: hookOk ? "pass" : "warn", message: hookOk ? "Hook installed" : "Hook not installed" });
22
+ // 3. Database
23
+ const historyDir = join(cwd, ".git-history");
24
+ const dbOk = hasDb(historyDir);
25
+ checks.push({ name: "history.db", status: dbOk ? "pass" : "fail", message: dbOk ? "Database exists" : "No database" });
26
+ // 4. Snapshot freshness + commit count
27
+ if (dbOk) {
28
+ const db = openDb(historyDir);
29
+ const meta = db.prepare("SELECT value FROM schema_meta WHERE key = 'last_snapshot'").get();
30
+ if (meta) {
31
+ const hoursAgo = (Date.now() - new Date(meta.value).getTime()) / 3600000;
32
+ checks.push({ name: "snapshot freshness", status: hoursAgo < 24 ? "pass" : "warn", message: `Last snapshot: ${Math.round(hoursAgo)}h ago` });
33
+ const count = db.prepare("SELECT COUNT(*) as c FROM commits").get().c;
34
+ checks.push({ name: "commit count", status: "pass", message: `${count} commits indexed` });
35
+ }
36
+ db.close();
37
+ }
38
+ // 5. .gitignore
39
+ const gitignorePath = join(cwd, ".gitignore");
40
+ if (existsSync(gitignorePath)) {
41
+ const hasEntry = readFileSync(gitignorePath, "utf-8").includes(".git-history");
42
+ checks.push({ name: ".gitignore", status: hasEntry ? "pass" : "warn", message: hasEntry ? ".git-history/ in .gitignore" : ".git-history/ not in .gitignore" });
43
+ }
44
+ // Output
45
+ if (opts.json) {
46
+ write(JSON.stringify({ checks }, null, 2) + "\n");
47
+ return;
48
+ }
49
+ write("\ngit-skill doctor\n");
50
+ write("─".repeat(40) + "\n");
51
+ for (const c of checks) {
52
+ const icon = c.status === "pass" ? "✓" : c.status === "warn" ? "!" : "✗";
53
+ write(` ${icon} ${c.name}: ${c.message}\n`);
54
+ }
55
+ write("\n");
56
+ if (checks.some(c => c.status === "fail"))
57
+ process.exit(1);
58
+ });
59
+ }
60
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE9C,SAAS,KAAK,CAAC,GAAW,IAAU,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAIhE,MAAM,UAAU,aAAa;IAC3B,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC;SACzB,WAAW,CAAC,uCAAuC,CAAC;SACpD,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;SAClC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QACf,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,cAAc;QACd,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,sBAAsB,EAAE,CAAC,CAAC;QAE1I,sBAAsB;QACtB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,oBAAoB,EAAE,CAAC,CAAC;QAEvI,cAAc;QACd,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QAC7C,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC;QAEvH,uCAAuC;QACvC,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;YAC9B,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,2DAA2D,CAAC,CAAC,GAAG,EAAS,CAAC;YAClG,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC;gBACzE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,MAAM,EAAE,QAAQ,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,kBAAkB,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC7I,MAAM,KAAK,GAAI,EAAE,CAAC,OAAO,CAAC,mCAAmC,CAAC,CAAC,GAAG,EAAU,CAAC,CAAC,CAAC;gBAC/E,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,kBAAkB,EAAE,CAAC,CAAC;YAC7F,CAAC;YACD,EAAE,CAAC,KAAK,EAAE,CAAC;QACb,CAAC;QAED,gBAAgB;QAChB,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QAC9C,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YAC9B,MAAM,QAAQ,GAAG,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;YAC/E,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,iCAAiC,EAAE,CAAC,CAAC;QACjK,CAAC;QAED,SAAS;QACT,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;YAClD,OAAO;QACT,CAAC;QAED,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAC9B,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QAC7B,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;YACzE,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC;QAC/C,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,CAAC;QAEZ,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function embedCommand(): Command;
@@ -0,0 +1,81 @@
1
+ import { Command } from "commander";
2
+ import { join } from "path";
3
+ import { openDb, hasDb } from "../util/db.js";
4
+ import { readConfig } from "../util/config.js";
5
+ import { generateEmbedding } from "../util/embedding.js";
6
+ export function embedCommand() {
7
+ return new Command("embed")
8
+ .description("Generate/refresh embeddings for commit messages")
9
+ .option("--limit <n>", "Max commits to embed", "100")
10
+ .option("--force", "Re-embed commits that already have embeddings")
11
+ .action(async (opts) => {
12
+ const config = readConfig();
13
+ if (!config?.embedding?.enabled || !config.embedding.url) {
14
+ process.stdout.write("Embeddings not configured. Set embedding.enabled and embedding.url in ~/.config/git-skill/config.json\n");
15
+ return;
16
+ }
17
+ const historyDir = join(process.cwd(), ".git-history");
18
+ if (!hasDb(historyDir)) {
19
+ process.stdout.write("No .git-history/ database found. Run `git-skill snapshot` first.\n");
20
+ process.exit(1);
21
+ }
22
+ const db = openDb(historyDir);
23
+ try {
24
+ const limit = parseInt(opts.limit, 10) || 100;
25
+ let commits;
26
+ if (opts.force) {
27
+ commits = db
28
+ .prepare("SELECT hash, message FROM commits ORDER BY timestamp DESC LIMIT ?")
29
+ .all(limit);
30
+ }
31
+ else {
32
+ // Get commits that don't have embeddings yet
33
+ commits = db
34
+ .prepare(`
35
+ SELECT c.hash, c.message
36
+ FROM commits c
37
+ LEFT JOIN embeddings e ON c.hash = e.commit_hash
38
+ WHERE e.commit_hash IS NULL
39
+ ORDER BY c.timestamp DESC
40
+ LIMIT ?
41
+ `)
42
+ .all(limit);
43
+ }
44
+ if (commits.length === 0) {
45
+ process.stdout.write("No commits to embed.\n");
46
+ return;
47
+ }
48
+ process.stdout.write(`Embedding ${commits.length} commits...\n`);
49
+ const insertEmbed = db.prepare(`
50
+ INSERT OR REPLACE INTO embeddings (commit_hash, content_type, vector, model, created_at)
51
+ VALUES (@commitHash, @contentType, @vector, @model, @createdAt)
52
+ `);
53
+ let successCount = 0;
54
+ let failCount = 0;
55
+ for (const commit of commits) {
56
+ const result = await generateEmbedding(commit.message);
57
+ if (result) {
58
+ const buf = Buffer.alloc(result.vector.length * 4);
59
+ const arr = new Float32Array(result.vector);
60
+ Buffer.from(arr.buffer).copy(buf);
61
+ insertEmbed.run({
62
+ commitHash: commit.hash,
63
+ contentType: "message",
64
+ vector: buf,
65
+ model: result.model,
66
+ createdAt: new Date().toISOString(),
67
+ });
68
+ successCount++;
69
+ }
70
+ else {
71
+ failCount++;
72
+ }
73
+ }
74
+ process.stdout.write(`Done. Embedded: ${successCount}, Failed: ${failCount}\n`);
75
+ }
76
+ finally {
77
+ db.close();
78
+ }
79
+ });
80
+ }
81
+ //# sourceMappingURL=embed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed.js","sourceRoot":"","sources":["../../src/commands/embed.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function enrichCommand(): Command;
@@ -0,0 +1,148 @@
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
+ import { readConfig } from "../util/config.js";
6
+ async function callLlm(url, model, apiKey, commit) {
7
+ const prompt = `Analyze this git commit and respond with ONLY a JSON object (no markdown, no explanation):
8
+ {
9
+ "intent": "one sentence describing what this commit does",
10
+ "reasoning": "why this change was likely made",
11
+ "category": "one of: feature, bugfix, refactor, docs, chore, test, style, perf",
12
+ "alternatives_considered": "brief note on alternatives (optional)",
13
+ "session_context": "broader context about what was being worked on (optional)"
14
+ }
15
+
16
+ Commit hash: ${commit.hash.slice(0, 7)}
17
+ Author: ${commit.author}
18
+ Date: ${commit.timestamp.slice(0, 10)}
19
+ Message: ${commit.message}`;
20
+ const headers = { "Content-Type": "application/json" };
21
+ if (apiKey)
22
+ headers["Authorization"] = `Bearer ${apiKey}`;
23
+ try {
24
+ const response = await fetch(url, {
25
+ method: "POST",
26
+ headers,
27
+ body: JSON.stringify({
28
+ model,
29
+ messages: [{ role: "user", content: prompt }],
30
+ max_tokens: 300,
31
+ temperature: 0,
32
+ }),
33
+ });
34
+ if (!response.ok)
35
+ return null;
36
+ const data = await response.json();
37
+ const text = data.choices?.[0]?.message?.content ?? data.content?.[0]?.text ?? "";
38
+ // Strip potential markdown code fences
39
+ const cleaned = text.replace(/^```(?:json)?\s*/i, "").replace(/\s*```\s*$/i, "").trim();
40
+ return JSON.parse(cleaned);
41
+ }
42
+ catch {
43
+ return null;
44
+ }
45
+ }
46
+ function resolveEnvVar(val) {
47
+ if (!val)
48
+ return undefined;
49
+ const match = val.match(/^\$\{(.+)\}$/);
50
+ return match ? process.env[match[1]] : val;
51
+ }
52
+ export function enrichCommand() {
53
+ return new Command("enrich")
54
+ .description("Backfill LLM enrichments for commit history")
55
+ .argument("[range]", "Git range to filter commits (e.g. v1.0..v1.1)")
56
+ .option("--dry-run", "Show what would be enriched without doing it")
57
+ .option("--limit <n>", "Max commits to enrich", "50")
58
+ .action(async (range, opts) => {
59
+ const historyDir = join(process.cwd(), ".git-history");
60
+ if (!hasDb(historyDir)) {
61
+ process.stdout.write("No .git-history/ database found. Run `git-skill snapshot` first.\n");
62
+ process.exit(1);
63
+ }
64
+ const db = openDb(historyDir);
65
+ try {
66
+ const limit = parseInt(opts.limit, 10) || 50;
67
+ // Get unenriched commits
68
+ let commits = db
69
+ .prepare(`
70
+ SELECT c.hash, c.message, c.author, c.timestamp
71
+ FROM commits c
72
+ LEFT JOIN enrichments e ON c.hash = e.commit_hash
73
+ WHERE e.commit_hash IS NULL
74
+ ORDER BY c.timestamp DESC
75
+ LIMIT ?
76
+ `)
77
+ .all(limit);
78
+ // Filter by range if provided
79
+ if (range) {
80
+ try {
81
+ const rangeHashes = execSync(`git rev-list ${range}`, {
82
+ cwd: process.cwd(),
83
+ encoding: "utf-8",
84
+ timeout: 10000,
85
+ }).trim().split("\n").filter(Boolean);
86
+ const rangeSet = new Set(rangeHashes);
87
+ commits = commits.filter((c) => rangeSet.has(c.hash));
88
+ }
89
+ catch {
90
+ process.stdout.write(`Warning: could not resolve range "${range}"\n`);
91
+ }
92
+ }
93
+ if (commits.length === 0) {
94
+ process.stdout.write("No commits to enrich.\n");
95
+ return;
96
+ }
97
+ const config = readConfig();
98
+ const enrichEnabled = config?.enrichment?.enabled && config.enrichment.url;
99
+ if (opts.dryRun) {
100
+ process.stdout.write(`Would enrich ${commits.length} commit${commits.length !== 1 ? "s" : ""}:\n`);
101
+ for (const c of commits.slice(0, 10)) {
102
+ process.stdout.write(` ${c.hash.slice(0, 7)} ${c.message.slice(0, 60)}\n`);
103
+ }
104
+ if (commits.length > 10) {
105
+ process.stdout.write(` ... and ${commits.length - 10} more\n`);
106
+ }
107
+ return;
108
+ }
109
+ if (!enrichEnabled) {
110
+ process.stdout.write(`Enrichment not configured. Set enrichment.enabled and enrichment.url in ~/.config/git-skill/config.json\n`);
111
+ process.stdout.write(`${commits.length} commit${commits.length !== 1 ? "s" : ""} would be enriched.\n`);
112
+ return;
113
+ }
114
+ process.stdout.write(`Enriching ${commits.length} commits...\n`);
115
+ const apiKey = resolveEnvVar(config.enrichment.apiKey);
116
+ const insertEnrichment = db.prepare(`
117
+ INSERT OR REPLACE INTO enrichments
118
+ (commit_hash, intent, reasoning, category, alternatives_considered, session_context)
119
+ VALUES
120
+ (@commitHash, @intent, @reasoning, @category, @alternativesConsidered, @sessionContext)
121
+ `);
122
+ let successCount = 0;
123
+ let failCount = 0;
124
+ for (const commit of commits) {
125
+ const result = await callLlm(config.enrichment.url, config.enrichment.model, apiKey, commit);
126
+ if (result) {
127
+ insertEnrichment.run({
128
+ commitHash: commit.hash,
129
+ intent: result.intent ?? null,
130
+ reasoning: result.reasoning ?? null,
131
+ category: result.category ?? null,
132
+ alternativesConsidered: result.alternatives_considered ?? null,
133
+ sessionContext: result.session_context ?? null,
134
+ });
135
+ successCount++;
136
+ }
137
+ else {
138
+ failCount++;
139
+ }
140
+ }
141
+ process.stdout.write(`Done. Enriched: ${successCount}, Failed: ${failCount}\n`);
142
+ }
143
+ finally {
144
+ db.close();
145
+ }
146
+ });
147
+ }
148
+ //# sourceMappingURL=enrich.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrich.js","sourceRoot":"","sources":["../../src/commands/enrich.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function expertsCommand(): Command;
@@ -0,0 +1,55 @@
1
+ import { Command } from "commander";
2
+ import { openDb } from "../util/db.js";
3
+ import { join } from "path";
4
+ export function expertsCommand() {
5
+ return new Command("experts")
6
+ .description("Show who has most expertise in a path")
7
+ .argument("<path>", "File path or pattern to check expertise for")
8
+ .option("--limit <n>", "Max results", "10")
9
+ .option("--json", "Output as JSON")
10
+ .action((filePath, opts) => {
11
+ const historyDir = join(process.cwd(), ".git-history");
12
+ const db = openDb(historyDir);
13
+ try {
14
+ const limit = parseInt(opts.limit, 10);
15
+ // Normalize the path: strip trailing slash for matching
16
+ const normalizedPath = filePath.replace(/\/+$/, "");
17
+ // Match rows where file_pattern equals or starts with the given prefix
18
+ const pattern = `${normalizedPath}%`;
19
+ const sql = `
20
+ SELECT
21
+ author,
22
+ file_pattern,
23
+ commit_count,
24
+ last_touched,
25
+ expertise_score
26
+ FROM author_expertise
27
+ WHERE file_pattern LIKE ?
28
+ ORDER BY expertise_score DESC
29
+ LIMIT ?
30
+ `;
31
+ const rows = db.prepare(sql).all(pattern, limit);
32
+ if (opts.json) {
33
+ process.stdout.write(JSON.stringify(rows, null, 2) + "\n");
34
+ return;
35
+ }
36
+ if (rows.length === 0) {
37
+ process.stdout.write(`No expertise data found for: ${filePath}\n`);
38
+ return;
39
+ }
40
+ process.stdout.write(`Experts for: ${filePath}\n`);
41
+ process.stdout.write(`${"─".repeat(80)}\n`);
42
+ const colWidth = Math.max(...rows.map((r) => r.author.length), 10);
43
+ process.stdout.write(`${"Author".padEnd(colWidth)} ${"Commits".padStart(7)} ${"Last Touched".padStart(12)} ${"Score".padStart(8)}\n`);
44
+ process.stdout.write(`${"─".repeat(colWidth + 32)}\n`);
45
+ for (const row of rows) {
46
+ const lastTouched = row.last_touched ? row.last_touched.slice(0, 10) : "unknown";
47
+ process.stdout.write(`${row.author.padEnd(colWidth)} ${String(row.commit_count).padStart(7)} ${lastTouched.padStart(12)} ${row.expertise_score.toFixed(3).padStart(8)}\n`);
48
+ }
49
+ }
50
+ finally {
51
+ db.close();
52
+ }
53
+ });
54
+ }
55
+ //# sourceMappingURL=experts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"experts.js","sourceRoot":"","sources":["../../src/commands/experts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,MAAM,UAAU,cAAc;IAC5B,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC;SAC1B,WAAW,CAAC,uCAAuC,CAAC;SACpD,QAAQ,CAAC,QAAQ,EAAE,6CAA6C,CAAC;SACjE,MAAM,CAAC,aAAa,EAAE,aAAa,EAAE,IAAI,CAAC;SAC1C,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;SAClC,MAAM,CAAC,CAAC,QAAgB,EAAE,IAAuC,EAAE,EAAE;QACpE,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAC;QACvD,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAEvC,wDAAwD;YACxD,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YACpD,uEAAuE;YACvE,MAAM,OAAO,GAAG,GAAG,cAAc,GAAG,CAAC;YAErC,MAAM,GAAG,GAAG;;;;;;;;;;;SAWX,CAAC;YAEF,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAM7C,CAAC;YAEH,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;gBAC3D,OAAO;YACT,CAAC;YAED,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,QAAQ,IAAI,CAAC,CAAC;gBACnE,OAAO;YACT,CAAC;YAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,QAAQ,IAAI,CAAC,CAAC;YACnD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;YAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;YACnE,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CACnH,CAAC;YACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YACvD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,MAAM,WAAW,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBACjF,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,GAAG,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CACxJ,CAAC;YACJ,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,EAAE,CAAC,KAAK,EAAE,CAAC;QACb,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function hotspotsCommand(): Command;