@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.
@@ -0,0 +1,201 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { Command } from 'commander';
4
+ import { BrelaExit } from '../errors.js';
5
+ // ── Guard strings ────────────────────────────────────────────────────────────
6
+ const PRE_GUARD_BEGIN = '# BRELA PRE-COMMIT BEGIN';
7
+ const PRE_GUARD_END = '# BRELA PRE-COMMIT END';
8
+ const POST_GUARD_BEGIN = '# BRELA POST-COMMIT BEGIN';
9
+ const POST_GUARD_END = '# BRELA POST-COMMIT END';
10
+ // ── Hook script bodies ───────────────────────────────────────────────────────
11
+ //
12
+ // Rules enforced throughout:
13
+ // • Pure POSIX sh — no bashisms, no process substitution
14
+ // • All logic inside a function called with `|| true`
15
+ // • Every external command has stderr redirected or is guarded
16
+ // • Script exits 0 regardless of what brela does
17
+ const PRE_COMMIT_BODY = `\
18
+ _brela_pre_commit() {
19
+ BRELA_DIR="$PWD/.brela"
20
+ [ -d "$BRELA_DIR" ] || return 0
21
+
22
+ SESSION_FILE="$BRELA_DIR/sessions/$(date +%Y-%m-%d).json"
23
+ [ -f "$SESSION_FILE" ] || return 0
24
+
25
+ STAGED=$(git diff --cached --name-only 2>/dev/null)
26
+ [ -z "$STAGED" ] && return 0
27
+
28
+ # ISO8601 timestamps sort lexicographically — string compare is safe
29
+ # Try GNU date first (Linux), fall back to BSD date (macOS)
30
+ CUTOFF=$(date -u -d '4 hours ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \\
31
+ || date -u -v-4H +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \\
32
+ || echo "0000-00-00T00:00:00Z")
33
+
34
+ TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
35
+ SESSION_ID=$(cat "$BRELA_DIR/current-session" 2>/dev/null | tr -d '[:space:]')
36
+ [ -z "$SESSION_ID" ] && SESSION_ID="unknown"
37
+
38
+ FILES_JSON=""
39
+ SEP=""
40
+
41
+ # Use heredoc + while-read so filenames with spaces are handled safely
42
+ while IFS= read -r STAGED_FILE; do
43
+ [ -z "$STAGED_FILE" ] && continue
44
+
45
+ # Find the last attribution entry for this exact file path
46
+ ENTRY=$(grep -F "\\"file\\":\\"$STAGED_FILE\\"" "$SESSION_FILE" 2>/dev/null | tail -1)
47
+ [ -z "$ENTRY" ] && continue
48
+
49
+ # Extract timestamp and apply 4-hour window filter
50
+ TS=$(printf '%s' "$ENTRY" | sed 's/.*"timestamp":"\\([^"]*\\)".*/\\1/')
51
+ # Sanity-check it looks like ISO8601 before comparing
52
+ case "$TS" in
53
+ [0-9][0-9][0-9][0-9]-*T*Z) ;;
54
+ *) continue ;;
55
+ esac
56
+ [ "$TS" \\< "$CUTOFF" ] && continue
57
+
58
+ TOOL=$(printf '%s' "$ENTRY" | sed 's/.*"tool":"\\([^"]*\\)".*/\\1/')
59
+ CONF=$(printf '%s' "$ENTRY" | sed 's/.*"confidence":"\\([^"]*\\)".*/\\1/')
60
+ DET=$(printf '%s' "$ENTRY" | sed 's/.*"detectionMethod":"\\([^"]*\\)".*/\\1/')
61
+
62
+ FILES_JSON="\${FILES_JSON}\${SEP}{\\"path\\":\\"\${STAGED_FILE}\\",\\"tool\\":\\"\${TOOL}\\",\\"confidence\\":\\"\${CONF}\\",\\"detectionMethod\\":\\"\${DET}\\"}"
63
+ SEP=","
64
+ done <<BRELA_STAGED_EOF
65
+ $STAGED
66
+ BRELA_STAGED_EOF
67
+
68
+ [ -z "\${FILES_JSON}" ] && return 0
69
+
70
+ RECORD="{\\"commitHash\\":\\"pending\\",\\"timestamp\\":\\"\${TIMESTAMP}\\",\\"files\\":[\${FILES_JSON}],\\"sessionId\\":\\"\${SESSION_ID}\\"}"
71
+ printf '%s\\n' "$RECORD" >> "$BRELA_DIR/commits.jsonl" 2>/dev/null
72
+ }
73
+ _brela_pre_commit || true
74
+ `;
75
+ const POST_COMMIT_BODY = `\
76
+ _brela_post_commit() {
77
+ BRELA_DIR="$PWD/.brela"
78
+ [ -d "$BRELA_DIR" ] || return 0
79
+
80
+ COMMITS_FILE="$BRELA_DIR/commits.jsonl"
81
+ [ -f "$COMMITS_FILE" ] || return 0
82
+
83
+ HASH=$(git rev-parse HEAD 2>/dev/null)
84
+ [ -z "$HASH" ] && return 0
85
+
86
+ # Replace only the LAST "commitHash":"pending" line with the real hash.
87
+ # awk buffers all lines, records the last matching line number, then on END
88
+ # replaces only that line before printing — atomic via temp file + mv.
89
+ TMP=$(mktemp "$BRELA_DIR/.commits.tmp.XXXXXX") || return 0
90
+ awk -v hash="$HASH" '
91
+ { lines[NR] = $0 }
92
+ /"commitHash":"pending"/ { last = NR }
93
+ END {
94
+ for (i = 1; i <= NR; i++) {
95
+ out = lines[i]
96
+ if (i == last) {
97
+ sub(/"commitHash":"pending"/, "\\"commitHash\\":\\"" hash "\\"", out)
98
+ }
99
+ print out
100
+ }
101
+ }
102
+ ' "$COMMITS_FILE" > "\${TMP}" 2>/dev/null \\
103
+ && mv "\${TMP}" "$COMMITS_FILE" 2>/dev/null
104
+ rm -f "\${TMP}" 2>/dev/null
105
+ }
106
+ _brela_post_commit || true
107
+ `;
108
+ // ── Low-level hook file manipulation ─────────────────────────────────────────
109
+ function readHookFile(hookPath) {
110
+ if (!fs.existsSync(hookPath))
111
+ return '';
112
+ return fs.readFileSync(hookPath, 'utf8');
113
+ }
114
+ function stripGuardBlock(content, begin, end) {
115
+ // Non-greedy match handles multiple stale blocks from botched earlier runs
116
+ return content
117
+ .replace(new RegExp(`\n?${begin}[\\s\\S]*?${end}\n?`, 'g'), '')
118
+ .trimEnd();
119
+ }
120
+ function writeHookFile(hookPath, content) {
121
+ fs.writeFileSync(hookPath, content, { encoding: 'utf8', mode: 0o755 });
122
+ // Explicit chmod — writeFileSync mode flag doesn't update an existing file's mode
123
+ fs.chmodSync(hookPath, 0o755);
124
+ }
125
+ function injectBlock(existing, begin, end, body) {
126
+ // Strip any prior brela section
127
+ const stripped = stripGuardBlock(existing, begin, end);
128
+ // Ensure there's a shebang if we're creating from scratch
129
+ const base = stripped.length > 0
130
+ ? stripped
131
+ : '#!/bin/sh';
132
+ return `${base}\n\n${begin}\n${body}${end}\n`;
133
+ }
134
+ // ── Public install / uninstall ───────────────────────────────────────────────
135
+ export function installGitHooks(projectRoot) {
136
+ const hooksDir = path.join(projectRoot, '.git', 'hooks');
137
+ if (!fs.existsSync(hooksDir)) {
138
+ throw new Error(`No .git/hooks directory found in ${projectRoot}`);
139
+ }
140
+ // pre-commit
141
+ const preCommitPath = path.join(hooksDir, 'pre-commit');
142
+ const preContent = injectBlock(readHookFile(preCommitPath), PRE_GUARD_BEGIN, PRE_GUARD_END, PRE_COMMIT_BODY);
143
+ writeHookFile(preCommitPath, preContent);
144
+ // post-commit
145
+ const postCommitPath = path.join(hooksDir, 'post-commit');
146
+ const postContent = injectBlock(readHookFile(postCommitPath), POST_GUARD_BEGIN, POST_GUARD_END, POST_COMMIT_BODY);
147
+ writeHookFile(postCommitPath, postContent);
148
+ }
149
+ export function uninstallGitHooks(projectRoot) {
150
+ const hooksDir = path.join(projectRoot, '.git', 'hooks');
151
+ if (!fs.existsSync(hooksDir))
152
+ return;
153
+ for (const [hookName, begin, end] of [
154
+ ['pre-commit', PRE_GUARD_BEGIN, PRE_GUARD_END],
155
+ ['post-commit', POST_GUARD_BEGIN, POST_GUARD_END],
156
+ ]) {
157
+ const hookPath = path.join(hooksDir, hookName);
158
+ if (!fs.existsSync(hookPath))
159
+ continue;
160
+ const content = fs.readFileSync(hookPath, 'utf8');
161
+ const stripped = stripGuardBlock(content, begin, end);
162
+ // If only the shebang (or nothing) remains after stripping, remove the file
163
+ const meaningful = stripped.replace(/^#!.*/, '').trim();
164
+ if (!meaningful) {
165
+ fs.rmSync(hookPath, { force: true });
166
+ }
167
+ else {
168
+ writeHookFile(hookPath, stripped + '\n');
169
+ }
170
+ }
171
+ }
172
+ // ── Command factory ───────────────────────────────────────────────────────────
173
+ export function hookCommand() {
174
+ const cmd = new Command('hook').description('Manage Brela git hook integration');
175
+ cmd
176
+ .command('install')
177
+ .description('Write pre-commit and post-commit hooks into .git/hooks/')
178
+ .action(() => {
179
+ try {
180
+ installGitHooks(process.cwd());
181
+ console.log('Brela git hooks installed (pre-commit + post-commit).');
182
+ }
183
+ catch (err) {
184
+ throw new BrelaExit(1, `Brela: ${String(err)}`);
185
+ }
186
+ });
187
+ cmd
188
+ .command('uninstall')
189
+ .description('Remove Brela sections from .git/hooks/')
190
+ .action(() => {
191
+ try {
192
+ uninstallGitHooks(process.cwd());
193
+ console.log('Brela git hooks removed.');
194
+ }
195
+ catch (err) {
196
+ throw new BrelaExit(1, `Brela: ${String(err)}`);
197
+ }
198
+ });
199
+ return cmd;
200
+ }
201
+ //# sourceMappingURL=hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.js","sourceRoot":"","sources":["../../src/commands/hook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function initCommand(): Command;
3
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiTpC,wBAAgB,WAAW,IAAI,OAAO,CAmDrC"}
@@ -0,0 +1,298 @@
1
+ import * as fs from 'node:fs';
2
+ import * as os from 'node:os';
3
+ import * as path from 'node:path';
4
+ import { spawn, spawnSync } from 'node:child_process';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { Command } from 'commander';
7
+ import { installGitHooks } from './hook.js';
8
+ import { BrelaExit } from '../errors.js';
9
+ // ── ANSI helpers ─────────────────────────────────────────────────────────────
10
+ const GREEN = '\x1b[32m';
11
+ const RED = '\x1b[31m';
12
+ const DIM = '\x1b[2m';
13
+ const BOLD = '\x1b[1m';
14
+ const RESET = '\x1b[0m';
15
+ const CHECK = `${GREEN}✓${RESET}`;
16
+ const CROSS = `${RED}✗${RESET}`;
17
+ const SKIP = `${DIM}–${RESET}`;
18
+ // ── Shell hook source blocks ────────────────────────────────────────────────
19
+ const BASH_ZSH_BLOCK = `
20
+ brela_log_intent() {
21
+ echo "{\\"tool\\":\\"$1\\",\\"args\\":\\"$2\\",\\"timestamp\\":\\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\\",\\"pwd\\":\\"$PWD\\"}" >> "$PWD/.brela/shell-intents.jsonl" 2>/dev/null
22
+ }
23
+ brela_snapshot() {
24
+ git -C "$PWD" diff --name-only HEAD 2>/dev/null >> "$PWD/.brela/snapshot-$(date +%s).txt" 2>/dev/null
25
+ }
26
+ claude() { brela_log_intent "claude-code" "$*"; command claude "$@"; brela_snapshot; }
27
+
28
+ # Copilot CLI
29
+ gh() {
30
+ if [ "$1" = "copilot" ]; then brela_log_intent "copilot-cli" "$*"; fi
31
+ command gh "$@"
32
+ if [ "$1" = "copilot" ]; then brela_snapshot; fi
33
+ }
34
+ `.trimStart();
35
+ const FISH_BLOCK = `
36
+ function brela_log_intent
37
+ set -l tool $argv[1]
38
+ set -l args (string join " " $argv[2..-1])
39
+ set -l timestamp (date -u +%Y-%m-%dT%H:%M:%SZ)
40
+ echo "{\\"tool\\":\\"$tool\\",\\"args\\":\\"$args\\",\\"timestamp\\":\\"$timestamp\\",\\"pwd\\":\\"$PWD\\"}" >> "$PWD/.brela/shell-intents.jsonl" 2>/dev/null
41
+ end
42
+
43
+ function brela_snapshot
44
+ git -C "$PWD" diff --name-only HEAD 2>/dev/null >> "$PWD/.brela/snapshot-(date +%s).txt" 2>/dev/null
45
+ end
46
+
47
+ function claude
48
+ brela_log_intent "claude-code" $argv
49
+ command claude $argv
50
+ brela_snapshot
51
+ end
52
+
53
+ function gh
54
+ if test "$argv[1]" = "copilot"
55
+ brela_log_intent "copilot-cli" $argv
56
+ end
57
+ command gh $argv
58
+ if test "$argv[1]" = "copilot"
59
+ brela_snapshot
60
+ end
61
+ end
62
+ `.trimStart();
63
+ const GUARD_BEGIN = '# BRELA BEGIN';
64
+ const GUARD_END = '# BRELA END';
65
+ function detectShell() {
66
+ const shellBin = process.env['SHELL'] ?? '';
67
+ const name = path.basename(shellBin).toLowerCase();
68
+ const home = os.homedir();
69
+ if (name === 'zsh') {
70
+ return { kind: 'zsh', rcPath: path.join(home, '.zshrc'), block: BASH_ZSH_BLOCK };
71
+ }
72
+ if (name === 'bash') {
73
+ return { kind: 'bash', rcPath: path.join(home, '.bashrc'), block: BASH_ZSH_BLOCK };
74
+ }
75
+ if (name === 'fish') {
76
+ const xdg = process.env['XDG_CONFIG_HOME'];
77
+ const fishDir = xdg ? path.join(xdg, 'fish') : path.join(home, '.config', 'fish');
78
+ return { kind: 'fish', rcPath: path.join(fishDir, 'config.fish'), block: FISH_BLOCK };
79
+ }
80
+ return { kind: 'unknown', rcPath: '', block: BASH_ZSH_BLOCK };
81
+ }
82
+ // ── RC file patching (idempotent) ────────────────────────────────────────────
83
+ function patchRcFile(rcPath, block) {
84
+ fs.mkdirSync(path.dirname(rcPath), { recursive: true });
85
+ if (!fs.existsSync(rcPath)) {
86
+ fs.writeFileSync(rcPath, '', 'utf8');
87
+ }
88
+ const current = fs.readFileSync(rcPath, 'utf8');
89
+ const stripped = current
90
+ .replace(new RegExp(`\\n?${GUARD_BEGIN}[\\s\\S]*?${GUARD_END}\\n?`, 'g'), '')
91
+ .trimEnd();
92
+ const patched = (stripped.length > 0 ? stripped + '\n' : '') +
93
+ `\n${GUARD_BEGIN}\n${block}${GUARD_END}\n`;
94
+ fs.writeFileSync(rcPath, patched, 'utf8');
95
+ }
96
+ // ── .brela bootstrap ───────────────────────────────────────────────────────
97
+ function bootstrapBrelaDir(projectRoot) {
98
+ const brelaDir = path.join(projectRoot, '.brela');
99
+ try {
100
+ fs.mkdirSync(brelaDir, { recursive: true });
101
+ }
102
+ catch (err) {
103
+ const code = err.code;
104
+ if (code === 'EACCES' || code === 'EPERM') {
105
+ throw new BrelaExit(1, `Cannot write to ${brelaDir} (permission denied).\nCheck directory permissions and try again.`);
106
+ }
107
+ throw err;
108
+ }
109
+ // .gitignore — keep session data local
110
+ const gitignorePath = path.join(brelaDir, '.gitignore');
111
+ if (!fs.existsSync(gitignorePath)) {
112
+ fs.writeFileSync(gitignorePath, '*\n', 'utf8');
113
+ }
114
+ // Pre-create sessions dir and shell-intents file so they exist immediately
115
+ fs.mkdirSync(path.join(brelaDir, 'sessions'), { recursive: true });
116
+ const intentsPath = path.join(brelaDir, 'shell-intents.jsonl');
117
+ if (!fs.existsSync(intentsPath)) {
118
+ fs.writeFileSync(intentsPath, '', 'utf8');
119
+ }
120
+ }
121
+ /**
122
+ * Resolve the path to the bundled .vsix relative to this compiled file.
123
+ * Layout: packages/cli/dist/commands/init.js
124
+ * → ../../../../vscode-extension → packages/vscode-extension/
125
+ */
126
+ function findVsix() {
127
+ try {
128
+ const here = path.dirname(fileURLToPath(import.meta.url));
129
+ const vsixDir = path.resolve(here, '..', '..', '..', 'vscode-extension');
130
+ if (!fs.existsSync(vsixDir))
131
+ return null;
132
+ const files = fs.readdirSync(vsixDir).filter((f) => f.endsWith('.vsix'));
133
+ if (files.length === 0)
134
+ return null;
135
+ // Pick the newest one if multiple exist
136
+ files.sort().reverse();
137
+ return path.join(vsixDir, files[0]);
138
+ }
139
+ catch {
140
+ return null;
141
+ }
142
+ }
143
+ function isCodeCliAvailable() {
144
+ const result = spawnSync('which', ['code'], { encoding: 'utf8' });
145
+ return result.status === 0 && result.stdout.trim().length > 0;
146
+ }
147
+ function installVsCodeExtension() {
148
+ if (!isCodeCliAvailable()) {
149
+ return {
150
+ label: 'VS Code extension',
151
+ ok: false,
152
+ note: 'install manually: https://marketplace.visualstudio.com/items?itemName=brela-ai.brela',
153
+ };
154
+ }
155
+ const vsixPath = findVsix();
156
+ if (vsixPath === null) {
157
+ return {
158
+ label: 'VS Code extension',
159
+ ok: false,
160
+ note: 'run "vsce package" in packages/vscode-extension, then re-run brela init',
161
+ };
162
+ }
163
+ const result = spawnSync('code', ['--install-extension', vsixPath], {
164
+ encoding: 'utf8',
165
+ });
166
+ if (result.status !== 0) {
167
+ const reason = (result.stderr ?? '').trim().split('\n')[0] ?? 'unknown error';
168
+ return { label: 'VS Code extension', ok: false, note: reason };
169
+ }
170
+ return { label: 'VS Code extension installed', ok: true };
171
+ }
172
+ // ── Daemon launch ────────────────────────────────────────────────────────────
173
+ function daemonScriptPath() {
174
+ const here = path.dirname(fileURLToPath(import.meta.url));
175
+ return path.resolve(here, '..', '..', '..', 'daemon', 'dist', 'daemon.js');
176
+ }
177
+ function pidPath(projectRoot) {
178
+ return path.join(projectRoot, '.brela', 'daemon.pid');
179
+ }
180
+ function isProcessRunning(pid) {
181
+ try {
182
+ process.kill(pid, 0);
183
+ return true;
184
+ }
185
+ catch {
186
+ return false;
187
+ }
188
+ }
189
+ function launchDaemon(projectRoot) {
190
+ const script = daemonScriptPath();
191
+ if (!fs.existsSync(script)) {
192
+ return {
193
+ label: 'Daemon',
194
+ ok: false,
195
+ note: 'daemon not built — run "npm run build" in packages/daemon',
196
+ };
197
+ }
198
+ // Check if already running
199
+ const pp = pidPath(projectRoot);
200
+ if (fs.existsSync(pp)) {
201
+ const raw = fs.readFileSync(pp, 'utf8').trim();
202
+ const existingPid = parseInt(raw, 10);
203
+ if (!isNaN(existingPid) && isProcessRunning(existingPid)) {
204
+ return { label: `Daemon running`, ok: true, note: `PID ${existingPid}` };
205
+ }
206
+ fs.rmSync(pp, { force: true });
207
+ }
208
+ try {
209
+ const child = spawn(process.execPath, [script, projectRoot], {
210
+ detached: true,
211
+ stdio: 'ignore',
212
+ });
213
+ child.unref();
214
+ const pid = child.pid;
215
+ if (pid === undefined) {
216
+ return { label: 'Daemon', ok: false, note: 'failed to spawn process' };
217
+ }
218
+ fs.writeFileSync(pp, String(pid), 'utf8');
219
+ return { label: `Daemon started`, ok: true, note: `PID ${pid}` };
220
+ }
221
+ catch (err) {
222
+ return { label: 'Daemon', ok: false, note: String(err) };
223
+ }
224
+ }
225
+ // ── Summary printer ──────────────────────────────────────────────────────────
226
+ function printSummary(results, shell) {
227
+ console.log('');
228
+ for (const r of results) {
229
+ const icon = r.ok ? CHECK : (r.note?.startsWith('skipped') ? SKIP : CROSS);
230
+ const label = r.ok ? r.label : `${RED}${r.label}${RESET}`;
231
+ const note = r.note ? ` ${DIM}${r.note}${RESET}` : '';
232
+ console.log(` ${icon} ${label}${note}`);
233
+ }
234
+ const allOk = results.every((r) => r.ok);
235
+ console.log('');
236
+ if (allOk) {
237
+ console.log(` ${BOLD}Brela is ready.${RESET} Start coding — attribution runs silently.`);
238
+ }
239
+ else {
240
+ console.log(` ${BOLD}Brela is partially set up.${RESET} Fix the items above and re-run ${DIM}brela init${RESET}.`);
241
+ }
242
+ if (shell.kind !== 'unknown') {
243
+ console.log(`\n ${DIM}Reload your shell: source ${shell.rcPath}${RESET}`);
244
+ }
245
+ console.log('');
246
+ }
247
+ // ── Command factory ──────────────────────────────────────────────────────────
248
+ export function initCommand() {
249
+ return new Command('init')
250
+ .description('Set up Brela: shell hooks, VS Code extension, daemon, and .brela/ directory')
251
+ .action(() => {
252
+ const projectRoot = process.cwd();
253
+ const results = [];
254
+ // ── Step 1: Shell hooks ──────────────────────────────────────────────
255
+ const shell = detectShell();
256
+ if (shell.kind === 'unknown') {
257
+ results.push({
258
+ label: 'Shell hooks',
259
+ ok: false,
260
+ note: `unrecognised shell (${process.env['SHELL'] ?? 'unset'}) — add hooks manually`,
261
+ });
262
+ }
263
+ else {
264
+ try {
265
+ patchRcFile(shell.rcPath, shell.block);
266
+ results.push({ label: `Shell hooks installed (${shell.kind})`, ok: true });
267
+ }
268
+ catch (err) {
269
+ results.push({ label: 'Shell hooks', ok: false, note: String(err) });
270
+ }
271
+ }
272
+ // ── Step 2: .brela/ directory + initial files ──────────────────────
273
+ try {
274
+ bootstrapBrelaDir(projectRoot);
275
+ results.push({ label: '.brela/ directory created', ok: true });
276
+ }
277
+ catch (err) {
278
+ // If we can't create the dir, bail — nothing else will work
279
+ const msg = err instanceof BrelaExit ? err.message : String(err);
280
+ throw new BrelaExit(1, msg);
281
+ }
282
+ // ── Step 3: Git hooks ────────────────────────────────────────────────
283
+ try {
284
+ installGitHooks(projectRoot);
285
+ results.push({ label: 'Git hooks installed', ok: true });
286
+ }
287
+ catch {
288
+ results.push({ label: 'Git hooks', ok: false, note: 'skipped (not a git repository)' });
289
+ }
290
+ // ── Step 4: VS Code extension ────────────────────────────────────────
291
+ results.push(installVsCodeExtension());
292
+ // ── Step 5: Daemon ───────────────────────────────────────────────────
293
+ results.push(launchDaemon(projectRoot));
294
+ // ── Summary ──────────────────────────────────────────────────────────
295
+ printSummary(results, shell);
296
+ });
297
+ }
298
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { Command } from 'commander';
2
+ export interface ReportMetrics {
3
+ generatedAt: string;
4
+ projectRoot: string;
5
+ daysAnalysed: number;
6
+ dateFrom: string;
7
+ dateTo: string;
8
+ insufficientData: boolean;
9
+ aiPercentage: number;
10
+ totalAiLines: number;
11
+ totalHumanLines: number;
12
+ perToolBreakdown: Record<string, number>;
13
+ perFileHeatmap: Array<{
14
+ file: string;
15
+ aiLines: number;
16
+ totalLines: number;
17
+ aiPct: number;
18
+ topTool: string;
19
+ }>;
20
+ perDayTrend: Array<{
21
+ date: string;
22
+ humanLines: number;
23
+ aiLines: number;
24
+ }>;
25
+ confidenceDistribution: {
26
+ high: number;
27
+ medium: number;
28
+ low: number;
29
+ };
30
+ unreviewedAiCommits: Array<{
31
+ hash: string;
32
+ shortHash: string;
33
+ date: string;
34
+ message: string;
35
+ author: string;
36
+ aiPct: number;
37
+ tools: string[];
38
+ }>;
39
+ backfillCount: number;
40
+ }
41
+ export declare function computeMetrics(projectRoot: string, days: number): Promise<ReportMetrics>;
42
+ export declare function reportCommand(): Command;
43
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/commands/report.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsCpC,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,OAAO,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,cAAc,EAAE,KAAK,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;KACnF,CAAC,CAAC;IACH,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1E,sBAAsB,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE,mBAAmB,EAAE,KAAK,CAAC;QACzB,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAC9C,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAC;KACjE,CAAC,CAAC;IACH,aAAa,EAAE,MAAM,CAAC;CACvB;AAuKD,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA0I9F;AA6XD,wBAAgB,aAAa,IAAI,OAAO,CA6DvC"}