@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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +335 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/db/queries.d.ts +69 -0
  7. package/dist/db/queries.js +109 -0
  8. package/dist/db/queries.js.map +1 -0
  9. package/dist/db/schema.d.ts +3 -0
  10. package/dist/db/schema.js +84 -0
  11. package/dist/db/schema.js.map +1 -0
  12. package/dist/detect/engine.d.ts +18 -0
  13. package/dist/detect/engine.js +214 -0
  14. package/dist/detect/engine.js.map +1 -0
  15. package/dist/export/formats.d.ts +26 -0
  16. package/dist/export/formats.js +273 -0
  17. package/dist/export/formats.js.map +1 -0
  18. package/dist/git/hooks.d.ts +4 -0
  19. package/dist/git/hooks.js +48 -0
  20. package/dist/git/hooks.js.map +1 -0
  21. package/dist/git/parser.d.ts +15 -0
  22. package/dist/git/parser.js +114 -0
  23. package/dist/git/parser.js.map +1 -0
  24. package/dist/scan/index.d.ts +4 -0
  25. package/dist/scan/index.js +92 -0
  26. package/dist/scan/index.js.map +1 -0
  27. package/dist/scan/store.d.ts +10 -0
  28. package/dist/scan/store.js +87 -0
  29. package/dist/scan/store.js.map +1 -0
  30. package/dist/server/dashboard.d.ts +1 -0
  31. package/dist/server/dashboard.js +115 -0
  32. package/dist/server/dashboard.js.map +1 -0
  33. package/dist/server/index.d.ts +1 -0
  34. package/dist/server/index.js +44 -0
  35. package/dist/server/index.js.map +1 -0
  36. package/dist/server/otel.d.ts +2 -0
  37. package/dist/server/otel.js +67 -0
  38. package/dist/server/otel.js.map +1 -0
  39. package/dist/server/webhook.d.ts +2 -0
  40. package/dist/server/webhook.js +22 -0
  41. package/dist/server/webhook.js.map +1 -0
  42. package/dist/types.d.ts +86 -0
  43. package/dist/types.js +2 -0
  44. package/dist/types.js.map +1 -0
  45. 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
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEzG,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,YAAY,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACxF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,kFAAkF,CAAC;KAC/F,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,uEAAuE;AAEvE,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,2EAA2E,CAAC;KACxF,MAAM,CAAC,oBAAoB,EAAE,qCAAqC,CAAC;KACnE,MAAM,CAAC,eAAe,EAAE,+BAA+B,CAAC;KACxD,MAAM,CAAC,mBAAmB,EAAE,iCAAiC,EAAE,MAAM,CAAC;KACtE,MAAM,CAAC,qBAAqB,EAAE,iCAAiC,CAAC;KAChE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;IACf,cAAc,EAAE,CAAC;IACjB,OAAO,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC;IACjE,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAElD,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACnC,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QAClD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtB,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,IAAI,qBAAqB,CAAC;QAClD,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC;QAC9C,OAAO;IACT,CAAC;IAED,IAAI,MAAM,CAAC,YAAY,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;QAC9D,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAExE,4EAA4E;IAC5E,MAAM,WAAW,GAA2B,EAAE,CAAC;IAC/C,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,EAAE,CAAC;QAC9B,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7D,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;SAC7C,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC;SAChC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;SAC3B,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,IAAI,KAAK,EAAE,CAAC;SAC5C,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,WAAW;IACX,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,iCAAiC,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,YAAY,GAAG,CAAC,CAAC;IAC/F,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,WAAW,YAAY,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,MAAM,CAAC,UAAU,KAAK,CAAC,IAAI,MAAM,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,gCAAgC,MAAM,CAAC,SAAS,mBAAmB,CAAC,CAAC;QACjF,OAAO;IACT,CAAC;IAED,iDAAiD;IACjD,MAAM,SAAS,GAAG,EAAE,CAAC;IACrB,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAElD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;QACnC,KAAK,MAAM,MAAM,IAAI,MAAM,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC;YACjD,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACrE,OAAO,CAAC,GAAG,CACT,KAAK,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,OAAO,GAAG,KAAK,MAAM,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,YAAY,MAAM,IAAI,IAAI,CAC3H,CAAC;QACJ,CAAC;QACD,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;YACtC,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,SAAS,OAAO,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;AAC1D,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,6CAA6C,CAAC;KAC1D,MAAM,CAAC,GAAG,EAAE;IACX,cAAc,EAAE,CAAC;IACjB,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAE7B,IAAI,KAAK,CAAC,YAAY,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;QAClE,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAEnF,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAC3B,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAC7D,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CACtB,EAAE,CAAC;YACF,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC5D,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,KAAK,KAAK,aAAa,GAAG,IAAI,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAC3B,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACjE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YAC7E,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,KAAK,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,KAAK,gBAAgB,GAAG,IAAI,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,uCAAuC,CAAC;KACpD,MAAM,CAAC,eAAe,EAAE,4BAA4B,CAAC;KACrD,MAAM,CAAC,iBAAiB,EAAE,8DAA8D,CAAC;KACzF,MAAM,CAAC,oBAAoB,EAAE,4CAA4C,CAAC;KAC1E,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;IACf,cAAc,EAAE,CAAC;IACjB,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAEnC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;QACnE,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,SAAS,OAAO,CAAC,MAAM,wBAAwB,CAAC,CAAC;IAC7D,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,WAAW,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,YAAY,IAAI,SAAS,EAAE,CAAC,CAAC;QAC5D,OAAO,CAAC,GAAG,CAAC,WAAW,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,YAAY,CAAC,MAAM,cAAc,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,YAAY,GAAG,CAAC,CAAC;QAC9G,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACrE,OAAO,CAAC,GAAG,CAAC,cAAc,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,kBAAkB,CAAC;KAC3B,WAAW,CAAC,0CAA0C,CAAC;KACvD,MAAM,CAAC,CAAC,IAAY,EAAE,EAAE;IACvB,cAAc,EAAE,CAAC;IACjB,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAE/B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,aAAa,CAAC,CAAC;QACzC,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,sBAAsB,MAAM,CAAC,UAAU,IAAI,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,YAAY,IAAI,SAAS,EAAE,CAAC,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IACrE,OAAO,CAAC,GAAG,CAAC,oBAAoB,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,QAAQ,IAAI,MAAM,EAAE,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC5B,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,sBAAsB,MAAM,CAAC,YAAY,CAAC,MAAM,IAAI,CAAC,CAAC;IAClE,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,UAAU,OAAO,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;IAE1E,IAAI,MAAM,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,wCAAwC,CAAC;KACrD,MAAM,CAAC,mBAAmB,EAAE,sCAAsC,EAAE,MAAM,CAAC;KAC3E,MAAM,CAAC,oBAAoB,EAAE,uBAAuB,CAAC;KACrD,MAAM,CAAC,qBAAqB,EAAE,iCAAiC,CAAC;KAChE,MAAM,CAAC,CAAC,IAAyD,EAAE,EAAE;IACpE,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAE/C,IAAI,MAAc,CAAC;IACnB,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACpB,KAAK,KAAK;YACR,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;YAC3B,MAAM;QACR,KAAK,MAAM;YACT,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;YAC5B,MAAM;QACR,KAAK,MAAM;YACT,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;YAC5B,IAAI,CAAC,IAAI,CAAC,MAAM;gBAAE,IAAI,CAAC,MAAM,GAAG,qBAAqB,CAAC;YACtD,MAAM;QACR,KAAK,MAAM,CAAC;QACZ;YACE,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;YAC5B,MAAM;IACV,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAClD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,uDAAuD,CAAC;KACpE,MAAM,CAAC,oBAAoB,EAAE,uBAAuB,CAAC;KACrD,MAAM,CAAC,UAAU,EAAE,wCAAwC,CAAC;KAC5D,MAAM,CAAC,CAAC,IAA0C,EAAE,EAAE;IACrD,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAEhC,MAAM,OAAO,GAAG,uBAAuB,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC;IACzD,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAE7B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG;YACb,MAAM,EAAE,QAAQ;YAChB,OAAO;YACP,YAAY,EAAE,WAAW,MAAM,CAAC,UAAU,OAAO;YACjD,QAAQ,EAAE,iCAAiC,MAAM,CAAC,UAAU,MAAM,MAAM,CAAC,OAAO,CAAC,iBAAiB,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,sBAAsB;SACxJ,CAAC;QACF,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAEzC,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAEzE,IAAI,CAAC;YAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;QAEjD,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,OAAO,MAAM,CAAC,OAAO,CAAC,iBAAiB,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,yBAAyB,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACjK,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CAAC;YAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;QACjD,OAAO,CAAC,KAAK,CAAC,yEAAyE,CAAC,CAAC;QACzF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,uEAAuE;AAEvE,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,0DAA0D,CAAC;KACvE,MAAM,CAAC,WAAW,EAAE,+BAA+B,CAAC;KACpD,MAAM,CAAC,CAAC,IAAuB,EAAE,EAAE;IAClC,cAAc,EAAE,CAAC;IACjB,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,YAAY,EAAE,CAAC;IAC9C,iBAAiB,EAAE,CAAC;IAEpB,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACpC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,sBAAsB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,cAAc,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IAElD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;QAE7B,OAAO,CAAC,GAAG,CAAC,sBAAsB,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,wBAAwB,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;QAExD,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;YAC7D,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9D,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,iEAAiE,CAAC;KAC9E,MAAM,CAAC,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,CAAC;KACxD,MAAM,CAAC,KAAK,EAAE,IAAsB,EAAE,EAAE;IACvC,IAAI,CAAC;QACH,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;QAC1D,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,IAAI,GAAG,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9D,OAAO,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;YAC9D,OAAO,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;YACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,uEAAuE;AAEvE,OAAO;KACJ,OAAO,CAAC,qBAAqB,CAAC;KAC9B,WAAW,CAAC,0DAA0D,CAAC;KACvE,MAAM,CAAC,CAAC,GAAW,EAAE,EAAE;IACtB,cAAc,EAAE,CAAC;IACjB,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACtC,IAAI,SAAS,CAAC,UAAU,GAAG,GAAG,EAAE,CAAC;QAC/B,iBAAiB,EAAE,CAAC;QACpB,YAAY,CAAC;YACX,UAAU,EAAE,MAAM,CAAC,IAAI;YACvB,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,OAAO,EAAE,SAAS,CAAC,OAAO;YAC1B,YAAY,EAAE,SAAS,CAAC,YAAY;YACpC,aAAa,EAAE,SAAS,CAAC,aAAa;YACtC,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,YAAY,EAAE,YAAY;YAC1B,QAAQ,EAAE,IAAI;YACd,UAAU,EAAE,SAAS,CAAC,UAAU;YAChC,OAAO,EAAE,SAAS,CAAC,OAAO;SAC3B,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,2CAA2C;AAC3C,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;IAC7B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -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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"}
@@ -0,0 +1,3 @@
1
+ import Database from "better-sqlite3";
2
+ export declare function getDb(dbPath?: string): Database.Database;
3
+ export declare function closeDb(): void;