@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.
Files changed (84) hide show
  1. package/README.md +93 -14
  2. package/dist/ai/agent.d.ts +66 -0
  3. package/dist/ai/agent.js +232 -0
  4. package/dist/ai/agent.js.map +1 -0
  5. package/dist/ai/knowledge/composer.md +90 -0
  6. package/dist/ai/knowledge/config-safety.md +46 -0
  7. package/dist/ai/knowledge/ddev-operations.md +41 -0
  8. package/dist/ai/knowledge/drupal-internals.md +52 -0
  9. package/dist/ai/knowledge/drupal-updates.md +90 -0
  10. package/dist/ai/knowledge/knowledge/composer.md +90 -0
  11. package/dist/ai/knowledge/knowledge/config-safety.md +46 -0
  12. package/dist/ai/knowledge/knowledge/ddev-operations.md +41 -0
  13. package/dist/ai/knowledge/knowledge/drupal-debugging.md +89 -0
  14. package/dist/ai/knowledge/knowledge/drupal-internals.md +52 -0
  15. package/dist/ai/knowledge/knowledge/drupal-updates.md +90 -0
  16. package/dist/ai/prompts/analyze-ticket.d.ts +30 -0
  17. package/dist/ai/prompts/analyze-ticket.js +116 -0
  18. package/dist/ai/prompts/analyze-ticket.js.map +1 -0
  19. package/dist/ai/prompts/fix-ticket.d.ts +27 -0
  20. package/dist/ai/prompts/fix-ticket.js +129 -0
  21. package/dist/ai/prompts/fix-ticket.js.map +1 -0
  22. package/dist/ai/prompts/pr-description.d.ts +19 -0
  23. package/dist/ai/prompts/pr-description.js +56 -0
  24. package/dist/ai/prompts/pr-description.js.map +1 -0
  25. package/dist/ai/prompts/update-package.d.ts +25 -0
  26. package/dist/ai/prompts/update-package.js +87 -0
  27. package/dist/ai/prompts/update-package.js.map +1 -0
  28. package/dist/ai/prompts/update-plan.d.ts +20 -0
  29. package/dist/ai/prompts/update-plan.js +66 -0
  30. package/dist/ai/prompts/update-plan.js.map +1 -0
  31. package/dist/ai/schemas/analysis-result.d.ts +44 -0
  32. package/dist/ai/schemas/analysis-result.js +101 -0
  33. package/dist/ai/schemas/analysis-result.js.map +1 -0
  34. package/dist/ai/schemas/fix-result.d.ts +34 -0
  35. package/dist/ai/schemas/fix-result.js +55 -0
  36. package/dist/ai/schemas/fix-result.js.map +1 -0
  37. package/dist/ai/schemas/pr-body.d.ts +12 -0
  38. package/dist/ai/schemas/pr-body.js +18 -0
  39. package/dist/ai/schemas/pr-body.js.map +1 -0
  40. package/dist/ai/schemas/update-plan.d.ts +20 -0
  41. package/dist/ai/schemas/update-plan.js +33 -0
  42. package/dist/ai/schemas/update-plan.js.map +1 -0
  43. package/dist/ai/schemas/update-result.d.ts +22 -0
  44. package/dist/ai/schemas/update-result.js +30 -0
  45. package/dist/ai/schemas/update-result.js.map +1 -0
  46. package/dist/cli.js +63 -1
  47. package/dist/cli.js.map +1 -1
  48. package/dist/commands/analyze.d.ts +25 -0
  49. package/dist/commands/analyze.js +377 -0
  50. package/dist/commands/analyze.js.map +1 -0
  51. package/dist/commands/doctor.js +61 -13
  52. package/dist/commands/doctor.js.map +1 -1
  53. package/dist/commands/fix.d.ts +35 -0
  54. package/dist/commands/fix.js +480 -0
  55. package/dist/commands/fix.js.map +1 -0
  56. package/dist/commands/init.d.ts +3 -2
  57. package/dist/commands/init.js +117 -160
  58. package/dist/commands/init.js.map +1 -1
  59. package/dist/commands/pr.d.ts +4 -0
  60. package/dist/commands/pr.js +121 -3
  61. package/dist/commands/pr.js.map +1 -1
  62. package/dist/commands/refresh.js +10 -57
  63. package/dist/commands/refresh.js.map +1 -1
  64. package/dist/commands/update.d.ts +2 -0
  65. package/dist/commands/update.js +463 -64
  66. package/dist/commands/update.js.map +1 -1
  67. package/dist/config.d.ts +16 -0
  68. package/dist/config.js +57 -0
  69. package/dist/config.js.map +1 -1
  70. package/dist/runner.js +12 -0
  71. package/dist/runner.js.map +1 -1
  72. package/dist/safety.d.ts +63 -0
  73. package/dist/safety.js +192 -0
  74. package/dist/safety.js.map +1 -0
  75. package/dist/types.d.ts +2 -0
  76. package/package.json +2 -3
  77. package/modules/bolt_inspect/bolt_inspect.info.yml +0 -6
  78. package/modules/bolt_inspect/bolt_inspect.services.yml +0 -22
  79. package/modules/bolt_inspect/composer.json +0 -16
  80. package/modules/bolt_inspect/drush.services.yml +0 -10
  81. package/modules/bolt_inspect/src/Drush/Commands/BoltInspectCommands.php +0 -203
  82. package/modules/bolt_inspect/src/Service/ContentGenerator.php +0 -586
  83. package/modules/bolt_inspect/src/Service/SiteProfiler.php +0 -362
  84. package/modules/bolt_inspect/src/Service/TestEntityTracker.php +0 -98
