@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,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Populates file_evolution table: file_path, first_seen, last_modified, total_commits, total_churn
|
|
3
|
+
*/
|
|
4
|
+
export function computeFileEvolution(db) {
|
|
5
|
+
db.exec("DELETE FROM file_evolution");
|
|
6
|
+
db.exec(`
|
|
7
|
+
INSERT INTO file_evolution (file_path, first_seen, last_modified, total_commits, total_churn)
|
|
8
|
+
SELECT
|
|
9
|
+
cf.file_path,
|
|
10
|
+
MIN(c.timestamp) AS first_seen,
|
|
11
|
+
MAX(c.timestamp) AS last_modified,
|
|
12
|
+
COUNT(DISTINCT c.hash) AS total_commits,
|
|
13
|
+
SUM(cf.insertions + cf.deletions) AS total_churn
|
|
14
|
+
FROM commit_files cf
|
|
15
|
+
JOIN commits c ON c.hash = cf.commit_hash
|
|
16
|
+
GROUP BY cf.file_path
|
|
17
|
+
`);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Populates churn_hotspots: file_path, period (strftime week), commits, insertions, deletions, unique_authors
|
|
21
|
+
*/
|
|
22
|
+
export function computeChurnHotspots(db) {
|
|
23
|
+
db.exec("DELETE FROM churn_hotspots");
|
|
24
|
+
db.exec(`
|
|
25
|
+
INSERT INTO churn_hotspots (file_path, period, commits, insertions, deletions, unique_authors)
|
|
26
|
+
SELECT
|
|
27
|
+
cf.file_path,
|
|
28
|
+
strftime('%Y-W%W', c.timestamp) AS period,
|
|
29
|
+
COUNT(DISTINCT c.hash) AS commits,
|
|
30
|
+
SUM(cf.insertions) AS insertions,
|
|
31
|
+
SUM(cf.deletions) AS deletions,
|
|
32
|
+
COUNT(DISTINCT c.author) AS unique_authors
|
|
33
|
+
FROM commit_files cf
|
|
34
|
+
JOIN commits c ON c.hash = cf.commit_hash
|
|
35
|
+
GROUP BY cf.file_path, strftime('%Y-W%W', c.timestamp)
|
|
36
|
+
`);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Populates coupling: file_a, file_b, co_commit_count, coupling_score
|
|
40
|
+
* Uses Jaccard-style scoring: co_commit_count / max(total_commits_a, total_commits_b)
|
|
41
|
+
*/
|
|
42
|
+
export function computeCoupling(db) {
|
|
43
|
+
db.exec("DELETE FROM coupling");
|
|
44
|
+
// Get eligible commits: more than 1 file but no more than 50
|
|
45
|
+
const eligibleCommits = db
|
|
46
|
+
.prepare(`SELECT hash FROM commits WHERE files_changed > 1 AND files_changed <= 50`)
|
|
47
|
+
.all();
|
|
48
|
+
if (eligibleCommits.length === 0)
|
|
49
|
+
return;
|
|
50
|
+
// Get files per commit
|
|
51
|
+
const getFiles = db.prepare(`SELECT file_path FROM commit_files WHERE commit_hash = ?`);
|
|
52
|
+
// Count co-occurrences
|
|
53
|
+
const coCommitCounts = new Map();
|
|
54
|
+
const fileTotalCommits = new Map();
|
|
55
|
+
for (const { hash } of eligibleCommits) {
|
|
56
|
+
const files = getFiles.all(hash).map((r) => r.file_path);
|
|
57
|
+
// Track per-file commit counts
|
|
58
|
+
for (const f of files) {
|
|
59
|
+
fileTotalCommits.set(f, (fileTotalCommits.get(f) ?? 0) + 1);
|
|
60
|
+
}
|
|
61
|
+
// Generate all pairs (sorted so file_a < file_b lexicographically)
|
|
62
|
+
for (let i = 0; i < files.length; i++) {
|
|
63
|
+
for (let j = i + 1; j < files.length; j++) {
|
|
64
|
+
const a = files[i] < files[j] ? files[i] : files[j];
|
|
65
|
+
const b = files[i] < files[j] ? files[j] : files[i];
|
|
66
|
+
const key = `${a}\0${b}`;
|
|
67
|
+
coCommitCounts.set(key, (coCommitCounts.get(key) ?? 0) + 1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const insertCoupling = db.prepare(`
|
|
72
|
+
INSERT INTO coupling (file_a, file_b, co_commit_count, coupling_score)
|
|
73
|
+
VALUES (?, ?, ?, ?)
|
|
74
|
+
`);
|
|
75
|
+
const insertAll = db.transaction(() => {
|
|
76
|
+
for (const [key, count] of coCommitCounts) {
|
|
77
|
+
if (count < 2)
|
|
78
|
+
continue;
|
|
79
|
+
const [a, b] = key.split("\0");
|
|
80
|
+
const totalA = fileTotalCommits.get(a) ?? 1;
|
|
81
|
+
const totalB = fileTotalCommits.get(b) ?? 1;
|
|
82
|
+
const score = count / Math.max(totalA, totalB);
|
|
83
|
+
insertCoupling.run(a, b, count, score);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
insertAll();
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Populates decision_points: commit_hash, type, impact_score, files_affected
|
|
90
|
+
*/
|
|
91
|
+
export function computeDecisionPoints(db) {
|
|
92
|
+
db.exec("DELETE FROM decision_points");
|
|
93
|
+
const commits = db
|
|
94
|
+
.prepare(`SELECT hash, message, insertions, deletions, files_changed, timestamp FROM commits`)
|
|
95
|
+
.all();
|
|
96
|
+
const getFiles = db.prepare(`SELECT file_path, status FROM commit_files WHERE commit_hash = ?`);
|
|
97
|
+
const depFiles = new Set([
|
|
98
|
+
"package.json",
|
|
99
|
+
"requirements.txt",
|
|
100
|
+
"Cargo.toml",
|
|
101
|
+
"go.mod",
|
|
102
|
+
]);
|
|
103
|
+
const configPatterns = [/\.env(\.|$)/i, /\.config(\.|$)/i];
|
|
104
|
+
const insert = db.prepare(`
|
|
105
|
+
INSERT INTO decision_points (commit_hash, type, impact_score, files_affected)
|
|
106
|
+
VALUES (?, ?, ?, ?)
|
|
107
|
+
`);
|
|
108
|
+
const checkNewDir = db.prepare(`
|
|
109
|
+
SELECT COUNT(*) as c FROM commit_files cf
|
|
110
|
+
JOIN commits cm ON cm.hash = cf.commit_hash
|
|
111
|
+
WHERE cf.file_path LIKE ? AND cm.hash != ? AND cm.timestamp < ?
|
|
112
|
+
`);
|
|
113
|
+
const insertAll = db.transaction(() => {
|
|
114
|
+
for (const commit of commits) {
|
|
115
|
+
const types = [];
|
|
116
|
+
const impact = (commit.insertions ?? 0) + (commit.deletions ?? 0);
|
|
117
|
+
// Revert detection
|
|
118
|
+
if (/revert/i.test(commit.message)) {
|
|
119
|
+
types.push("revert");
|
|
120
|
+
}
|
|
121
|
+
// Big refactor: >= 20 files changed
|
|
122
|
+
if ((commit.files_changed ?? 0) >= 20) {
|
|
123
|
+
types.push("big_refactor");
|
|
124
|
+
}
|
|
125
|
+
// Major removal: deletions > insertions * 2 AND deletions > 20
|
|
126
|
+
if ((commit.deletions ?? 0) > (commit.insertions ?? 0) * 2 &&
|
|
127
|
+
(commit.deletions ?? 0) > 20) {
|
|
128
|
+
types.push("major_removal");
|
|
129
|
+
}
|
|
130
|
+
// File-based detections
|
|
131
|
+
const files = getFiles.all(commit.hash);
|
|
132
|
+
const filePaths = files.map((f) => f.file_path);
|
|
133
|
+
const fileNames = filePaths.map((p) => p.split("/").pop() ?? p);
|
|
134
|
+
// Dependency change
|
|
135
|
+
if (fileNames.some((n) => depFiles.has(n))) {
|
|
136
|
+
types.push("dependency_change");
|
|
137
|
+
}
|
|
138
|
+
// Config change
|
|
139
|
+
if (filePaths.some((p) => configPatterns.some((re) => re.test(p)))) {
|
|
140
|
+
types.push("config_change");
|
|
141
|
+
}
|
|
142
|
+
// Architecture change: new top-level src dirs created
|
|
143
|
+
const newDirs = new Set();
|
|
144
|
+
for (const f of files) {
|
|
145
|
+
if (f.status === "A") {
|
|
146
|
+
const parts = f.file_path.split("/");
|
|
147
|
+
// e.g. src/core/app.ts -> top-level dir under src is "src/core"
|
|
148
|
+
if (parts.length >= 3 && parts[0] === "src") {
|
|
149
|
+
newDirs.add(`${parts[0]}/${parts[1]}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (newDirs.size > 0) {
|
|
154
|
+
// Check if any of these dirs are brand new (no prior commits touching them)
|
|
155
|
+
for (const srcDir of newDirs) {
|
|
156
|
+
const prior = checkNewDir.get(`${srcDir}/%`, commit.hash, commit.timestamp);
|
|
157
|
+
if (prior.c === 0) {
|
|
158
|
+
types.push("architecture_change");
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Insert one row per detected type
|
|
164
|
+
for (const type of types) {
|
|
165
|
+
insert.run(commit.hash, type, impact, commit.files_changed ?? 0);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
insertAll();
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Populates author_expertise: author, file_pattern (directory), commit_count, last_touched, expertise_score
|
|
173
|
+
* Groups by author and first 2 path segments.
|
|
174
|
+
*/
|
|
175
|
+
export function computeAuthorExpertise(db) {
|
|
176
|
+
db.exec("DELETE FROM author_expertise");
|
|
177
|
+
db.exec(`
|
|
178
|
+
INSERT INTO author_expertise (author, file_pattern, commit_count, last_touched, expertise_score)
|
|
179
|
+
SELECT
|
|
180
|
+
c.author,
|
|
181
|
+
CASE
|
|
182
|
+
WHEN instr(cf.file_path, '/') = 0 THEN cf.file_path
|
|
183
|
+
ELSE
|
|
184
|
+
CASE
|
|
185
|
+
WHEN instr(substr(cf.file_path, instr(cf.file_path, '/') + 1), '/') = 0
|
|
186
|
+
THEN cf.file_path
|
|
187
|
+
ELSE
|
|
188
|
+
substr(cf.file_path, 1,
|
|
189
|
+
instr(cf.file_path, '/') +
|
|
190
|
+
instr(substr(cf.file_path, instr(cf.file_path, '/') + 1), '/') - 1
|
|
191
|
+
)
|
|
192
|
+
END
|
|
193
|
+
END AS dir_prefix,
|
|
194
|
+
COUNT(DISTINCT c.hash) AS commit_count,
|
|
195
|
+
MAX(c.timestamp) AS last_touched,
|
|
196
|
+
CAST(COUNT(DISTINCT c.hash) AS REAL) / (
|
|
197
|
+
SELECT CAST(COUNT(DISTINCT c2.hash) AS REAL)
|
|
198
|
+
FROM commits c2
|
|
199
|
+
JOIN commit_files cf2 ON cf2.commit_hash = c2.hash
|
|
200
|
+
WHERE cf2.file_path LIKE
|
|
201
|
+
CASE
|
|
202
|
+
WHEN instr(cf.file_path, '/') = 0 THEN cf.file_path || '%'
|
|
203
|
+
ELSE
|
|
204
|
+
CASE
|
|
205
|
+
WHEN instr(substr(cf.file_path, instr(cf.file_path, '/') + 1), '/') = 0
|
|
206
|
+
THEN cf.file_path || '%'
|
|
207
|
+
ELSE
|
|
208
|
+
substr(cf.file_path, 1,
|
|
209
|
+
instr(cf.file_path, '/') +
|
|
210
|
+
instr(substr(cf.file_path, instr(cf.file_path, '/') + 1), '/') - 1
|
|
211
|
+
) || '%'
|
|
212
|
+
END
|
|
213
|
+
END
|
|
214
|
+
) AS expertise_score
|
|
215
|
+
FROM commit_files cf
|
|
216
|
+
JOIN commits c ON c.hash = cf.commit_hash
|
|
217
|
+
GROUP BY c.author,
|
|
218
|
+
CASE
|
|
219
|
+
WHEN instr(cf.file_path, '/') = 0 THEN cf.file_path
|
|
220
|
+
ELSE
|
|
221
|
+
CASE
|
|
222
|
+
WHEN instr(substr(cf.file_path, instr(cf.file_path, '/') + 1), '/') = 0
|
|
223
|
+
THEN cf.file_path
|
|
224
|
+
ELSE
|
|
225
|
+
substr(cf.file_path, 1,
|
|
226
|
+
instr(cf.file_path, '/') +
|
|
227
|
+
instr(substr(cf.file_path, instr(cf.file_path, '/') + 1), '/') - 1
|
|
228
|
+
)
|
|
229
|
+
END
|
|
230
|
+
END
|
|
231
|
+
`);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Populates trends: metric_name, period, value, delta, direction
|
|
235
|
+
* Computes weekly stats and compares to previous period.
|
|
236
|
+
*/
|
|
237
|
+
export function computeTrends(db) {
|
|
238
|
+
db.exec("DELETE FROM trends");
|
|
239
|
+
// Compute weekly stats
|
|
240
|
+
const weeklyStats = db
|
|
241
|
+
.prepare(`SELECT
|
|
242
|
+
strftime('%Y-W%W', timestamp) AS period,
|
|
243
|
+
COUNT(*) AS commits,
|
|
244
|
+
AVG(files_changed) AS avg_files,
|
|
245
|
+
SUM(insertions + deletions) AS total_churn,
|
|
246
|
+
SUM(CASE WHEN lower(message) LIKE '%revert%' THEN 1 ELSE 0 END) AS reverts,
|
|
247
|
+
SUM(CASE WHEN lower(message) LIKE 'fix%' OR lower(message) LIKE '%fix:%' THEN 1 ELSE 0 END) AS fixes
|
|
248
|
+
FROM commits
|
|
249
|
+
GROUP BY strftime('%Y-W%W', timestamp)
|
|
250
|
+
ORDER BY period`)
|
|
251
|
+
.all();
|
|
252
|
+
if (weeklyStats.length === 0)
|
|
253
|
+
return;
|
|
254
|
+
const insert = db.prepare(`
|
|
255
|
+
INSERT INTO trends (metric_name, period, value, delta, direction)
|
|
256
|
+
VALUES (?, ?, ?, ?, ?)
|
|
257
|
+
`);
|
|
258
|
+
const metrics = [
|
|
259
|
+
{ name: "commits_per_week", getValue: (s) => s.commits },
|
|
260
|
+
{ name: "avg_files_per_commit", getValue: (s) => s.avg_files ?? 0 },
|
|
261
|
+
{ name: "total_churn", getValue: (s) => s.total_churn ?? 0 },
|
|
262
|
+
{
|
|
263
|
+
name: "revert_rate",
|
|
264
|
+
getValue: (s) => (s.commits > 0 ? s.reverts / s.commits : 0),
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
name: "fix_rate",
|
|
268
|
+
getValue: (s) => (s.commits > 0 ? s.fixes / s.commits : 0),
|
|
269
|
+
},
|
|
270
|
+
];
|
|
271
|
+
const insertAll = db.transaction(() => {
|
|
272
|
+
for (const metric of metrics) {
|
|
273
|
+
let prevValue = null;
|
|
274
|
+
for (const week of weeklyStats) {
|
|
275
|
+
const value = metric.getValue(week);
|
|
276
|
+
let delta = null;
|
|
277
|
+
let direction = null;
|
|
278
|
+
if (prevValue !== null) {
|
|
279
|
+
delta = value - prevValue;
|
|
280
|
+
if (Math.abs(delta) < 0.001) {
|
|
281
|
+
direction = "stable";
|
|
282
|
+
}
|
|
283
|
+
else if (delta > 0) {
|
|
284
|
+
direction = "up";
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
direction = "down";
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
insert.run(metric.name, week.period, value, delta, direction);
|
|
291
|
+
prevValue = value;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
insertAll();
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Runs all analytics computations in order.
|
|
299
|
+
*/
|
|
300
|
+
export function runAllAnalytics(db) {
|
|
301
|
+
computeFileEvolution(db);
|
|
302
|
+
computeChurnHotspots(db);
|
|
303
|
+
computeCoupling(db);
|
|
304
|
+
computeDecisionPoints(db);
|
|
305
|
+
computeAuthorExpertise(db);
|
|
306
|
+
computeTrends(db);
|
|
307
|
+
}
|
|
308
|
+
//# sourceMappingURL=analytics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../src/util/analytics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
2
|
+
import { dirname } from "path";
|
|
3
|
+
const MARKER_START = "<!-- git-skill:start -->";
|
|
4
|
+
const MARKER_END = "<!-- git-skill:end -->";
|
|
5
|
+
export function upsertSection(filePath, content) {
|
|
6
|
+
const snippet = `${MARKER_START}\n${content}\n${MARKER_END}`;
|
|
7
|
+
if (!existsSync(filePath)) {
|
|
8
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
9
|
+
writeFileSync(filePath, snippet + "\n");
|
|
10
|
+
return "created";
|
|
11
|
+
}
|
|
12
|
+
const existing = readFileSync(filePath, "utf-8");
|
|
13
|
+
const startIdx = existing.indexOf(MARKER_START);
|
|
14
|
+
const endIdx = existing.indexOf(MARKER_END);
|
|
15
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
16
|
+
const currentSection = existing.slice(startIdx, endIdx + MARKER_END.length);
|
|
17
|
+
if (currentSection === snippet)
|
|
18
|
+
return "unchanged";
|
|
19
|
+
const updated = existing.slice(0, startIdx) + snippet + existing.slice(endIdx + MARKER_END.length);
|
|
20
|
+
writeFileSync(filePath, updated);
|
|
21
|
+
return "updated";
|
|
22
|
+
}
|
|
23
|
+
const separator = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
24
|
+
writeFileSync(filePath, existing + separator + snippet + "\n");
|
|
25
|
+
return "updated";
|
|
26
|
+
}
|
|
27
|
+
export function removeSection(filePath) {
|
|
28
|
+
if (!existsSync(filePath))
|
|
29
|
+
return "not_found";
|
|
30
|
+
const content = readFileSync(filePath, "utf-8");
|
|
31
|
+
const startIdx = content.indexOf(MARKER_START);
|
|
32
|
+
const endIdx = content.indexOf(MARKER_END);
|
|
33
|
+
if (startIdx === -1 || endIdx === -1)
|
|
34
|
+
return "not_found";
|
|
35
|
+
const before = content.slice(0, startIdx).replace(/\n+$/, "");
|
|
36
|
+
const after = content.slice(endIdx + MARKER_END.length).replace(/^\n+/, "");
|
|
37
|
+
const result = before + (after ? "\n\n" + after : "") + "\n";
|
|
38
|
+
writeFileSync(filePath, result);
|
|
39
|
+
return "removed";
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=claude-md.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-md.js","sourceRoot":"","sources":["../../src/util/claude-md.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,MAAM,YAAY,GAAG,0BAA0B,CAAC;AAChD,MAAM,UAAU,GAAG,wBAAwB,CAAC;AAE5C,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,OAAe;IAC7D,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,OAAO,KAAK,UAAU,EAAE,CAAC;IAE7D,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,aAAa,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC,CAAC;QACxC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAE5C,IAAI,QAAQ,KAAK,CAAC,CAAC,IAAI,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;QACrC,MAAM,cAAc,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;QAC5E,IAAI,cAAc,KAAK,OAAO;YAAE,OAAO,WAAW,CAAC;QACnD,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;QACnG,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACjC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IAC1D,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;IAC/D,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,WAAW,CAAC;IAC9C,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3C,IAAI,QAAQ,KAAK,CAAC,CAAC,IAAI,MAAM,KAAK,CAAC,CAAC;QAAE,OAAO,WAAW,CAAC;IACzD,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC5E,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;IAC7D,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAChC,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface GitSkillConfig {
|
|
2
|
+
embedding: {
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
provider: string;
|
|
5
|
+
model: string;
|
|
6
|
+
url: string;
|
|
7
|
+
apiKey: string;
|
|
8
|
+
dimensions: number;
|
|
9
|
+
};
|
|
10
|
+
enrichment: {
|
|
11
|
+
enabled: boolean;
|
|
12
|
+
url: string;
|
|
13
|
+
model: string;
|
|
14
|
+
apiKey: string;
|
|
15
|
+
batchSize: number;
|
|
16
|
+
maxTokensPerCommit: number;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export declare function getDefaultConfig(): GitSkillConfig;
|
|
20
|
+
export declare function readConfig(): GitSkillConfig | null;
|
|
21
|
+
export declare function writeConfig(config: GitSkillConfig): void;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
const CONFIG_DIR = join(homedir(), ".config", "git-skill");
|
|
5
|
+
const CONFIG_PATH = join(CONFIG_DIR, "config.json");
|
|
6
|
+
export function getDefaultConfig() {
|
|
7
|
+
return {
|
|
8
|
+
embedding: { enabled: false, provider: "openai", model: "text-embedding-3-small", url: "", apiKey: "", dimensions: 1536 },
|
|
9
|
+
enrichment: { enabled: false, url: "", model: "gpt-4o-mini", apiKey: "", batchSize: 10, maxTokensPerCommit: 500 },
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export function readConfig() {
|
|
13
|
+
try {
|
|
14
|
+
if (!existsSync(CONFIG_PATH))
|
|
15
|
+
return null;
|
|
16
|
+
return JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function writeConfig(config) {
|
|
23
|
+
mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
24
|
+
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/util/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAqB7B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;AAC3D,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEpD,MAAM,UAAU,gBAAgB;IAC9B,OAAO;QACL,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE;QACzH,UAAU,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,kBAAkB,EAAE,GAAG,EAAE;KAClH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAsB;IAChD,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACxD,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAC/E,CAAC"}
|
package/dist/util/db.js
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { existsSync } from "fs";
|
|
4
|
+
const SCHEMA_VERSION = 1;
|
|
5
|
+
export function openDb(historyDir) {
|
|
6
|
+
const dbPath = join(historyDir, "history.db");
|
|
7
|
+
const db = new Database(dbPath);
|
|
8
|
+
db.pragma("journal_mode = WAL");
|
|
9
|
+
db.pragma("busy_timeout = 5000");
|
|
10
|
+
db.pragma("foreign_keys = OFF");
|
|
11
|
+
initSchema(db);
|
|
12
|
+
return db;
|
|
13
|
+
}
|
|
14
|
+
export function hasDb(historyDir) {
|
|
15
|
+
return existsSync(join(historyDir, "history.db"));
|
|
16
|
+
}
|
|
17
|
+
function initSchema(db) {
|
|
18
|
+
const currentVersion = getSchemaVersion(db);
|
|
19
|
+
if (currentVersion >= SCHEMA_VERSION)
|
|
20
|
+
return;
|
|
21
|
+
db.exec(`
|
|
22
|
+
-- Layer 1: Raw Git Data
|
|
23
|
+
CREATE TABLE IF NOT EXISTS commits (
|
|
24
|
+
hash TEXT PRIMARY KEY,
|
|
25
|
+
message TEXT,
|
|
26
|
+
author TEXT,
|
|
27
|
+
email TEXT,
|
|
28
|
+
timestamp TEXT,
|
|
29
|
+
branch TEXT,
|
|
30
|
+
parent_hash TEXT,
|
|
31
|
+
merge_commit INTEGER DEFAULT 0,
|
|
32
|
+
insertions INTEGER DEFAULT 0,
|
|
33
|
+
deletions INTEGER DEFAULT 0,
|
|
34
|
+
files_changed INTEGER DEFAULT 0
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
CREATE TABLE IF NOT EXISTS commit_files (
|
|
38
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
39
|
+
commit_hash TEXT,
|
|
40
|
+
file_path TEXT,
|
|
41
|
+
status TEXT,
|
|
42
|
+
insertions INTEGER DEFAULT 0,
|
|
43
|
+
deletions INTEGER DEFAULT 0,
|
|
44
|
+
old_path TEXT
|
|
45
|
+
);
|
|
46
|
+
CREATE INDEX IF NOT EXISTS idx_commit_files_hash ON commit_files(commit_hash);
|
|
47
|
+
CREATE INDEX IF NOT EXISTS idx_commit_files_path ON commit_files(file_path);
|
|
48
|
+
|
|
49
|
+
CREATE TABLE IF NOT EXISTS branches (
|
|
50
|
+
name TEXT PRIMARY KEY,
|
|
51
|
+
head_hash TEXT,
|
|
52
|
+
created_at TEXT,
|
|
53
|
+
is_active INTEGER DEFAULT 1
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
CREATE TABLE IF NOT EXISTS tags (
|
|
57
|
+
name TEXT PRIMARY KEY,
|
|
58
|
+
hash TEXT,
|
|
59
|
+
timestamp TEXT,
|
|
60
|
+
message TEXT
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
-- Layer 2: Derived Analytics
|
|
64
|
+
CREATE TABLE IF NOT EXISTS file_evolution (
|
|
65
|
+
file_path TEXT PRIMARY KEY,
|
|
66
|
+
first_seen TEXT,
|
|
67
|
+
last_modified TEXT,
|
|
68
|
+
total_commits INTEGER DEFAULT 0,
|
|
69
|
+
total_churn INTEGER DEFAULT 0,
|
|
70
|
+
current_size INTEGER DEFAULT 0,
|
|
71
|
+
growth_rate REAL DEFAULT 0
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
CREATE TABLE IF NOT EXISTS churn_hotspots (
|
|
75
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
76
|
+
file_path TEXT,
|
|
77
|
+
period TEXT,
|
|
78
|
+
commits INTEGER DEFAULT 0,
|
|
79
|
+
insertions INTEGER DEFAULT 0,
|
|
80
|
+
deletions INTEGER DEFAULT 0,
|
|
81
|
+
unique_authors INTEGER DEFAULT 0
|
|
82
|
+
);
|
|
83
|
+
CREATE INDEX IF NOT EXISTS idx_churn_path ON churn_hotspots(file_path);
|
|
84
|
+
|
|
85
|
+
CREATE TABLE IF NOT EXISTS coupling (
|
|
86
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
87
|
+
file_a TEXT,
|
|
88
|
+
file_b TEXT,
|
|
89
|
+
co_commit_count INTEGER DEFAULT 0,
|
|
90
|
+
coupling_score REAL DEFAULT 0
|
|
91
|
+
);
|
|
92
|
+
CREATE INDEX IF NOT EXISTS idx_coupling_a ON coupling(file_a);
|
|
93
|
+
CREATE INDEX IF NOT EXISTS idx_coupling_b ON coupling(file_b);
|
|
94
|
+
|
|
95
|
+
CREATE TABLE IF NOT EXISTS trends (
|
|
96
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
97
|
+
metric_name TEXT,
|
|
98
|
+
period TEXT,
|
|
99
|
+
value REAL,
|
|
100
|
+
delta REAL,
|
|
101
|
+
direction TEXT
|
|
102
|
+
);
|
|
103
|
+
CREATE INDEX IF NOT EXISTS idx_trends_metric ON trends(metric_name);
|
|
104
|
+
|
|
105
|
+
CREATE TABLE IF NOT EXISTS decision_points (
|
|
106
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
107
|
+
commit_hash TEXT,
|
|
108
|
+
type TEXT,
|
|
109
|
+
impact_score REAL DEFAULT 0,
|
|
110
|
+
files_affected INTEGER DEFAULT 0
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
CREATE TABLE IF NOT EXISTS author_expertise (
|
|
114
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
115
|
+
author TEXT,
|
|
116
|
+
file_pattern TEXT,
|
|
117
|
+
commit_count INTEGER DEFAULT 0,
|
|
118
|
+
last_touched TEXT,
|
|
119
|
+
expertise_score REAL DEFAULT 0
|
|
120
|
+
);
|
|
121
|
+
CREATE INDEX IF NOT EXISTS idx_expertise_author ON author_expertise(author);
|
|
122
|
+
|
|
123
|
+
-- Layer 3: LLM Enrichment
|
|
124
|
+
CREATE TABLE IF NOT EXISTS enrichments (
|
|
125
|
+
commit_hash TEXT PRIMARY KEY,
|
|
126
|
+
intent TEXT,
|
|
127
|
+
reasoning TEXT,
|
|
128
|
+
category TEXT,
|
|
129
|
+
alternatives_considered TEXT,
|
|
130
|
+
session_context TEXT
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
-- Search Layer
|
|
134
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS history_fts USING fts5(
|
|
135
|
+
hash, type, path, message, detail,
|
|
136
|
+
tokenize='porter unicode61'
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
CREATE TABLE IF NOT EXISTS embeddings (
|
|
140
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
141
|
+
commit_hash TEXT,
|
|
142
|
+
content_type TEXT,
|
|
143
|
+
vector BLOB,
|
|
144
|
+
model TEXT,
|
|
145
|
+
created_at TEXT
|
|
146
|
+
);
|
|
147
|
+
CREATE INDEX IF NOT EXISTS idx_embeddings_hash ON embeddings(commit_hash);
|
|
148
|
+
|
|
149
|
+
CREATE TABLE IF NOT EXISTS embed_queue (
|
|
150
|
+
commit_hash TEXT PRIMARY KEY,
|
|
151
|
+
queued_at TEXT,
|
|
152
|
+
status TEXT DEFAULT 'pending',
|
|
153
|
+
error TEXT
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
-- Metrics Layer
|
|
157
|
+
CREATE TABLE IF NOT EXISTS metric_values (
|
|
158
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
159
|
+
commit_hash TEXT,
|
|
160
|
+
metric_name TEXT,
|
|
161
|
+
value REAL,
|
|
162
|
+
captured_at TEXT
|
|
163
|
+
);
|
|
164
|
+
CREATE INDEX IF NOT EXISTS idx_metric_values_name ON metric_values(metric_name);
|
|
165
|
+
|
|
166
|
+
-- Infrastructure
|
|
167
|
+
CREATE TABLE IF NOT EXISTS schema_meta (
|
|
168
|
+
key TEXT PRIMARY KEY,
|
|
169
|
+
value TEXT
|
|
170
|
+
);
|
|
171
|
+
`);
|
|
172
|
+
db.prepare("INSERT OR REPLACE INTO schema_meta (key, value) VALUES ('schema_version', ?)").run(String(SCHEMA_VERSION));
|
|
173
|
+
}
|
|
174
|
+
function getSchemaVersion(db) {
|
|
175
|
+
try {
|
|
176
|
+
const row = db.prepare("SELECT value FROM schema_meta WHERE key = 'schema_version'").get();
|
|
177
|
+
return row ? parseInt(row.value, 10) : 0;
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
return 0;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/util/db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAEhC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB,MAAM,UAAU,MAAM,CAAC,UAAkB;IACvC,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAC9C,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAChC,EAAE,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;IACjC,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAChC,UAAU,CAAC,EAAE,CAAC,CAAC;IACf,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,UAAkB;IACtC,OAAO,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,UAAU,CAAC,EAAqB;IACvC,MAAM,cAAc,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAC;IAC5C,IAAI,cAAc,IAAI,cAAc;QAAE,OAAO;IAE7C,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsJP,CAAC,CAAC;IAEH,EAAE,CAAC,OAAO,CAAC,8EAA8E,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;AACzH,CAAC;AAED,SAAS,gBAAgB,CAAC,EAAqB;IAC7C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,4DAA4D,CAAC,CAAC,GAAG,EAAmC,CAAC;QAC5H,OAAO,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { existsSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
export function detectProjectType(cwd) {
|
|
4
|
+
if (existsSync(join(cwd, "package.json")))
|
|
5
|
+
return "nodejs";
|
|
6
|
+
if (existsSync(join(cwd, "requirements.txt")) || existsSync(join(cwd, "pyproject.toml")))
|
|
7
|
+
return "python";
|
|
8
|
+
if (existsSync(join(cwd, "Cargo.toml")))
|
|
9
|
+
return "rust";
|
|
10
|
+
if (existsSync(join(cwd, "go.mod")))
|
|
11
|
+
return "go";
|
|
12
|
+
return "generic";
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.js","sourceRoot":"","sources":["../../src/util/detect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI5B,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC3D,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC1G,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC;IACvD,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACjD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|