@electriccitizen/bolt 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -14
- package/dist/ai/agent.d.ts +66 -0
- package/dist/ai/agent.js +232 -0
- package/dist/ai/agent.js.map +1 -0
- package/dist/ai/knowledge/composer.md +90 -0
- package/dist/ai/knowledge/config-safety.md +46 -0
- package/dist/ai/knowledge/ddev-operations.md +41 -0
- package/dist/ai/knowledge/drupal-internals.md +52 -0
- package/dist/ai/knowledge/drupal-updates.md +90 -0
- package/dist/ai/knowledge/knowledge/composer.md +90 -0
- package/dist/ai/knowledge/knowledge/config-safety.md +46 -0
- package/dist/ai/knowledge/knowledge/ddev-operations.md +41 -0
- package/dist/ai/knowledge/knowledge/drupal-debugging.md +89 -0
- package/dist/ai/knowledge/knowledge/drupal-internals.md +52 -0
- package/dist/ai/knowledge/knowledge/drupal-updates.md +90 -0
- package/dist/ai/prompts/analyze-ticket.d.ts +30 -0
- package/dist/ai/prompts/analyze-ticket.js +116 -0
- package/dist/ai/prompts/analyze-ticket.js.map +1 -0
- package/dist/ai/prompts/fix-ticket.d.ts +27 -0
- package/dist/ai/prompts/fix-ticket.js +129 -0
- package/dist/ai/prompts/fix-ticket.js.map +1 -0
- package/dist/ai/prompts/pr-description.d.ts +19 -0
- package/dist/ai/prompts/pr-description.js +56 -0
- package/dist/ai/prompts/pr-description.js.map +1 -0
- package/dist/ai/prompts/update-package.d.ts +25 -0
- package/dist/ai/prompts/update-package.js +87 -0
- package/dist/ai/prompts/update-package.js.map +1 -0
- package/dist/ai/prompts/update-plan.d.ts +20 -0
- package/dist/ai/prompts/update-plan.js +66 -0
- package/dist/ai/prompts/update-plan.js.map +1 -0
- package/dist/ai/schemas/analysis-result.d.ts +44 -0
- package/dist/ai/schemas/analysis-result.js +101 -0
- package/dist/ai/schemas/analysis-result.js.map +1 -0
- package/dist/ai/schemas/fix-result.d.ts +34 -0
- package/dist/ai/schemas/fix-result.js +55 -0
- package/dist/ai/schemas/fix-result.js.map +1 -0
- package/dist/ai/schemas/pr-body.d.ts +12 -0
- package/dist/ai/schemas/pr-body.js +18 -0
- package/dist/ai/schemas/pr-body.js.map +1 -0
- package/dist/ai/schemas/update-plan.d.ts +20 -0
- package/dist/ai/schemas/update-plan.js +33 -0
- package/dist/ai/schemas/update-plan.js.map +1 -0
- package/dist/ai/schemas/update-result.d.ts +22 -0
- package/dist/ai/schemas/update-result.js +30 -0
- package/dist/ai/schemas/update-result.js.map +1 -0
- package/dist/cli.js +63 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/analyze.d.ts +25 -0
- package/dist/commands/analyze.js +377 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/doctor.js +61 -13
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/fix.d.ts +35 -0
- package/dist/commands/fix.js +480 -0
- package/dist/commands/fix.js.map +1 -0
- package/dist/commands/init.d.ts +3 -2
- package/dist/commands/init.js +117 -160
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/pr.d.ts +4 -0
- package/dist/commands/pr.js +121 -3
- package/dist/commands/pr.js.map +1 -1
- package/dist/commands/refresh.js +10 -57
- package/dist/commands/refresh.js.map +1 -1
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.js +463 -64
- package/dist/commands/update.js.map +1 -1
- package/dist/config.d.ts +16 -0
- package/dist/config.js +57 -0
- package/dist/config.js.map +1 -1
- package/dist/runner.js +12 -0
- package/dist/runner.js.map +1 -1
- package/dist/safety.d.ts +63 -0
- package/dist/safety.js +192 -0
- package/dist/safety.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/package.json +2 -3
- package/modules/bolt_inspect/bolt_inspect.info.yml +0 -6
- package/modules/bolt_inspect/bolt_inspect.services.yml +0 -22
- package/modules/bolt_inspect/composer.json +0 -16
- package/modules/bolt_inspect/drush.services.yml +0 -10
- package/modules/bolt_inspect/src/Drush/Commands/BoltInspectCommands.php +0 -203
- package/modules/bolt_inspect/src/Service/ContentGenerator.php +0 -586
- package/modules/bolt_inspect/src/Service/SiteProfiler.php +0 -362
- package/modules/bolt_inspect/src/Service/TestEntityTracker.php +0 -98
package/dist/commands/init.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* bolt init — connect bolt to a client site.
|
|
3
3
|
*
|
|
4
|
-
* Full init:
|
|
5
|
-
* Upgrade mode (--upgrade):
|
|
4
|
+
* Full init: composer require bolt-inspect, enable module, create config.
|
|
5
|
+
* Upgrade mode (--upgrade): composer update bolt-inspect, clear caches.
|
|
6
6
|
*/
|
|
7
7
|
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
8
|
-
import { join
|
|
9
|
-
import { fileURLToPath } from 'url';
|
|
10
|
-
import { dirname } from 'path';
|
|
8
|
+
import { join } from 'path';
|
|
11
9
|
import { execFile } from 'child_process';
|
|
12
10
|
import { promisify } from 'util';
|
|
13
11
|
import { generateConfigTemplate } from '../config.js';
|
|
12
|
+
import { checkGitState, warnDefaultBranch } from '../safety.js';
|
|
14
13
|
const execFileAsync = promisify(execFile);
|
|
14
|
+
const PACKAGE_NAME = 'electriccitizen/bolt-inspect';
|
|
15
15
|
/** Write progress messages to stderr. */
|
|
16
16
|
function log(msg) {
|
|
17
17
|
process.stderr.write(` ${msg}\n`);
|
|
@@ -22,27 +22,8 @@ function logOk(msg) {
|
|
|
22
22
|
function logSkip(msg) {
|
|
23
23
|
process.stderr.write(` ⊘ ${msg}\n`);
|
|
24
24
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
* Works from both git clone (dev) and npm global install.
|
|
28
|
-
*/
|
|
29
|
-
function getBoltRoot() {
|
|
30
|
-
const thisFile = fileURLToPath(import.meta.url);
|
|
31
|
-
// dist/commands/init.js → bolt root
|
|
32
|
-
return resolve(dirname(thisFile), '..', '..');
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Get bolt CLI version from package.json.
|
|
36
|
-
*/
|
|
37
|
-
function getBoltVersion() {
|
|
38
|
-
const boltRoot = getBoltRoot();
|
|
39
|
-
try {
|
|
40
|
-
const pkg = JSON.parse(readFileSync(join(boltRoot, 'package.json'), 'utf-8'));
|
|
41
|
-
return pkg.version ?? 'unknown';
|
|
42
|
-
}
|
|
43
|
-
catch {
|
|
44
|
-
return 'unknown';
|
|
45
|
-
}
|
|
25
|
+
function logWarn(msg) {
|
|
26
|
+
process.stderr.write(` ⚠ ${msg}\n`);
|
|
46
27
|
}
|
|
47
28
|
/**
|
|
48
29
|
* Run a shell command and return the result.
|
|
@@ -68,21 +49,46 @@ async function exec(command, args) {
|
|
|
68
49
|
}
|
|
69
50
|
}
|
|
70
51
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
52
|
+
* Migrate from the old volume-mount/path-repo install to Packagist.
|
|
53
|
+
* Removes .ddev/docker-compose.bolt.yaml, path repo, and old package name.
|
|
54
|
+
*/
|
|
55
|
+
async function migrateFromPathRepo(cwd) {
|
|
56
|
+
// Remove old volume mount file.
|
|
57
|
+
const dockerComposePath = join(cwd, '.ddev', 'docker-compose.bolt.yaml');
|
|
58
|
+
if (existsSync(dockerComposePath)) {
|
|
59
|
+
const { unlinkSync } = await import('fs');
|
|
60
|
+
unlinkSync(dockerComposePath);
|
|
61
|
+
logOk('Removed old .ddev/docker-compose.bolt.yaml (no longer needed)');
|
|
62
|
+
}
|
|
63
|
+
// Remove old path repository from composer.json.
|
|
64
|
+
const composerPath = join(cwd, 'composer.json');
|
|
65
|
+
if (existsSync(composerPath)) {
|
|
66
|
+
const composerJson = JSON.parse(readFileSync(composerPath, 'utf-8'));
|
|
67
|
+
const repos = composerJson.repositories;
|
|
68
|
+
if (repos) {
|
|
69
|
+
// Check for path repo pointing to /mnt/bolt_inspect.
|
|
70
|
+
const hasPathRepo = Array.isArray(repos)
|
|
71
|
+
? repos.some((r) => r.url === '/mnt/bolt_inspect')
|
|
72
|
+
: Object.values(repos).some((r) => r.url === '/mnt/bolt_inspect');
|
|
73
|
+
if (hasPathRepo) {
|
|
74
|
+
await exec('ddev', ['composer', 'config', '--unset', 'repositories.bolt_inspect']);
|
|
75
|
+
logOk('Removed old path repository from composer.json');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Remove old package name if present.
|
|
79
|
+
const requires = composerJson.require ?? {};
|
|
80
|
+
if (requires['bolt/bolt_inspect']) {
|
|
81
|
+
await exec('ddev', ['composer', 'remove', 'bolt/bolt_inspect', '--no-interaction']);
|
|
82
|
+
logOk('Removed old bolt/bolt_inspect package');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Upgrade mode: updates the module via Composer and clears caches.
|
|
73
88
|
*/
|
|
74
89
|
async function upgradeCommand(cwd) {
|
|
75
|
-
const boltRoot = getBoltRoot();
|
|
76
|
-
const boltInspectPath = join(boltRoot, 'modules', 'bolt_inspect');
|
|
77
|
-
const boltVersion = getBoltVersion();
|
|
78
90
|
process.stderr.write('\nbolt init --upgrade\n');
|
|
79
91
|
process.stderr.write('━'.repeat(50) + '\n\n');
|
|
80
|
-
// Verify bolt_inspect module exists in the package.
|
|
81
|
-
if (!existsSync(boltInspectPath)) {
|
|
82
|
-
process.stderr.write(`Error: bolt_inspect module not found at ${boltInspectPath}\n` +
|
|
83
|
-
'Is bolt installed correctly?\n');
|
|
84
|
-
process.exit(2);
|
|
85
|
-
}
|
|
86
92
|
// Verify we're in a DDEV project.
|
|
87
93
|
const ddevConfigPath = join(cwd, '.ddev', 'config.yaml');
|
|
88
94
|
if (!existsSync(ddevConfigPath)) {
|
|
@@ -90,61 +96,44 @@ async function upgradeCommand(cwd) {
|
|
|
90
96
|
'Run this from a DDEV-configured Drupal project directory.\n');
|
|
91
97
|
process.exit(2);
|
|
92
98
|
}
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
writeFileSync(dockerComposePath, volumeConfig, 'utf-8');
|
|
107
|
-
logOk('Updated volume mount path');
|
|
99
|
+
// Migrate from old path-repo install if needed.
|
|
100
|
+
await migrateFromPathRepo(cwd);
|
|
101
|
+
// Check if the package is already installed.
|
|
102
|
+
const showResult = await exec('ddev', ['composer', 'show', PACKAGE_NAME]);
|
|
103
|
+
if (showResult.exitCode === 0) {
|
|
104
|
+
// Already installed — update it.
|
|
105
|
+
log('Updating bolt-inspect...');
|
|
106
|
+
const updateResult = await exec('ddev', ['composer', 'update', PACKAGE_NAME, '--no-interaction']);
|
|
107
|
+
if (updateResult.exitCode !== 0) {
|
|
108
|
+
process.stderr.write(`Error: Could not update ${PACKAGE_NAME}.\n${updateResult.stderr}\n`);
|
|
109
|
+
process.exit(2);
|
|
108
110
|
}
|
|
111
|
+
logOk('Updated bolt-inspect');
|
|
109
112
|
}
|
|
110
113
|
else {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
'Start DDEV manually.\n');
|
|
120
|
-
process.exit(2);
|
|
121
|
-
}
|
|
122
|
-
logOk('DDEV restarted');
|
|
123
|
-
// Clear Drupal cache so it picks up any module code changes.
|
|
124
|
-
log('Clearing caches...');
|
|
125
|
-
const crResult = await exec('ddev', ['drush', 'cr']);
|
|
126
|
-
if (crResult.exitCode !== 0) {
|
|
127
|
-
process.stderr.write(`Warning: drush cr failed.\n${crResult.stderr}\n`);
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
logOk('Caches cleared');
|
|
114
|
+
// Not installed — require it (migration from old package, or fresh install).
|
|
115
|
+
log('Installing bolt-inspect...');
|
|
116
|
+
const requireResult = await exec('ddev', ['composer', 'require', PACKAGE_NAME, '--no-interaction']);
|
|
117
|
+
if (requireResult.exitCode !== 0) {
|
|
118
|
+
process.stderr.write(`Error: Could not install ${PACKAGE_NAME}.\n${requireResult.stderr}\n`);
|
|
119
|
+
process.exit(2);
|
|
120
|
+
}
|
|
121
|
+
logOk('Installed bolt-inspect');
|
|
131
122
|
}
|
|
132
|
-
//
|
|
123
|
+
// Enable module (in case it was disabled).
|
|
124
|
+
await exec('ddev', ['drush', 'en', 'bolt_inspect', '-y']);
|
|
125
|
+
// Clear caches + run database updates.
|
|
133
126
|
log('Running database updates...');
|
|
134
127
|
const updbResult = await exec('ddev', ['drush', 'updb', '-y']);
|
|
135
|
-
if (updbResult.
|
|
136
|
-
|
|
128
|
+
if (updbResult.stdout.includes('No pending updates')) {
|
|
129
|
+
logOk('No pending database updates');
|
|
137
130
|
}
|
|
138
131
|
else {
|
|
139
|
-
|
|
140
|
-
logOk('No pending database updates');
|
|
141
|
-
}
|
|
142
|
-
else {
|
|
143
|
-
logOk('Database updates applied');
|
|
144
|
-
}
|
|
132
|
+
logOk('Database updates applied');
|
|
145
133
|
}
|
|
146
|
-
|
|
147
|
-
|
|
134
|
+
await exec('ddev', ['drush', 'cr']);
|
|
135
|
+
logOk('Caches cleared');
|
|
136
|
+
process.stderr.write('\nbolt-inspect upgraded.\n');
|
|
148
137
|
process.stderr.write('Run: bolt doctor (verify environment)\n\n');
|
|
149
138
|
}
|
|
150
139
|
export async function initCommand(options) {
|
|
@@ -154,22 +143,22 @@ export async function initCommand(options) {
|
|
|
154
143
|
await upgradeCommand(cwd);
|
|
155
144
|
return;
|
|
156
145
|
}
|
|
157
|
-
const boltRoot = getBoltRoot();
|
|
158
|
-
const boltInspectPath = join(boltRoot, 'modules', 'bolt_inspect');
|
|
159
146
|
process.stderr.write('\nbolt init\n');
|
|
160
147
|
process.stderr.write('━'.repeat(50) + '\n\n');
|
|
161
|
-
// 0.
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
148
|
+
// 0. Check branch — init modifies composer.json, should be on a feature branch.
|
|
149
|
+
const gitState = await checkGitState();
|
|
150
|
+
if (gitState.isGitRepo) {
|
|
151
|
+
const proceed = await warnDefaultBranch(gitState, {
|
|
152
|
+
yes: options.yes,
|
|
153
|
+
suggestion: 'bolt init modifies composer.json — this should go on a dedicated branch.\n Consider: git checkout -b bolt',
|
|
154
|
+
});
|
|
155
|
+
if (!proceed) {
|
|
156
|
+
log('Aborted. Create a feature branch first.\n');
|
|
157
|
+
process.exit(0);
|
|
158
|
+
}
|
|
159
|
+
if (gitState.isDirty) {
|
|
160
|
+
logWarn('Uncommitted changes detected — bolt init changes will be mixed in.');
|
|
169
161
|
}
|
|
170
|
-
}
|
|
171
|
-
catch {
|
|
172
|
-
// Not a git repo or git not available — skip the check.
|
|
173
162
|
}
|
|
174
163
|
// 1. Verify we're in a DDEV project.
|
|
175
164
|
const ddevConfigPath = join(cwd, '.ddev', 'config.yaml');
|
|
@@ -179,85 +168,53 @@ export async function initCommand(options) {
|
|
|
179
168
|
process.exit(2);
|
|
180
169
|
}
|
|
181
170
|
logOk('DDEV project detected');
|
|
182
|
-
// 2.
|
|
183
|
-
|
|
184
|
-
process.stderr.write(`Error: bolt_inspect module not found at ${boltInspectPath}\n` +
|
|
185
|
-
'Is bolt installed correctly?\n');
|
|
186
|
-
process.exit(2);
|
|
187
|
-
}
|
|
188
|
-
// 3. Create DDEV volume mount.
|
|
189
|
-
const dockerComposePath = join(cwd, '.ddev', 'docker-compose.bolt.yaml');
|
|
190
|
-
if (existsSync(dockerComposePath)) {
|
|
191
|
-
logOk('DDEV volume mount already configured');
|
|
192
|
-
}
|
|
193
|
-
else {
|
|
194
|
-
const volumeConfig = `services:
|
|
195
|
-
web:
|
|
196
|
-
volumes:
|
|
197
|
-
- ${boltRoot}/modules/bolt_inspect:/mnt/bolt_inspect:cached
|
|
198
|
-
`;
|
|
199
|
-
writeFileSync(dockerComposePath, volumeConfig, 'utf-8');
|
|
200
|
-
logOk('Created .ddev/docker-compose.bolt.yaml');
|
|
201
|
-
}
|
|
171
|
+
// 2. Migrate from old path-repo install if present.
|
|
172
|
+
await migrateFromPathRepo(cwd);
|
|
202
173
|
if (!options.skipComposer) {
|
|
203
|
-
//
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
174
|
+
// 3. Ensure DDEV is running.
|
|
175
|
+
const statusResult = await exec('ddev', ['describe', '-j']);
|
|
176
|
+
if (statusResult.exitCode !== 0) {
|
|
177
|
+
log('Starting DDEV...');
|
|
178
|
+
const startResult = await exec('ddev', ['start']);
|
|
179
|
+
if (startResult.exitCode !== 0) {
|
|
180
|
+
process.stderr.write(`Error: DDEV start failed.\n${startResult.stderr}\n`);
|
|
181
|
+
process.exit(2);
|
|
182
|
+
}
|
|
183
|
+
logOk('DDEV started');
|
|
210
184
|
}
|
|
211
|
-
|
|
212
|
-
|
|
185
|
+
else {
|
|
186
|
+
logOk('DDEV is running');
|
|
187
|
+
}
|
|
188
|
+
// 4. Require bolt-inspect via Composer.
|
|
213
189
|
const composerPath = join(cwd, 'composer.json');
|
|
214
190
|
if (!existsSync(composerPath)) {
|
|
215
191
|
process.stderr.write('Error: No composer.json found in project root.\n');
|
|
216
192
|
process.exit(2);
|
|
217
193
|
}
|
|
218
194
|
const composerJson = JSON.parse(readFileSync(composerPath, 'utf-8'));
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
logOk('Composer path repository already configured');
|
|
195
|
+
const requires = composerJson.require ?? {};
|
|
196
|
+
if (requires[PACKAGE_NAME]) {
|
|
197
|
+
logOk('bolt-inspect already in composer.json');
|
|
223
198
|
}
|
|
224
199
|
else {
|
|
225
|
-
log('
|
|
226
|
-
const
|
|
227
|
-
'composer', '
|
|
228
|
-
'{"type": "path", "url": "/mnt/bolt_inspect", "options": {"symlink": true}}',
|
|
200
|
+
log('Installing bolt-inspect module...');
|
|
201
|
+
const requireResult = await exec('ddev', [
|
|
202
|
+
'composer', 'require', PACKAGE_NAME, '--no-interaction',
|
|
229
203
|
]);
|
|
230
|
-
if (
|
|
231
|
-
process.stderr.write(`
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
logOk('Added Composer path repository');
|
|
204
|
+
if (requireResult.exitCode !== 0) {
|
|
205
|
+
process.stderr.write(`Error: composer require failed.\n${requireResult.stderr}\n`);
|
|
206
|
+
process.stderr.write(`Make sure ${PACKAGE_NAME} is available on Packagist.\n`);
|
|
207
|
+
process.exit(2);
|
|
235
208
|
}
|
|
236
|
-
|
|
237
|
-
// 6. Require bolt_inspect.
|
|
238
|
-
log('Installing bolt_inspect module...');
|
|
239
|
-
const requireResult = await exec('ddev', [
|
|
240
|
-
'composer', 'require', 'bolt/bolt_inspect:@dev',
|
|
241
|
-
]);
|
|
242
|
-
if (requireResult.exitCode !== 0) {
|
|
243
|
-
// May already be installed.
|
|
244
|
-
if (requireResult.stderr.includes('already present')) {
|
|
245
|
-
logOk('bolt_inspect already in composer.json');
|
|
246
|
-
}
|
|
247
|
-
else {
|
|
248
|
-
process.stderr.write(`Warning: composer require failed.\n${requireResult.stderr}\n`);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
else {
|
|
252
|
-
logOk('Installed bolt_inspect via Composer');
|
|
209
|
+
logOk('Installed bolt-inspect via Composer');
|
|
253
210
|
}
|
|
254
211
|
}
|
|
255
212
|
else {
|
|
256
|
-
logSkip('Skipping Composer
|
|
213
|
+
logSkip('Skipping Composer install (--skip-composer)');
|
|
257
214
|
}
|
|
258
215
|
if (!options.skipModule) {
|
|
259
|
-
// 7. Enable the module.
|
|
260
216
|
if (!options.skipComposer) {
|
|
217
|
+
// 5. Enable the module.
|
|
261
218
|
log('Enabling bolt_inspect module...');
|
|
262
219
|
const enResult = await exec('ddev', ['drush', 'en', 'bolt_inspect', '-y']);
|
|
263
220
|
if (enResult.exitCode !== 0) {
|
|
@@ -276,7 +233,7 @@ export async function initCommand(options) {
|
|
|
276
233
|
else {
|
|
277
234
|
logSkip('Skipping module enable (--skip-module)');
|
|
278
235
|
}
|
|
279
|
-
//
|
|
236
|
+
// 6. Drop .bolt.yml config template.
|
|
280
237
|
const boltYmlPath = join(cwd, '.bolt.yml');
|
|
281
238
|
if (existsSync(boltYmlPath)) {
|
|
282
239
|
logOk('.bolt.yml already exists');
|
|
@@ -285,13 +242,13 @@ export async function initCommand(options) {
|
|
|
285
242
|
writeFileSync(boltYmlPath, generateConfigTemplate(), 'utf-8');
|
|
286
243
|
logOk('Created .bolt.yml config template');
|
|
287
244
|
}
|
|
288
|
-
//
|
|
245
|
+
// 7. Add bolt artifacts to .gitignore.
|
|
289
246
|
const gitignorePath = join(cwd, '.gitignore');
|
|
290
247
|
const boltIgnores = [
|
|
291
248
|
'# Bolt (local testing artifacts)',
|
|
292
249
|
'.bolt/logs/',
|
|
250
|
+
'.boltrc.yml',
|
|
293
251
|
'vr-screenshots/',
|
|
294
|
-
'.ddev/docker-compose.bolt.yaml',
|
|
295
252
|
];
|
|
296
253
|
if (existsSync(gitignorePath)) {
|
|
297
254
|
const existing = readFileSync(gitignorePath, 'utf-8');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/pr.d.ts
CHANGED
|
@@ -14,6 +14,10 @@ export interface PrOptions {
|
|
|
14
14
|
draft: boolean;
|
|
15
15
|
/** Create PRs for all update/* branches. */
|
|
16
16
|
all: boolean;
|
|
17
|
+
/** Disable AI-generated PR descriptions. */
|
|
18
|
+
noAi?: boolean;
|
|
19
|
+
/** Skip confirmation prompts. */
|
|
20
|
+
yes: boolean;
|
|
17
21
|
/** Resolved .bolt.yml config. */
|
|
18
22
|
boltConfig?: BoltConfig;
|
|
19
23
|
}
|
package/dist/commands/pr.js
CHANGED
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { execFile } from 'child_process';
|
|
8
8
|
import { promisify } from 'util';
|
|
9
|
+
import { isClaudeAvailable, runAgent } from '../ai/agent.js';
|
|
10
|
+
import { buildPrDescriptionTask } from '../ai/prompts/pr-description.js';
|
|
11
|
+
import { validatePrBody } from '../ai/schemas/pr-body.js';
|
|
12
|
+
import { checkGitState, warnDirtyTree, confirm } from '../safety.js';
|
|
9
13
|
const execFileAsync = promisify(execFile);
|
|
10
14
|
/** Write progress messages to stderr. */
|
|
11
15
|
function log(msg) {
|
|
@@ -115,6 +119,72 @@ function buildPrBody(info) {
|
|
|
115
119
|
lines.push('Generated by [Bolt](https://github.com/electriccitizen/bolt)');
|
|
116
120
|
return lines.join('\n');
|
|
117
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Build an UpdateResult from parsed branch info for the AI prompt.
|
|
124
|
+
*/
|
|
125
|
+
function toUpdateResult(info, branch) {
|
|
126
|
+
// Parse test summary from commit body if present.
|
|
127
|
+
let testSummary;
|
|
128
|
+
const testMatch = info.commitBody.match(/Bolt test: \w+ \((\d+) passed, (\d+) failed, (\d+) suppressed\)/);
|
|
129
|
+
if (testMatch) {
|
|
130
|
+
testSummary = {
|
|
131
|
+
passed: parseInt(testMatch[1], 10),
|
|
132
|
+
failed: parseInt(testMatch[2], 10),
|
|
133
|
+
suppressed: parseInt(testMatch[3], 10),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
// Parse db updates from commit body.
|
|
137
|
+
const dbMatch = info.commitBody.match(/Database: .+\((.+)\)/);
|
|
138
|
+
const dbUpdates = dbMatch && !dbMatch[1].includes('no pending') ? 1 : 0;
|
|
139
|
+
return {
|
|
140
|
+
package: info.package,
|
|
141
|
+
oldVersion: info.oldVersion,
|
|
142
|
+
newVersion: info.newVersion,
|
|
143
|
+
status: 'pass',
|
|
144
|
+
branch,
|
|
145
|
+
testSummary,
|
|
146
|
+
dbUpdates,
|
|
147
|
+
duration: 0,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Generate PR title and body using AI agent.
|
|
152
|
+
*/
|
|
153
|
+
async function aiPrDescription(info, branch, baseBranch) {
|
|
154
|
+
// Gather context for the AI.
|
|
155
|
+
const diffStatResult = await exec('git', ['diff', '--stat', `${baseBranch}...${branch}`]);
|
|
156
|
+
const diffStat = diffStatResult.stdout.trim();
|
|
157
|
+
const commitResult = await exec('git', ['log', `${baseBranch}..${branch}`, '--format=%B', '--reverse']);
|
|
158
|
+
const commitMessages = commitResult.stdout.trim();
|
|
159
|
+
// Get config changes from the diff.
|
|
160
|
+
const diffNamesResult = await exec('git', ['diff', '--name-only', `${baseBranch}...${branch}`]);
|
|
161
|
+
const configChanges = diffNamesResult.stdout
|
|
162
|
+
.trim()
|
|
163
|
+
.split('\n')
|
|
164
|
+
.filter((f) => f.startsWith('config/') || f.endsWith('.yml'));
|
|
165
|
+
const result = toUpdateResult(info, branch);
|
|
166
|
+
const task = buildPrDescriptionTask({
|
|
167
|
+
result,
|
|
168
|
+
diffStat,
|
|
169
|
+
commitMessages,
|
|
170
|
+
configChanges,
|
|
171
|
+
});
|
|
172
|
+
log('Generating AI PR description...');
|
|
173
|
+
const agentResult = await runAgent(task);
|
|
174
|
+
if (!agentResult.success) {
|
|
175
|
+
logWarn('AI did not return structured output for PR description');
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
const validated = validatePrBody(agentResult.output);
|
|
179
|
+
if (!validated) {
|
|
180
|
+
logWarn('AI PR description failed schema validation');
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
if (agentResult.costUsd) {
|
|
184
|
+
log(` AI cost: $${agentResult.costUsd.toFixed(4)} (${agentResult.numTurns} turns)`);
|
|
185
|
+
}
|
|
186
|
+
return validated;
|
|
187
|
+
}
|
|
118
188
|
/**
|
|
119
189
|
* Check if `gh` CLI is available.
|
|
120
190
|
*/
|
|
@@ -145,7 +215,7 @@ async function prExists(branch) {
|
|
|
145
215
|
/**
|
|
146
216
|
* Create a PR for a single branch.
|
|
147
217
|
*/
|
|
148
|
-
async function createPrForBranch(branch, prConfig, options) {
|
|
218
|
+
async function createPrForBranch(branch, prConfig, options, useAi) {
|
|
149
219
|
const baseBranch = options.base || prConfig.base_branch || 'main';
|
|
150
220
|
const remote = prConfig.remote || 'origin';
|
|
151
221
|
const isDraft = options.draft || prConfig.draft;
|
|
@@ -154,7 +224,20 @@ async function createPrForBranch(branch, prConfig, options) {
|
|
|
154
224
|
// Build title and body.
|
|
155
225
|
let title;
|
|
156
226
|
let body;
|
|
157
|
-
if (info) {
|
|
227
|
+
if (info && useAi) {
|
|
228
|
+
// AI path — let Claude write the PR description.
|
|
229
|
+
const aiResult = await aiPrDescription(info, branch, baseBranch);
|
|
230
|
+
if (aiResult) {
|
|
231
|
+
title = aiResult.title;
|
|
232
|
+
body = aiResult.body;
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
// AI failed — fall back to scripted.
|
|
236
|
+
title = `Update ${info.package} from ${info.oldVersion} to ${info.newVersion}`;
|
|
237
|
+
body = buildPrBody(info);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
else if (info) {
|
|
158
241
|
title = `Update ${info.package} from ${info.oldVersion} to ${info.newVersion}`;
|
|
159
242
|
body = buildPrBody(info);
|
|
160
243
|
}
|
|
@@ -223,6 +306,19 @@ export async function prCommand(options) {
|
|
|
223
306
|
'Then run: gh auth login\n');
|
|
224
307
|
process.exit(2);
|
|
225
308
|
}
|
|
309
|
+
// --- Git safety checks ---
|
|
310
|
+
const baseBranch = options.base ?? prConfig.base_branch ?? 'main';
|
|
311
|
+
const gitState = await checkGitState(baseBranch);
|
|
312
|
+
if (gitState.isDirty) {
|
|
313
|
+
const proceed = await warnDirtyTree(gitState, {
|
|
314
|
+
yes: options.yes,
|
|
315
|
+
reason: 'PRs will be created from committed state only — uncommitted changes are not included.',
|
|
316
|
+
});
|
|
317
|
+
if (!proceed) {
|
|
318
|
+
log('Aborted. Commit or stash your changes first.\n');
|
|
319
|
+
process.exit(0);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
226
322
|
// Determine which branches to create PRs for.
|
|
227
323
|
let branches;
|
|
228
324
|
if (options.all) {
|
|
@@ -241,12 +337,34 @@ export async function prCommand(options) {
|
|
|
241
337
|
}
|
|
242
338
|
branches = [current];
|
|
243
339
|
}
|
|
340
|
+
// Detect AI availability.
|
|
341
|
+
let useAi = false;
|
|
342
|
+
if (!options.noAi) {
|
|
343
|
+
const claudeReady = await isClaudeAvailable();
|
|
344
|
+
if (claudeReady) {
|
|
345
|
+
useAi = true;
|
|
346
|
+
logOk('AI mode enabled for PR descriptions');
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
// Confirm before pushing.
|
|
350
|
+
if (!options.yes) {
|
|
351
|
+
process.stderr.write('\n Branches to push and create PRs for:\n');
|
|
352
|
+
for (const b of branches) {
|
|
353
|
+
process.stderr.write(` ${b}\n`);
|
|
354
|
+
}
|
|
355
|
+
process.stderr.write('\n');
|
|
356
|
+
const proceed = await confirm(`Push ${branches.length} branch(es) to remote and create PRs?`);
|
|
357
|
+
if (!proceed) {
|
|
358
|
+
log('Aborted.\n');
|
|
359
|
+
process.exit(0);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
244
362
|
process.stderr.write('\n');
|
|
245
363
|
// Create PRs.
|
|
246
364
|
const results = [];
|
|
247
365
|
for (const branch of branches) {
|
|
248
366
|
log(`Creating PR for ${branch}...`);
|
|
249
|
-
const result = await createPrForBranch(branch, prConfig, options);
|
|
367
|
+
const result = await createPrForBranch(branch, prConfig, options, useAi);
|
|
250
368
|
results.push(result);
|
|
251
369
|
switch (result.status) {
|
|
252
370
|
case 'created':
|