@grvmithas/create-aies-kit 1.0.0 → 1.1.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.
@@ -0,0 +1,693 @@
1
+ import fs from 'node:fs';
2
+ import { EMBEDDED_CORPUS } from './embedded-corpus.js';
3
+ import {
4
+ MCP_SPECS,
5
+ buildRecommendedMcpConfig,
6
+ detectRepoSignals,
7
+ stackMcpIds,
8
+ } from './mcp-catalog.js';
9
+ import { describeInstallLayout, layoutFor } from './install-api.js';
10
+ import { SITE_URL, STACK_LABELS, STACKS } from './options.js';
11
+
12
+ export { buildInstallQuery, describeInstallLayout, getInstallCommands, layoutFor } from './install-api.js';
13
+
14
+ const CORE_SKILLS = [
15
+ 'planning',
16
+ 'debug',
17
+ 'devops',
18
+ 'code-review',
19
+ 'evaluation',
20
+ 'security',
21
+ 'testing',
22
+ 'architecture',
23
+ 'context',
24
+ 'prompt',
25
+ 'documentation',
26
+ ];
27
+
28
+ const CORE_PROMPTS = [
29
+ 'story-kickoff',
30
+ 'implementation-plan',
31
+ 'coding',
32
+ 'security-review',
33
+ 'enhance-repo',
34
+ 'create-prompt',
35
+ 'create-skill',
36
+ 'create-agent',
37
+ ];
38
+
39
+ const CORE_AGENTS = ['planner', 'coder', 'reviewer', 'prompt-engineer'];
40
+
41
+ function corpus(key) {
42
+ const body = EMBEDDED_CORPUS[key];
43
+ if (!body) {
44
+ return `<!-- Missing embedded corpus: ${key}. Re-run: npm run kit:embed -->\n`;
45
+ }
46
+ return body;
47
+ }
48
+
49
+ function stackMeta(stack) {
50
+ return STACKS.find(s => s.id === stack) ?? { id: stack, label: stack, skillKey: null, cookbook: null };
51
+ }
52
+
53
+ function stripFrontmatter(md) {
54
+ if (!md.startsWith('---')) return md;
55
+ const end = md.indexOf('\n---', 3);
56
+ if (end === -1) return md;
57
+ return md.slice(end + 4).replace(/^\s+/, '');
58
+ }
59
+
60
+ function skillDescription(name, body) {
61
+ const purpose = body.match(/## Purpose\s*\n+([^\n]+)/);
62
+ if (purpose) return purpose[1].trim().slice(0, 180);
63
+ return `AIES ${name} skill — use when this procedure applies.`;
64
+ }
65
+
66
+ function writeSkill(files, L, name, body) {
67
+ if (L.skillStyle === 'cursor-skill') {
68
+ const cleaned = stripFrontmatter(body);
69
+ const desc = skillDescription(name, body).replace(/"/g, "'").replace(/\r?\n/g, ' ');
70
+ files[`${L.skillsDir}/${name}/SKILL.md`] = `---
71
+ name: ${name}
72
+ description: "${desc}"
73
+ ---
74
+
75
+ ${cleaned}
76
+ `;
77
+ } else {
78
+ files[`${L.skillsDir}/${name}.skill.md`] = body;
79
+ }
80
+ }
81
+
82
+ function modelPolicy(profile) {
83
+ const model = profile.model ?? 'undecided';
84
+ const dataClass = profile.dataClass ?? 'internal';
85
+ return `# Model & data policy (AIES)
86
+
87
+ Generated for: **${model}** · data class **${dataClass}**
88
+
89
+ ## Provider posture
90
+
91
+ | Choice | Guidance |
92
+ |--------|----------|
93
+ | claude / gpt / gemini | Pin model IDs in CI and agent configs; record versions in PRs that change prompts |
94
+ | multi | Route via an org gateway; do not hard-code vendor SDKs in feature code without an abstraction |
95
+ | local | Keep offline evals; never assume cloud tool APIs exist |
96
+ | undecided | Default to least privilege; pick a primary model before production |
97
+
98
+ ## Data class rules (${dataClass})
99
+
100
+ ${
101
+ dataClass === 'public'
102
+ ? '- Public data may use cloud models with org-approved logging.\n- Still ban secrets in prompts.'
103
+ : dataClass === 'confidential'
104
+ ? '- Confidential/regulated: prefer private endpoints / VPC; disable training opt-in.\n- No production PII in prompts, traces, or MCP tool args.\n- MCP servers stay empty until security approves allowlist.\n- Require HITL for any tool that can write external systems.'
105
+ : '- Internal data: use org-approved providers only.\n- Redact secrets and customer identifiers from prompts and logs.\n- MCP: enable only from \`_aiesRecommended\` after handbook review.'
106
+ }
107
+
108
+ ## Non-negotiables
109
+
110
+ 1. Human review is accountable — model output is advisory
111
+ 2. Fill \`implementation_plan.md\` before multi-file coding
112
+ 3. Keep \`mcpServers: {}\` until a human enables approved stubs
113
+ 4. Eval gates for AI-touched paths before production
114
+
115
+ Online: ${SITE_URL}/docs/handbook/mcp-when-and-how
116
+ `;
117
+ }
118
+
119
+ function maturityReadingPath(maturity) {
120
+ if (maturity === 'beginner') {
121
+ return `1. \`guides/skills-vs-prompts-vs-agents.md\` + \`guides/human-in-the-loop.md\`
122
+ 2. Fill \`implementation_plan.md\` using \`prompts/implementation-plan.prompt.md\`
123
+ 3. Run **enhance** (below) so artifacts match this repo
124
+ 4. Use cookbook generate → coding → review
125
+ 5. Online: ${SITE_URL}/docs/handbook/README`;
126
+ }
127
+ if (maturity === 'intermediate') {
128
+ return `1. Fill plan → enhance repo → cookbook generate/review
129
+ 2. Wire \`guides/evals-as-quality-gates.md\` into CI
130
+ 3. Enable MCP only from recommended stubs after review
131
+ 4. Online: ${SITE_URL}/workflows`;
132
+ }
133
+ if (maturity === 'advanced') {
134
+ return `1. Enhance repo + MCP handbook
135
+ 2. Compose agents (planner → coder → reviewer) with budgets
136
+ 3. Security skill before write tools
137
+ 4. Online: ${SITE_URL}/docs/04-agent-engineering/README`;
138
+ }
139
+ return `1. Enhance repo + SoA mapping (${SITE_URL}/portal)
140
+ 2. Migration bible: ${SITE_URL}/docs/handbook/ai-migration-bible-path
141
+ 3. Eval CI + MCP allowlists + segregation of duties
142
+ 4. Enterprise evidence retained on PRs`;
143
+ }
144
+
145
+ function roleNext(role) {
146
+ const map = {
147
+ 'product-manager': 'idea',
148
+ architect: 'architecture',
149
+ frontend: 'ai-coding',
150
+ backend: 'ai-coding',
151
+ fullstack: 'implementation-planning',
152
+ qa: 'testing',
153
+ devops: 'devops',
154
+ 'engineering-manager': 'project-kickoff',
155
+ 'ai-engineer': 'implementation-planning',
156
+ };
157
+ return map[role] ?? 'implementation-planning';
158
+ }
159
+
160
+ function cookbookKeys(cookbookId) {
161
+ const prefix = `cookbook/${cookbookId}/`;
162
+ return Object.keys(EMBEDDED_CORPUS)
163
+ .filter(k => k.startsWith(prefix))
164
+ .sort();
165
+ }
166
+
167
+ function pathBasename(p) {
168
+ const parts = p.split('/');
169
+ return parts[parts.length - 1] ?? p;
170
+ }
171
+
172
+ function skillPath(L, name) {
173
+ return L.skillStyle === 'cursor-skill' ? `${L.skillsDir}/${name}/SKILL.md` : `${L.skillsDir}/${name}.skill.md`;
174
+ }
175
+
176
+ function buildRootInstructions(profile, label, L) {
177
+ return `# AIES project instructions — ${label}
178
+
179
+ This repository uses the **AI Engineering Standard (AIES)** harness.
180
+
181
+ ## Profile
182
+
183
+ - Stack: ${label}
184
+ - Role: ${profile.role}
185
+ - Maturity: ${profile.maturity} (docs reading path only)
186
+ - Primary IDE selection: ${profile.ide}
187
+ - Model: ${profile.model ?? 'undecided'}
188
+ - Data class: ${profile.dataClass ?? 'internal'}
189
+
190
+ ## Non-negotiables
191
+
192
+ 1. Read \`AIES.md\` before coding with AI
193
+ 2. Fill and approve \`implementation_plan.md\` before multi-file changes
194
+ 3. Prefer installed skills/prompts/cookbook over ad-hoc chat
195
+ 4. Human owns merges — AI is advisory
196
+ 5. No secrets in prompts, logs, or MCP args
197
+ 6. Keep MCP \`mcpServers\` empty until a human enables stubs from \`_aiesRecommended\`
198
+
199
+ ## Where to look
200
+
201
+ | Need | Path |
202
+ |------|------|
203
+ | Operator guide | \`AIES.md\` |
204
+ | Plan of record | \`implementation_plan.md\` |
205
+ | Skills | \`${L.skillsDir}/\` |
206
+ | Prompts | \`${L.promptsDir}/\` |
207
+ | Stack cookbook | \`${L.cookbookDir}/\` |
208
+ | Agents | \`${L.agentsDir}/\` |
209
+ | MCP specs | \`${L.mcpsDir}/\` |
210
+ | MCP config | \`${L.mcpFile}\` |
211
+ | Policy | \`${L.policyFile}\` |
212
+
213
+ ## First commands after install
214
+
215
+ \`\`\`bash
216
+ npx @grvmithas/create-aies-kit enhance
217
+ \`\`\`
218
+
219
+ Then open \`${L.promptsDir}/enhance-repo.prompt.md\` in your IDE agent and run it against this repo.
220
+
221
+ ## Workflow
222
+
223
+ Plan (\`implementation-plan\`) → Enhance → Cookbook generate → Coding → Review → Security (as needed)
224
+ `;
225
+ }
226
+
227
+ function buildAiesReadme({ profile, label, L, stack, flags, now, recommendedIds }) {
228
+ const model = profile.model ?? 'undecided';
229
+ const dataClass = profile.dataClass ?? 'internal';
230
+ const enhancePrompt = `${L.promptsDir}/enhance-repo.prompt.md`;
231
+
232
+ return `# AIES — Operator guide (${label})
233
+
234
+ **Generated:** ${now}
235
+ **Profile:** ${profile.role} · ${profile.ide} · ${profile.maturity} · ${label} · model **${model}** · data **${dataClass}**
236
+
237
+ This install is **always complete**. Maturity only changes the reading path — not which files were written.
238
+ There is **no** \`.aies/\` folder. Artifacts live in IDE-native paths plus root instruction files.
239
+
240
+ ---
241
+
242
+ ## 0. Start from the word go (do this first)
243
+
244
+ 1. **Read this file** (AIES.md).
245
+ 2. **Enhance for *this* repo** (adapts skills/prompts/MCP/rules to your conventions):
246
+
247
+ \`\`\`bash
248
+ npx @grvmithas/create-aies-kit enhance
249
+ \`\`\`
250
+
251
+ 3. In your IDE agent, open and run:
252
+
253
+ \`${enhancePrompt}\`
254
+
255
+ That prompt scans the repo and upgrades installed artifacts (and may create new files) so you can develop immediately.
256
+
257
+ 4. Fill \`implementation_plan.md\` (see §1) and get human approval.
258
+ 5. Use the right prompt + skill (§2–§3), then code.
259
+
260
+ **Re-install kit (force):**
261
+
262
+ \`\`\`bash
263
+ npx @grvmithas/create-aies-kit ${flags} --force
264
+ \`\`\`
265
+
266
+ ---
267
+
268
+ ## 1. How to create and use \`implementation_plan.md\`
269
+
270
+ ### Create / fill
271
+
272
+ 1. Open root \`implementation_plan.md\`.
273
+ 2. Attach \`${L.promptsDir}/implementation-plan.prompt.md\` in chat (or run the **planning** skill).
274
+ 3. Also load \`${L.guidesDir}/how-to-set-up-planning.md\`.
275
+ 4. Fill: Goal, In/Out of scope, Tasks with verification, Risks, Rollback, Human approval.
276
+
277
+ ### Use
278
+
279
+ - **Before** any multi-file AI coding: plan must be filled and approved.
280
+ - Attach the plan file in every coding session for that slice.
281
+ - Update the plan when scope changes — do not silently expand.
282
+
283
+ ### Anti-patterns
284
+
285
+ - Coding from a chat transcript with no plan file
286
+ - Approving your own high-risk plan without a second human when policy requires it
287
+
288
+ ---
289
+
290
+ ## 2. How to use the right prompts
291
+
292
+ | Situation | Prompt |
293
+ |-----------|--------|
294
+ | New story / kickoff | \`${L.promptsDir}/story-kickoff.prompt.md\` |
295
+ | Build the plan | \`${L.promptsDir}/implementation-plan.prompt.md\` |
296
+ | Implement approved plan | \`${L.promptsDir}/coding.prompt.md\` |
297
+ | Security pass | \`${L.promptsDir}/security-review.prompt.md\` |
298
+ | Adapt harness to this repo | \`${enhancePrompt}\` |
299
+ | Author a new prompt | \`${L.promptsDir}/create-prompt.prompt.md\` |
300
+ | Author a new skill | \`${L.promptsDir}/create-skill.prompt.md\` |
301
+ | Author a new agent | \`${L.promptsDir}/create-agent.prompt.md\` |
302
+ | Stack generate / review / debug | \`${L.cookbookDir}/prompts/\` |
303
+
304
+ **Rule:** Prefer cookbook prompts for stack-idiomatic work; prefer AIDLC prompts for lifecycle gates.
305
+
306
+ ---
307
+
308
+ ## 3. How to use the right skills
309
+
310
+ | Situation | Skill |
311
+ |-----------|--------|
312
+ | Multi-step plan | \`${skillPath(L, 'planning')}\` |
313
+ | Bug / incident | \`${skillPath(L, 'debug')}\` |
314
+ | PR review | \`${skillPath(L, 'code-review')}\` |
315
+ | Tests | \`${skillPath(L, 'testing')}\` |
316
+ | Architecture / ADR | \`${skillPath(L, 'architecture')}\` |
317
+ | Context packing | \`${skillPath(L, 'context')}\` |
318
+ | CI/CD / release | \`${skillPath(L, 'devops')}\` |
319
+ | Eval gates | \`${skillPath(L, 'evaluation')}\` |
320
+ | Threat / AuthZ | \`${skillPath(L, 'security')}\` |
321
+ | Write better prompts | \`${skillPath(L, 'prompt')}\` |
322
+ | Docs | \`${skillPath(L, 'documentation')}\` |
323
+ | Stack-specific | skill under \`${L.skillsDir}/\` matching ${label} |
324
+
325
+ **Cursor:** skills are \`.cursor/skills/{name}/SKILL.md\` (auto-discoverable).
326
+ **Copilot / VS Code:** open the \`.skill.md\` file and attach it.
327
+
328
+ ---
329
+
330
+ ## 4. Agents
331
+
332
+ | Agent | Path | Use when |
333
+ |-------|------|----------|
334
+ | Planner | \`${L.agentsDir}/planner.agent.md\` | Complex multi-file planning |
335
+ | Coder | \`${L.agentsDir}/coder.agent.md\` | Execution against an approved plan |
336
+ | Reviewer | \`${L.agentsDir}/reviewer.agent.md\` | Severity-calibrated review |
337
+ | Prompt engineer | \`${L.agentsDir}/prompt-engineer.agent.md\` | Designing new prompts/skills |
338
+
339
+ Compose agents; do not give them merge authority.
340
+
341
+ ---
342
+
343
+ ## 5. MCP connections (relevant + safe)
344
+
345
+ Specs (all catalog entries shipped): \`${L.mcpsDir}/\`
346
+ Config: \`${L.mcpFile}\`
347
+
348
+ - \`mcpServers\` starts **empty** (safe default).
349
+ - \`_aiesRecommended\` lists enable-ready stubs for this stack/profile: **${recommendedIds.join(', ')}**
350
+ - After \`enhance\`, recommendations update from repo signals (Docker, Playwright, Postgres, etc.).
351
+ - To enable: copy a stub from \`_aiesRecommended\` → \`mcpServers\`, set env secrets outside git, re-read \`${L.guidesDir}/mcp-when-and-how.md\`.
352
+
353
+ **Never** commit tokens. Prefer read-only scopes first.
354
+
355
+ ---
356
+
357
+ ## 6. Root instruction files (always present)
358
+
359
+ | File | Role |
360
+ |------|------|
361
+ | \`CLAUDE.md\` | Claude Code / multi-IDE contract at repo root |
362
+ | \`AGENTS.md\` | Agent-oriented project contract (Cursor/Codex-compatible) |
363
+ | \`copilot-instructions.md\` | Copilot-oriented instructions at repo root |
364
+ | \`.github/copilot-instructions.md\` | Same content for GitHub Copilot discovery |
365
+ | \`${L.rulesFile}\` | Primary IDE rules for **${profile.ide}** |
366
+
367
+ ---
368
+
369
+ ## 7. Layout (${profile.ide})
370
+
371
+ | Path | Purpose |
372
+ |------|---------|
373
+ | \`AIES.md\` | This operator guide |
374
+ | \`implementation_plan.md\` | Plan of record |
375
+ | \`${L.skillsDir}/\` | Skills (complete) |
376
+ | \`${L.promptsDir}/\` | AIDLC + create/enhance prompts |
377
+ | \`${L.cookbookDir}/\` | Full stack cookbook |
378
+ | \`${L.agentsDir}/\` | Agent definitions |
379
+ | \`${L.mcpsDir}/\` | MCP integration specs |
380
+ | \`${L.guidesDir}/\` | Handbook slices |
381
+ | \`${L.templatesDir}/\` | System prompt template |
382
+ | \`${L.policyFile}\` | Model + data policy |
383
+
384
+ ---
385
+
386
+ ## 8. Reading path (${profile.maturity})
387
+
388
+ ${maturityReadingPath(profile.maturity)}
389
+
390
+ ## 9. Role next workflow
391
+
392
+ ${SITE_URL}/workflows/${roleNext(profile.role)}
393
+
394
+ ## 10. Online
395
+
396
+ - Quick start: ${SITE_URL}/quickstart
397
+ - Cookbook: ${SITE_URL}/docs/cookbook/${stack.cookbook ?? 'README'}/README
398
+ - MCP handbook: ${SITE_URL}/docs/handbook/mcp-when-and-how
399
+ - Workflows: ${SITE_URL}/workflows
400
+ `;
401
+ }
402
+
403
+ function implementationPlanTemplate(promptsDir) {
404
+ return `# Implementation Plan
405
+
406
+ > AIES plan of record. **Approve before multi-file coding.**
407
+ > Author with \`${promptsDir}/implementation-plan.prompt.md\` + the planning skill.
408
+
409
+ ## Goal
410
+
411
+ <!-- One sentence outcome -->
412
+
413
+ ## Context
414
+
415
+ <!-- Links: tickets, ADRs, designs, prior PRs -->
416
+
417
+ ## Scope
418
+
419
+ ### In scope
420
+
421
+ -
422
+
423
+ ### Out of scope / non-goals
424
+
425
+ -
426
+
427
+ ## Tasks
428
+
429
+ | ID | Task | Files / areas | Verification command or evidence | Owner | Done |
430
+ |----|------|---------------|----------------------------------|-------|------|
431
+ | 1 | | | | | [ ] |
432
+
433
+ ## Dependencies & sequencing
434
+
435
+ -
436
+
437
+ ## Risks
438
+
439
+ | Risk | Likelihood | Impact | Mitigation |
440
+ |------|------------|--------|------------|
441
+ | | | | |
442
+
443
+ ## Rollback
444
+
445
+ -
446
+
447
+ ## Test / eval plan
448
+
449
+ -
450
+
451
+ ## Human approval
452
+
453
+ - [ ] Plan reviewed for completeness and scope leakage
454
+ - [ ] Approved by: _______________
455
+ - [ ] Date: _______________
456
+
457
+ ## Changelog
458
+
459
+ | Date | Change |
460
+ |------|--------|
461
+ | | Initial |
462
+ `;
463
+ }
464
+
465
+ /**
466
+ * @param {object} profile
467
+ * @param {{ recommendedMcpIds?: string[] }} [opts]
468
+ */
469
+ export function generateStarterKit(profile, opts = {}) {
470
+ const stack = stackMeta(profile.stack);
471
+ const label = STACK_LABELS[profile.stack] ?? profile.stack;
472
+ const now = new Date().toISOString();
473
+ const model = profile.model ?? 'undecided';
474
+ const dataClass = profile.dataClass ?? 'internal';
475
+ const L = layoutFor(profile.ide);
476
+ const recommendedIds = opts.recommendedMcpIds ?? stackMcpIds(profile.stack);
477
+ const recommended = buildRecommendedMcpConfig(recommendedIds);
478
+
479
+ const flags = [
480
+ `--stack ${profile.stack}`,
481
+ `--ide ${profile.ide}`,
482
+ `--role ${profile.role}`,
483
+ `--maturity ${profile.maturity}`,
484
+ `--goal ${profile.goal}`,
485
+ `--model ${model}`,
486
+ `--data-class ${dataClass}`,
487
+ '--yes',
488
+ ].join(' ');
489
+
490
+ /** @type {Record<string, string>} */
491
+ const files = {};
492
+
493
+ for (const name of CORE_PROMPTS) {
494
+ files[`${L.promptsDir}/${name}.prompt.md`] = corpus(`aidlc/${name}.prompt.md`);
495
+ }
496
+
497
+ for (const name of CORE_SKILLS) {
498
+ writeSkill(files, L, name, corpus(`skills/${name}.skill.md`));
499
+ }
500
+
501
+ for (const name of CORE_AGENTS) {
502
+ files[`${L.agentsDir}/${name}.agent.md`] = corpus(`agents/${name}.agent.md`);
503
+ }
504
+
505
+ files[`${L.templatesDir}/system-prompt.template.md`] = corpus('templates/system-prompt.template.md');
506
+
507
+ if (stack.cookbook) {
508
+ const keys = cookbookKeys(stack.cookbook);
509
+ for (const key of keys) {
510
+ const rel = key.slice(`cookbook/${stack.cookbook}/`.length);
511
+ files[`${L.cookbookDir}/${rel}`] = corpus(key);
512
+ }
513
+ const skillKey = keys.find(k => k.includes('/skills/') && k.endsWith('.skill.md'));
514
+ if (skillKey) {
515
+ const skillName = pathBasename(skillKey).replace(/\.skill\.md$/, '');
516
+ writeSkill(files, L, skillName, corpus(skillKey));
517
+ }
518
+ }
519
+
520
+ files[`${L.guidesDir}/human-in-the-loop.md`] = corpus('handbook/human-in-the-loop.md');
521
+ files[`${L.guidesDir}/evals-as-quality-gates.md`] = corpus('handbook/evals-as-quality-gates.md');
522
+ files[`${L.guidesDir}/mcp-when-and-how.md`] = corpus('handbook/mcp-when-and-how.md');
523
+ files[`${L.guidesDir}/skills-vs-prompts-vs-agents.md`] = corpus('handbook/skills-vs-prompts-vs-agents.md');
524
+ files[`${L.guidesDir}/how-to-set-up-planning.md`] = corpus('handbook/how-to-set-up-planning.md');
525
+
526
+ files[`${L.mcpsDir}/README.md`] = corpus('mcps/README.md');
527
+ for (const spec of MCP_SPECS) {
528
+ files[`${L.mcpsDir}/${spec.file}`] = corpus(`mcps/${spec.file}`);
529
+ }
530
+
531
+ files[L.policyFile] = modelPolicy(profile);
532
+
533
+ const mcpDoc = {
534
+ mcpServers: {},
535
+ _aiesRecommended: recommended,
536
+ _aies: {
537
+ note: 'mcpServers stays empty until a human copies stubs from _aiesRecommended and sets secrets.',
538
+ guide: `${SITE_URL}/docs/handbook/mcp-when-and-how`,
539
+ dataClass,
540
+ recommendedIds,
541
+ specsDir: L.mcpsDir,
542
+ },
543
+ };
544
+ files[L.mcpFile] = JSON.stringify(mcpDoc, null, 2);
545
+
546
+ files[L.hooksFile] = JSON.stringify(
547
+ {
548
+ version: '1',
549
+ hooks: [
550
+ { id: 'pre-planning', phase: 'before-plan', requiredEvidence: ['requirements-path', 'risk-tier'] },
551
+ { id: 'pre-code', phase: 'before-code', requiredEvidence: ['approved-plan-path'] },
552
+ ],
553
+ _aies: { hooksGuide: `${SITE_URL}/docs/04-agent-engineering/hooks/README` },
554
+ },
555
+ null,
556
+ 2,
557
+ );
558
+
559
+ const rootInstructions = buildRootInstructions(profile, label, L);
560
+ files['CLAUDE.md'] = rootInstructions;
561
+ files['AGENTS.md'] = rootInstructions;
562
+ files['copilot-instructions.md'] = rootInstructions;
563
+ files['.github/copilot-instructions.md'] = rootInstructions;
564
+
565
+ if (profile.ide === 'cursor') {
566
+ files[L.rulesFile] = `---
567
+ description: AIES project harness rules
568
+ globs:
569
+ alwaysApply: true
570
+ ---
571
+
572
+ ${rootInstructions}
573
+ `;
574
+ } else if (profile.ide === 'claude-code') {
575
+ // CLAUDE.md already written as rootInstructions
576
+ } else if (profile.ide === 'copilot') {
577
+ // .github/copilot-instructions.md already written
578
+ } else if (profile.ide === 'continue') {
579
+ files[L.rulesFile] = rootInstructions;
580
+ files['.continue/config.snippet.json'] = JSON.stringify(
581
+ {
582
+ comment: 'Merge into Continue config — do not overwrite blindly',
583
+ contextProviders: [
584
+ { name: 'file', params: { path: 'implementation_plan.md' } },
585
+ { name: 'file', params: { path: L.cookbookDir } },
586
+ { name: 'file', params: { path: L.skillsDir } },
587
+ ],
588
+ },
589
+ null,
590
+ 2,
591
+ );
592
+ } else {
593
+ files[L.rulesFile] = rootInstructions;
594
+ }
595
+
596
+ files['implementation_plan.md'] = implementationPlanTemplate(L.promptsDir);
597
+
598
+ files['AIES.md'] = buildAiesReadme({
599
+ profile: { ...profile, model, dataClass },
600
+ label,
601
+ L,
602
+ stack,
603
+ flags,
604
+ now,
605
+ recommendedIds,
606
+ });
607
+
608
+ return {
609
+ stack: profile.stack,
610
+ generatedAt: now,
611
+ profile: { ...profile, model, dataClass },
612
+ layout: describeInstallLayout(profile.ide),
613
+ files,
614
+ };
615
+ }
616
+
617
+ /**
618
+ * Enhance mode: rescan repo, refresh MCP recommendations + AIES.md section, keep corpus.
619
+ * Requires an existing profile — recovered from AIES.md markers or passed flags.
620
+ */
621
+ export function enhanceStarterKit(cwd, profile) {
622
+ const { signals, recommendedMcpIds } = detectRepoSignals(cwd, fs);
623
+ const mergedIds = [...new Set([...stackMcpIds(profile.stack), ...recommendedMcpIds])];
624
+ const bundle = generateStarterKit(profile, { recommendedMcpIds: mergedIds });
625
+
626
+ const scanReport = `# AIES repo scan
627
+
628
+ Generated: ${new Date().toISOString()}
629
+
630
+ ## Signals detected
631
+
632
+ \`\`\`json
633
+ ${JSON.stringify(signals, null, 2)}
634
+ \`\`\`
635
+
636
+ ## Recommended MCP ids
637
+
638
+ ${mergedIds.map(id => `- ${id}`).join('\n')}
639
+
640
+ ## Next
641
+
642
+ 1. Review \`${layoutFor(profile.ide).mcpFile}\` → \`_aiesRecommended\`
643
+ 2. Run \`${layoutFor(profile.ide).promptsDir}/enhance-repo.prompt.md\` in your IDE agent
644
+ 3. Fill \`implementation_plan.md\` before multi-file coding
645
+ `;
646
+
647
+ bundle.files['AIES_REPO_SCAN.md'] = scanReport;
648
+ bundle.scan = { signals, recommendedMcpIds: mergedIds };
649
+ return bundle;
650
+ }
651
+
652
+ export function renderBashInstallScript(bundle) {
653
+ const lines = [
654
+ '#!/usr/bin/env bash',
655
+ 'set -euo pipefail',
656
+ 'echo "AIES kit — scaffolding IDE-native harness into $(pwd)"',
657
+ '',
658
+ ];
659
+ for (const [relPath, content] of Object.entries(bundle.files)) {
660
+ const dir = relPath.includes('/') ? relPath.slice(0, relPath.lastIndexOf('/')) : '';
661
+ if (dir) lines.push(`mkdir -p "${dir}"`);
662
+ const delim = `AIES_EOF_${Buffer.from(relPath).toString('hex').slice(0, 12)}`;
663
+ lines.push(`cat > "${relPath}" <<'${delim}'`);
664
+ lines.push(content.replace(/\r\n/g, '\n'));
665
+ lines.push(delim);
666
+ lines.push('');
667
+ }
668
+ lines.push('echo "Done. Read AIES.md — then: npx @grvmithas/create-aies-kit enhance"');
669
+ lines.push(`echo "Open: ${SITE_URL}/quickstart"`);
670
+ return lines.join('\n');
671
+ }
672
+
673
+ export function renderPowerShellInstallScript(bundle) {
674
+ const lines = [
675
+ '$ErrorActionPreference = "Stop"',
676
+ 'Write-Host "AIES kit — scaffolding IDE-native harness into $(Get-Location)"',
677
+ '',
678
+ ];
679
+ for (const [relPath, content] of Object.entries(bundle.files)) {
680
+ const dir = relPath.includes('/') ? relPath.slice(0, relPath.lastIndexOf('/')) : '';
681
+ const psPath = relPath.replace(/\//g, '\\');
682
+ if (dir) {
683
+ lines.push(`New-Item -ItemType Directory -Force -Path "${dir.replace(/\//g, '\\')}" | Out-Null`);
684
+ }
685
+ const b64 = Buffer.from(content, 'utf8').toString('base64');
686
+ lines.push(
687
+ `[System.IO.File]::WriteAllText((Join-Path (Get-Location) "${psPath}"), [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String("${b64}")))`,
688
+ );
689
+ }
690
+ lines.push('Write-Host "Done. Read AIES.md — then: npx @grvmithas/create-aies-kit enhance"');
691
+ lines.push(`Write-Host "Open: ${SITE_URL}/quickstart"`);
692
+ return lines.join('\n');
693
+ }