package/README.md CHANGED
@@ -157,16 +157,19 @@ bolt update [options]
157
157
  --dry-run Show what would be updated without doing it
158
158
  --skip-refresh Skip the pre-update refresh step
159
159
  --skip-test Skip the baseline test
160
+ --no-ai Disable AI reasoning (use scripted fallback)
160
161
  --yes Skip confirmation prompts
161
162
  ```
162
163
 
163
164
  What it does:
164
- 1. Pre-flight: refreshes local state, runs baseline test, gets outdated packages
165
- 2. Per-module loop: creates branch, updates via Composer, runs `drush updb`, runs full test suite
165
+ 1. Pre-flight: refreshes local state, runs baseline test, captures VR baselines, gets outdated packages
166
+ 2. Per-module loop: creates branch, updates via Composer, runs `drush updb`, runs full test suite + VR comparison
166
167
  3. If tests pass: exports config, commits on update branch
167
168
  4. If tests fail: rolls back changes, deletes branch, continues to next module
168
169
  5. Produces summary report with per-module results
169
170
 
171
+ **Visual regression:** Before any updates begin, bolt captures screenshots of all representative pages. After each module update, it compares against those baselines. Module updates should produce zero visual changes — any difference triggers a test failure and rollback. VR runs automatically during updates even if skipped in `.bolt.yml`.
172
+
170
173
  Each update gets its own branch (`update/<package>-<version>`) off the base branch for clean per-module PRs.
171
174
 
172
175
  **Exit codes:** 0 = at least one update succeeded, 1 = all failed, 2 = error.
@@ -191,13 +194,17 @@ bolt pr [options]
191
194
  --reviewers <list> Comma-separated GitHub usernames
192
195
  --draft Create as draft PR
193
196
  --all Create PRs for all update/* branches
197
+ --no-ai Disable AI-generated PR descriptions
198
+ --yes Skip confirmation prompts
194
199
  ```
195
200
 
196
201
  What it does:
197
- 1. Finds update branches (current branch or `--all` for all `update/*` branches)
198
- 2. Parses commit messages for update details (package, versions, test results)
199
- 3. Pushes branch to remote
200
- 4. Creates PR with structured body via `gh pr create`
202
+ 1. Warns if uncommitted changes exist (PRs only include committed state)
203
+ 2. Finds update branches (current branch or `--all` for all `update/*` branches)
204
+ 3. Confirms before pushing (lists branches that will be pushed)
205
+ 4. Parses commit messages for update details (package, versions, test results)
206
+ 5. Pushes branch to remote
207
+ 6. Creates PR with structured body via `gh pr create`
201
208
  5. Checks for existing PRs to avoid duplicates
202
209
 
203
210
  **Examples:**
