@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 +90 -0
- package/dist/commands/daemon-cmd.d.ts +3 -0
- package/dist/commands/daemon-cmd.d.ts.map +1 -0
- package/dist/commands/daemon-cmd.js +94 -0
- package/dist/commands/daemon-cmd.js.map +1 -0
- package/dist/commands/explain.d.ts +3 -0
- package/dist/commands/explain.d.ts.map +1 -0
- package/dist/commands/explain.js +363 -0
- package/dist/commands/explain.js.map +1 -0
- package/dist/commands/hook.d.ts +5 -0
- package/dist/commands/hook.d.ts.map +1 -0
- package/dist/commands/hook.js +201 -0
- package/dist/commands/hook.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +298 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/report.d.ts +43 -0
- package/dist/commands/report.d.ts.map +1 -0
- package/dist/commands/report.js +725 -0
- package/dist/commands/report.js.map +1 -0
- package/dist/errors.d.ts +14 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +29 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/package.json +42 -0
|
@@ -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 @@
|
|
|
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"}
|