@james-wall/codegov 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/LICENSE +21 -0
- package/README.md +83 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +335 -0
- package/dist/cli.js.map +1 -0
- package/dist/db/queries.d.ts +69 -0
- package/dist/db/queries.js +109 -0
- package/dist/db/queries.js.map +1 -0
- package/dist/db/schema.d.ts +3 -0
- package/dist/db/schema.js +84 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/detect/engine.d.ts +18 -0
- package/dist/detect/engine.js +214 -0
- package/dist/detect/engine.js.map +1 -0
- package/dist/export/formats.d.ts +26 -0
- package/dist/export/formats.js +273 -0
- package/dist/export/formats.js.map +1 -0
- package/dist/git/hooks.d.ts +4 -0
- package/dist/git/hooks.js +48 -0
- package/dist/git/hooks.js.map +1 -0
- package/dist/git/parser.d.ts +15 -0
- package/dist/git/parser.js +114 -0
- package/dist/git/parser.js.map +1 -0
- package/dist/scan/index.d.ts +4 -0
- package/dist/scan/index.js +92 -0
- package/dist/scan/index.js.map +1 -0
- package/dist/scan/store.d.ts +10 -0
- package/dist/scan/store.js +87 -0
- package/dist/scan/store.js.map +1 -0
- package/dist/server/dashboard.d.ts +1 -0
- package/dist/server/dashboard.js +115 -0
- package/dist/server/dashboard.js.map +1 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +44 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/otel.d.ts +2 -0
- package/dist/server/otel.js +67 -0
- package/dist/server/otel.js.map +1 -0
- package/dist/server/webhook.d.ts +2 -0
- package/dist/server/webhook.js +22 -0
- package/dist/server/webhook.js.map +1 -0
- package/dist/types.d.ts +86 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 James Wall
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# codegov
|
|
2
|
+
|
|
3
|
+
Know what AI wrote in your codebase.
|
|
4
|
+
|
|
5
|
+
CodeGov scans your git history and detects commits authored by AI coding tools — Claude Code, Cursor, GitHub Copilot, Devin, and Aider — from git metadata alone. No config, no API keys, no agents to install.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
$ npx codegov scan
|
|
9
|
+
|
|
10
|
+
82.3% of commits are AI-authored (283/344)
|
|
11
|
+
Agents: 280 claude-code, 2 copilot, 1 cursor
|
|
12
|
+
|
|
13
|
+
Detected commits:
|
|
14
|
+
c7e2a46 claude-code [Claude Opus 4.6] +0/-22 (95%)
|
|
15
|
+
07d9deb claude-code [Claude Sonnet 4.6] +8/-8 (95%)
|
|
16
|
+
5f90db7 copilot +83/-22 (95%)
|
|
17
|
+
...
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx codegov scan # try it now, no install needed
|
|
24
|
+
npm install -g codegov # or install globally
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Commands
|
|
28
|
+
|
|
29
|
+
### Zero-config (works on any repo)
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
codegov scan # scan full history
|
|
33
|
+
codegov scan --since 3m # last 3 months
|
|
34
|
+
codegov scan --format html # generate shareable HTML report
|
|
35
|
+
codegov stats # agent breakdown + monthly trends
|
|
36
|
+
codegov query --agent cursor --since 90d
|
|
37
|
+
codegov forensics <hash> # deep dive on a single commit
|
|
38
|
+
codegov export --format csv # export for spreadsheets
|
|
39
|
+
codegov export --format sbom # SPDX 2.3 compliance artifact
|
|
40
|
+
codegov share # upload HTML report as a GitHub Gist
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Ongoing monitoring
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
codegov init # install post-commit hook + scan history
|
|
47
|
+
codegov server # start OTEL collector + live dashboard
|
|
48
|
+
codegov server --port 8080 # custom port
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The server accepts OpenTelemetry traces at `POST /v1/traces` (Claude Code natively supports OTEL export) and git commit metadata at `POST /v1/hooks/commit`, then correlates them to build tool-to-commit attribution.
|
|
52
|
+
|
|
53
|
+
## How detection works
|
|
54
|
+
|
|
55
|
+
CodeGov identifies AI-authored commits by matching patterns in git metadata:
|
|
56
|
+
|
|
57
|
+
| Tool | Detection signals |
|
|
58
|
+
|------|------------------|
|
|
59
|
+
| **Claude Code** | `Co-Authored-By: Claude` trailer, `Generated by Claude Code` marker |
|
|
60
|
+
| **Cursor** | `cursor[bot]` author, `cursoragent@cursor.com` co-author, `Made-with: Cursor` trailer |
|
|
61
|
+
| **Copilot** | `copilot@github.com` co-author, `copilot-swe-agent[bot]` author, `Agent-Logs-Url` trailer |
|
|
62
|
+
| **Devin** | `devin-ai-integration[bot]` author email |
|
|
63
|
+
| **Aider** | `aider (model) <aider@aider.chat>` co-author, `aider:` message prefix |
|
|
64
|
+
|
|
65
|
+
Each detection carries a confidence score (0-100%). The threshold is 30% — anything below is classified as human-authored.
|
|
66
|
+
|
|
67
|
+
## Export formats
|
|
68
|
+
|
|
69
|
+
- **JSON** — full audit report with summary + all records
|
|
70
|
+
- **CSV** — tabular, import into any spreadsheet
|
|
71
|
+
- **SBOM** — SPDX 2.3 for compliance workflows
|
|
72
|
+
- **HTML** — dark-themed dashboard, shareable as a standalone file
|
|
73
|
+
|
|
74
|
+
## Use cases
|
|
75
|
+
|
|
76
|
+
- **Engineering leaders**: understand what % of your codebase AI wrote and which tools produce the most merged code
|
|
77
|
+
- **Compliance teams**: generate provenance artifacts for SOC2 auditors asking about AI-generated code
|
|
78
|
+
- **Open source maintainers**: add transparency about AI contributions
|
|
79
|
+
- **Individual devs**: track your own AI tool usage across projects
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
MIT
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { writeFileSync, unlinkSync } from "node:fs";
|
|
4
|
+
import { execFileSync } from "node:child_process";
|
|
5
|
+
import { installHooks } from "./git/hooks.js";
|
|
6
|
+
import { scanHistory, forensics, computeStats } from "./scan/index.js";
|
|
7
|
+
import { queryRecords, readRecords, ensureStoreExists } from "./scan/store.js";
|
|
8
|
+
import { getCommitDetail } from "./git/parser.js";
|
|
9
|
+
import { detectAgent } from "./detect/engine.js";
|
|
10
|
+
import { appendRecord } from "./scan/store.js";
|
|
11
|
+
import { generateAuditReport, exportJson, exportCsv, exportSbom, exportHtml } from "./export/formats.js";
|
|
12
|
+
function requireGitRepo() {
|
|
13
|
+
try {
|
|
14
|
+
execFileSync("git", ["rev-parse", "--git-dir"], { encoding: "utf-8", stdio: "pipe" });
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
console.error("Not a git repository. Run this command inside a git repo.");
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const program = new Command();
|
|
22
|
+
program
|
|
23
|
+
.name("codegov")
|
|
24
|
+
.description("AI code governance — attribution, telemetry, and ROI for AI-assisted development")
|
|
25
|
+
.version("0.1.0");
|
|
26
|
+
// ── Zero-config commands (no server, no SQLite) ─────────────────────
|
|
27
|
+
program
|
|
28
|
+
.command("scan")
|
|
29
|
+
.description("Scan git history for AI-authored commits (zero-config, works on any repo)")
|
|
30
|
+
.option("--since <duration>", "Time period to scan (e.g., 90d, 6m)")
|
|
31
|
+
.option("--path <path>", "Limit scan to a specific path")
|
|
32
|
+
.option("--format <format>", "Output format: text, json, html", "text")
|
|
33
|
+
.option("-o, --output <file>", "Write to file instead of stdout")
|
|
34
|
+
.action((opts) => {
|
|
35
|
+
requireGitRepo();
|
|
36
|
+
console.log("Scanning git history for AI-authored commits...\n");
|
|
37
|
+
const result = scanHistory(opts.since, opts.path);
|
|
38
|
+
if (opts.format === "json") {
|
|
39
|
+
const report = generateAuditReport(opts.since);
|
|
40
|
+
const output = exportJson(report);
|
|
41
|
+
if (opts.output) {
|
|
42
|
+
writeFileSync(opts.output, output);
|
|
43
|
+
console.log(`Report written to ${opts.output}`);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
console.log(output);
|
|
47
|
+
}
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (opts.format === "html") {
|
|
51
|
+
const report = generateAuditReport(opts.since);
|
|
52
|
+
const output = exportHtml(report);
|
|
53
|
+
const file = opts.output ?? "codegov-report.html";
|
|
54
|
+
writeFileSync(file, output);
|
|
55
|
+
console.log(`HTML report written to ${file}`);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (result.totalCommits === 0) {
|
|
59
|
+
console.log("No commits found. Are you in a git repository?");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const pct = ((result.aiCommits / result.totalCommits) * 100).toFixed(1);
|
|
63
|
+
// Agent breakdown from all stored records (includes new ones just appended)
|
|
64
|
+
const agentCounts = {};
|
|
65
|
+
for (const r of readRecords()) {
|
|
66
|
+
agentCounts[r.agentId] = (agentCounts[r.agentId] || 0) + 1;
|
|
67
|
+
}
|
|
68
|
+
const agentSummary = Object.entries(agentCounts)
|
|
69
|
+
.filter(([, count]) => count > 0)
|
|
70
|
+
.sort((a, b) => b[1] - a[1])
|
|
71
|
+
.map(([agent, count]) => `${count} ${agent}`)
|
|
72
|
+
.join(", ");
|
|
73
|
+
// Headline
|
|
74
|
+
console.log(`${pct}% of commits are AI-authored (${result.aiCommits}/${result.totalCommits})`);
|
|
75
|
+
if (agentSummary) {
|
|
76
|
+
console.log(`Agents: ${agentSummary}`);
|
|
77
|
+
}
|
|
78
|
+
if (result.newRecords === 0 && result.aiCommits > 0) {
|
|
79
|
+
console.log(`\n(no new AI commits found — ${result.aiCommits} already tracked)`);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
// Show up to 15 commits, then summarize the rest
|
|
83
|
+
const MAX_SHOWN = 15;
|
|
84
|
+
const toShow = result.records.slice(0, MAX_SHOWN);
|
|
85
|
+
if (toShow.length > 0) {
|
|
86
|
+
console.log(`\nDetected commits:`);
|
|
87
|
+
for (const record of toShow) {
|
|
88
|
+
const conf = Math.round(record.confidence * 100);
|
|
89
|
+
const model = record.modelVersion ? ` [${record.modelVersion}]` : "";
|
|
90
|
+
console.log(` ${record.commitHash.slice(0, 7)} ${record.agentId}${model} +${record.linesAdded}/-${record.linesRemoved} (${conf}%)`);
|
|
91
|
+
}
|
|
92
|
+
if (result.records.length > MAX_SHOWN) {
|
|
93
|
+
console.log(` ... and ${result.records.length - MAX_SHOWN} more`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
console.log(`\nResults saved to .codegov/events.jsonl`);
|
|
97
|
+
});
|
|
98
|
+
program
|
|
99
|
+
.command("stats")
|
|
100
|
+
.description("Show summary statistics of AI-authored code")
|
|
101
|
+
.action(() => {
|
|
102
|
+
requireGitRepo();
|
|
103
|
+
const stats = computeStats();
|
|
104
|
+
if (stats.totalCommits === 0) {
|
|
105
|
+
console.log("No commit history found. Run 'codegov scan' first.");
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
console.log("CodeGov Statistics\n");
|
|
109
|
+
console.log(`Total commits: ${stats.totalCommits}`);
|
|
110
|
+
console.log(`AI-authored: ${stats.aiCommits} (${stats.aiPercentage.toFixed(1)}%)`);
|
|
111
|
+
if (Object.keys(stats.byAgent).length > 0) {
|
|
112
|
+
console.log(`\nBy Agent:`);
|
|
113
|
+
for (const [agent, count] of Object.entries(stats.byAgent).sort((a, b) => b[1] - a[1])) {
|
|
114
|
+
const pct = ((count / stats.totalCommits) * 100).toFixed(1);
|
|
115
|
+
console.log(` ${agent}: ${count} commits (${pct}%)`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (Object.keys(stats.byMonth).length > 0) {
|
|
119
|
+
console.log(`\nBy Month:`);
|
|
120
|
+
for (const [month, data] of Object.entries(stats.byMonth).sort()) {
|
|
121
|
+
const pct = data.total > 0 ? ((data.ai / data.total) * 100).toFixed(0) : "0";
|
|
122
|
+
console.log(` ${month}: ${data.ai}/${data.total} AI commits (${pct}%)`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
program
|
|
127
|
+
.command("query")
|
|
128
|
+
.description("Query provenance records with filters")
|
|
129
|
+
.option("--path <path>", "Filter by file path prefix")
|
|
130
|
+
.option("--agent <agent>", "Filter by agent (claude-code, cursor, copilot, devin, aider)")
|
|
131
|
+
.option("--since <duration>", "Filter by time (e.g., 90d, 6m, 2024-01-01)")
|
|
132
|
+
.action((opts) => {
|
|
133
|
+
requireGitRepo();
|
|
134
|
+
const records = queryRecords(opts);
|
|
135
|
+
if (records.length === 0) {
|
|
136
|
+
console.log("No matching records found.");
|
|
137
|
+
console.log("Run 'codegov scan' first to populate the event log.");
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
console.log(`Found ${records.length} matching record(s):\n`);
|
|
141
|
+
for (const record of records) {
|
|
142
|
+
console.log(`Commit: ${record.commitHash.slice(0, 7)}`);
|
|
143
|
+
console.log(` Agent: ${record.agentId}`);
|
|
144
|
+
console.log(` Model: ${record.modelVersion || "unknown"}`);
|
|
145
|
+
console.log(` Time: ${record.timestamp}`);
|
|
146
|
+
console.log(` Files: ${record.filesChanged.length} changed (+${record.linesAdded}/-${record.linesRemoved})`);
|
|
147
|
+
console.log(` Confidence: ${Math.round(record.confidence * 100)}%`);
|
|
148
|
+
console.log(` Signals: ${record.signals.join(", ")}`);
|
|
149
|
+
console.log("");
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
program
|
|
153
|
+
.command("forensics <hash>")
|
|
154
|
+
.description("Show full provenance record for a commit")
|
|
155
|
+
.action((hash) => {
|
|
156
|
+
requireGitRepo();
|
|
157
|
+
const record = forensics(hash);
|
|
158
|
+
if (!record) {
|
|
159
|
+
console.log(`Commit ${hash} not found.`);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
console.log(`Provenance Record: ${record.commitHash}\n`);
|
|
163
|
+
console.log(` Agent: ${record.agentId}`);
|
|
164
|
+
console.log(` Model: ${record.modelVersion || "unknown"}`);
|
|
165
|
+
console.log(` Timestamp: ${record.timestamp}`);
|
|
166
|
+
console.log(` Confidence: ${Math.round(record.confidence * 100)}%`);
|
|
167
|
+
console.log(` Review Status: ${record.reviewStatus}`);
|
|
168
|
+
console.log(` Reviewer: ${record.reviewer || "none"}`);
|
|
169
|
+
console.log(`\n Signals:`);
|
|
170
|
+
for (const signal of record.signals) {
|
|
171
|
+
console.log(` - ${signal}`);
|
|
172
|
+
}
|
|
173
|
+
console.log(`\n Files Changed (${record.filesChanged.length}):`);
|
|
174
|
+
for (const file of record.filesChanged) {
|
|
175
|
+
console.log(` ${file}`);
|
|
176
|
+
}
|
|
177
|
+
console.log(`\n Lines: +${record.linesAdded} / -${record.linesRemoved}`);
|
|
178
|
+
if (record.agentId === "human") {
|
|
179
|
+
console.log(`\n Note: No AI authorship signals detected for this commit.`);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
program
|
|
183
|
+
.command("export")
|
|
184
|
+
.description("Export audit report in various formats")
|
|
185
|
+
.option("--format <format>", "Output format: json, csv, sbom, html", "json")
|
|
186
|
+
.option("--since <duration>", "Filter by time period")
|
|
187
|
+
.option("-o, --output <file>", "Write to file instead of stdout")
|
|
188
|
+
.action((opts) => {
|
|
189
|
+
const report = generateAuditReport(opts.since);
|
|
190
|
+
let output;
|
|
191
|
+
switch (opts.format) {
|
|
192
|
+
case "csv":
|
|
193
|
+
output = exportCsv(report);
|
|
194
|
+
break;
|
|
195
|
+
case "sbom":
|
|
196
|
+
output = exportSbom(report);
|
|
197
|
+
break;
|
|
198
|
+
case "html":
|
|
199
|
+
output = exportHtml(report);
|
|
200
|
+
if (!opts.output)
|
|
201
|
+
opts.output = "codegov-report.html";
|
|
202
|
+
break;
|
|
203
|
+
case "json":
|
|
204
|
+
default:
|
|
205
|
+
output = exportJson(report);
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
if (opts.output) {
|
|
209
|
+
writeFileSync(opts.output, output);
|
|
210
|
+
console.log(`Report written to ${opts.output}`);
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
console.log(output);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
program
|
|
217
|
+
.command("share")
|
|
218
|
+
.description("Generate an HTML report and share it as a GitHub Gist")
|
|
219
|
+
.option("--since <duration>", "Filter by time period")
|
|
220
|
+
.option("--public", "Make the Gist public (default: secret)")
|
|
221
|
+
.action((opts) => {
|
|
222
|
+
const report = generateAuditReport(opts.since);
|
|
223
|
+
const html = exportHtml(report);
|
|
224
|
+
const tmpFile = `/tmp/codegov-report-${Date.now()}.html`;
|
|
225
|
+
writeFileSync(tmpFile, html);
|
|
226
|
+
try {
|
|
227
|
+
const ghArgs = [
|
|
228
|
+
"gist", "create",
|
|
229
|
+
tmpFile,
|
|
230
|
+
"--filename", `codegov-${report.repository}.html`,
|
|
231
|
+
"--desc", `CodeGov provenance report for ${report.repository} — ${report.summary.aiAuthoredCommits}/${report.summary.totalCommits} AI-authored commits`,
|
|
232
|
+
];
|
|
233
|
+
if (opts.public)
|
|
234
|
+
ghArgs.push("--public");
|
|
235
|
+
const gistUrl = execFileSync("gh", ghArgs, { encoding: "utf-8" }).trim();
|
|
236
|
+
try {
|
|
237
|
+
unlinkSync(tmpFile);
|
|
238
|
+
}
|
|
239
|
+
catch { /* noop */ }
|
|
240
|
+
console.log(`\nReport shared!`);
|
|
241
|
+
console.log(` Gist: ${gistUrl}`);
|
|
242
|
+
console.log(`\n ${report.summary.aiAuthoredCommits}/${report.summary.totalCommits} commits AI-authored (${report.summary.aiAuthoredPercentage.toFixed(1)}%)`);
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
try {
|
|
246
|
+
unlinkSync(tmpFile);
|
|
247
|
+
}
|
|
248
|
+
catch { /* noop */ }
|
|
249
|
+
console.error("Failed to create Gist. Make sure gh CLI is installed and authenticated.");
|
|
250
|
+
process.exit(1);
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
// ── Setup + server commands ─────────────────────────────────────────
|
|
254
|
+
program
|
|
255
|
+
.command("init")
|
|
256
|
+
.description("Install git hooks, initialize tracking, and scan history")
|
|
257
|
+
.option("--no-scan", "Skip the initial history scan")
|
|
258
|
+
.action((opts) => {
|
|
259
|
+
requireGitRepo();
|
|
260
|
+
const { installed, skipped } = installHooks();
|
|
261
|
+
ensureStoreExists();
|
|
262
|
+
console.log("CodeGov initialized.");
|
|
263
|
+
if (installed.length > 0) {
|
|
264
|
+
console.log(` Installed hooks: ${installed.join(", ")}`);
|
|
265
|
+
}
|
|
266
|
+
if (skipped.length > 0) {
|
|
267
|
+
console.log(` Skipped: ${skipped.join(", ")}`);
|
|
268
|
+
}
|
|
269
|
+
console.log(" Event log: .codegov/events.jsonl");
|
|
270
|
+
if (opts.scan) {
|
|
271
|
+
console.log("\nScanning git history...\n");
|
|
272
|
+
const result = scanHistory();
|
|
273
|
+
console.log(` Commits scanned: ${result.totalCommits}`);
|
|
274
|
+
console.log(` AI-authored found: ${result.aiCommits}`);
|
|
275
|
+
if (result.records.length > 0) {
|
|
276
|
+
const agents = new Set(result.records.map((r) => r.agentId));
|
|
277
|
+
console.log(` Agents detected: ${[...agents].join(", ")}`);
|
|
278
|
+
}
|
|
279
|
+
console.log("\nRun 'codegov stats' for full breakdown.");
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
program
|
|
283
|
+
.command("server")
|
|
284
|
+
.description("Start the CodeGov collector server (OTEL + webhook + dashboard)")
|
|
285
|
+
.option("-p, --port <port>", "Port to listen on", "4318")
|
|
286
|
+
.action(async (opts) => {
|
|
287
|
+
try {
|
|
288
|
+
const { startServer } = await import("./server/index.js");
|
|
289
|
+
startServer(parseInt(opts.port, 10));
|
|
290
|
+
}
|
|
291
|
+
catch (err) {
|
|
292
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
293
|
+
if (msg.includes("better-sqlite3") || msg.includes("express")) {
|
|
294
|
+
console.error("The server requires additional dependencies.");
|
|
295
|
+
console.error("Run: npm install better-sqlite3 express");
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
298
|
+
throw err;
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
// ── Internal command (used by git hook) ─────────────────────────────
|
|
302
|
+
program
|
|
303
|
+
.command("record-commit <ref>")
|
|
304
|
+
.description("Record provenance for a single commit (used by git hook)")
|
|
305
|
+
.action((ref) => {
|
|
306
|
+
requireGitRepo();
|
|
307
|
+
const commit = getCommitDetail(ref);
|
|
308
|
+
if (!commit) {
|
|
309
|
+
process.exit(1);
|
|
310
|
+
}
|
|
311
|
+
const detection = detectAgent(commit);
|
|
312
|
+
if (detection.confidence > 0.3) {
|
|
313
|
+
ensureStoreExists();
|
|
314
|
+
appendRecord({
|
|
315
|
+
commitHash: commit.hash,
|
|
316
|
+
timestamp: commit.timestamp,
|
|
317
|
+
agentId: detection.agentId,
|
|
318
|
+
modelVersion: detection.modelVersion,
|
|
319
|
+
promptSummary: detection.promptSummary,
|
|
320
|
+
filesChanged: commit.filesChanged,
|
|
321
|
+
linesAdded: commit.linesAdded,
|
|
322
|
+
linesRemoved: commit.linesRemoved,
|
|
323
|
+
reviewStatus: "unreviewed",
|
|
324
|
+
reviewer: null,
|
|
325
|
+
confidence: detection.confidence,
|
|
326
|
+
signals: detection.signals,
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
// Default to scan when no subcommand given
|
|
331
|
+
if (process.argv.length <= 2) {
|
|
332
|
+
process.argv.push("scan");
|
|
333
|
+
}
|
|
334
|
+
program.parse();
|
|
335
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export interface ToolEventInsert {
|
|
2
|
+
tool: string;
|
|
3
|
+
developer: string;
|
|
4
|
+
timestamp: string;
|
|
5
|
+
event_type: string;
|
|
6
|
+
file_path?: string;
|
|
7
|
+
lines_added?: number;
|
|
8
|
+
lines_removed?: number;
|
|
9
|
+
model?: string;
|
|
10
|
+
tokens_in?: number;
|
|
11
|
+
tokens_out?: number;
|
|
12
|
+
cost_usd?: number;
|
|
13
|
+
session_id?: string;
|
|
14
|
+
raw_span?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface CommitInsert {
|
|
17
|
+
hash: string;
|
|
18
|
+
author: string;
|
|
19
|
+
timestamp: string;
|
|
20
|
+
repo?: string;
|
|
21
|
+
branch?: string;
|
|
22
|
+
message?: string;
|
|
23
|
+
total_additions?: number;
|
|
24
|
+
total_deletions?: number;
|
|
25
|
+
files: Array<{
|
|
26
|
+
path: string;
|
|
27
|
+
additions: number;
|
|
28
|
+
deletions: number;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
export declare function insertToolEvent(event: ToolEventInsert): number;
|
|
32
|
+
export declare function insertCommit(commit: CommitInsert): void;
|
|
33
|
+
export declare function correlateCommit(commitHash: string, windowMinutes?: number): void;
|
|
34
|
+
export interface DashboardMetrics {
|
|
35
|
+
totalEvents: number;
|
|
36
|
+
totalCommits: number;
|
|
37
|
+
totalAttributions: number;
|
|
38
|
+
eventsByTool: Array<{
|
|
39
|
+
tool: string;
|
|
40
|
+
count: number;
|
|
41
|
+
}>;
|
|
42
|
+
recentEvents: Array<{
|
|
43
|
+
id: number;
|
|
44
|
+
tool: string;
|
|
45
|
+
developer: string;
|
|
46
|
+
timestamp: string;
|
|
47
|
+
event_type: string;
|
|
48
|
+
file_path: string | null;
|
|
49
|
+
}>;
|
|
50
|
+
recentCommits: Array<{
|
|
51
|
+
hash: string;
|
|
52
|
+
author: string;
|
|
53
|
+
timestamp: string;
|
|
54
|
+
message: string | null;
|
|
55
|
+
total_additions: number;
|
|
56
|
+
total_deletions: number;
|
|
57
|
+
}>;
|
|
58
|
+
attributionsByTool: Array<{
|
|
59
|
+
tool: string;
|
|
60
|
+
confidence: string;
|
|
61
|
+
count: number;
|
|
62
|
+
}>;
|
|
63
|
+
devActivity: Array<{
|
|
64
|
+
developer: string;
|
|
65
|
+
events: number;
|
|
66
|
+
commits: number;
|
|
67
|
+
}>;
|
|
68
|
+
}
|
|
69
|
+
export declare function getDashboardMetrics(days?: number): DashboardMetrics;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { getDb } from "./schema.js";
|
|
2
|
+
export function insertToolEvent(event) {
|
|
3
|
+
const db = getDb();
|
|
4
|
+
const stmt = db.prepare(`
|
|
5
|
+
INSERT INTO tool_events (tool, developer, timestamp, event_type, file_path,
|
|
6
|
+
lines_added, lines_removed, model, tokens_in, tokens_out, cost_usd, session_id, raw_span)
|
|
7
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
8
|
+
`);
|
|
9
|
+
const result = stmt.run(event.tool, event.developer, event.timestamp, event.event_type, event.file_path ?? null, event.lines_added ?? 0, event.lines_removed ?? 0, event.model ?? null, event.tokens_in ?? 0, event.tokens_out ?? 0, event.cost_usd ?? 0, event.session_id ?? null, event.raw_span ?? null);
|
|
10
|
+
return Number(result.lastInsertRowid);
|
|
11
|
+
}
|
|
12
|
+
export function insertCommit(commit) {
|
|
13
|
+
const db = getDb();
|
|
14
|
+
const commitStmt = db.prepare(`
|
|
15
|
+
INSERT OR IGNORE INTO commits (hash, author, timestamp, repo, branch, message, total_additions, total_deletions)
|
|
16
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
17
|
+
`);
|
|
18
|
+
const fileStmt = db.prepare(`
|
|
19
|
+
INSERT INTO commit_files (commit_hash, file_path, additions, deletions)
|
|
20
|
+
VALUES (?, ?, ?, ?)
|
|
21
|
+
`);
|
|
22
|
+
const transaction = db.transaction(() => {
|
|
23
|
+
commitStmt.run(commit.hash, commit.author, commit.timestamp, commit.repo ?? null, commit.branch ?? null, commit.message ?? null, commit.total_additions ?? 0, commit.total_deletions ?? 0);
|
|
24
|
+
for (const file of commit.files) {
|
|
25
|
+
fileStmt.run(commit.hash, file.path, file.additions, file.deletions);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
transaction();
|
|
29
|
+
}
|
|
30
|
+
function insertAttribution(attr) {
|
|
31
|
+
const db = getDb();
|
|
32
|
+
const stmt = db.prepare(`
|
|
33
|
+
INSERT INTO attributions (commit_hash, tool_event_id, tool, developer, file_path, confidence, method)
|
|
34
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
35
|
+
`);
|
|
36
|
+
stmt.run(attr.commit_hash, attr.tool_event_id, attr.tool, attr.developer, attr.file_path ?? null, attr.confidence, attr.method);
|
|
37
|
+
}
|
|
38
|
+
const DEFAULT_WINDOW_MINUTES = 30;
|
|
39
|
+
export function correlateCommit(commitHash, windowMinutes = DEFAULT_WINDOW_MINUTES) {
|
|
40
|
+
const db = getDb();
|
|
41
|
+
const commit = db.prepare("SELECT * FROM commits WHERE hash = ?").get(commitHash);
|
|
42
|
+
if (!commit)
|
|
43
|
+
return;
|
|
44
|
+
const commitFiles = db.prepare("SELECT * FROM commit_files WHERE commit_hash = ?").all(commitHash);
|
|
45
|
+
for (const file of commitFiles) {
|
|
46
|
+
const matchingEvents = db.prepare(`
|
|
47
|
+
SELECT id, tool, developer, file_path FROM tool_events
|
|
48
|
+
WHERE developer = ?
|
|
49
|
+
AND file_path = ?
|
|
50
|
+
AND datetime(timestamp) BETWEEN datetime(?, '-${windowMinutes} minutes') AND datetime(?)
|
|
51
|
+
ORDER BY timestamp DESC
|
|
52
|
+
`).all(commit.author, file.file_path, commit.timestamp, commit.timestamp);
|
|
53
|
+
if (matchingEvents.length === 0)
|
|
54
|
+
continue;
|
|
55
|
+
const confidence = matchingEvents.length === 1 ? "high" : "low";
|
|
56
|
+
for (const event of matchingEvents) {
|
|
57
|
+
insertAttribution({
|
|
58
|
+
commit_hash: commitHash,
|
|
59
|
+
tool_event_id: event.id,
|
|
60
|
+
tool: event.tool,
|
|
61
|
+
developer: event.developer,
|
|
62
|
+
file_path: file.file_path,
|
|
63
|
+
confidence,
|
|
64
|
+
method: "file_time_window",
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export function getDashboardMetrics(days = 30) {
|
|
70
|
+
const db = getDb();
|
|
71
|
+
const since = new Date(Date.now() - days * 86400000).toISOString();
|
|
72
|
+
const totalEvents = db.prepare("SELECT COUNT(*) as count FROM tool_events WHERE timestamp >= ?").get(since).count;
|
|
73
|
+
const totalCommits = db.prepare("SELECT COUNT(*) as count FROM commits WHERE timestamp >= ?").get(since).count;
|
|
74
|
+
const totalAttributions = db.prepare("SELECT COUNT(*) as count FROM attributions WHERE created_at >= ?").get(since).count;
|
|
75
|
+
const eventsByTool = db.prepare(`
|
|
76
|
+
SELECT tool, COUNT(*) as count FROM tool_events
|
|
77
|
+
WHERE timestamp >= ? GROUP BY tool ORDER BY count DESC
|
|
78
|
+
`).all(since);
|
|
79
|
+
const recentEvents = db.prepare(`
|
|
80
|
+
SELECT id, tool, developer, timestamp, event_type, file_path
|
|
81
|
+
FROM tool_events ORDER BY timestamp DESC LIMIT 20
|
|
82
|
+
`).all();
|
|
83
|
+
const recentCommits = db.prepare(`
|
|
84
|
+
SELECT hash, author, timestamp, message, total_additions, total_deletions
|
|
85
|
+
FROM commits ORDER BY timestamp DESC LIMIT 20
|
|
86
|
+
`).all();
|
|
87
|
+
const attributionsByTool = db.prepare(`
|
|
88
|
+
SELECT tool, confidence, COUNT(*) as count FROM attributions
|
|
89
|
+
WHERE created_at >= ? GROUP BY tool, confidence ORDER BY count DESC
|
|
90
|
+
`).all(since);
|
|
91
|
+
const devActivity = db.prepare(`
|
|
92
|
+
SELECT developer, COUNT(*) as events, 0 as commits FROM tool_events
|
|
93
|
+
WHERE timestamp >= ? GROUP BY developer
|
|
94
|
+
`).all(since);
|
|
95
|
+
const commitCounts = db.prepare(`
|
|
96
|
+
SELECT author as developer, COUNT(*) as commits FROM commits
|
|
97
|
+
WHERE timestamp >= ? GROUP BY author
|
|
98
|
+
`).all(since);
|
|
99
|
+
const commitMap = new Map(commitCounts.map(c => [c.developer, c.commits]));
|
|
100
|
+
for (const dev of devActivity) {
|
|
101
|
+
dev.commits = commitMap.get(dev.developer) ?? 0;
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
totalEvents, totalCommits, totalAttributions,
|
|
105
|
+
eventsByTool, recentEvents, recentCommits,
|
|
106
|
+
attributionsByTool, devActivity,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=queries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/db/queries.ts"],"names":[],"mappings":"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"}
|