opencode-agile-agent 1.0.1 → 1.0.2
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 +61 -71
- package/bin/cli.js +344 -434
- package/bin/sync-templates.js +45 -0
- package/bin/validate-templates.js +44 -6
- package/package.json +2 -1
- package/templates/.opencode/ARCHITECTURE.md +82 -368
- package/templates/.opencode/README.md +110 -391
- package/templates/.opencode/agents/api-designer.md +45 -312
- package/templates/.opencode/agents/backend-specialist.md +46 -214
- package/templates/.opencode/agents/code-archaeologist.md +45 -260
- package/templates/.opencode/agents/context-gatherer.md +51 -0
- package/templates/.opencode/agents/database-architect.md +45 -212
- package/templates/.opencode/agents/debugger.md +45 -302
- package/templates/.opencode/agents/developer.md +45 -523
- package/templates/.opencode/agents/devops-engineer.md +45 -253
- package/templates/.opencode/agents/documentation-writer.md +45 -247
- package/templates/.opencode/agents/explorer-agent.md +49 -233
- package/templates/.opencode/agents/feature-lead.md +62 -302
- package/templates/.opencode/agents/frontend-specialist.md +46 -186
- package/templates/.opencode/agents/game-developer.md +45 -391
- package/templates/.opencode/agents/mobile-developer.md +45 -264
- package/templates/.opencode/agents/orchestrator.md +48 -463
- package/templates/.opencode/agents/penetration-tester.md +44 -254
- package/templates/.opencode/agents/performance-optimizer.md +45 -292
- package/templates/.opencode/agents/pr-reviewer.md +45 -468
- package/templates/.opencode/agents/product-manager.md +46 -225
- package/templates/.opencode/agents/project-planner.md +45 -248
- package/templates/.opencode/agents/qa-automation-engineer.md +45 -275
- package/templates/.opencode/agents/security-auditor.md +44 -258
- package/templates/.opencode/agents/seo-specialist.md +45 -266
- package/templates/.opencode/agents/system-analyst.md +48 -428
- package/templates/.opencode/agents/test-engineer.md +45 -229
- package/templates/.opencode/archive/README.md +24 -0
- package/templates/.opencode/commands/brainstorm.md +10 -0
- package/templates/.opencode/commands/create.md +11 -0
- package/templates/.opencode/commands/debug.md +10 -0
- package/templates/.opencode/commands/plan.md +9 -0
- package/templates/.opencode/commands/review.md +11 -0
- package/templates/.opencode/commands/status.md +9 -0
- package/templates/.opencode/commands/test.md +10 -0
- package/templates/.opencode/skills/api-patterns/SKILL.md +25 -149
- package/templates/.opencode/skills/brainstorming/SKILL.md +26 -242
- package/templates/.opencode/skills/clean-code/SKILL.md +27 -339
- package/templates/.opencode/skills/code-philosophy/SKILL.md +27 -499
- package/templates/.opencode/skills/context-archive/SKILL.md +47 -0
- package/templates/.opencode/skills/context-gathering/SKILL.md +51 -0
- package/templates/.opencode/skills/frontend-design/SKILL.md +26 -224
- package/templates/.opencode/skills/intelligent-routing/SKILL.md +25 -182
- package/templates/.opencode/skills/parallel-agents/SKILL.md +25 -261
- package/templates/.opencode/skills/plan-writing/SKILL.md +28 -238
- package/templates/.opencode/skills/redteam-validation/SKILL.md +33 -0
- package/templates/.opencode/skills/security-gate/SKILL.md +33 -0
- package/templates/.opencode/skills/systematic-debugging/SKILL.md +25 -197
- package/templates/.opencode/skills/testing-patterns/SKILL.md +25 -238
- package/templates/AGENTS.template.md +300 -426
- package/templates/.opencode/agents/product-owner.md +0 -264
- package/templates/.opencode/workflows/brainstorm.md +0 -110
- package/templates/.opencode/workflows/create.md +0 -108
- package/templates/.opencode/workflows/debug.md +0 -128
- package/templates/.opencode/workflows/deploy.md +0 -160
- package/templates/.opencode/workflows/enhance.md +0 -253
- package/templates/.opencode/workflows/orchestrate.md +0 -130
- package/templates/.opencode/workflows/plan.md +0 -163
- package/templates/.opencode/workflows/review.md +0 -135
- package/templates/.opencode/workflows/status.md +0 -102
- package/templates/.opencode/workflows/test.md +0 -146
package/bin/cli.js
CHANGED
|
@@ -1,434 +1,344 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { fileURLToPath } from 'url';
|
|
4
|
-
import { dirname, join } from 'path';
|
|
5
|
-
import { existsSync, mkdirSync, cpSync, writeFileSync, readFileSync } from 'fs';
|
|
6
|
-
import { createInterface } from 'readline';
|
|
7
|
-
|
|
8
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
-
const __dirname = dirname(__filename);
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const colors = {
|
|
14
|
-
reset: '\x1b[0m',
|
|
15
|
-
bright: '\x1b[1m',
|
|
16
|
-
green: '\x1b[32m',
|
|
17
|
-
blue: '\x1b[34m',
|
|
18
|
-
yellow: '\x1b[33m',
|
|
19
|
-
cyan: '\x1b[36m',
|
|
20
|
-
red: '\x1b[31m',
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const log = {
|
|
24
|
-
info: (msg) => console.log(`${colors.blue}
|
|
25
|
-
success: (msg) => console.log(`${colors.green}
|
|
26
|
-
warn: (msg) => console.log(`${colors.yellow}
|
|
27
|
-
error: (msg) => console.log(`${colors.red}
|
|
28
|
-
title: (msg) => console.log(`\n${colors.bright}${colors.cyan}${msg}${colors.reset}\n`),
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
${colors.cyan}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
###
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
// Styling
|
|
346
|
-
const stylingInput = await question(`Styling (tailwind/css-modules/styled-components/scss/other) [default: tailwind]: `);
|
|
347
|
-
const styling = stylingInput || 'tailwind';
|
|
348
|
-
|
|
349
|
-
// State management
|
|
350
|
-
const stateInput = await question(`State management (pinia/zustand/redux/none) [default: none]: `);
|
|
351
|
-
const stateManagement = stateInput || 'none';
|
|
352
|
-
|
|
353
|
-
// Testing
|
|
354
|
-
const testingInput = await question(`Testing (jest/vitest/mocha/none) [default: vitest]: `);
|
|
355
|
-
const testing = testingInput || 'vitest';
|
|
356
|
-
|
|
357
|
-
const config = { projectName, framework, language, styling, stateManagement, testing };
|
|
358
|
-
|
|
359
|
-
log.title('📦 Installing OpenCode Agile Agent...');
|
|
360
|
-
|
|
361
|
-
// Create .opencode directory
|
|
362
|
-
try {
|
|
363
|
-
// Copy templates
|
|
364
|
-
log.info('Copying templates...');
|
|
365
|
-
|
|
366
|
-
// Create .opencode directory
|
|
367
|
-
if (!existsSync(opencodePath)) {
|
|
368
|
-
mkdirSync(opencodePath, { recursive: true });
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// Copy all template files
|
|
372
|
-
const templateOpencode = join(templatesDir, '.opencode');
|
|
373
|
-
if (existsSync(templateOpencode)) {
|
|
374
|
-
cpSync(templateOpencode, opencodePath, { recursive: true, overwrite: true });
|
|
375
|
-
log.success('Templates copied successfully');
|
|
376
|
-
} else {
|
|
377
|
-
log.error('Templates directory not found!');
|
|
378
|
-
rl.close();
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
// Generate AGENTS.md
|
|
383
|
-
log.info('Generating AGENTS.md...');
|
|
384
|
-
const agentsMd = generateAgentsMd(config);
|
|
385
|
-
writeFileSync(join(process.cwd(), 'AGENTS.md'), agentsMd);
|
|
386
|
-
log.success('AGENTS.md generated');
|
|
387
|
-
|
|
388
|
-
// Success message
|
|
389
|
-
log.title('✅ Installation Complete!');
|
|
390
|
-
|
|
391
|
-
console.log(`
|
|
392
|
-
${colors.green}OpenCode Agile Agent has been installed successfully!${colors.reset}
|
|
393
|
-
|
|
394
|
-
${colors.cyan}What's included:${colors.reset}
|
|
395
|
-
✓ .opencode/agents/ - Full LLM SpecKit agent set
|
|
396
|
-
✓ .opencode/skills/ - Reusable skill modules
|
|
397
|
-
✓ .opencode/workflows/ - Workflow command templates
|
|
398
|
-
✓ .opencode/rules/ - Shared coding and git conventions
|
|
399
|
-
✓ .opencode/README.md - Kit documentation
|
|
400
|
-
✓ AGENTS.md - Project-specific coding standards
|
|
401
|
-
|
|
402
|
-
${colors.cyan}Next steps:${colors.reset}
|
|
403
|
-
1. Review and customize AGENTS.md for your project
|
|
404
|
-
2. Start using agents with your AI assistant
|
|
405
|
-
3. Read .opencode/README.md for detailed workflow
|
|
406
|
-
|
|
407
|
-
${colors.cyan}Example usage:${colors.reset}
|
|
408
|
-
"I want to implement user authentication with JWT"
|
|
409
|
-
|
|
410
|
-
The agents will:
|
|
411
|
-
→ Gather requirements
|
|
412
|
-
→ Create specs and task breakdown
|
|
413
|
-
→ Implement the feature
|
|
414
|
-
→ Review code quality
|
|
415
|
-
→ ✅ Deliver production-ready code
|
|
416
|
-
|
|
417
|
-
${colors.yellow}Happy coding with AI-powered agile development! 🚀${colors.reset}
|
|
418
|
-
`);
|
|
419
|
-
|
|
420
|
-
} catch (error) {
|
|
421
|
-
log.error(`Installation failed: ${error.message}`);
|
|
422
|
-
console.error(error);
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
rl.close();
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// Run installation
|
|
429
|
-
install().catch((error) => {
|
|
430
|
-
log.error(`Unexpected error: ${error.message}`);
|
|
431
|
-
console.error(error);
|
|
432
|
-
rl.close();
|
|
433
|
-
process.exit(1);
|
|
434
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { dirname, join, sep } from 'path';
|
|
5
|
+
import { existsSync, mkdirSync, cpSync, writeFileSync, readFileSync, rmSync } from 'fs';
|
|
6
|
+
import { createInterface } from 'readline';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
10
|
+
const rootDir = join(__dirname, '..');
|
|
11
|
+
const templatesDir = join(rootDir, 'templates');
|
|
12
|
+
|
|
13
|
+
const colors = {
|
|
14
|
+
reset: '\x1b[0m',
|
|
15
|
+
bright: '\x1b[1m',
|
|
16
|
+
green: '\x1b[32m',
|
|
17
|
+
blue: '\x1b[34m',
|
|
18
|
+
yellow: '\x1b[33m',
|
|
19
|
+
cyan: '\x1b[36m',
|
|
20
|
+
red: '\x1b[31m',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const log = {
|
|
24
|
+
info: (msg) => console.log(`${colors.blue}[i]${colors.reset} ${msg}`),
|
|
25
|
+
success: (msg) => console.log(`${colors.green}[ok]${colors.reset} ${msg}`),
|
|
26
|
+
warn: (msg) => console.log(`${colors.yellow}[!]${colors.reset} ${msg}`),
|
|
27
|
+
error: (msg) => console.log(`${colors.red}[x]${colors.reset} ${msg}`),
|
|
28
|
+
title: (msg) => console.log(`\n${colors.bright}${colors.cyan}${msg}${colors.reset}\n`),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const banner = `
|
|
32
|
+
${colors.cyan}========================================${colors.reset}
|
|
33
|
+
${colors.cyan} OpenCode Agile Agent Installer ${colors.reset}
|
|
34
|
+
${colors.cyan} Spec-driven, one-prompt setup ${colors.reset}
|
|
35
|
+
${colors.cyan}========================================${colors.reset}
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
const rl = createInterface({
|
|
39
|
+
input: process.stdin,
|
|
40
|
+
output: process.stdout,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const question = (prompt) => new Promise((resolve) => {
|
|
44
|
+
rl.question(prompt, resolve);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const args = process.argv.slice(2);
|
|
48
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
49
|
+
console.log(`
|
|
50
|
+
OpenCode Agile Agent Installer
|
|
51
|
+
|
|
52
|
+
Usage:
|
|
53
|
+
opencode-agile-agent
|
|
54
|
+
|
|
55
|
+
What it does:
|
|
56
|
+
- Asks one yes/no question.
|
|
57
|
+
- Detects the project stack automatically.
|
|
58
|
+
- Copies .opencode and generates AGENTS.md.
|
|
59
|
+
|
|
60
|
+
Commands:
|
|
61
|
+
--help, -h Show this help message
|
|
62
|
+
`);
|
|
63
|
+
rl.close();
|
|
64
|
+
process.exit(0);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function shouldCopyPath(path) {
|
|
68
|
+
return !path.includes(`${sep}node_modules${sep}`) && !path.endsWith(`${sep}node_modules`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function detectProjectContext() {
|
|
72
|
+
const defaults = {
|
|
73
|
+
projectName: 'My Project',
|
|
74
|
+
framework: 'Generic',
|
|
75
|
+
language: 'JavaScript',
|
|
76
|
+
styling: 'Follow existing styles',
|
|
77
|
+
stateManagement: 'None / follow existing patterns',
|
|
78
|
+
testing: 'Follow existing tests',
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const packageJsonPath = join(rootDir, 'package.json');
|
|
82
|
+
|
|
83
|
+
if (!existsSync(packageJsonPath)) {
|
|
84
|
+
return defaults;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
89
|
+
const deps = { ...(packageJson.dependencies ?? {}), ...(packageJson.devDependencies ?? {}) };
|
|
90
|
+
const has = (name) => Boolean(deps[name]);
|
|
91
|
+
|
|
92
|
+
const framework = has('next')
|
|
93
|
+
? 'Next.js'
|
|
94
|
+
: has('nuxt')
|
|
95
|
+
? 'Nuxt.js'
|
|
96
|
+
: has('@angular/core')
|
|
97
|
+
? 'Angular'
|
|
98
|
+
: has('svelte')
|
|
99
|
+
? 'Svelte'
|
|
100
|
+
: has('vue') || has('vue2') || has('vue3')
|
|
101
|
+
? 'Vue'
|
|
102
|
+
: has('react-native') || has('expo')
|
|
103
|
+
? 'React Native'
|
|
104
|
+
: has('react') || has('react-dom')
|
|
105
|
+
? 'React'
|
|
106
|
+
: has('express')
|
|
107
|
+
? 'Express'
|
|
108
|
+
: has('fastify')
|
|
109
|
+
? 'Fastify'
|
|
110
|
+
: has('nestjs') || has('@nestjs/core')
|
|
111
|
+
? 'NestJS'
|
|
112
|
+
: 'Generic';
|
|
113
|
+
|
|
114
|
+
const language = has('typescript') || existsSync(join(rootDir, 'tsconfig.json'))
|
|
115
|
+
? 'TypeScript'
|
|
116
|
+
: 'JavaScript';
|
|
117
|
+
|
|
118
|
+
const styling = has('tailwindcss')
|
|
119
|
+
? 'Tailwind'
|
|
120
|
+
: has('styled-components')
|
|
121
|
+
? 'Styled Components'
|
|
122
|
+
: has('sass') || has('scss')
|
|
123
|
+
? 'SCSS'
|
|
124
|
+
: has('css-modules')
|
|
125
|
+
? 'CSS Modules'
|
|
126
|
+
: 'Follow existing styles';
|
|
127
|
+
|
|
128
|
+
const stateManagement = has('pinia')
|
|
129
|
+
? 'Pinia'
|
|
130
|
+
: has('zustand')
|
|
131
|
+
? 'Zustand'
|
|
132
|
+
: has('redux') || has('@reduxjs/toolkit')
|
|
133
|
+
? 'Redux'
|
|
134
|
+
: has('mobx')
|
|
135
|
+
? 'MobX'
|
|
136
|
+
: 'None / follow existing patterns';
|
|
137
|
+
|
|
138
|
+
const testing = has('vitest')
|
|
139
|
+
? 'Vitest'
|
|
140
|
+
: has('jest')
|
|
141
|
+
? 'Jest'
|
|
142
|
+
: has('playwright')
|
|
143
|
+
? 'Playwright'
|
|
144
|
+
: has('cypress')
|
|
145
|
+
? 'Cypress'
|
|
146
|
+
: 'Follow existing tests';
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
...defaults,
|
|
150
|
+
projectName: packageJson.name || defaults.projectName,
|
|
151
|
+
framework,
|
|
152
|
+
language,
|
|
153
|
+
styling,
|
|
154
|
+
stateManagement,
|
|
155
|
+
testing,
|
|
156
|
+
};
|
|
157
|
+
} catch {
|
|
158
|
+
return defaults;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function generateAgentsMd(context) {
|
|
163
|
+
return `# AGENTS.md - ${context.projectName}
|
|
164
|
+
|
|
165
|
+
> Instructions for AI agents working on this project.
|
|
166
|
+
>
|
|
167
|
+
> How to build lives here; what to build comes from feature specs.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Project Stack
|
|
172
|
+
|
|
173
|
+
- Framework: ${context.framework}
|
|
174
|
+
- Language: ${context.language}
|
|
175
|
+
- State Management: ${context.stateManagement}
|
|
176
|
+
- Styling: ${context.styling}
|
|
177
|
+
- Testing: ${context.testing}
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Core Documentation
|
|
182
|
+
|
|
183
|
+
Review these before making architectural or styling decisions:
|
|
184
|
+
|
|
185
|
+
| Document | Purpose | Location |
|
|
186
|
+
|----------|---------|----------|
|
|
187
|
+
| OpenCode README | Kit overview and flow | .opencode/README.md |
|
|
188
|
+
| OpenCode Architecture | Agent lifecycle and gates | .opencode/ARCHITECTURE.md |
|
|
189
|
+
| Agent prompts | Role-specific behavior | .opencode/agents/*.md |
|
|
190
|
+
| Commands | Custom slash commands | .opencode/commands/*.md |
|
|
191
|
+
| Rules | Shared coding standards | .opencode/rules/*.md |
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## OpenCode Delivery Model
|
|
196
|
+
|
|
197
|
+
- Primary agent: @feature-lead
|
|
198
|
+
- First call: @context-gatherer maps the current project state before planning or proof.
|
|
199
|
+
- Other agents are subagents and are called with @ awareness.
|
|
200
|
+
- Security-sensitive work: @security-auditor first, then @penetration-tester for redteam validation when needed.
|
|
201
|
+
|
|
202
|
+
## Compact Context Bundle
|
|
203
|
+
|
|
204
|
+
- proposal.md: why, value, scope
|
|
205
|
+
- goal.md: target outcome, constraints, default choice
|
|
206
|
+
- spec.md: contract, data flow, edge cases, risks
|
|
207
|
+
- task.md: ordered checklist, dependencies, owners
|
|
208
|
+
- important.md: facts, blockers, links, decisions
|
|
209
|
+
|
|
210
|
+
## Archive
|
|
211
|
+
|
|
212
|
+
- Archive completed bundles in .opencode/archive/<feature-slug>/.
|
|
213
|
+
|
|
214
|
+
## Decision Style
|
|
215
|
+
|
|
216
|
+
- Default first: choose a safe default when the downside is small.
|
|
217
|
+
- Ask only when scope, security, or architecture changes materially.
|
|
218
|
+
- Keep handoffs compact and explicit.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Code Conventions
|
|
223
|
+
|
|
224
|
+
### File Naming
|
|
225
|
+
|
|
226
|
+
| Type | Pattern | Example |
|
|
227
|
+
|------|---------|---------|
|
|
228
|
+
| Components | PascalCase.tsx | UserCard.tsx |
|
|
229
|
+
| Pages | PascalCasePage.tsx | LoginPage.tsx |
|
|
230
|
+
| Stores | camelCase.store.ts | auth.store.ts |
|
|
231
|
+
| Hooks/Composables | useCamelCase.ts | useAuth.ts |
|
|
232
|
+
| Types | camelCase.types.ts | user.types.ts |
|
|
233
|
+
| Utils | camelCase.utils.ts | date.utils.ts |
|
|
234
|
+
| API | camelCase.api.ts | auth.api.ts |
|
|
235
|
+
| Tests | *.test.ts or *.spec.ts | auth.test.ts |
|
|
236
|
+
|
|
237
|
+
### Code Style
|
|
238
|
+
|
|
239
|
+
- Indentation: 2 spaces
|
|
240
|
+
- Quotes: single
|
|
241
|
+
- Semicolons: required
|
|
242
|
+
- Line Width: 100
|
|
243
|
+
- Trailing Commas: es5
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Project-Specific Rules
|
|
248
|
+
|
|
249
|
+
- Keep changes aligned to the compact spec bundle.
|
|
250
|
+
- Prefer defaults when a tradeoff is low risk.
|
|
251
|
+
- Surface options only when the decision changes scope, security, or architecture.
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Architecture Patterns
|
|
256
|
+
|
|
257
|
+
### State Management
|
|
258
|
+
|
|
259
|
+
- Describe where state lives.
|
|
260
|
+
- Keep async work inside the owning module.
|
|
261
|
+
- Make loading and error states explicit.
|
|
262
|
+
|
|
263
|
+
### API Layer
|
|
264
|
+
|
|
265
|
+
- Keep request and response shapes explicit.
|
|
266
|
+
- Normalize errors near the boundary.
|
|
267
|
+
- Version breaking contract changes.
|
|
268
|
+
|
|
269
|
+
### Component Structure
|
|
270
|
+
|
|
271
|
+
- Keep presentation and side effects separated.
|
|
272
|
+
- Put validation near the boundary.
|
|
273
|
+
- Make loading and error states visible.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Testing Standards
|
|
278
|
+
|
|
279
|
+
- Unit tests: pure logic and helper functions.
|
|
280
|
+
- Integration tests: API calls and service boundaries.
|
|
281
|
+
- E2E tests: critical user journeys.
|
|
282
|
+
- Quality gate: verify behavior before release.
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Quick Reference
|
|
287
|
+
|
|
288
|
+
- Validate templates: node bin/validate-templates.js
|
|
289
|
+
- Sync templates: node bin/sync-templates.js
|
|
290
|
+
- Entry point: @feature-lead
|
|
291
|
+
`;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
async function install() {
|
|
295
|
+
console.log(banner);
|
|
296
|
+
log.title('OpenCode Agile Agent Installer');
|
|
297
|
+
|
|
298
|
+
const confirm = await question('Install the OpenCode agent kit now? [y/N]: ');
|
|
299
|
+
if (!/^y(es)?$/i.test(confirm.trim())) {
|
|
300
|
+
log.info('Install cancelled.');
|
|
301
|
+
rl.close();
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const context = detectProjectContext();
|
|
306
|
+
log.info(`Detected project: ${context.projectName} (${context.framework}, ${context.language})`);
|
|
307
|
+
|
|
308
|
+
const source = join(templatesDir, '.opencode');
|
|
309
|
+
const target = join(rootDir, '.opencode');
|
|
310
|
+
|
|
311
|
+
if (!existsSync(templatesDir) || !existsSync(source)) {
|
|
312
|
+
log.error('Template source not found.');
|
|
313
|
+
rl.close();
|
|
314
|
+
process.exitCode = 1;
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (!existsSync(target)) {
|
|
319
|
+
mkdirSync(target, { recursive: true });
|
|
320
|
+
} else {
|
|
321
|
+
rmSync(target, { recursive: true, force: true });
|
|
322
|
+
mkdirSync(target, { recursive: true });
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
cpSync(source, target, {
|
|
326
|
+
recursive: true,
|
|
327
|
+
overwrite: true,
|
|
328
|
+
filter: shouldCopyPath,
|
|
329
|
+
});
|
|
330
|
+
writeFileSync(join(rootDir, 'AGENTS.md'), generateAgentsMd(context), 'utf-8');
|
|
331
|
+
|
|
332
|
+
log.success('Installed .opencode and generated AGENTS.md.');
|
|
333
|
+
log.title('Done');
|
|
334
|
+
console.log('Start with @feature-lead and review .opencode/README.md for the flow.');
|
|
335
|
+
|
|
336
|
+
rl.close();
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
install().catch((error) => {
|
|
340
|
+
log.error(`Unexpected error: ${error.message}`);
|
|
341
|
+
console.error(error);
|
|
342
|
+
rl.close();
|
|
343
|
+
process.exit(1);
|
|
344
|
+
});
|