@@ -210,6 +217,76 @@ bolt update --all # creates multiple update branches
210
217
  bolt pr --all --draft # creates draft PRs for all of them
211
218
  ```
212
219
 
220
+ ### `bolt analyze`
221
+
222
+ AI-powered ticket analysis — produces an investigation plan from a Jira ticket or description.
223
+
224
+ ```bash
225
+ bolt analyze [options]
226
+ --ticket <key> Jira ticket key (e.g. PROJ-123) — pulls via Jira MCP
227
+ --description <text> Bug description (manual, no Jira needed)
228
+ --url <url> Site URL (auto-detected from DDEV if omitted)
229
+ --output <format> text | json | markdown (default: text)
230
+ --report <path> Write analysis to file
231
+ ```
232
+
233
+ **Requires AI** — there is no `--no-ai` fallback for this command, since analysis IS the AI.
234
+
235
+ Input methods:
236
+ - `--ticket PROJ-123` — pulls from Jira via Atlassian MCP (configured per user)
237
+ - `--description "..."` — manual text input
238
+ - `cat ticket.txt | bolt analyze` — stdin
239
+
240
+ Output includes: problem summary, likely root causes (ranked), investigation steps with specific commands, risk assessment, suggested bolt tests to run after fix, and a confidence assessment for whether the issue can be fixed autonomously.
241
+
242
+ **Examples:**
243
+
244
+ ```bash
245
+ bolt analyze --ticket EC-42 # Jira integration
246
+ bolt analyze --description "Media upload broken" # manual input
247
+ bolt analyze --ticket EC-42 --output markdown --report analysis.md
248
+ ```
249
+
250
+ ### `bolt fix`
251
+
252
+ Autonomous ticket resolution — analyze, fix, test, and create a PR.
253
+
254
+ ```bash
255
+ bolt fix [options]
256
+ --ticket <key> Jira ticket key (runs analysis internally)
257
+ --description <text> Bug description (manual, no Jira needed)
258
+ --analysis <path> Path to saved bolt analyze report (JSON)
259
+ --context <text> Additional context (answers to questions from analyze)
260
+ --interactive Launch interactive Claude session (converse instead of autonomous)
261
+ --dry-run Show planned changes without modifying files
262
+ --skip-test Skip post-fix test run
263
+ --skip-pr Skip PR creation
264
+ --branch <name> Branch name (default: fix/<ticket-key>)
265
+ --yes Skip confirmation prompts
266
+ ```
267
+
268
+ **Requires AI** — no `--no-ai` fallback.
269
+
270
+ Two modes:
271
+ - **Autonomous** (default): Claude runs unattended with full tool access (ddev, drush, file editing). The confidence model from `bolt analyze` gates entry — if it says "needs info" or "needs human", bolt exits with instructions.
272
+ - **Interactive** (`--interactive`): Launches a live Claude session with the ticket analysis, site profile, and Drupal knowledge pre-loaded. You converse with Claude to guide the fix.
273
+
274
+ **Examples:**
275
+
276
+ ```bash
277
+ # Full autonomous flow
278
+ bolt fix --ticket EC-42 # analyze → fix → test → PR
279
+
280
+ # Provide answers to questions from analyze
281
+ bolt fix --ticket EC-42 --context "Chrome only, content_editor role"
282
+
283
+ # Interactive — converse with Claude
284
+ bolt fix --ticket EC-42 --interactive
285
+
286
+ # Dry run — see what would change
287
+ bolt fix --description "footer logo broken" --dry-run
288
+ ```
289
+
213
290
  ### `bolt init`
214
291
 
215
292
  Connect bolt to a client site. Run from the site's project root.
@@ -218,16 +295,18 @@ Connect bolt to a client site. Run from the site's project root.
218
295
  bolt init [options]
219
296
  --skip-composer Skip Composer setup
220
297
  --skip-module Skip module enable
221
- --upgrade Update bolt_inspect module only (no config changes)
298
+ --upgrade Update bolt-inspect module via Composer
299
+ --yes Skip confirmation prompts
222
300
  ```
223
301
 
224
302
  What it does:
