@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.
- package/dist/commands/approve.d.ts +2 -0
- package/dist/commands/approve.js +56 -0
- package/dist/commands/approve.js.map +1 -0
- package/dist/commands/blame.d.ts +2 -0
- package/dist/commands/blame.js +139 -0
- package/dist/commands/blame.js.map +1 -0
- package/dist/commands/capture.d.ts +2 -0
- package/dist/commands/capture.js +68 -0
- package/dist/commands/capture.js.map +1 -0
- package/dist/commands/coupling.d.ts +2 -0
- package/dist/commands/coupling.js +48 -0
- package/dist/commands/coupling.js.map +1 -0
- package/dist/commands/cron.d.ts +2 -0
- package/dist/commands/cron.js +70 -0
- package/dist/commands/cron.js.map +1 -0
- package/dist/commands/decisions.d.ts +2 -0
- package/dist/commands/decisions.js +62 -0
- package/dist/commands/decisions.js.map +1 -0
- package/dist/commands/diff-summary.d.ts +2 -0
- package/dist/commands/diff-summary.js +151 -0
- package/dist/commands/diff-summary.js.map +1 -0
- package/dist/commands/docs.d.ts +3 -0
- package/dist/commands/docs.js +38 -0
- package/dist/commands/docs.js.map +1 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +60 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/embed.d.ts +2 -0
- package/dist/commands/embed.js +81 -0
- package/dist/commands/embed.js.map +1 -0
- package/dist/commands/enrich.d.ts +2 -0
- package/dist/commands/enrich.js +148 -0
- package/dist/commands/enrich.js.map +1 -0
- package/dist/commands/experts.d.ts +2 -0
- package/dist/commands/experts.js +55 -0
- package/dist/commands/experts.js.map +1 -0
- package/dist/commands/hotspots.d.ts +2 -0
- package/dist/commands/hotspots.js +46 -0
- package/dist/commands/hotspots.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +91 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/install.d.ts +2 -0
- package/dist/commands/install.js +59 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/metric.d.ts +2 -0
- package/dist/commands/metric.js +26 -0
- package/dist/commands/metric.js.map +1 -0
- package/dist/commands/regression.d.ts +2 -0
- package/dist/commands/regression.js +166 -0
- package/dist/commands/regression.js.map +1 -0
- package/dist/commands/release-notes.d.ts +2 -0
- package/dist/commands/release-notes.js +244 -0
- package/dist/commands/release-notes.js.map +1 -0
- package/dist/commands/search.d.ts +2 -0
- package/dist/commands/search.js +93 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/snapshot.d.ts +6 -0
- package/dist/commands/snapshot.js +154 -0
- package/dist/commands/snapshot.js.map +1 -0
- package/dist/commands/timeline.d.ts +2 -0
- package/dist/commands/timeline.js +78 -0
- package/dist/commands/timeline.js.map +1 -0
- package/dist/commands/trends.d.ts +2 -0
- package/dist/commands/trends.js +92 -0
- package/dist/commands/trends.js.map +1 -0
- package/dist/commands/uninstall.d.ts +2 -0
- package/dist/commands/uninstall.js +79 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.js +59 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/why.d.ts +2 -0
- package/dist/commands/why.js +111 -0
- package/dist/commands/why.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +65 -0
- package/dist/index.js.map +1 -0
- package/dist/templates/walkthrough.d.ts +1 -0
- package/dist/templates/walkthrough.js +13 -0
- package/dist/templates/walkthrough.js.map +1 -0
- package/dist/util/analytics.d.ts +32 -0
- package/dist/util/analytics.js +308 -0
- package/dist/util/analytics.js.map +1 -0
- package/dist/util/claude-md.d.ts +2 -0
- package/dist/util/claude-md.js +41 -0
- package/dist/util/claude-md.js.map +1 -0
- package/dist/util/config.d.ts +21 -0
- package/dist/util/config.js +26 -0
- package/dist/util/config.js.map +1 -0
- package/dist/util/db.d.ts +3 -0
- package/dist/util/db.js +183 -0
- package/dist/util/db.js.map +1 -0
- package/dist/util/detect.d.ts +2 -0
- package/dist/util/detect.js +14 -0
- package/dist/util/detect.js.map +1 -0
- package/dist/util/embedding.d.ts +6 -0
- package/dist/util/embedding.js +48 -0
- package/dist/util/embedding.js.map +1 -0
- package/dist/util/git.d.ts +45 -0
- package/dist/util/git.js +191 -0
- package/dist/util/git.js.map +1 -0
- package/dist/util/hooks.d.ts +3 -0
- package/dist/util/hooks.js +43 -0
- package/dist/util/hooks.js.map +1 -0
- package/dist/util/metrics.d.ts +2 -0
- package/dist/util/metrics.js +42 -0
- package/dist/util/metrics.js.map +1 -0
- package/dist/util/search-hybrid.d.ts +10 -0
- package/dist/util/search-hybrid.js +33 -0
- package/dist/util/search-hybrid.js.map +1 -0
- package/package.json +35 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { readConfig } from "./config.js";
|
|
2
|
+
export async function generateEmbedding(text) {
|
|
3
|
+
const config = readConfig();
|
|
4
|
+
if (!config?.embedding?.enabled || !config.embedding.url)
|
|
5
|
+
return null;
|
|
6
|
+
const apiKey = resolveEnvVar(config.embedding.apiKey);
|
|
7
|
+
try {
|
|
8
|
+
const response = await fetch(config.embedding.url, {
|
|
9
|
+
method: "POST",
|
|
10
|
+
headers: { "Content-Type": "application/json", ...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}) },
|
|
11
|
+
body: JSON.stringify({ model: config.embedding.model, input: text }),
|
|
12
|
+
});
|
|
13
|
+
if (!response.ok)
|
|
14
|
+
return null;
|
|
15
|
+
const data = await response.json();
|
|
16
|
+
// OpenAI format
|
|
17
|
+
if (data.data?.[0]?.embedding)
|
|
18
|
+
return { vector: data.data[0].embedding, model: config.embedding.model };
|
|
19
|
+
// Ollama /api/embed format (embeddings array)
|
|
20
|
+
if (data.embeddings?.[0])
|
|
21
|
+
return { vector: data.embeddings[0], model: config.embedding.model };
|
|
22
|
+
// Ollama legacy format
|
|
23
|
+
if (data.embedding)
|
|
24
|
+
return { vector: data.embedding, model: config.embedding.model };
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function cosineSimilarity(a, b) {
|
|
32
|
+
if (a.length !== b.length)
|
|
33
|
+
return 0;
|
|
34
|
+
let dot = 0, normA = 0, normB = 0;
|
|
35
|
+
for (let i = 0; i < a.length; i++) {
|
|
36
|
+
dot += a[i] * b[i];
|
|
37
|
+
normA += a[i] * a[i];
|
|
38
|
+
normB += b[i] * b[i];
|
|
39
|
+
}
|
|
40
|
+
return dot / (Math.sqrt(normA) * Math.sqrt(normB) || 1);
|
|
41
|
+
}
|
|
42
|
+
function resolveEnvVar(val) {
|
|
43
|
+
if (!val)
|
|
44
|
+
return undefined;
|
|
45
|
+
const match = val.match(/^\$\{(.+)\}$/);
|
|
46
|
+
return match ? process.env[match[1]] : val;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=embedding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding.js","sourceRoot":"","sources":["../../src/util/embedding.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export interface GitCommit {
|
|
2
|
+
hash: string;
|
|
3
|
+
message: string;
|
|
4
|
+
author: string;
|
|
5
|
+
email: string;
|
|
6
|
+
timestamp: string;
|
|
7
|
+
branch: string;
|
|
8
|
+
parentHash: string;
|
|
9
|
+
mergeCommit: boolean;
|
|
10
|
+
insertions: number;
|
|
11
|
+
deletions: number;
|
|
12
|
+
filesChanged: number;
|
|
13
|
+
}
|
|
14
|
+
export interface GitFile {
|
|
15
|
+
path: string;
|
|
16
|
+
status: string;
|
|
17
|
+
insertions: number;
|
|
18
|
+
deletions: number;
|
|
19
|
+
oldPath: string | null;
|
|
20
|
+
}
|
|
21
|
+
export interface GitBranch {
|
|
22
|
+
name: string;
|
|
23
|
+
headHash: string;
|
|
24
|
+
isActive: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface GitTag {
|
|
27
|
+
name: string;
|
|
28
|
+
hash: string;
|
|
29
|
+
timestamp: string;
|
|
30
|
+
message: string;
|
|
31
|
+
}
|
|
32
|
+
interface LogOptions {
|
|
33
|
+
limit?: number;
|
|
34
|
+
since?: string;
|
|
35
|
+
until?: string;
|
|
36
|
+
author?: string;
|
|
37
|
+
branch?: string;
|
|
38
|
+
}
|
|
39
|
+
export declare function isGitRepo(dir: string): boolean;
|
|
40
|
+
export declare function getLastCommitHash(cwd: string): string;
|
|
41
|
+
export declare function getLog(cwd: string, opts?: LogOptions): GitCommit[];
|
|
42
|
+
export declare function getDiffTree(cwd: string, hash: string): GitFile[];
|
|
43
|
+
export declare function getBranches(cwd: string): GitBranch[];
|
|
44
|
+
export declare function getTags(cwd: string): GitTag[];
|
|
45
|
+
export {};
|
package/dist/util/git.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
const EXEC_OPTS = { timeout: 60000, encoding: "utf-8", maxBuffer: 50 * 1024 * 1024 };
|
|
3
|
+
const SEP = "---GIT-SKILL-SEP---";
|
|
4
|
+
export function isGitRepo(dir) {
|
|
5
|
+
try {
|
|
6
|
+
execSync("git rev-parse --git-dir", { ...EXEC_OPTS, cwd: dir, stdio: "pipe" });
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function getLastCommitHash(cwd) {
|
|
14
|
+
try {
|
|
15
|
+
return execSync("git rev-parse HEAD", { ...EXEC_OPTS, cwd }).trim();
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return "";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function getLog(cwd, opts = {}) {
|
|
22
|
+
try {
|
|
23
|
+
const args = [
|
|
24
|
+
"git",
|
|
25
|
+
"log",
|
|
26
|
+
`--format=${SEP}%H${SEP}%s${SEP}%an${SEP}%ae${SEP}%aI${SEP}%P`,
|
|
27
|
+
"--numstat",
|
|
28
|
+
];
|
|
29
|
+
if (opts.limit)
|
|
30
|
+
args.push(`-n`, String(opts.limit));
|
|
31
|
+
if (opts.since)
|
|
32
|
+
args.push(`--since=${opts.since}`);
|
|
33
|
+
if (opts.until)
|
|
34
|
+
args.push(`--until=${opts.until}`);
|
|
35
|
+
if (opts.author)
|
|
36
|
+
args.push(`--author=${opts.author}`);
|
|
37
|
+
if (opts.branch)
|
|
38
|
+
args.push(opts.branch);
|
|
39
|
+
const raw = execSync(args.join(" "), { ...EXEC_OPTS, cwd });
|
|
40
|
+
// Split on the SEP that begins each commit header
|
|
41
|
+
// Each commit block starts with SEP
|
|
42
|
+
const blocks = raw.split(new RegExp(`^${SEP}`, "m")).filter(Boolean);
|
|
43
|
+
const commits = [];
|
|
44
|
+
for (const block of blocks) {
|
|
45
|
+
// First line is the fields (after stripping the leading SEP from split)
|
|
46
|
+
const newlineIdx = block.indexOf("\n");
|
|
47
|
+
const headerLine = newlineIdx === -1 ? block : block.slice(0, newlineIdx);
|
|
48
|
+
const numstatSection = newlineIdx === -1 ? "" : block.slice(newlineIdx + 1);
|
|
49
|
+
// Fields: hash SEP message SEP author SEP email SEP timestamp SEP parentHash
|
|
50
|
+
const parts = headerLine.split(SEP);
|
|
51
|
+
if (parts.length < 6)
|
|
52
|
+
continue;
|
|
53
|
+
const [hash, message, author, email, timestamp, parentHashRaw] = parts;
|
|
54
|
+
const parentHash = parentHashRaw?.trim() ?? "";
|
|
55
|
+
const mergeCommit = parentHash.includes(" ");
|
|
56
|
+
// Parse numstat lines: "<insertions>\t<deletions>\t<filepath>"
|
|
57
|
+
let insertions = 0;
|
|
58
|
+
let deletions = 0;
|
|
59
|
+
let filesChanged = 0;
|
|
60
|
+
const numstatLines = numstatSection
|
|
61
|
+
.split("\n")
|
|
62
|
+
.map((l) => l.trim())
|
|
63
|
+
.filter(Boolean);
|
|
64
|
+
for (const line of numstatLines) {
|
|
65
|
+
const parts = line.split("\t");
|
|
66
|
+
if (parts.length < 3)
|
|
67
|
+
continue;
|
|
68
|
+
const ins = parseInt(parts[0], 10);
|
|
69
|
+
const del = parseInt(parts[1], 10);
|
|
70
|
+
if (!isNaN(ins))
|
|
71
|
+
insertions += ins;
|
|
72
|
+
if (!isNaN(del))
|
|
73
|
+
deletions += del;
|
|
74
|
+
filesChanged++;
|
|
75
|
+
}
|
|
76
|
+
commits.push({
|
|
77
|
+
hash: hash.trim(),
|
|
78
|
+
message: message.trim(),
|
|
79
|
+
author: author.trim(),
|
|
80
|
+
email: email.trim(),
|
|
81
|
+
timestamp: timestamp.trim(),
|
|
82
|
+
branch: "",
|
|
83
|
+
parentHash,
|
|
84
|
+
mergeCommit,
|
|
85
|
+
insertions,
|
|
86
|
+
deletions,
|
|
87
|
+
filesChanged,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return commits;
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export function getDiffTree(cwd, hash) {
|
|
97
|
+
try {
|
|
98
|
+
const numstatRaw = execSync(`git diff-tree --no-commit-id -r --numstat -M ${hash}`, { ...EXEC_OPTS, cwd });
|
|
99
|
+
const nameStatusRaw = execSync(`git diff-tree --no-commit-id -r --name-status -M ${hash}`, { ...EXEC_OPTS, cwd });
|
|
100
|
+
// Build a map from path -> status
|
|
101
|
+
const statusMap = new Map();
|
|
102
|
+
for (const line of nameStatusRaw.split("\n")) {
|
|
103
|
+
const trimmed = line.trim();
|
|
104
|
+
if (!trimmed)
|
|
105
|
+
continue;
|
|
106
|
+
const parts = trimmed.split("\t");
|
|
107
|
+
if (parts.length < 2)
|
|
108
|
+
continue;
|
|
109
|
+
const statusCode = parts[0][0]; // e.g. R100 -> R, M -> M
|
|
110
|
+
if (parts.length === 3) {
|
|
111
|
+
// Rename: old\tnew
|
|
112
|
+
statusMap.set(parts[2], { status: statusCode, oldPath: parts[1] });
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
statusMap.set(parts[1], { status: statusCode, oldPath: null });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const files = [];
|
|
119
|
+
for (const line of numstatRaw.split("\n")) {
|
|
120
|
+
const trimmed = line.trim();
|
|
121
|
+
if (!trimmed)
|
|
122
|
+
continue;
|
|
123
|
+
const parts = trimmed.split("\t");
|
|
124
|
+
if (parts.length < 3)
|
|
125
|
+
continue;
|
|
126
|
+
const ins = parseInt(parts[0], 10);
|
|
127
|
+
const del = parseInt(parts[1], 10);
|
|
128
|
+
// For renames, numstat uses "old => new" path or two tabs
|
|
129
|
+
const filePath = parts[2];
|
|
130
|
+
const statusInfo = statusMap.get(filePath) ?? { status: "M", oldPath: null };
|
|
131
|
+
files.push({
|
|
132
|
+
path: filePath,
|
|
133
|
+
status: statusInfo.status,
|
|
134
|
+
insertions: isNaN(ins) ? 0 : ins,
|
|
135
|
+
deletions: isNaN(del) ? 0 : del,
|
|
136
|
+
oldPath: statusInfo.oldPath,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return files;
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
export function getBranches(cwd) {
|
|
146
|
+
try {
|
|
147
|
+
const raw = execSync(`git branch -a --format="%(refname:short)\t%(HEAD)\t%(objectname:short)"`, { ...EXEC_OPTS, cwd });
|
|
148
|
+
const branches = [];
|
|
149
|
+
for (const line of raw.split("\n")) {
|
|
150
|
+
const trimmed = line.trim().replace(/^"|"$/g, "");
|
|
151
|
+
if (!trimmed)
|
|
152
|
+
continue;
|
|
153
|
+
const parts = trimmed.split("\t");
|
|
154
|
+
if (parts.length < 3)
|
|
155
|
+
continue;
|
|
156
|
+
const name = parts[0].trim();
|
|
157
|
+
const isActive = parts[1].trim() === "*";
|
|
158
|
+
const headHash = parts[2].trim();
|
|
159
|
+
branches.push({ name, headHash, isActive });
|
|
160
|
+
}
|
|
161
|
+
return branches;
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return [];
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
export function getTags(cwd) {
|
|
168
|
+
try {
|
|
169
|
+
const raw = execSync(`git tag -l --format="%(refname:short)\t%(objectname:short)\t%(creatordate:iso-strict)\t%(subject)"`, { ...EXEC_OPTS, cwd });
|
|
170
|
+
const tags = [];
|
|
171
|
+
for (const line of raw.split("\n")) {
|
|
172
|
+
const trimmed = line.trim().replace(/^"|"$/g, "");
|
|
173
|
+
if (!trimmed)
|
|
174
|
+
continue;
|
|
175
|
+
const parts = trimmed.split("\t");
|
|
176
|
+
if (parts.length < 4)
|
|
177
|
+
continue;
|
|
178
|
+
tags.push({
|
|
179
|
+
name: parts[0].trim(),
|
|
180
|
+
hash: parts[1].trim(),
|
|
181
|
+
timestamp: parts[2].trim(),
|
|
182
|
+
message: parts[3].trim(),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
return tags;
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
return [];
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/util/git.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, chmodSync, unlinkSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
const HOOK_MARKER = "# git-skill hook";
|
|
4
|
+
const HOOK_CONTENT = `\n${HOOK_MARKER}\ngit-skill capture --hook 2>/dev/null &\n`;
|
|
5
|
+
export function installHook(gitDir) {
|
|
6
|
+
const hookPath = join(gitDir, "hooks", "post-commit");
|
|
7
|
+
if (existsSync(hookPath)) {
|
|
8
|
+
const content = readFileSync(hookPath, "utf-8");
|
|
9
|
+
if (content.includes(HOOK_MARKER))
|
|
10
|
+
return "already_installed";
|
|
11
|
+
writeFileSync(hookPath, content + HOOK_CONTENT);
|
|
12
|
+
chmodSync(hookPath, 0o755);
|
|
13
|
+
return "updated";
|
|
14
|
+
}
|
|
15
|
+
writeFileSync(hookPath, `#!/bin/sh\n${HOOK_CONTENT}`);
|
|
16
|
+
chmodSync(hookPath, 0o755);
|
|
17
|
+
return "installed";
|
|
18
|
+
}
|
|
19
|
+
export function removeHook(gitDir) {
|
|
20
|
+
const hookPath = join(gitDir, "hooks", "post-commit");
|
|
21
|
+
if (!existsSync(hookPath))
|
|
22
|
+
return "not_found";
|
|
23
|
+
const content = readFileSync(hookPath, "utf-8");
|
|
24
|
+
if (!content.includes(HOOK_MARKER))
|
|
25
|
+
return "not_found";
|
|
26
|
+
const lines = content.split("\n");
|
|
27
|
+
const filtered = lines.filter(line => !line.includes(HOOK_MARKER) && !line.includes("git-skill capture"));
|
|
28
|
+
const result = filtered.join("\n").trim();
|
|
29
|
+
if (result === "#!/bin/sh" || result === "") {
|
|
30
|
+
unlinkSync(hookPath);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
writeFileSync(hookPath, result + "\n");
|
|
34
|
+
}
|
|
35
|
+
return "removed";
|
|
36
|
+
}
|
|
37
|
+
export function hasHook(gitDir) {
|
|
38
|
+
const hookPath = join(gitDir, "hooks", "post-commit");
|
|
39
|
+
if (!existsSync(hookPath))
|
|
40
|
+
return false;
|
|
41
|
+
return readFileSync(hookPath, "utf-8").includes(HOOK_MARKER);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/util/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACpF,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,MAAM,WAAW,GAAG,kBAAkB,CAAC;AACvC,MAAM,YAAY,GAAG,KAAK,WAAW,4CAA4C,CAAC;AAElF,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;IAEtD,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChD,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;YAAE,OAAO,mBAAmB,CAAC;QAC9D,aAAa,CAAC,QAAQ,EAAE,OAAO,GAAG,YAAY,CAAC,CAAC;QAChD,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC3B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,aAAa,CAAC,QAAQ,EAAE,cAAc,YAAY,EAAE,CAAC,CAAC;IACtD,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC3B,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;IACtD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,WAAW,CAAC;IAC9C,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAChD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;QAAE,OAAO,WAAW,CAAC;IACvD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAC1G,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1C,IAAI,MAAM,KAAK,WAAW,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;QAC5C,UAAU,CAAC,QAAQ,CAAC,CAAC;IACvB,CAAC;SAAM,CAAC;QACN,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,MAAc;IACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;IACtD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,OAAO,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export function computeBuiltinMetrics(db) {
|
|
2
|
+
// Clear existing built-in metrics
|
|
3
|
+
db.prepare("DELETE FROM metric_values WHERE metric_name IN ('revert_rate', 'fix_on_fix_rate', 'scope_creep', 'time_to_commit', 'same_file_churn', 'dependency_churn')").run();
|
|
4
|
+
const commits = db.prepare("SELECT hash, message, timestamp, files_changed FROM commits ORDER BY timestamp ASC").all();
|
|
5
|
+
const insert = db.prepare("INSERT INTO metric_values (commit_hash, metric_name, value, captured_at) VALUES (?, ?, ?, ?)");
|
|
6
|
+
const now = new Date().toISOString();
|
|
7
|
+
const window = 10;
|
|
8
|
+
db.transaction(() => {
|
|
9
|
+
for (let i = 0; i < commits.length; i++) {
|
|
10
|
+
const c = commits[i];
|
|
11
|
+
const windowStart = Math.max(0, i - window + 1);
|
|
12
|
+
const windowCommits = commits.slice(windowStart, i + 1);
|
|
13
|
+
// Revert rate (rolling)
|
|
14
|
+
const reverts = windowCommits.filter(wc => /revert/i.test(wc.message)).length;
|
|
15
|
+
insert.run(c.hash, "revert_rate", reverts / windowCommits.length, now);
|
|
16
|
+
// Fix-on-fix rate
|
|
17
|
+
const fixes = windowCommits.filter(wc => /\bfix\b/i.test(wc.message)).length;
|
|
18
|
+
insert.run(c.hash, "fix_on_fix_rate", fixes / windowCommits.length, now);
|
|
19
|
+
// Scope creep (files per commit)
|
|
20
|
+
insert.run(c.hash, "scope_creep", c.files_changed, now);
|
|
21
|
+
// Time-to-commit (minutes since previous)
|
|
22
|
+
if (i > 0) {
|
|
23
|
+
const minutes = (new Date(c.timestamp).getTime() - new Date(commits[i - 1].timestamp).getTime()) / 60000;
|
|
24
|
+
insert.run(c.hash, "time_to_commit", minutes, now);
|
|
25
|
+
}
|
|
26
|
+
// Same-file churn (files edited 3+ times in last 5 commits)
|
|
27
|
+
if (i >= 2) {
|
|
28
|
+
const recentHashes = commits.slice(Math.max(0, i - 4), i + 1).map(rc => rc.hash);
|
|
29
|
+
const placeholders = recentHashes.map(() => "?").join(",");
|
|
30
|
+
const churnFiles = db.prepare(`
|
|
31
|
+
SELECT file_path, COUNT(*) as cnt FROM commit_files
|
|
32
|
+
WHERE commit_hash IN (${placeholders}) GROUP BY file_path HAVING cnt >= 3
|
|
33
|
+
`).all(...recentHashes);
|
|
34
|
+
insert.run(c.hash, "same_file_churn", churnFiles.length, now);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
insert.run(c.hash, "same_file_churn", 0, now);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
})();
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/util/metrics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type Database from "better-sqlite3";
|
|
2
|
+
export interface SearchResult {
|
|
3
|
+
hash: string;
|
|
4
|
+
type: string;
|
|
5
|
+
path: string;
|
|
6
|
+
message: string;
|
|
7
|
+
detail: string;
|
|
8
|
+
score: number;
|
|
9
|
+
}
|
|
10
|
+
export declare function searchBM25(db: Database.Database, query: string, limit?: number): SearchResult[];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export function searchBM25(db, query, limit = 20) {
|
|
2
|
+
const safeQuery = query.replace(/['"]/g, "").trim();
|
|
3
|
+
if (!safeQuery)
|
|
4
|
+
return [];
|
|
5
|
+
try {
|
|
6
|
+
// Try FTS5 phrase + prefix match
|
|
7
|
+
const results = db.prepare(`
|
|
8
|
+
SELECT hash, type, path, message, detail, rank as score
|
|
9
|
+
FROM history_fts WHERE history_fts MATCH ? ORDER BY rank LIMIT ?
|
|
10
|
+
`).all(`"${safeQuery}"*`, limit);
|
|
11
|
+
if (results.length > 0)
|
|
12
|
+
return results;
|
|
13
|
+
// Fallback: individual terms
|
|
14
|
+
const terms = safeQuery.split(/\s+/).map(t => `"${t}"*`).join(" OR ");
|
|
15
|
+
return db.prepare(`
|
|
16
|
+
SELECT hash, type, path, message, detail, rank as score
|
|
17
|
+
FROM history_fts WHERE history_fts MATCH ? ORDER BY rank LIMIT ?
|
|
18
|
+
`).all(terms, limit);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// Final fallback: LIKE on base tables (FTS5 doesn't support LIKE)
|
|
22
|
+
const commitMatches = db.prepare(`
|
|
23
|
+
SELECT hash, 'commit' as type, '' as path, message, '' as detail, 0 as score
|
|
24
|
+
FROM commits WHERE message LIKE ? LIMIT ?
|
|
25
|
+
`).all(`%${safeQuery}%`, limit);
|
|
26
|
+
const fileMatches = db.prepare(`
|
|
27
|
+
SELECT commit_hash as hash, 'file' as type, file_path as path, '' as message, status as detail, 0 as score
|
|
28
|
+
FROM commit_files WHERE file_path LIKE ? LIMIT ?
|
|
29
|
+
`).all(`%${safeQuery}%`, limit);
|
|
30
|
+
return [...commitMatches, ...fileMatches].slice(0, limit);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=search-hybrid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-hybrid.js","sourceRoot":"","sources":["../../src/util/search-hybrid.ts"],"names":[],"mappings":"AAWA,MAAM,UAAU,UAAU,CAAC,EAAqB,EAAE,KAAa,EAAE,KAAK,GAAG,EAAE;IACzE,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACpD,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,CAAC;IAE1B,IAAI,CAAC;QACH,iCAAiC;QACjC,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC;;;KAG1B,CAAC,CAAC,GAAG,CAAC,IAAI,SAAS,IAAI,EAAE,KAAK,CAAmB,CAAC;QACnD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,OAAO,CAAC;QAEvC,6BAA6B;QAC7B,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtE,OAAO,EAAE,CAAC,OAAO,CAAC;;;KAGjB,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAmB,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,kEAAkE;QAClE,MAAM,aAAa,GAAG,EAAE,CAAC,OAAO,CAAC;;;KAGhC,CAAC,CAAC,GAAG,CAAC,IAAI,SAAS,GAAG,EAAE,KAAK,CAAmB,CAAC;QAClD,MAAM,WAAW,GAAG,EAAE,CAAC,OAAO,CAAC;;;KAG9B,CAAC,CAAC,GAAG,CAAC,IAAI,SAAS,GAAG,EAAE,KAAK,CAAmB,CAAC;QAClD,OAAO,CAAC,GAAG,aAAa,EAAE,GAAG,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@m2015agg/git-skill",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Git history intelligence for LLMs — institutional memory over codebase evolution",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"git-skill": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "tsc --watch",
|
|
13
|
+
"test": "vitest run",
|
|
14
|
+
"test:watch": "vitest",
|
|
15
|
+
"test:coverage": "vitest run --coverage",
|
|
16
|
+
"link": "npm run build && npm link",
|
|
17
|
+
"prepublishOnly": "npm run build",
|
|
18
|
+
"postinstall": "node -e \"process.stdout.write('\\n git-skill installed! Run: git-skill install\\n\\n')\""
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"better-sqlite3": "^12.8.0",
|
|
22
|
+
"commander": "^13.1.0",
|
|
23
|
+
"simple-statistics": "^7.8.7"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
27
|
+
"@types/node": "^25.5.0",
|
|
28
|
+
"typescript": "^5.7.0",
|
|
29
|
+
"vitest": "^3.0.0"
|
|
30
|
+
},
|
|
31
|
+
"files": ["dist", "README.md"],
|
|
32
|
+
"keywords": ["git", "history", "ai", "llm", "cli", "intelligence"],
|
|
33
|
+
"author": "m2015agg",
|
|
34
|
+
"license": "MIT"
|
|
35
|
+
}
|