@codebakers/cli 3.3.18 → 3.4.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/dist/commands/go.d.ts +1 -0
- package/dist/commands/go.js +75 -33
- package/dist/commands/install-precommit.d.ts +1 -0
- package/dist/commands/install-precommit.js +229 -0
- package/dist/commands/upgrade.js +284 -4
- package/dist/index.js +5 -0
- package/dist/mcp/server.js +325 -256
- package/package.json +1 -1
- package/src/commands/go.ts +91 -36
- package/src/commands/install-precommit.ts +234 -0
- package/src/commands/upgrade.ts +314 -5
- package/src/index.ts +6 -0
- package/src/mcp/server.ts +335 -266
package/dist/commands/go.d.ts
CHANGED
package/dist/commands/go.js
CHANGED
|
@@ -11,6 +11,7 @@ const fs_1 = require("fs");
|
|
|
11
11
|
const path_1 = require("path");
|
|
12
12
|
const readline_1 = require("readline");
|
|
13
13
|
const config_js_1 = require("../config.js");
|
|
14
|
+
const api_js_1 = require("../lib/api.js");
|
|
14
15
|
const fingerprint_js_1 = require("../lib/fingerprint.js");
|
|
15
16
|
function prompt(question) {
|
|
16
17
|
const rl = (0, readline_1.createInterface)({
|
|
@@ -68,6 +69,7 @@ function log(message, options) {
|
|
|
68
69
|
}
|
|
69
70
|
/**
|
|
70
71
|
* Zero-friction entry point - start using CodeBakers instantly
|
|
72
|
+
* Single command for both trial and paid users
|
|
71
73
|
*/
|
|
72
74
|
async function go(options = {}) {
|
|
73
75
|
log('Starting go command...', options);
|
|
@@ -76,19 +78,20 @@ async function go(options = {}) {
|
|
|
76
78
|
console.log(chalk_1.default.blue(`
|
|
77
79
|
╔═══════════════════════════════════════════════════════════╗
|
|
78
80
|
║ ║
|
|
79
|
-
║ ${chalk_1.default.bold.white('CodeBakers -
|
|
81
|
+
║ ${chalk_1.default.bold.white('CodeBakers - Get Started')} ║
|
|
80
82
|
║ ║
|
|
81
83
|
╚═══════════════════════════════════════════════════════════╝
|
|
82
84
|
`));
|
|
83
85
|
// Check if user already has an API key (paid user)
|
|
84
86
|
log('Checking for existing API key...', options);
|
|
85
|
-
const
|
|
86
|
-
if (
|
|
87
|
-
log(`Found API key: ${
|
|
88
|
-
console.log(chalk_1.default.green(' ✓ You\'re already logged in
|
|
89
|
-
//
|
|
90
|
-
await installPatternsWithApiKey(
|
|
87
|
+
const existingApiKey = (0, config_js_1.getApiKey)();
|
|
88
|
+
if (existingApiKey) {
|
|
89
|
+
log(`Found API key: ${existingApiKey.substring(0, 8)}...`, options);
|
|
90
|
+
console.log(chalk_1.default.green(' ✓ You\'re already logged in!\n'));
|
|
91
|
+
// Install patterns if not already installed
|
|
92
|
+
await installPatternsWithApiKey(existingApiKey, options);
|
|
91
93
|
await configureMCP(options);
|
|
94
|
+
await showSuccessAndRestart();
|
|
92
95
|
return;
|
|
93
96
|
}
|
|
94
97
|
log('No API key found, checking trial state...', options);
|
|
@@ -104,21 +107,33 @@ async function go(options = {}) {
|
|
|
104
107
|
// Install patterns if not already installed
|
|
105
108
|
await installPatterns(existingTrial.trialId, options);
|
|
106
109
|
await configureMCP(options);
|
|
110
|
+
await showSuccessAndRestart();
|
|
107
111
|
return;
|
|
108
112
|
}
|
|
109
113
|
// Check if trial expired
|
|
110
114
|
if (existingTrial && (0, config_js_1.isTrialExpired)()) {
|
|
111
115
|
console.log(chalk_1.default.yellow(' ⚠️ Your trial has expired.\n'));
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
// Offer to login with API key or extend
|
|
117
|
+
console.log(chalk_1.default.white(' Options:\n'));
|
|
118
|
+
console.log(chalk_1.default.cyan(' [1] Login with API key') + chalk_1.default.gray(' (I have an account)'));
|
|
119
|
+
console.log(chalk_1.default.cyan(' [2] Extend trial') + chalk_1.default.gray(' (7 more days with GitHub)\n'));
|
|
120
|
+
const choice = await prompt(chalk_1.default.gray(' Enter 1 or 2: '));
|
|
121
|
+
if (choice === '1') {
|
|
122
|
+
await handleApiKeyLogin(options);
|
|
123
|
+
return;
|
|
117
124
|
}
|
|
118
125
|
else {
|
|
119
|
-
console.log(chalk_1.default.
|
|
120
|
-
|
|
126
|
+
console.log(chalk_1.default.cyan('\n Run: codebakers extend\n'));
|
|
127
|
+
return;
|
|
121
128
|
}
|
|
129
|
+
}
|
|
130
|
+
// New user - ask how they want to proceed
|
|
131
|
+
console.log(chalk_1.default.white(' How would you like to get started?\n'));
|
|
132
|
+
console.log(chalk_1.default.cyan(' [1] Start free 7-day trial') + chalk_1.default.gray(' (no signup required)'));
|
|
133
|
+
console.log(chalk_1.default.cyan(' [2] Login with API key') + chalk_1.default.gray(' (I have an account)\n'));
|
|
134
|
+
const choice = await prompt(chalk_1.default.gray(' Enter 1 or 2: '));
|
|
135
|
+
if (choice === '2') {
|
|
136
|
+
await handleApiKeyLogin(options);
|
|
122
137
|
return;
|
|
123
138
|
}
|
|
124
139
|
// Start new trial
|
|
@@ -183,18 +198,8 @@ async function go(options = {}) {
|
|
|
183
198
|
await installPatterns(data.trialId, options);
|
|
184
199
|
// Configure MCP
|
|
185
200
|
await configureMCP(options);
|
|
186
|
-
// Show success
|
|
187
|
-
|
|
188
|
-
╔═══════════════════════════════════════════════════════════╗
|
|
189
|
-
║ ✅ CodeBakers is ready! ║
|
|
190
|
-
║ ║
|
|
191
|
-
║ ${chalk_1.default.white('Your 7-day free trial has started.')} ║
|
|
192
|
-
║ ║
|
|
193
|
-
║ ${chalk_1.default.gray('Try: "Build me a todo app with authentication"')} ║
|
|
194
|
-
╚═══════════════════════════════════════════════════════════╝
|
|
195
|
-
`));
|
|
196
|
-
// Attempt auto-restart Claude Code
|
|
197
|
-
await attemptAutoRestart();
|
|
201
|
+
// Show success and restart
|
|
202
|
+
await showSuccessAndRestart();
|
|
198
203
|
}
|
|
199
204
|
catch (error) {
|
|
200
205
|
spinner.fail('Failed to start trial');
|
|
@@ -235,9 +240,50 @@ async function configureMCP(options = {}) {
|
|
|
235
240
|
}
|
|
236
241
|
}
|
|
237
242
|
}
|
|
238
|
-
|
|
243
|
+
/**
|
|
244
|
+
* Handle API key login flow (for paid users)
|
|
245
|
+
*/
|
|
246
|
+
async function handleApiKeyLogin(options = {}) {
|
|
247
|
+
console.log(chalk_1.default.white('\n Enter your API key\n'));
|
|
248
|
+
console.log(chalk_1.default.gray(' Find it at: https://codebakers.ai/dashboard\n'));
|
|
249
|
+
const apiKey = await prompt(chalk_1.default.cyan(' API Key: '));
|
|
250
|
+
if (!apiKey) {
|
|
251
|
+
console.log(chalk_1.default.red('\n API key is required.\n'));
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const spinner = (0, ora_1.default)('Validating API key...').start();
|
|
255
|
+
try {
|
|
256
|
+
await (0, api_js_1.validateApiKey)(apiKey);
|
|
257
|
+
spinner.succeed('API key validated');
|
|
258
|
+
// Save API key
|
|
259
|
+
(0, config_js_1.setApiKey)(apiKey);
|
|
260
|
+
console.log(chalk_1.default.green(' ✓ Logged in successfully!\n'));
|
|
261
|
+
// Install patterns
|
|
262
|
+
await installPatternsWithApiKey(apiKey, options);
|
|
263
|
+
// Configure MCP
|
|
264
|
+
await configureMCP(options);
|
|
265
|
+
// Show success
|
|
266
|
+
await showSuccessAndRestart();
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
spinner.fail('Invalid API key');
|
|
270
|
+
console.log(chalk_1.default.red('\n Could not validate API key.'));
|
|
271
|
+
console.log(chalk_1.default.gray(' Check your key at: https://codebakers.ai/dashboard\n'));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Show success message and offer to restart
|
|
276
|
+
*/
|
|
277
|
+
async function showSuccessAndRestart() {
|
|
239
278
|
const cwd = process.cwd();
|
|
240
|
-
console.log(chalk_1.default.
|
|
279
|
+
console.log(chalk_1.default.green(`
|
|
280
|
+
╔═══════════════════════════════════════════════════════════╗
|
|
281
|
+
║ ✅ CodeBakers is ready! ║
|
|
282
|
+
║ ║
|
|
283
|
+
║ ${chalk_1.default.gray('Try: "Build me a todo app with authentication"')} ║
|
|
284
|
+
╚═══════════════════════════════════════════════════════════╝
|
|
285
|
+
`));
|
|
286
|
+
console.log(chalk_1.default.yellow(' ⚠️ RESTART REQUIRED\n'));
|
|
241
287
|
console.log(chalk_1.default.gray(' Claude Code needs to restart to load CodeBakers.\n'));
|
|
242
288
|
const answer = await prompt(chalk_1.default.cyan(' Restart Claude Code now? (Y/n): '));
|
|
243
289
|
if (answer === 'n' || answer === 'no') {
|
|
@@ -249,7 +295,6 @@ async function attemptAutoRestart() {
|
|
|
249
295
|
try {
|
|
250
296
|
const isWindows = process.platform === 'win32';
|
|
251
297
|
if (isWindows) {
|
|
252
|
-
// On Windows, spawn a new Claude process detached and exit
|
|
253
298
|
(0, child_process_1.spawn)('cmd', ['/c', 'start', 'claude'], {
|
|
254
299
|
cwd,
|
|
255
300
|
detached: true,
|
|
@@ -258,7 +303,6 @@ async function attemptAutoRestart() {
|
|
|
258
303
|
}).unref();
|
|
259
304
|
}
|
|
260
305
|
else {
|
|
261
|
-
// On Mac/Linux, spawn claude in new terminal
|
|
262
306
|
(0, child_process_1.spawn)('claude', [], {
|
|
263
307
|
cwd,
|
|
264
308
|
detached: true,
|
|
@@ -268,12 +312,10 @@ async function attemptAutoRestart() {
|
|
|
268
312
|
}
|
|
269
313
|
console.log(chalk_1.default.green(' ✓ Claude Code is restarting...\n'));
|
|
270
314
|
console.log(chalk_1.default.gray(' This terminal will close. Claude Code will open in a new window.\n'));
|
|
271
|
-
// Give the spawn a moment to start
|
|
272
315
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
273
|
-
// Exit this process
|
|
274
316
|
process.exit(0);
|
|
275
317
|
}
|
|
276
|
-
catch
|
|
318
|
+
catch {
|
|
277
319
|
console.log(chalk_1.default.yellow(' Could not auto-restart. Please restart Claude Code manually.\n'));
|
|
278
320
|
}
|
|
279
321
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function installPrecommit(): Promise<void>;
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.installPrecommit = installPrecommit;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const path_1 = require("path");
|
|
10
|
+
const PRE_COMMIT_SCRIPT = `#!/bin/sh
|
|
11
|
+
# CodeBakers Pre-Commit Hook - Session Enforcement
|
|
12
|
+
# Blocks commits unless AI called discover_patterns and validate_complete
|
|
13
|
+
|
|
14
|
+
# Run the validation script
|
|
15
|
+
node "$(dirname "$0")/validate-session.js"
|
|
16
|
+
exit $?
|
|
17
|
+
`;
|
|
18
|
+
const VALIDATE_SESSION_SCRIPT = `#!/usr/bin/env node
|
|
19
|
+
/**
|
|
20
|
+
* CodeBakers Pre-Commit Validation
|
|
21
|
+
* Blocks commits unless a valid session exists
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
const fs = require('fs');
|
|
25
|
+
const path = require('path');
|
|
26
|
+
|
|
27
|
+
const RED = '\\x1b[31m';
|
|
28
|
+
const GREEN = '\\x1b[32m';
|
|
29
|
+
const YELLOW = '\\x1b[33m';
|
|
30
|
+
const CYAN = '\\x1b[36m';
|
|
31
|
+
const RESET = '\\x1b[0m';
|
|
32
|
+
|
|
33
|
+
function log(color, message) {
|
|
34
|
+
console.log(color + message + RESET);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function validateSession() {
|
|
38
|
+
const cwd = process.cwd();
|
|
39
|
+
const stateFile = path.join(cwd, '.codebakers.json');
|
|
40
|
+
|
|
41
|
+
// Check if this is a CodeBakers project
|
|
42
|
+
if (!fs.existsSync(stateFile)) {
|
|
43
|
+
return { valid: true, reason: 'not-codebakers-project' };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let state;
|
|
47
|
+
try {
|
|
48
|
+
state = JSON.parse(fs.readFileSync(stateFile, 'utf-8'));
|
|
49
|
+
} catch (error) {
|
|
50
|
+
return { valid: false, reason: 'invalid-state-file' };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Check if v6.0 server-enforced mode
|
|
54
|
+
if (!state.serverEnforced) {
|
|
55
|
+
return { valid: true, reason: 'legacy-project' };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Check for session token (means discover_patterns was called)
|
|
59
|
+
const sessionToken = state.currentSessionToken;
|
|
60
|
+
if (!sessionToken) {
|
|
61
|
+
// Check if there's a recent passed validation
|
|
62
|
+
const lastValidation = state.lastValidation;
|
|
63
|
+
if (!lastValidation || !lastValidation.passed) {
|
|
64
|
+
return {
|
|
65
|
+
valid: false,
|
|
66
|
+
reason: 'no-session',
|
|
67
|
+
message: 'No active CodeBakers session.\\nAI must call discover_patterns before writing code.'
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Check session expiry
|
|
73
|
+
const sessionExpiry = state.sessionExpiresAt;
|
|
74
|
+
if (sessionExpiry && new Date(sessionExpiry) < new Date()) {
|
|
75
|
+
return {
|
|
76
|
+
valid: false,
|
|
77
|
+
reason: 'session-expired',
|
|
78
|
+
message: 'CodeBakers session has expired.\\nAI must call discover_patterns again.'
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Check if validation was completed
|
|
83
|
+
const lastValidation = state.lastValidation;
|
|
84
|
+
if (!lastValidation) {
|
|
85
|
+
return {
|
|
86
|
+
valid: false,
|
|
87
|
+
reason: 'no-validation',
|
|
88
|
+
message: 'No validation completed.\\nAI must call validate_complete before committing.'
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Check if validation passed
|
|
93
|
+
if (!lastValidation.passed) {
|
|
94
|
+
const issues = lastValidation.issues?.map(i => i.message || i).join(', ') || 'Unknown issues';
|
|
95
|
+
return {
|
|
96
|
+
valid: false,
|
|
97
|
+
reason: 'validation-failed',
|
|
98
|
+
message: 'Validation failed: ' + issues + '\\nAI must fix issues and call validate_complete again.'
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Check if validation is recent (within last 30 minutes)
|
|
103
|
+
const validationTime = new Date(lastValidation.timestamp);
|
|
104
|
+
const thirtyMinutesAgo = new Date(Date.now() - 30 * 60 * 1000);
|
|
105
|
+
if (validationTime < thirtyMinutesAgo) {
|
|
106
|
+
return {
|
|
107
|
+
valid: false,
|
|
108
|
+
reason: 'validation-stale',
|
|
109
|
+
message: 'Validation is stale (older than 30 minutes).\\nAI must call validate_complete again.'
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return { valid: true, reason: 'session-valid' };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function main() {
|
|
117
|
+
console.log('');
|
|
118
|
+
log(CYAN, ' 🍪 CodeBakers Pre-Commit Validation');
|
|
119
|
+
console.log('');
|
|
120
|
+
|
|
121
|
+
const result = await validateSession();
|
|
122
|
+
|
|
123
|
+
if (result.valid) {
|
|
124
|
+
if (result.reason === 'not-codebakers-project') {
|
|
125
|
+
log(GREEN, ' ✓ Not a CodeBakers project - commit allowed');
|
|
126
|
+
} else if (result.reason === 'legacy-project') {
|
|
127
|
+
log(GREEN, ' ✓ Legacy project (pre-6.0) - commit allowed');
|
|
128
|
+
} else {
|
|
129
|
+
log(GREEN, ' ✓ Valid CodeBakers session - commit allowed');
|
|
130
|
+
}
|
|
131
|
+
console.log('');
|
|
132
|
+
process.exit(0);
|
|
133
|
+
} else {
|
|
134
|
+
log(RED, ' ✗ Commit blocked: ' + result.reason);
|
|
135
|
+
console.log('');
|
|
136
|
+
if (result.message) {
|
|
137
|
+
log(YELLOW, ' ' + result.message.split('\\n').join('\\n '));
|
|
138
|
+
}
|
|
139
|
+
console.log('');
|
|
140
|
+
log(CYAN, ' How to fix:');
|
|
141
|
+
log(RESET, ' 1. AI must call discover_patterns before writing code');
|
|
142
|
+
log(RESET, ' 2. AI must call validate_complete before saying "done"');
|
|
143
|
+
log(RESET, ' 3. Both tools must pass for commits to be allowed');
|
|
144
|
+
console.log('');
|
|
145
|
+
log(YELLOW, ' To bypass (not recommended): git commit --no-verify');
|
|
146
|
+
console.log('');
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
main().catch(error => {
|
|
152
|
+
log(RED, ' Error: ' + error.message);
|
|
153
|
+
process.exit(1);
|
|
154
|
+
});
|
|
155
|
+
`;
|
|
156
|
+
async function installPrecommit() {
|
|
157
|
+
console.log(chalk_1.default.blue('\n CodeBakers Pre-Commit Hook Installation\n'));
|
|
158
|
+
const cwd = process.cwd();
|
|
159
|
+
// Check if this is a git repository
|
|
160
|
+
const gitDir = (0, path_1.join)(cwd, '.git');
|
|
161
|
+
if (!(0, fs_1.existsSync)(gitDir)) {
|
|
162
|
+
console.log(chalk_1.default.red(' ✗ Not a git repository'));
|
|
163
|
+
console.log(chalk_1.default.gray(' Initialize git first: git init\n'));
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
// Check if this is a CodeBakers project
|
|
167
|
+
const stateFile = (0, path_1.join)(cwd, '.codebakers.json');
|
|
168
|
+
if (!(0, fs_1.existsSync)(stateFile)) {
|
|
169
|
+
console.log(chalk_1.default.yellow(' ⚠️ No .codebakers.json found'));
|
|
170
|
+
console.log(chalk_1.default.gray(' Run codebakers upgrade first to enable server enforcement\n'));
|
|
171
|
+
}
|
|
172
|
+
// Create hooks directory if it doesn't exist
|
|
173
|
+
const hooksDir = (0, path_1.join)(gitDir, 'hooks');
|
|
174
|
+
if (!(0, fs_1.existsSync)(hooksDir)) {
|
|
175
|
+
(0, fs_1.mkdirSync)(hooksDir, { recursive: true });
|
|
176
|
+
}
|
|
177
|
+
// Write the pre-commit hook
|
|
178
|
+
const preCommitPath = (0, path_1.join)(hooksDir, 'pre-commit');
|
|
179
|
+
(0, fs_1.writeFileSync)(preCommitPath, PRE_COMMIT_SCRIPT);
|
|
180
|
+
// Make it executable (Unix only, Windows ignores this)
|
|
181
|
+
try {
|
|
182
|
+
(0, fs_1.chmodSync)(preCommitPath, '755');
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
// Windows doesn't support chmod
|
|
186
|
+
}
|
|
187
|
+
console.log(chalk_1.default.green(' ✓ Created pre-commit hook'));
|
|
188
|
+
// Write the validation script
|
|
189
|
+
const validatePath = (0, path_1.join)(hooksDir, 'validate-session.js');
|
|
190
|
+
(0, fs_1.writeFileSync)(validatePath, VALIDATE_SESSION_SCRIPT);
|
|
191
|
+
console.log(chalk_1.default.green(' ✓ Created validation script'));
|
|
192
|
+
// Check if husky is being used
|
|
193
|
+
const huskyDir = (0, path_1.join)(cwd, '.husky');
|
|
194
|
+
if ((0, fs_1.existsSync)(huskyDir)) {
|
|
195
|
+
// Also install in husky
|
|
196
|
+
const huskyPreCommit = (0, path_1.join)(huskyDir, 'pre-commit');
|
|
197
|
+
let huskyContent = '';
|
|
198
|
+
if ((0, fs_1.existsSync)(huskyPreCommit)) {
|
|
199
|
+
huskyContent = (0, fs_1.readFileSync)(huskyPreCommit, 'utf-8');
|
|
200
|
+
if (!huskyContent.includes('validate-session')) {
|
|
201
|
+
huskyContent += '\n# CodeBakers session enforcement\nnode .git/hooks/validate-session.js\n';
|
|
202
|
+
(0, fs_1.writeFileSync)(huskyPreCommit, huskyContent);
|
|
203
|
+
console.log(chalk_1.default.green(' ✓ Added to existing husky pre-commit'));
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
console.log(chalk_1.default.gray(' ✓ Husky hook already configured'));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
huskyContent = '#!/usr/bin/env sh\n. "$(dirname -- "$0")/_/husky.sh"\n\n# CodeBakers session enforcement\nnode .git/hooks/validate-session.js\n';
|
|
211
|
+
(0, fs_1.writeFileSync)(huskyPreCommit, huskyContent);
|
|
212
|
+
try {
|
|
213
|
+
(0, fs_1.chmodSync)(huskyPreCommit, '755');
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// Windows
|
|
217
|
+
}
|
|
218
|
+
console.log(chalk_1.default.green(' ✓ Created husky pre-commit hook'));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
console.log(chalk_1.default.green('\n ✅ Pre-commit hook installed!\n'));
|
|
222
|
+
console.log(chalk_1.default.cyan(' What this does:'));
|
|
223
|
+
console.log(chalk_1.default.gray(' - Blocks commits unless AI called discover_patterns'));
|
|
224
|
+
console.log(chalk_1.default.gray(' - Blocks commits unless AI called validate_complete'));
|
|
225
|
+
console.log(chalk_1.default.gray(' - Requires validation to pass before committing'));
|
|
226
|
+
console.log(chalk_1.default.gray(' - Validation expires after 30 minutes\n'));
|
|
227
|
+
console.log(chalk_1.default.yellow(' To bypass (not recommended):'));
|
|
228
|
+
console.log(chalk_1.default.gray(' git commit --no-verify\n'));
|
|
229
|
+
}
|