225
- 1. Warns if on `main`/`master` branch (bolt changes should go on a dedicated branch)
226
- 2. Creates DDEV volume mount for `bolt_inspect` module
227
- 3. Adds Composer path repository
228
- 4. Installs and enables `bolt_inspect`
229
- 5. Creates `.bolt.yml` config template
230
- 6. Adds bolt artifacts to `.gitignore`
303
+ 1. Prompts if on `main`/`master` branch (bolt changes should go on a dedicated branch)
304
+ 2. Installs `electriccitizen/bolt-inspect` via Composer (from Packagist)
305
+ 3. Enables `bolt_inspect` Drupal module
306
+ 4. Creates `.bolt.yml` config template
307
+ 5. Adds bolt artifacts to `.gitignore`
308
+
309
+ Other developers on the same project just run `composer install` — the module is in `composer.json` like any other dependency. No additional setup needed beyond installing the bolt CLI globally.
231
310
 
232
311
  Idempotent — safe to re-run.
233
312
 
@@ -346,7 +425,7 @@ bolt init --upgrade
346
425
  bolt doctor # verify versions match
347
426
  ```
348
427
 
349
- `bolt init --upgrade` updates the volume mount and module only — no config changes, no re-init.
428
+ `bolt init --upgrade` runs `composer update electriccitizen/bolt-inspect` and clears caches — no config changes, no re-init.
350
429
 
351
430
  ## Roadmap
352
431
 
@@ -0,0 +1,66 @@
1
+ /**
2
+ * AI agent infrastructure — spawns Claude Code as a subprocess
3
+ * for reasoning tasks (conflict resolution, error diagnosis, etc.).
4
+ *
5
+ * Pattern: deterministic TypeScript gathers context → Claude reasons → structured JSON back.
6
+ */
7
+ export interface AgentTask {
8
+ /** Human-readable goal for the agent. */
9
+ goal: string;
10
+ /** Structured context data passed to the agent. */
11
+ context: Record<string, unknown>;
12
+ /** Knowledge domains to include in the prompt. */
13
+ knowledge: KnowledgeDomain[];
14
+ /** JSON schema description for expected output format. */
15
+ outputFormat: string;
16
+ /** Maximum turns the agent can take (default: 25). */
17
+ maxTurns?: number;
18
+ /** Timeout in milliseconds (default: 300_000 = 5 min). */
19
+ timeout?: number;
20
+ /** Allowed tools for the agent (default: Bash only). */
21
+ allowedTools?: string[];
22
+ }
23
+ export interface AgentResult {
24
+ /** Whether the agent completed successfully. */
25
+ success: boolean;
26
+ /** Parsed output matching the requested format. */
27
+ output: Record<string, unknown>;
28
+ /** Raw text response from Claude. */
29
+ rawResponse: string;
30
+ /** Number of turns the agent used. */
31
+ numTurns: number;
32
+ /** Duration in milliseconds. */
33
+ duration: number;
34
+ /** Cost in USD (if reported). */
35
+ costUsd?: number;
36
+ }
37
+ export type KnowledgeDomain = 'composer' | 'drupal-updates' | 'config-safety' | 'ddev-operations' | 'drupal-internals' | 'drupal-debugging';
38
+ /**
39
+ * Check if Claude Code CLI is installed and accessible.
40
+ * Result is cached for the process lifetime.
41
+ */
42
+ export declare function isClaudeAvailable(): Promise<boolean>;
43
+ /**
44
+ * Get Claude Code version string, or null if not available.
45
+ */
46
+ export declare function getClaudeVersion(): Promise<string | null>;
47
+ /**
48
+ * Load a knowledge file from src/ai/knowledge/.
49
+ * Files are read at runtime from the dist directory.
50
+ */
51
+ export declare function loadKnowledge(domain: KnowledgeDomain): string;
52
+ /**
53
+ * Build a complete prompt from an AgentTask.
54
+ */
55
+ export declare function buildPrompt(task: AgentTask): string;
56
+ /**
57
+ * Parse a JSON code block from Claude's response text.
58
+ */
59
+ export declare function parseJsonFromResponse(text: string): Record<string, unknown> | null;
60
+ /**
61
+ * Run an agent task via Claude Code subprocess.
62
+ *
63
+ * Spawns `claude -p <prompt> --output-format json` and parses
64
+ * the structured result.
65
+ */
66
+ export declare function runAgent(task: AgentTask): Promise<AgentResult>;
@@ -0,0 +1,232 @@
1
+ /**
2
+ * AI agent infrastructure — spawns Claude Code as a subprocess
3
+ * for reasoning tasks (conflict resolution, error diagnosis, etc.).
4
+ *
5
+ * Pattern: deterministic TypeScript gathers context → Claude reasons → structured JSON back.
6
+ */
7
+ import { execFile, spawn } from 'child_process';
8
+ import { promisify } from 'util';
9
+ import { readFileSync } from 'fs';
10
+ import { resolve, dirname } from 'path';
11
+ import { fileURLToPath } from 'url';
12
+ const execFileAsync = promisify(execFile);
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = dirname(__filename);
15
+ // --- Claude Availability ---
16
+ let claudeAvailable = null;
17
+ /**
18
+ * Check if Claude Code CLI is installed and accessible.
19
+ * Result is cached for the process lifetime.
20
+ */
21
+ export async function isClaudeAvailable() {
22
+ if (claudeAvailable !== null)
23
+ return claudeAvailable;
24
+ try {
25
+ const { stdout } = await execFileAsync('claude', ['--version'], {
26
+ timeout: 5_000,
27
+ });
28
+ claudeAvailable = stdout.trim().length > 0;
29
+ }
30
+ catch {
31
+ claudeAvailable = false;
32
+ }
33
+ return claudeAvailable;
34
+ }
35
+ /**
36
+ * Get Claude Code version string, or null if not available.
37
+ */
38
+ export async function getClaudeVersion() {
39
+ try {
40
+ const { stdout } = await execFileAsync('claude', ['--version'], {
41
+ timeout: 5_000,
42
+ });
43
+ return stdout.trim() || null;
44
+ }
45
+ catch {
46
+ return null;
47
+ }
48
+ }
49
+ // --- Knowledge Loading ---
50
+ const knowledgeCache = new Map();
51
+ /**
52
+ * Load a knowledge file from src/ai/knowledge/.
53
+ * Files are read at runtime from the dist directory.
54
+ */
55
+ export function loadKnowledge(domain) {
56
+ if (knowledgeCache.has(domain)) {
57
+ return knowledgeCache.get(domain);
58
+ }
59
+ const knowledgePath = resolve(__dirname, 'knowledge', `${domain}.md`);
60
+ try {
61
+ const content = readFileSync(knowledgePath, 'utf-8');
62
+ knowledgeCache.set(domain, content);
63
+ return content;
64
+ }
65
+ catch {
66
+ // Knowledge file not found — return empty (non-fatal).
67
+ return '';
68
+ }
69
+ }
70
+ // --- Prompt Building ---
71
+ /**
72
+ * Build a complete prompt from an AgentTask.
73
+ */
74
+ export function buildPrompt(task) {
75
+ const sections = [];
76
+ // Role and goal.
77
+ sections.push(`# Task\n\n${task.goal}`);
78
+ // Context data.
79
+ if (Object.keys(task.context).length > 0) {
80
+ sections.push(`# Context\n\n\`\`\`json\n${JSON.stringify(task.context, null, 2)}\n\`\`\``);
81
+ }
82
+ // Knowledge sections.
83
+ for (const domain of task.knowledge) {
84
+ const content = loadKnowledge(domain);
85
+ if (content) {
86
+ sections.push(content);
87
+ }
88
+ }
89
+ // Output format instructions.
90
+ sections.push(`# Output Format\n\n` +
91
+ `When you have completed the task, output your result as a single JSON code block.\n` +
92
+ `The JSON must match this format:\n\n` +
93
+ `\`\`\`\n${task.outputFormat}\n\`\`\`\n\n` +
94
+ `IMPORTANT: Your final message must contain exactly one JSON code block with the result. ` +
95
+ `Do not include any other text after the JSON block.`);
96
+ return sections.join('\n\n---\n\n');
97
+ }
98
+ // --- Agent Execution ---
99
+ /**
100
+ * Parse a JSON code block from Claude's response text.
101
+ */
102
+ export function parseJsonFromResponse(text) {
103
+ // Find all code blocks and try the last one first (most likely the final result).
104
+ const allBlocks = [...text.matchAll(/```(?:json)?\s*\n([\s\S]*?)\n```/g)];
105
+ if (allBlocks.length > 0) {
106
+ // Try last block first (agent's final answer).
107
+ for (let i = allBlocks.length - 1; i >= 0; i--) {
108
+ try {
109
+ return JSON.parse(allBlocks[i][1]);
110
+ }
111
+ catch {
112
+ // Try the next block.
113
+ }
114
+ }
115
+ }
116
+ // Try parsing the entire response as JSON (unlikely but possible).
117
+ try {
118
+ return JSON.parse(text);
119
+ }
120
+ catch {
121
+ return null;
122
+ }
123
+ }
124
+ /**
125
+ * Run an agent task via Claude Code subprocess.
126
+ *
127
+ * Spawns `claude -p <prompt> --output-format json` and parses
128
+ * the structured result.
129
+ */
130
+ export async function runAgent(task) {
131
+ const startTime = Date.now();
132
+ const prompt = buildPrompt(task);
133
+ const timeout = task.timeout ?? 300_000;
134
+ const maxTurns = task.maxTurns ?? 25;
135
+ // Build claude CLI args — use --print with stdin to avoid arg length limits.
136
+ const args = [
137
+ '--print',
138
+ '--output-format', 'json',
139
+ '--max-turns', String(maxTurns),
140
+ ];
141
+ // Restrict tools if specified.
142
+ if (task.allowedTools && task.allowedTools.length > 0) {
143
+ args.push('--allowedTools', task.allowedTools.join(','));
144
+ }
145
+ try {
146
+ const stdout = await new Promise((resolvePromise, reject) => {
147
+ const child = spawn('claude', args, {
148
+ env: {
149
+ ...process.env,
150
+ CI: '1',
151
+ },
152
+ stdio: ['pipe', 'pipe', 'pipe'],
153
+ });
154
+ const chunks = [];
155
+ let stderrOutput = '';
156
+ child.stdout.on('data', (chunk) => chunks.push(chunk));
157
+ child.stderr.on('data', (chunk) => { stderrOutput += chunk.toString(); });
158
+ child.on('close', (code) => {
159
+ const output = Buffer.concat(chunks).toString('utf-8');
160
+ if (code === 0) {
161
+ resolvePromise(output);
162
+ }
163
+ else {
164
+ reject(new Error(`claude exited with code ${code}: ${stderrOutput || output}`));
165
+ }
166
+ });
167
+ child.on('error', (err) => reject(err));
168
+ // Write prompt to stdin and close.
169
+ child.stdin.write(prompt);
170
+ child.stdin.end();
171
+ // Timeout handling.
172
+ const timer = setTimeout(() => {
173
+ child.kill('SIGTERM');
174
+ reject(new Error(`Agent timed out after ${timeout}ms`));
175
+ }, timeout);
176
+ child.on('close', () => clearTimeout(timer));
177
+ });
178
+ const duration = Date.now() - startTime;
179
+ // Parse Claude Code's JSON output format.
180
+ // { type: "result", result: "...", num_turns: N, cost_usd: N, ... }
181
+ let claudeOutput;
182
+ try {
183
+ claudeOutput = JSON.parse(stdout);
184
+ }
185
+ catch {
186
+ // If the output isn't valid JSON, treat the raw text as the response.
187
+ return {
188
+ success: false,
189
+ output: {},
190
+ rawResponse: stdout,
191
+ numTurns: 0,
192
+ duration,
193
+ };
194
+ }
195
+ const resultText = String(claudeOutput.result ?? '');
196
+ const numTurns = claudeOutput.num_turns ?? 0;
197
+ const costUsd = claudeOutput.cost_usd ?? undefined;
198
+ const isError = claudeOutput.is_error ?? false;
199
+ if (isError) {
200
+ return {
201
+ success: false,
202
+ output: { error: resultText },
203
+ rawResponse: resultText,
204
+ numTurns,
205
+ duration,
206
+ costUsd,
207
+ };
208
+ }
209
+ // Parse the structured JSON from Claude's response text.
210
+ const parsed = parseJsonFromResponse(resultText);
211
+ return {
212
+ success: parsed !== null,
213
+ output: parsed ?? { rawText: resultText },
214
+ rawResponse: resultText,
215
+ numTurns,
216
+ duration,
217
+ costUsd,
218
+ };
219
+ }
220
+ catch (err) {
221
+ const duration = Date.now() - startTime;
222
+ const message = err instanceof Error ? err.message : String(err);
223
+ return {
224
+ success: false,
225
+ output: { error: message },
226
+ rawResponse: message,
227
+ numTurns: 0,
228
+ duration,
229
+ };
230
+ }
231
+ }
232
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/ai/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ # Composer Conflict Resolution
2
+
3
+ You are an expert at resolving Composer dependency conflicts for Drupal projects.
4
+
5
+ ## Diagnostic Workflow
6
+
7
+ When a `composer update` fails, follow this sequence:
8
+
9
+ 1. **Identify the blocker:** `composer why-not vendor/package <target-version>`
10
+ - Shows the dependency chain preventing the upgrade
11
+ - Read the output carefully — it tells you exactly which package constrains the version
12
+
13
+ 2. **Trace reverse dependencies:** `composer why vendor/package`
14
+ - Shows which installed packages depend on the blocked package
15
+ - Helps identify if updating a parent would unlock the target
16
+
17
+ 3. **Check available versions:** `composer show --all vendor/package`
18
+ - Lists all available versions
19
+ - Helps find the highest compatible version if the target isn't achievable
20
+
21
+ 4. **Apply the right update strategy** (see below)
22
+
23
+ 5. **Harden constraints after success:** `composer bump` (applications only, not libraries)
24
+ - Raises lower bounds to currently installed versions
25
+ - Prevents accidental downgrades
26
+
27
+ ## Update Strategies (in order of preference)
28
+
29
+ ### Strategy 1: Standard update with transitive deps
30
+ ```bash
31
+ composer update vendor/package --with-dependencies
32
+ ```
33
+ Tries first because it has the smallest blast radius.
34
+
35
+ ### Strategy 2: Update with all dependencies
36
+ ```bash
37
+ composer update vendor/package --with-all-dependencies
38
+ ```
39
+ Broader resolution — allows all transitive deps to change.
40
+
41
+ ### Strategy 3: Require with caret constraint
42
+ ```bash
43
+ composer require vendor/package:^X.Y --update-with-all-dependencies
44
+ ```
45
+ Rewrites the constraint in composer.json. Use when the existing constraint is too tight.
46
+
47
+ ### Strategy 4: Require with tilde constraint
48
+ ```bash
49
+ composer require vendor/package:~X.Y --update-with-all-dependencies
50
+ ```
51
+ More conservative — only allows patch updates within the minor version.
52
+
53
+ ### Strategy 5: Update alongside core
54
+ ```bash
55
+ composer update vendor/package drupal/core-recommended drupal/core-composer-scaffold drupal/core-project-message --with-all-dependencies
56
+ ```
57
+ Common Drupal pattern — many modules constrain against core version.
58
+
59
+ ### Strategy 6: Read the error and adapt
60
+ If all standard strategies fail, READ the actual error output:
61
+ - If it says "package X requires Y ^2.0 but Z is locked at 1.5" → update Z first
62
+ - If it says "root composer.json requires X ^1.0" → you may need to change the constraint
63
+ - If it says "package X conflicts with Y" → check if X has a newer version that resolves it
64
+ - Use `composer why-not` output to understand the exact constraint chain
65
+
66
+ ## Version Constraint Reference
67
+
68
+ | Constraint | Meaning |
69
+ |------------|---------|
70
+ | `^1.2.3` | `>=1.2.3 <2.0.0` (allows minor+patch) |
71
+ | `~1.2.3` | `>=1.2.3 <1.3.0` (allows patch only) |
72
+ | `>=1.0 <2.0` | Explicit range |
73
+ | `1.2.*` | Any 1.2.x patch |
74
+ | `*` | Any version |
75
+
76
+ ## Key Flags
77
+
78
+ - `--dry-run` — simulate without applying (always safe to run first)
79
+ - `--with-dependencies` — also update deps of specified packages
80
+ - `--with-all-dependencies` — also update deps AND reverse deps
81
+ - `--no-update` — modify composer.json without running update (combine with `composer update` separately)
82
+ - `--prefer-stable` — prefer stable over dev versions
83
+
84
+ ## Important Rules
85
+
86
+ - Always run `composer update` with package names specified — never bare `composer update` (too broad)
87
+ - After resolving a conflict, verify with `composer show vendor/package` that the installed version is correct
88
+ - If the target version requires a newer PHP, that's a hard blocker — skip the update
89
+ - If the target version requires a newer Drupal core, check if core can also be updated
90
+ - `composer audit` shows security advisories — security updates should be prioritized
@@ -0,0 +1,46 @@
1
+ # Configuration Management Safety
2
+
3
+ You are working with Drupal configuration. Follow these safety patterns.
4
+
5
+ ## Safe Config Export
6
+
7
+ After a module update, export config changes:
8
+ ```bash
9
+ ddev drush cex -y
10
+ ```
11
+
12
+ ### Review before committing
13
+ - Check `git diff config/` to see what actually changed
14
+ - Module updates may introduce new config files (new permissions, new field settings)
15
+ - Module updates may modify existing config (schema changes, new default values)
16
+ - Unexpected config changes may indicate a problem
17
+
18
+ ### What's normal after an update
19
+ - New config files for new module features
20
+ - Schema version changes in `.info.yml`
21
+ - Updated default values in existing config
22
+ - New permissions added by the module
23
+
24
+ ### What's suspicious after an update
25
+ - Config deletions you didn't expect
26
+ - Changes to content type or field config you didn't modify
27
+ - Changes to views or blocks unrelated to the updated module
28
+ - System config changes (site name, mail settings, etc.)
29
+
30
+ ## Config Status Check
31
+
32
+ ```bash
33
+ # Check if config is in sync
34
+ ddev drush config:status
35
+
36
+ # Show diff without importing
37
+ ddev drush cim --no --diff
38
+ ```
39
+
40
+ ## Important Rules
41
+
42
+ - NEVER run `ddev drush cim -y` during an update pipeline — only `cex`
43
+ - Config import (`cim`) is for syncing environments, not for updates
44
+ - Always export (`cex`) after `drush updb` — database updates may generate config changes
45
+ - If `config:status` shows unexpected changes, investigate before exporting
46
+ - One module update per commit keeps config changes traceable
@@ -0,0 +1,41 @@
1
+ # DDEV Operations
2
+
3
+ All commands run through DDEV. Use `ddev` prefix for all drush and composer commands.
4
+
5
+ ## Essential Commands
6
+
7
+ ```bash
8
+ ddev drush <command> # Run drush in container
9
+ ddev composer <command> # Run composer in container
10
+ ddev drush cr # Clear all caches
11
+ ddev drush updb -y # Apply database updates
12
+ ddev drush cex -y # Export configuration
13
+ ddev drush status # Check Drupal status
14
+ ddev drush watchdog:show # View recent log entries
15
+ ddev describe # Show project info + URL
16
+ ddev logs # View container logs
17
+ ddev snapshot --name=<name> # Create safety snapshot
18
+ ddev snapshot restore --name=<name> # Restore snapshot
19
+ ```
20
+
21
+ ## Safety Patterns
22
+
23
+ - **Snapshot before risky operations:** `ddev snapshot --name=pre-update-$(date +%Y%m%d-%H%M%S)`
24
+ - **Check DDEV is running:** `ddev describe` — if it fails, run `ddev start`
25
+ - **After composer changes:** always run `ddev drush cr` to clear caches
26
+ - **Diagnose problems:** `ddev logs -f` to follow container logs in real-time
27
+
28
+ ## Error Diagnosis
29
+
30
+ When something fails:
31
+ 1. Check drush watchdog: `ddev drush watchdog:show --count=20 --severity=Error`
32
+ 2. Check container logs: `ddev logs`
33
+ 3. Verify database connection: `ddev drush status`
34
+ 4. Try cache rebuild: `ddev drush cr`
35
+
36
+ ## Important Notes
37
+
38
+ - All file paths inside commands are container paths (e.g., `/var/www/html/web/`)
39
+ - Host paths and container paths are different — DDEV maps them automatically
40
+ - `composer install` syncs to lockfile (safe); `composer update` changes lockfile (update operation)
41
+ - DDEV auto-starts services but may need manual restart after config changes: `ddev restart`