@brela-dev/cli 0.1.0-alpha.1

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/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # @brela-dev/cli
2
+
3
+ CLI for [Brela](https://github.com/kaustubhsaxena/brela) — set up AI code attribution in any project with one command.
4
+
5
+ Brela runs silently in the background and tracks which AI tools wrote which lines: GitHub Copilot, Claude Code, Cursor, Windsurf, Cline, Aider, Continue, and more. All data stays local — nothing leaves your machine.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install -g @brela-dev/cli
11
+ ```
12
+
13
+ ## Commands
14
+
15
+ ### `brela init`
16
+
17
+ One-command project setup. Run once in your project root:
18
+
19
+ ```bash
20
+ cd your-repo
21
+ brela init
22
+ ```
23
+
24
+ What it does:
25
+ - Adds shell wrappers to `.zshrc` / `.bashrc` so `claude` and `gh copilot` log intent before running
26
+ - Installs the `brela-vscode` VS Code extension
27
+ - Starts the background daemon that watches for agent file writes
28
+ - Creates `.brela/` session directory and git pre-commit hook
29
+
30
+ ### `brela report`
31
+
32
+ Print an AI attribution breakdown:
33
+
34
+ ```bash
35
+ brela report # today
36
+ brela report --days 7 # last 7 days
37
+ brela report --from 2024-01-01 --to 2024-01-31
38
+ ```
39
+
40
+ ### `brela explain <file>`
41
+
42
+ Full attribution history for a specific file:
43
+
44
+ ```bash
45
+ brela explain src/utils/api.ts
46
+ brela explain src/utils/api.ts --days 30
47
+ brela explain src/utils/api.ts --json
48
+ brela explain src/utils/api.ts --since 2026-03-01
49
+ ```
50
+
51
+ Shows:
52
+ - Attribution summary (tools, events, chars inserted)
53
+ - Timeline of every AI event in that file
54
+ - Risk assessment (unreviewed AI sections, test coverage)
55
+
56
+ ### `brela daemon`
57
+
58
+ Control the background file-watcher daemon:
59
+
60
+ ```bash
61
+ brela daemon start
62
+ brela daemon stop
63
+ brela daemon status
64
+ ```
65
+
66
+ Started automatically by `brela init`.
67
+
68
+ ### `brela hook`
69
+
70
+ Manually install or uninstall git hooks:
71
+
72
+ ```bash
73
+ brela hook install
74
+ brela hook uninstall
75
+ ```
76
+
77
+ ## Session data
78
+
79
+ All data is local to your project under `.brela/` (gitignored automatically):
80
+
81
+ ```
82
+ .brela/
83
+ sessions/ # NDJSON attribution log, one file per day
84
+ shell-intents.jsonl # written by shell wrappers before AI CLI runs
85
+ daemon.pid
86
+ ```
87
+
88
+ ## Part of Brela
89
+
90
+ See the [root repo](https://github.com/kaustubhsaxena/brela) for the VS Code extension and full documentation.
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function daemonCommand(): Command;
3
+ //# sourceMappingURL=daemon-cmd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon-cmd.d.ts","sourceRoot":"","sources":["../../src/commands/daemon-cmd.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+FpC,wBAAgB,aAAa,IAAI,OAAO,CAcvC"}
@@ -0,0 +1,94 @@
1
+ import { spawn } from 'node:child_process';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { Command } from 'commander';
6
+ import { BrelaExit } from '../errors.js';
7
+ const PID_FILE = '.brela/daemon.pid';
8
+ // Resolve the daemon entry point relative to this file's compiled location.
9
+ // Layout: packages/cli/dist/commands/ → ../../.. → packages/ → daemon/dist/daemon.js
10
+ function daemonScriptPath() {
11
+ const here = path.dirname(fileURLToPath(import.meta.url));
12
+ return path.resolve(here, '..', '..', '..', 'daemon', 'dist', 'daemon.js');
13
+ }
14
+ function pidPath(projectRoot) {
15
+ return path.join(projectRoot, PID_FILE);
16
+ }
17
+ function readPid(projectRoot) {
18
+ const p = pidPath(projectRoot);
19
+ if (!fs.existsSync(p))
20
+ return null;
21
+ const raw = fs.readFileSync(p, 'utf8').trim();
22
+ const n = parseInt(raw, 10);
23
+ return isNaN(n) ? null : n;
24
+ }
25
+ function isRunning(pid) {
26
+ try {
27
+ // Signal 0 checks existence without sending a real signal
28
+ process.kill(pid, 0);
29
+ return true;
30
+ }
31
+ catch {
32
+ return false;
33
+ }
34
+ }
35
+ function startDaemon(projectRoot) {
36
+ const script = daemonScriptPath();
37
+ if (!fs.existsSync(script)) {
38
+ throw new BrelaExit(1, `Brela: daemon script not found at ${script}\n` +
39
+ `Run "npm run build" in packages/daemon first.`);
40
+ }
41
+ const existingPid = readPid(projectRoot);
42
+ if (existingPid !== null && isRunning(existingPid)) {
43
+ console.log(`Brela daemon is already running (PID ${existingPid}).`);
44
+ return;
45
+ }
46
+ // Ensure .brela/ exists before the daemon tries to write into it
47
+ fs.mkdirSync(path.join(projectRoot, '.brela'), { recursive: true });
48
+ const child = spawn(process.execPath, [script, projectRoot], {
49
+ detached: true,
50
+ stdio: 'ignore',
51
+ });
52
+ child.unref();
53
+ // Give the child a moment to start, then record its PID
54
+ const pid = child.pid;
55
+ if (pid === undefined) {
56
+ throw new BrelaExit(1, 'Brela: failed to spawn daemon process.');
57
+ }
58
+ fs.writeFileSync(pidPath(projectRoot), String(pid), 'utf8');
59
+ console.log(`Brela daemon started (PID ${pid}).`);
60
+ }
61
+ function stopDaemon(projectRoot) {
62
+ const pid = readPid(projectRoot);
63
+ if (pid === null) {
64
+ console.log('Brela daemon is not running (no PID file).');
65
+ return;
66
+ }
67
+ if (!isRunning(pid)) {
68
+ fs.rmSync(pidPath(projectRoot), { force: true });
69
+ console.log('Brela daemon was not running. PID file cleaned up.');
70
+ return;
71
+ }
72
+ try {
73
+ process.kill(pid, 'SIGTERM');
74
+ fs.rmSync(pidPath(projectRoot), { force: true });
75
+ console.log(`Brela daemon stopped (PID ${pid}).`);
76
+ }
77
+ catch (err) {
78
+ throw new BrelaExit(1, `Brela: failed to stop daemon — ${String(err)}`);
79
+ }
80
+ }
81
+ // ── Command factory ──────────────────────────────────────────────────────────
82
+ export function daemonCommand() {
83
+ const cmd = new Command('daemon').description('Manage the Brela background watcher');
84
+ cmd
85
+ .command('start')
86
+ .description('Start the daemon in the background')
87
+ .action(() => startDaemon(process.cwd()));
88
+ cmd
89
+ .command('stop')
90
+ .description('Stop the running daemon')
91
+ .action(() => stopDaemon(process.cwd()));
92
+ return cmd;
93
+ }
94
+ //# sourceMappingURL=daemon-cmd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon-cmd.js","sourceRoot":"","sources":["../../src/commands/daemon-cmd.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function explainCommand(): Command;
3
+ //# sourceMappingURL=explain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain.d.ts","sourceRoot":"","sources":["../../src/commands/explain.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0bpC,wBAAgB,cAAc,IAAI,OAAO,CAkBxC"}
@@ -0,0 +1,363 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { Command } from 'commander';
4
+ import { simpleGit } from 'simple-git';
5
+ import { SidecarWriter } from '@brela-dev/core';
6
+ import { logError } from '../errors.js';
7
+ // ── ANSI helpers ──────────────────────────────────────────────────────────────
8
+ const NO_COLOR = !!process.env['NO_COLOR'];
9
+ function c(code, text) {
10
+ if (NO_COLOR)
11
+ return text;
12
+ return `\x1b[${code}m${text}\x1b[0m`;
13
+ }
14
+ const blue = (t) => c('34', t);
15
+ const orange = (t) => c('33', t);
16
+ const purple = (t) => c('35', t);
17
+ const grey = (t) => c('90', t);
18
+ const green = (t) => c('32', t);
19
+ const yellow = (t) => c('33', t);
20
+ const red = (t) => c('31', t);
21
+ const bold = (t) => c('1', t);
22
+ const dim = (t) => c('2', t);
23
+ function toolColour(tool) {
24
+ if (tool.startsWith('COPILOT'))
25
+ return blue;
26
+ if (tool.startsWith('CLAUDE'))
27
+ return orange;
28
+ if (tool.startsWith('CURSOR'))
29
+ return purple;
30
+ if (tool === 'CHATGPT_PASTE')
31
+ return grey;
32
+ if (tool === 'CODEIUM')
33
+ return purple;
34
+ return (t) => t;
35
+ }
36
+ function confidenceDot(confidence) {
37
+ if (confidence === 'high')
38
+ return green('●');
39
+ if (confidence === 'medium')
40
+ return yellow('●');
41
+ return red('●');
42
+ }
43
+ // ── Tool labels ───────────────────────────────────────────────────────────────
44
+ const TOOL_LABELS = {
45
+ COPILOT: 'Copilot',
46
+ COPILOT_AGENT: 'Copilot Agent',
47
+ COPILOT_CLI: 'Copilot CLI',
48
+ CLAUDE_CODE: 'Claude Code',
49
+ CLAUDE_CODE_AGENT: 'Claude Code Agent',
50
+ CURSOR: 'Cursor',
51
+ CURSOR_AGENT: 'Cursor Agent',
52
+ CODEIUM: 'Windsurf/Codeium',
53
+ CLINE: 'Cline',
54
+ AIDER: 'Aider',
55
+ CONTINUE: 'Continue',
56
+ CHATGPT_PASTE: 'ChatGPT Paste',
57
+ GENERIC_AGENT: 'AI Agent',
58
+ UNKNOWN: 'Unknown',
59
+ };
60
+ function label(tool) {
61
+ return TOOL_LABELS[tool] ?? tool;
62
+ }
63
+ // ── Box drawing ───────────────────────────────────────────────────────────────
64
+ const BOX_WIDTH = 56; // inner content width (between borders)
65
+ function header(title) {
66
+ const inner = ` ${title} `.padEnd(BOX_WIDTH);
67
+ return [
68
+ `╔${'═'.repeat(BOX_WIDTH)}╗`,
69
+ `║${inner}║`,
70
+ `╚${'═'.repeat(BOX_WIDTH)}╝`,
71
+ ].join('\n');
72
+ }
73
+ function box(title, lines) {
74
+ const topBar = ` ┌─ ${title} ${'─'.repeat(Math.max(0, BOX_WIDTH - title.length - 4))}┐`;
75
+ const bottomBar = ` └${'─'.repeat(BOX_WIDTH - 1)}┘`;
76
+ const body = lines.map((l) => ` │ ${l.padEnd(BOX_WIDTH - 5)}│`).join('\n');
77
+ return [topBar, body, bottomBar].join('\n');
78
+ }
79
+ async function getReviewInfo(projectRoot, filePath) {
80
+ try {
81
+ const git = simpleGit(projectRoot);
82
+ // Get commits that touched this file
83
+ const log = await git.log({ file: filePath, maxCount: 50 });
84
+ let reviewed = 0;
85
+ let unreviewed = 0;
86
+ for (const commit of log.all) {
87
+ const msg = (commit.message + ' ' + (commit.body ?? '')).toLowerCase();
88
+ if (msg.includes('reviewed-by') ||
89
+ msg.includes('approved-by') ||
90
+ msg.includes('co-authored') ||
91
+ msg.includes('reviewed') ||
92
+ msg.includes('approved')) {
93
+ reviewed++;
94
+ }
95
+ else {
96
+ unreviewed++;
97
+ }
98
+ }
99
+ return { reviewed, unreviewed };
100
+ }
101
+ catch {
102
+ return { reviewed: 0, unreviewed: 0 };
103
+ }
104
+ }
105
+ // ── Project root resolution ───────────────────────────────────────────────────
106
+ async function findProjectRoot(startDir) {
107
+ try {
108
+ const git = simpleGit(startDir);
109
+ const root = await git.revparse(['--show-toplevel']);
110
+ return root.trim();
111
+ }
112
+ catch {
113
+ // Walk up looking for .brela/
114
+ let dir = startDir;
115
+ for (let i = 0; i < 10; i++) {
116
+ if (fs.existsSync(path.join(dir, '.brela')))
117
+ return dir;
118
+ const parent = path.dirname(dir);
119
+ if (parent === dir)
120
+ break;
121
+ dir = parent;
122
+ }
123
+ return startDir;
124
+ }
125
+ }
126
+ // ── Date helpers ──────────────────────────────────────────────────────────────
127
+ function toDateStr(date) {
128
+ return date.toISOString().slice(0, 10);
129
+ }
130
+ function addDays(date, n) {
131
+ const d = new Date(date);
132
+ d.setUTCDate(d.getUTCDate() + n);
133
+ return d;
134
+ }
135
+ // ── File matching ─────────────────────────────────────────────────────────────
136
+ /**
137
+ * Returns true if the stored entry.file matches the target path.
138
+ * Handles: exact match, relative-from-root, and basename match.
139
+ */
140
+ function fileMatches(entryFile, targetRel, targetBase) {
141
+ const norm = entryFile.replace(/\\/g, '/');
142
+ const targetNorm = targetRel.replace(/\\/g, '/');
143
+ if (norm === targetNorm)
144
+ return true;
145
+ // stored as absolute — check suffix
146
+ if (norm.endsWith('/' + targetNorm))
147
+ return true;
148
+ // basename match
149
+ if (path.basename(norm) === targetBase)
150
+ return true;
151
+ return false;
152
+ }
153
+ // ── Main command logic ────────────────────────────────────────────────────────
154
+ async function runExplain(filePath, opts) {
155
+ // 1. Resolve project root
156
+ const cwd = process.cwd();
157
+ const projectRoot = opts.repo
158
+ ? path.resolve(opts.repo)
159
+ : await findProjectRoot(cwd);
160
+ // 2. Resolve file to relative path from project root
161
+ const absFile = path.isAbsolute(filePath)
162
+ ? filePath
163
+ : path.resolve(cwd, filePath);
164
+ const relFile = path.relative(projectRoot, absFile);
165
+ const baseFile = path.basename(relFile);
166
+ // 3. Warn if file doesn't exist on disk (still show historical data)
167
+ const fileExistsOnDisk = fs.existsSync(absFile);
168
+ if (!fileExistsOnDisk && !opts.json) {
169
+ process.stdout.write(yellow('⚠') +
170
+ ` ${relFile} does not exist on disk — showing historical attribution data only.\n\n`);
171
+ }
172
+ // 4. Check .brela/ exists
173
+ const brelaDir = path.join(projectRoot, '.brela');
174
+ if (!fs.existsSync(brelaDir)) {
175
+ process.stdout.write([
176
+ red('✗') + ' No .brela/ directory found in ' + projectRoot,
177
+ '',
178
+ ' Run ' + bold('brela init') + ' to set up attribution tracking in this project.',
179
+ ].join('\n') + '\n');
180
+ return;
181
+ }
182
+ // 5. Compute date range
183
+ const toDate = new Date();
184
+ let fromDate;
185
+ let analysedDays;
186
+ if (opts.since) {
187
+ fromDate = new Date(opts.since);
188
+ analysedDays = Math.ceil((toDate.getTime() - fromDate.getTime()) / 86_400_000);
189
+ }
190
+ else {
191
+ analysedDays = Math.max(1, parseInt(opts.days, 10) || 90);
192
+ fromDate = addDays(toDate, -analysedDays);
193
+ }
194
+ // 6. Read and filter session entries
195
+ const writer = new SidecarWriter(projectRoot);
196
+ const allEntries = writer.readRange(toDateStr(fromDate), toDateStr(toDate));
197
+ const entries = allEntries.filter((e) => fileMatches(e.file, relFile, baseFile));
198
+ // 7. Sort ascending for timeline
199
+ entries.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
200
+ // 8. No data case
201
+ if (entries.length === 0) {
202
+ if (opts.json) {
203
+ process.stdout.write(JSON.stringify({
204
+ file: relFile,
205
+ analysedDays,
206
+ totalEvents: 0,
207
+ totalCharsInserted: 0,
208
+ tools: {},
209
+ confidence: {},
210
+ attributedLineRanges: [],
211
+ timeline: [],
212
+ risk: { unreviewedAISections: 0, reviewedAISections: 0, hasTestCoverageOnAILines: false },
213
+ }, null, 2) + '\n');
214
+ }
215
+ else {
216
+ process.stdout.write(`No attribution data found for ${bold(relFile)} in the last ${analysedDays} days.\n` +
217
+ `Either this file had no AI-assisted edits, or brela was not active.\n`);
218
+ }
219
+ return;
220
+ }
221
+ // 9. Aggregate stats
222
+ const totalChars = entries.reduce((s, e) => s + e.charsInserted, 0);
223
+ const toolCounts = {};
224
+ const confCounts = {};
225
+ for (const e of entries) {
226
+ toolCounts[e.tool] = (toolCounts[e.tool] ?? 0) + 1;
227
+ confCounts[e.confidence] = (confCounts[e.confidence] ?? 0) + 1;
228
+ }
229
+ // Deduplicate + collect line ranges
230
+ const ranges = entries
231
+ .filter((e) => e.linesStart > 0 || e.linesEnd > 0)
232
+ .map((e) => [e.linesStart, e.linesEnd]);
233
+ // 10. Risk signals
234
+ const reviewInfo = await getReviewInfo(projectRoot, relFile);
235
+ const aiSections = entries.length;
236
+ const reviewedSections = Math.min(reviewInfo.reviewed, aiSections);
237
+ const unreviewedSections = Math.max(0, aiSections - reviewedSections);
238
+ // Test coverage: simple heuristic — check if a test file exists for this file
239
+ const stem = path.basename(relFile, path.extname(relFile));
240
+ const possibleTestFiles = [
241
+ path.join(projectRoot, 'src', '__tests__', `${stem}.test.ts`),
242
+ path.join(projectRoot, 'src', `${stem}.test.ts`),
243
+ path.join(projectRoot, 'tests', `${stem}.test.ts`),
244
+ path.join(path.dirname(absFile), '__tests__', `${stem}.test.ts`),
245
+ path.join(path.dirname(absFile), `${stem}.test.ts`),
246
+ path.join(path.dirname(absFile), `${stem}.spec.ts`),
247
+ ];
248
+ const hasTests = possibleTestFiles.some((f) => fs.existsSync(f));
249
+ // 11. Output
250
+ if (opts.json) {
251
+ const out = {
252
+ file: relFile,
253
+ analysedDays,
254
+ totalEvents: entries.length,
255
+ totalCharsInserted: totalChars,
256
+ tools: toolCounts,
257
+ confidence: confCounts,
258
+ attributedLineRanges: ranges,
259
+ timeline: entries.map((e) => ({
260
+ timestamp: e.timestamp,
261
+ tool: e.tool,
262
+ linesStart: e.linesStart,
263
+ linesEnd: e.linesEnd,
264
+ confidence: e.confidence,
265
+ detectionMethod: e.detectionMethod,
266
+ charsInserted: e.charsInserted,
267
+ })),
268
+ risk: {
269
+ unreviewedAISections: unreviewedSections,
270
+ reviewedAISections: reviewedSections,
271
+ hasTestCoverageOnAILines: hasTests,
272
+ },
273
+ };
274
+ process.stdout.write(JSON.stringify(out, null, 2) + '\n');
275
+ return;
276
+ }
277
+ // ── Pretty terminal output ────────────────────────────────────────────────
278
+ // Sessions = distinct dates touched
279
+ const sessionDates = new Set(entries.map((e) => e.timestamp.slice(0, 10)));
280
+ // Header
281
+ process.stdout.write('\n' + header(`brela explain — ${relFile}`) + '\n\n');
282
+ // Meta line
283
+ process.stdout.write(` ${dim('File:')} ${relFile}\n` +
284
+ ` ${dim('Analysed:')} last ${analysedDays} days (${sessionDates.size} session${sessionDates.size !== 1 ? 's' : ''} found)\n\n`);
285
+ // ── Attribution Summary box ───────────────────────────────────────────────
286
+ const toolSummary = Object.entries(toolCounts)
287
+ .sort((a, b) => b[1] - a[1])
288
+ .map(([tool, n]) => toolColour(tool)(`${label(tool)} (${n})`))
289
+ .join(', ');
290
+ const confSummary = Object.entries(confCounts)
291
+ .map(([c, n]) => `${c[0].toUpperCase() + c.slice(1)} (${n})`)
292
+ .join(', ');
293
+ const rangeStr = ranges.length > 0
294
+ ? ranges.slice(0, 5).map(([s, e]) => `L${s}-${e}`).join(', ') +
295
+ (ranges.length > 5 ? ` +${ranges.length - 5} more` : '')
296
+ : 'n/a';
297
+ const summaryLines = [
298
+ `AI-assisted insertions: ${bold(String(entries.length))} events`,
299
+ `Total AI chars inserted: ${bold(totalChars.toLocaleString())}`,
300
+ `Tools detected: ${toolSummary}`,
301
+ `Confidence: ${confSummary}`,
302
+ `Lines attributed: ${rangeStr}`,
303
+ ];
304
+ process.stdout.write(box('Attribution Summary', summaryLines) + '\n\n');
305
+ // ── Timeline box ─────────────────────────────────────────────────────────
306
+ const timelineLines = entries.slice(0, 10).map((e) => {
307
+ const date = e.timestamp.slice(0, 10);
308
+ const time = e.timestamp.slice(11, 16);
309
+ const toolStr = toolColour(e.tool)(label(e.tool).padEnd(18));
310
+ const lineStr = e.linesEnd > 0 ? `L${e.linesStart}-${e.linesEnd}` : 'n/a';
311
+ const conf = e.confidence === 'high' ? 'HIGH' : e.confidence === 'medium' ? 'MED ' : 'LOW ';
312
+ return `${dim(date + ' ' + time)} ${confidenceDot(e.confidence)} ${toolStr} ${lineStr.padEnd(10)} ${conf}`;
313
+ });
314
+ if (entries.length > 10) {
315
+ timelineLines.push(dim(` … and ${entries.length - 10} more events`));
316
+ }
317
+ process.stdout.write(box('Timeline', timelineLines) + '\n\n');
318
+ // ── Risk Assessment box ───────────────────────────────────────────────────
319
+ const riskLines = [];
320
+ if (unreviewedSections > 0) {
321
+ riskLines.push(yellow('⚠') + ` ${unreviewedSections} AI section${unreviewedSections !== 1 ? 's' : ''} have never been in a reviewed commit`);
322
+ }
323
+ if (reviewedSections > 0) {
324
+ riskLines.push(green('✓') + ` ${reviewedSections} AI section${reviewedSections !== 1 ? 's' : ''} were committed with review signals`);
325
+ }
326
+ if (!hasTests) {
327
+ riskLines.push(red('✗') + ` No test file found for ${baseFile}`);
328
+ }
329
+ else {
330
+ riskLines.push(green('✓') + ` Test file found for ${baseFile}`);
331
+ }
332
+ if (confCounts['low'] ?? 0 > 0) {
333
+ riskLines.push(yellow('⚠') + ` ${confCounts['low']} low-confidence attribution${(confCounts['low'] ?? 0) !== 1 ? 's' : ''} — review manually`);
334
+ }
335
+ if (riskLines.length === 0) {
336
+ riskLines.push(green('✓') + ' No risk signals detected');
337
+ }
338
+ process.stdout.write(box('Risk Assessment', riskLines) + '\n\n');
339
+ // Tip
340
+ process.stdout.write(dim(` Tip: Run \`brela explain ${relFile} --json\` for machine-readable output.\n`) + '\n');
341
+ }
342
+ // ── Commander registration ────────────────────────────────────────────────────
343
+ export function explainCommand() {
344
+ return new Command('explain')
345
+ .description('Show AI attribution history for a specific file')
346
+ .argument('<file>', 'file path to explain (relative or absolute)')
347
+ .option('--days <n>', 'days of history to analyse', '90')
348
+ .option('--json', 'output as JSON')
349
+ .option('--since <date>', 'analyse from date (YYYY-MM-DD)')
350
+ .option('--repo <path>', 'project root path')
351
+ .action(async (file, opts) => {
352
+ try {
353
+ await runExplain(file, opts);
354
+ }
355
+ catch (err) {
356
+ logError(process.cwd(), err);
357
+ if (!opts.json) {
358
+ process.stdout.write(red('✗') + ` Unexpected error: ${String(err)}\n`);
359
+ }
360
+ }
361
+ });
362
+ }
363
+ //# sourceMappingURL=explain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain.js","sourceRoot":"","sources":["../../src/commands/explain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { Command } from 'commander';
2
+ export declare function installGitHooks(projectRoot: string): void;
3
+ export declare function uninstallGitHooks(projectRoot: string): void;
4
+ export declare function hookCommand(): Command;
5
+ //# sourceMappingURL=hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../src/commands/hook.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuJpC,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CA0BzD;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAsB3D;AAID,wBAAgB,WAAW,IAAI,OAAO,CA4BrC"}