@grvmithas/create-aies-kit 1.0.0 → 1.3.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,794 @@
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. Multi-file work uses approved \`plans/{STORY_ID}-plan.md\` (ephemeral)
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. Run enhance (CLI + agent chat invoke in §0)
123
+ 3. Create \`plans/{STORY_ID}-plan.md\` from \`plans/_TEMPLATE.md\`
124
+ 4. Cookbook generate → coding → \`reviews/{STORY_ID}-code-review.md\`
125
+ 5. Online: ${SITE_URL}/docs/handbook/README`;
126
+ }
127
+ if (maturity === 'intermediate') {
128
+ return `1. Enhance repo → ephemeral plan → cookbook generate/review
129
+ 2. Wire \`guides/evals-as-quality-gates.md\` into CI
130
+ 3. Use \`hooks/\` before commit; enable MCP only from recommended stubs
131
+ 4. Online: ${SITE_URL}/workflows`;
132
+ }
133
+ if (maturity === 'advanced') {
134
+ return `1. Enhance repo + MCP handbook + agent hooks
135
+ 2. Compose agents (planner → coder → reviewer) with budgets
136
+ 3. Security skill before write tools; story-scoped plans/reviews
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 + hooks + segregation of duties
142
+ 4. Attach \`plans/{STORY_ID}-plan.md\` + \`reviews/{STORY_ID}-code-review.md\` on PRs — then stop maintaining them`;
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
+ const enhancePrompt = `${L.promptsDir}/enhance-repo.prompt.md`;
178
+ const enhanceChat = invokeEnhanceChat(profile.ide, enhancePrompt);
179
+ return `# AIES project instructions — ${label}
180
+
181
+ This repository uses the **AI Engineering Standard (AIES)** harness.
182
+
183
+ ## Profile
184
+
185
+ - Stack: ${label}
186
+ - Role: ${profile.role}
187
+ - Maturity: ${profile.maturity} (docs reading path only)
188
+ - Primary IDE selection: ${profile.ide}
189
+ - Model: ${profile.model ?? 'undecided'}
190
+ - Data class: ${profile.dataClass ?? 'internal'}
191
+
192
+ ## Non-negotiables
193
+
194
+ 1. Read \`AIES.md\` before coding with AI
195
+ 2. Multi-file work requires approved \`plans/{STORY_ID}-plan.md\` (ephemeral — not a forever root plan)
196
+ 3. Prefer installed skills/prompts/cookbook over ad-hoc chat
197
+ 4. Human owns merges — AI is advisory; write \`reviews/{STORY_ID}-code-review.md\` on AI-touched PRs
198
+ 5. No secrets in prompts, logs, or MCP args
199
+ 6. Keep MCP \`mcpServers\` empty until a human enables stubs from \`_aiesRecommended\`
200
+ 7. Respect this repo’s lint, typecheck, format, and style-guide configs — never weaken them
201
+ 8. Honor agent hooks under \`hooks/\` for plan/code/review gates
202
+
203
+ ## Where to look
204
+
205
+ | Need | Path |
206
+ |------|------|
207
+ | Operator guide | \`AIES.md\` |
208
+ | Plan index | \`implementation_plan.md\` |
209
+ | Active plan | \`plans/{STORY_ID}-plan.md\` |
210
+ | Review report | \`reviews/{STORY_ID}-code-review.md\` |
211
+ | Agent hooks | \`hooks/\` · \`${L.hooksFile}\` |
212
+ | Skills | \`${L.skillsDir}/\` |
213
+ | Prompts | \`${L.promptsDir}/\` |
214
+ | Agents | \`${L.agentsDir}/\` |
215
+ | Stack cookbook | \`${L.cookbookDir}/\` (repo root) |
216
+ | MCP specs | \`${L.mcpsDir}/\` |
217
+ | MCP config | \`${L.mcpFile}\` |
218
+ | Guides | \`${L.guidesDir}/\` |
219
+ | Policy | \`${L.policyFile}\` |
220
+
221
+ **Layout rule:** IDE folders hold **prompts, skills, and agents** only. Cookbook/guides/mcps/templates stay at repo root.
222
+
223
+ ## First commands after install
224
+
225
+ \`\`\`bash
226
+ npx @grvmithas/create-aies-kit enhance
227
+ \`\`\`
228
+
229
+ Then paste into agent chat:
230
+
231
+ \`\`\`text
232
+ ${enhanceChat}
233
+ \`\`\`
234
+
235
+ ## Workflow
236
+
237
+ Enhance → \`plans/{STORY_ID}-plan.md\` (approve) → coding with plan attached → verify (lint/test) → \`reviews/{STORY_ID}-code-review.md\` → PR
238
+ `;
239
+ }
240
+
241
+ function buildAiesReadme({ profile, label, L, stack, flags, now, recommendedIds }) {
242
+ const model = profile.model ?? 'undecided';
243
+ const dataClass = profile.dataClass ?? 'internal';
244
+ const enhancePrompt = `${L.promptsDir}/enhance-repo.prompt.md`;
245
+
246
+ return `# AIES — Operator guide (${label})
247
+
248
+ **Generated:** ${now}
249
+ **Profile:** ${profile.role} · ${profile.ide} · ${profile.maturity} · ${label} · model **${model}** · data **${dataClass}**
250
+
251
+ This install is **always complete**. Maturity only changes the reading path — not which files were written.
252
+ There is **no** \`.aies/\` folder.
253
+ **IDE folders** hold prompts, skills, and agents. **Cookbook, guides, MCP specs, and templates** live at repo root (never under \`.github/cookbook\`).
254
+
255
+ ---
256
+
257
+ ## 0. Start from the word go (do this first)
258
+
259
+ 1. **Read this file** (AIES.md).
260
+ 2. **Refresh kit signals** (MCP recommendations from repo scan):
261
+
262
+ \`\`\`bash
263
+ npx @grvmithas/create-aies-kit enhance
264
+ \`\`\`
265
+
266
+ 3. **Run the enhance prompt in your IDE agent chat** (copy-paste):
267
+
268
+ \`\`\`text
269
+ ${invokeEnhanceChat(profile.ide, enhancePrompt)}
270
+ \`\`\`
271
+
272
+ Prompt path: \`${enhancePrompt}\`
273
+ That scan rewrites harness files to match **this** repo’s lint, style guides, FE/BE layout, and guardrails.
274
+
275
+ 4. Create an **ephemeral** plan: \`plans/{STORY_ID}-plan.md\` (see §1) — approve before multi-file coding.
276
+ 5. Code with the plan attached → write \`reviews/{STORY_ID}-code-review.md\` → open PR with both attached.
277
+
278
+ **Re-install kit (force):**
279
+
280
+ \`\`\`bash
281
+ npx @grvmithas/create-aies-kit ${flags} --force
282
+ \`\`\`
283
+
284
+ ---
285
+
286
+ ## 1. Ephemeral plans & review reports (not forever-docs)
287
+
288
+ **Plans and review reports are temporary.** Scope ends when the story/PR completes. Keeping a single living \`implementation_plan.md\` forever is an anti-pattern.
289
+
290
+ | Artifact | Path | After merge |
291
+ |----------|------|-------------|
292
+ | Plan | \`plans/{STORY_ID}-plan.md\` | Attach to PR; archive or delete — **do not maintain** |
293
+ | Code review | \`reviews/{STORY_ID}-code-review.md\` | Attach to PR; freeze — file issues for leftovers |
294
+ | Index only | \`implementation_plan.md\` | Points here — not the active plan |
295
+
296
+ ### Create / fill a plan
297
+
298
+ 1. Copy \`plans/_TEMPLATE.md\` → \`plans/{STORY_ID}-plan.md\`
299
+ 2. Attach \`${L.promptsDir}/implementation-plan.prompt.md\` (or planning skill)
300
+ 3. Fill tasks with verification commands from **this** repo (see enhance output)
301
+ 4. Human approval before multi-file coding
302
+
303
+ ### Temporary memory
304
+
305
+ - Attach the plan file every agent turn for that story
306
+ - Optional sticky/context include by \`STORY_ID\`
307
+ - Never dump the full plan into forever rules (\`CLAUDE.md\` / \`AGENTS.md\`)
308
+
309
+ ### Anti-patterns
310
+
311
+ - Forever-editing one root plan for every feature
312
+ - Coding multi-file work from chat with no \`plans/{STORY_ID}-plan.md\`
313
+ - Skipping \`reviews/{STORY_ID}-code-review.md\` on AI-touched PRs
314
+
315
+ ---
316
+
317
+ ## 2. How to use the right prompts
318
+
319
+ | Situation | Prompt |
320
+ |-----------|--------|
321
+ | New story / kickoff | \`${L.promptsDir}/story-kickoff.prompt.md\` |
322
+ | Build the plan | \`${L.promptsDir}/implementation-plan.prompt.md\` |
323
+ | Implement approved plan | \`${L.promptsDir}/coding.prompt.md\` |
324
+ | Security pass | \`${L.promptsDir}/security-review.prompt.md\` |
325
+ | Adapt harness to this repo | \`${enhancePrompt}\` — see §0 chat invoke |
326
+ | Author a new prompt | \`${L.promptsDir}/create-prompt.prompt.md\` |
327
+ | Author a new skill | \`${L.promptsDir}/create-skill.prompt.md\` |
328
+ | Author a new agent | \`${L.promptsDir}/create-agent.prompt.md\` |
329
+ | Stack generate / review / debug | \`${L.cookbookDir}/prompts/\` |
330
+
331
+ **Rule:** Prefer cookbook prompts for stack-idiomatic work; prefer AIDLC prompts for lifecycle gates.
332
+
333
+ ---
334
+
335
+ ## 3. How to use the right skills
336
+
337
+ | Situation | Skill |
338
+ |-----------|--------|
339
+ | Multi-step plan | \`${skillPath(L, 'planning')}\` |
340
+ | Bug / incident | \`${skillPath(L, 'debug')}\` |
341
+ | PR review | \`${skillPath(L, 'code-review')}\` |
342
+ | Tests | \`${skillPath(L, 'testing')}\` |
343
+ | Architecture / ADR | \`${skillPath(L, 'architecture')}\` |
344
+ | Context packing | \`${skillPath(L, 'context')}\` |
345
+ | CI/CD / release | \`${skillPath(L, 'devops')}\` |
346
+ | Eval gates | \`${skillPath(L, 'evaluation')}\` |
347
+ | Threat / AuthZ | \`${skillPath(L, 'security')}\` |
348
+ | Write better prompts | \`${skillPath(L, 'prompt')}\` |
349
+ | Docs | \`${skillPath(L, 'documentation')}\` |
350
+ | Stack-specific | skill under \`${L.skillsDir}/\` matching ${label} |
351
+
352
+ **Cursor:** skills are \`.cursor/skills/{name}/SKILL.md\` (auto-discoverable).
353
+ **Copilot / VS Code:** open the \`.skill.md\` file and attach it.
354
+
355
+ ---
356
+
357
+ ## 4. Agents
358
+
359
+ | Agent | Path | Use when |
360
+ |-------|------|----------|
361
+ | Planner | \`${L.agentsDir}/planner.agent.md\` | Complex multi-file planning |
362
+ | Coder | \`${L.agentsDir}/coder.agent.md\` | Execution against an approved plan |
363
+ | Reviewer | \`${L.agentsDir}/reviewer.agent.md\` | Severity-calibrated review |
364
+ | Prompt engineer | \`${L.agentsDir}/prompt-engineer.agent.md\` | Designing new prompts/skills |
365
+
366
+ Compose agents; do not give them merge authority.
367
+
368
+ ---
369
+
370
+ ## 5. Agent hooks (evidence gates)
371
+
372
+ Scripts: \`hooks/*.hook.sh\` · Operator notes: \`hooks/README.md\` · Full contract: \`hooks/CONTRACT.md\`
373
+ Registry: \`${L.hooksFile}\`
374
+
375
+ Use hooks so agents cannot skip plan approval, lint evidence, or high-effect tools. Wire evidence to **this repo’s** verify commands after enhance.
376
+
377
+ Typical loop: \`plans/{STORY_ID}-plan.md\` → pre-code hook → coding → lint/test evidence → \`reviews/{STORY_ID}-code-review.md\` → pre-review/pre-commit → PR.
378
+
379
+ ---
380
+
381
+ ## 6. MCP connections (relevant + safe)
382
+
383
+ Specs (all catalog entries shipped): \`${L.mcpsDir}/\`
384
+ Config: \`${L.mcpFile}\`
385
+
386
+ - \`mcpServers\` starts **empty** (safe default).
387
+ - \`_aiesRecommended\` lists enable-ready stubs for this stack/profile: **${recommendedIds.join(', ')}**
388
+ - After \`enhance\`, recommendations update from repo signals (Docker, Playwright, Postgres, etc.).
389
+ - To enable: copy a stub from \`_aiesRecommended\` → \`mcpServers\`, set env secrets outside git, re-read \`${L.guidesDir}/mcp-when-and-how.md\`.
390
+
391
+ **Never** commit tokens. Prefer read-only scopes first.
392
+
393
+ ---
394
+
395
+ ## 7. Root instruction files (always present)
396
+
397
+ | File | Role |
398
+ |------|------|
399
+ | \`CLAUDE.md\` | Claude Code / multi-IDE contract at repo root |
400
+ | \`AGENTS.md\` | Agent-oriented project contract (Cursor/Codex-compatible) |
401
+ | \`copilot-instructions.md\` | Copilot-oriented instructions at repo root |
402
+ | \`.github/copilot-instructions.md\` | Same content for GitHub Copilot discovery |
403
+ | \`${L.rulesFile}\` | Primary IDE rules for **${profile.ide}** |
404
+
405
+ ---
406
+
407
+ ## 8. Layout (${profile.ide})
408
+
409
+ | Path | Purpose |
410
+ |------|---------|
411
+ | \`AIES.md\` | This operator guide |
412
+ | \`implementation_plan.md\` | Ephemeral-plan **index** (not the active plan) |
413
+ | \`plans/{STORY_ID}-plan.md\` | Active plan — temporary |
414
+ | \`reviews/{STORY_ID}-code-review.md\` | Review report — temporary |
415
+ | \`hooks/\` | Agent evidence-gate scripts |
416
+ | \`${L.hooksFile}\` | Hook registry (agentHooks) |
417
+ | \`${L.promptsDir}/\` | AIDLC + create/enhance prompts (**IDE**) |
418
+ | \`${L.skillsDir}/\` | Skills (**IDE**) |
419
+ | \`${L.agentsDir}/\` | Agent definitions (**IDE**) |
420
+ | \`${L.cookbookDir}/\` | Full stack cookbook (**repo root**) |
421
+ | \`${L.guidesDir}/\` | Handbook slices (**repo root**) |
422
+ | \`${L.mcpsDir}/\` | MCP integration specs (**repo root**) |
423
+ | \`${L.templatesDir}/\` | System prompt template (**repo root**) |
424
+ | \`${L.mcpFile}\` | MCP config (empty \`mcpServers\` by default) |
425
+ | \`${L.policyFile}\` | Model + data policy |
426
+
427
+ **Anti-pattern:** Do not nest cookbook/guides/mcps under \`.github\` — that folder is for Copilot discovery (instructions, prompts, skills, agents) and GitHub metadata only.
428
+
429
+ ---
430
+
431
+ ## 9. Reading path (${profile.maturity})
432
+
433
+ ${maturityReadingPath(profile.maturity)}
434
+
435
+ ## 10. Role next workflow
436
+
437
+ ${SITE_URL}/workflows/${roleNext(profile.role)}
438
+
439
+ ## 11. Online
440
+
441
+ - Quick start: ${SITE_URL}/quickstart
442
+ - Cookbook: ${SITE_URL}/docs/cookbook/${stack.cookbook ?? 'README'}/README
443
+ - MCP handbook: ${SITE_URL}/docs/handbook/mcp-when-and-how
444
+ - Workflows: ${SITE_URL}/workflows
445
+ `;
446
+ }
447
+
448
+ function invokeEnhanceChat(ide, enhancePrompt) {
449
+ switch (ide) {
450
+ case 'cursor':
451
+ return `@${enhancePrompt} Scan this repo and enhance the AIES harness. Follow the XML instructions exactly.`;
452
+ case 'copilot':
453
+ return `#file:${enhancePrompt} Scan this repo and enhance the AIES harness. Follow the XML instructions exactly.`;
454
+ case 'claude-code':
455
+ return `Read ${enhancePrompt} and execute it against this repository.`;
456
+ default:
457
+ return `Open ${enhancePrompt} and execute it — scan first, then patch AIES artifacts only.`;
458
+ }
459
+ }
460
+
461
+ function implementationPlanIndex(promptsDir) {
462
+ return `# Implementation plans (ephemeral index)
463
+
464
+ > **Not a living document.** Plans exist only for the duration of one story/task.
465
+ > Maintaining a forever-updated root plan is an **anti-pattern**.
466
+
467
+ ## Create a plan for this story
468
+
469
+ 1. Copy \`plans/_TEMPLATE.md\` → \`plans/{STORY_ID}-plan.md\`
470
+ 2. Fill it with \`${promptsDir}/implementation-plan.prompt.md\` + the planning skill
471
+ 3. Get human approval before multi-file coding
472
+ 4. **Attach** \`plans/{STORY_ID}-plan.md\` in every agent chat for that story
473
+ 5. Attach the plan to the PR; when the PR merges, **stop maintaining it** (archive or delete)
474
+
475
+ ## Naming
476
+
477
+ | Artifact | Path |
478
+ |----------|------|
479
+ | Plan | \`plans/{STORY_ID}-plan.md\` |
480
+ | Code review report | \`reviews/{STORY_ID}-code-review.md\` |
481
+
482
+ Examples: \`plans/JIRA-1234-plan.md\`, \`reviews/JIRA-1234-code-review.md\`
483
+
484
+ ## Temporary memory
485
+
486
+ - Prefer attaching the plan file each session (durable, reviewable)
487
+ - Optional: IDE sticky/context include keyed by story id
488
+ - Do **not** paste the full plan into \`CLAUDE.md\` / \`AGENTS.md\` / forever rules
489
+
490
+ See \`plans/README.md\` and \`reviews/README.md\`.
491
+ `;
492
+ }
493
+
494
+ function agentHooksRegistry(L) {
495
+ return {
496
+ version: '2',
497
+ description: 'AIES agent hooks — evidence gates for AI-assisted development',
498
+ hooksDir: 'hooks',
499
+ artifacts: {
500
+ plan: 'plans/{STORY_ID}-plan.md',
501
+ review: 'reviews/{STORY_ID}-code-review.md',
502
+ },
503
+ hooks: [
504
+ {
505
+ id: 'pre-planning',
506
+ phase: 'before-plan',
507
+ script: 'hooks/pre-planning.hook.sh',
508
+ requiredEvidence: ['requirements-path', 'risk-tier'],
509
+ },
510
+ {
511
+ id: 'pre-code',
512
+ phase: 'before-code',
513
+ script: 'hooks/pre-code.hook.sh',
514
+ requiredEvidence: ['approved-plan-path', 'human-approval'],
515
+ },
516
+ {
517
+ id: 'post-code',
518
+ phase: 'after-code',
519
+ script: 'hooks/post-code.hook.sh',
520
+ requiredEvidence: ['verify-evidence'],
521
+ },
522
+ {
523
+ id: 'pre-review',
524
+ phase: 'before-review',
525
+ script: 'hooks/pre-review.hook.sh',
526
+ requiredEvidence: ['format-evidence', 'lint-evidence'],
527
+ },
528
+ {
529
+ id: 'pre-commit',
530
+ phase: 'before-commit',
531
+ script: 'hooks/pre-commit.hook.sh',
532
+ requiredEvidence: ['test-evidence', 'secret-scan-evidence'],
533
+ },
534
+ {
535
+ id: 'pre-tool-call',
536
+ phase: 'before-tool',
537
+ script: 'hooks/pre-tool-call.hook.sh',
538
+ requiredEvidence: ['tool-effect', 'approval-if-high'],
539
+ },
540
+ {
541
+ id: 'budget-guard',
542
+ phase: 'budget',
543
+ script: 'hooks/budget-guard.hook.sh',
544
+ requiredEvidence: ['budget-profile', 'budget-remaining'],
545
+ },
546
+ {
547
+ id: 'deployment',
548
+ phase: 'before-deploy',
549
+ script: 'hooks/deployment.hook.sh',
550
+ requiredEvidence: ['release-manifest', 'approval', 'release-evidence'],
551
+ },
552
+ ],
553
+ agentGuidance: {
554
+ beforeMultiFileCoding: `Attach plans/{STORY_ID}-plan.md and confirm human approval`,
555
+ beforePr: `Write reviews/{STORY_ID}-code-review.md; run repo lint/typecheck/test`,
556
+ mcp: `Keep mcpServers empty until human copies from ${L.mcpFile} _aiesRecommended`,
557
+ },
558
+ _aies: {
559
+ hooksGuide: `${SITE_URL}/docs/handbook/hooks-in-practice`,
560
+ contract: 'hooks/CONTRACT.md',
561
+ },
562
+ };
563
+ }
564
+
565
+ /**
566
+ * @param {object} profile
567
+ * @param {{ recommendedMcpIds?: string[] }} [opts]
568
+ */
569
+ export function generateStarterKit(profile, opts = {}) {
570
+ const stack = stackMeta(profile.stack);
571
+ const label = STACK_LABELS[profile.stack] ?? profile.stack;
572
+ const now = new Date().toISOString();
573
+ const model = profile.model ?? 'undecided';
574
+ const dataClass = profile.dataClass ?? 'internal';
575
+ const L = layoutFor(profile.ide, { cookbookId: stack.cookbook ?? null });
576
+ const recommendedIds = opts.recommendedMcpIds ?? stackMcpIds(profile.stack);
577
+ const recommended = buildRecommendedMcpConfig(recommendedIds);
578
+
579
+ const flags = [
580
+ `--stack ${profile.stack}`,
581
+ `--ide ${profile.ide}`,
582
+ `--role ${profile.role}`,
583
+ `--maturity ${profile.maturity}`,
584
+ `--goal ${profile.goal}`,
585
+ `--model ${model}`,
586
+ `--data-class ${dataClass}`,
587
+ '--yes',
588
+ ].join(' ');
589
+
590
+ /** @type {Record<string, string>} */
591
+ const files = {};
592
+
593
+ for (const name of CORE_PROMPTS) {
594
+ files[`${L.promptsDir}/${name}.prompt.md`] = corpus(`aidlc/${name}.prompt.md`);
595
+ }
596
+
597
+ for (const name of CORE_SKILLS) {
598
+ writeSkill(files, L, name, corpus(`skills/${name}.skill.md`));
599
+ }
600
+
601
+ for (const name of CORE_AGENTS) {
602
+ files[`${L.agentsDir}/${name}.agent.md`] = corpus(`agents/${name}.agent.md`);
603
+ }
604
+
605
+ files[`${L.templatesDir}/system-prompt.template.md`] = corpus('templates/system-prompt.template.md');
606
+
607
+ files['plans/README.md'] = corpus('kit/plans-README.md');
608
+ files['plans/_TEMPLATE.md'] = corpus('kit/plan-TEMPLATE.md');
609
+ files['reviews/README.md'] = corpus('kit/reviews-README.md');
610
+ files['reviews/_TEMPLATE.md'] = corpus('kit/review-TEMPLATE.md');
611
+
612
+ files['hooks/README.md'] = corpus('kit/hooks-README.md');
613
+ files['hooks/CONTRACT.md'] = corpus('hooks/CONTRACT.md');
614
+ for (const key of Object.keys(EMBEDDED_CORPUS).filter(k => k.startsWith('hooks/') && k.endsWith('.hook.sh'))) {
615
+ files[key] = corpus(key);
616
+ }
617
+
618
+ if (stack.cookbook) {
619
+ const keys = cookbookKeys(stack.cookbook);
620
+ for (const key of keys) {
621
+ const rel = key.slice(`cookbook/${stack.cookbook}/`.length);
622
+ files[`${L.cookbookDir}/${rel}`] = corpus(key);
623
+ }
624
+ const skillKey = keys.find(k => k.includes('/skills/') && k.endsWith('.skill.md'));
625
+ if (skillKey) {
626
+ const skillName = pathBasename(skillKey).replace(/\.skill\.md$/, '');
627
+ writeSkill(files, L, skillName, corpus(skillKey));
628
+ }
629
+ }
630
+
631
+ files[`${L.guidesDir}/human-in-the-loop.md`] = corpus('handbook/human-in-the-loop.md');
632
+ files[`${L.guidesDir}/evals-as-quality-gates.md`] = corpus('handbook/evals-as-quality-gates.md');
633
+ files[`${L.guidesDir}/mcp-when-and-how.md`] = corpus('handbook/mcp-when-and-how.md');
634
+ files[`${L.guidesDir}/skills-vs-prompts-vs-agents.md`] = corpus('handbook/skills-vs-prompts-vs-agents.md');
635
+ files[`${L.guidesDir}/how-to-set-up-planning.md`] = corpus('handbook/how-to-set-up-planning.md');
636
+
637
+ files[`${L.mcpsDir}/README.md`] = corpus('mcps/README.md');
638
+ for (const spec of MCP_SPECS) {
639
+ files[`${L.mcpsDir}/${spec.file}`] = corpus(`mcps/${spec.file}`);
640
+ }
641
+
642
+ files[L.policyFile] = modelPolicy(profile);
643
+
644
+ const mcpDoc = {
645
+ mcpServers: {},
646
+ _aiesRecommended: recommended,
647
+ _aies: {
648
+ note: 'mcpServers stays empty until a human copies stubs from _aiesRecommended and sets secrets.',
649
+ guide: `${SITE_URL}/docs/handbook/mcp-when-and-how`,
650
+ dataClass,
651
+ recommendedIds,
652
+ specsDir: L.mcpsDir,
653
+ },
654
+ };
655
+ files[L.mcpFile] = JSON.stringify(mcpDoc, null, 2);
656
+
657
+ files[L.hooksFile] = JSON.stringify(agentHooksRegistry(L), null, 2);
658
+
659
+ const rootInstructions = buildRootInstructions(profile, label, L);
660
+ files['CLAUDE.md'] = rootInstructions;
661
+ files['AGENTS.md'] = rootInstructions;
662
+ files['copilot-instructions.md'] = rootInstructions;
663
+ files['.github/copilot-instructions.md'] = rootInstructions;
664
+
665
+ if (profile.ide === 'cursor') {
666
+ files[L.rulesFile] = `---
667
+ description: AIES project harness rules
668
+ globs:
669
+ alwaysApply: true
670
+ ---
671
+
672
+ ${rootInstructions}
673
+ `;
674
+ } else if (profile.ide === 'claude-code') {
675
+ // CLAUDE.md already written as rootInstructions
676
+ } else if (profile.ide === 'copilot') {
677
+ // .github/copilot-instructions.md already written — do not nest cookbook under .github
678
+ } else if (profile.ide === 'continue') {
679
+ files[L.rulesFile] = rootInstructions;
680
+ files['.continue/config.snippet.json'] = JSON.stringify(
681
+ {
682
+ comment: 'Merge into Continue config — do not overwrite blindly',
683
+ contextProviders: [
684
+ { name: 'file', params: { path: 'implementation_plan.md' } },
685
+ { name: 'file', params: { path: L.cookbookDir } },
686
+ { name: 'file', params: { path: L.skillsDir } },
687
+ { name: 'file', params: { path: L.promptsDir } },
688
+ ],
689
+ },
690
+ null,
691
+ 2,
692
+ );
693
+ } else {
694
+ files[L.rulesFile] = rootInstructions;
695
+ }
696
+
697
+ files['implementation_plan.md'] = implementationPlanIndex(L.promptsDir);
698
+
699
+ files['AIES.md'] = buildAiesReadme({
700
+ profile: { ...profile, model, dataClass },
701
+ label,
702
+ L,
703
+ stack,
704
+ flags,
705
+ now,
706
+ recommendedIds,
707
+ });
708
+
709
+ return {
710
+ stack: profile.stack,
711
+ generatedAt: now,
712
+ profile: { ...profile, model, dataClass },
713
+ layout: describeInstallLayout(profile.ide, { cookbookId: stack.cookbook ?? null }),
714
+ files,
715
+ };
716
+ }
717
+
718
+ /**
719
+ * Enhance mode: rescan repo, refresh MCP recommendations + AIES.md section, keep corpus.
720
+ * Requires an existing profile — recovered from AIES.md markers or passed flags.
721
+ */
722
+ export function enhanceStarterKit(cwd, profile) {
723
+ const { signals, recommendedMcpIds } = detectRepoSignals(cwd, fs);
724
+ const mergedIds = [...new Set([...stackMcpIds(profile.stack), ...recommendedMcpIds])];
725
+ const bundle = generateStarterKit(profile, { recommendedMcpIds: mergedIds });
726
+
727
+ const scanReport = `# AIES repo scan
728
+
729
+ Generated: ${new Date().toISOString()}
730
+
731
+ ## Signals detected
732
+
733
+ \`\`\`json
734
+ ${JSON.stringify(signals, null, 2)}
735
+ \`\`\`
736
+
737
+ ## Recommended MCP ids
738
+
739
+ ${mergedIds.map(id => `- ${id}`).join('\n')}
740
+
741
+ ## Next
742
+
743
+ 1. Review \`${layoutFor(profile.ide, { cookbookId: stackMeta(profile.stack).cookbook }).mcpFile}\` → \`_aiesRecommended\`
744
+ 2. Run \`${layoutFor(profile.ide, { cookbookId: stackMeta(profile.stack).cookbook }).promptsDir}/enhance-repo.prompt.md\` in your IDE agent
745
+ 3. Fill \`implementation_plan.md\` before multi-file coding
746
+ `;
747
+
748
+ bundle.files['AIES_REPO_SCAN.md'] = scanReport;
749
+ bundle.scan = { signals, recommendedMcpIds: mergedIds };
750
+ return bundle;
751
+ }
752
+
753
+ export function renderBashInstallScript(bundle) {
754
+ const lines = [
755
+ '#!/usr/bin/env bash',
756
+ 'set -euo pipefail',
757
+ 'echo "AIES kit — scaffolding IDE-native harness into $(pwd)"',
758
+ '',
759
+ ];
760
+ for (const [relPath, content] of Object.entries(bundle.files)) {
761
+ const dir = relPath.includes('/') ? relPath.slice(0, relPath.lastIndexOf('/')) : '';
762
+ if (dir) lines.push(`mkdir -p "${dir}"`);
763
+ const delim = `AIES_EOF_${Buffer.from(relPath).toString('hex').slice(0, 12)}`;
764
+ lines.push(`cat > "${relPath}" <<'${delim}'`);
765
+ lines.push(content.replace(/\r\n/g, '\n'));
766
+ lines.push(delim);
767
+ lines.push('');
768
+ }
769
+ lines.push('echo "Done. Read AIES.md — then: npx @grvmithas/create-aies-kit enhance"');
770
+ lines.push(`echo "Open: ${SITE_URL}/quickstart"`);
771
+ return lines.join('\n');
772
+ }
773
+
774
+ export function renderPowerShellInstallScript(bundle) {
775
+ const lines = [
776
+ '$ErrorActionPreference = "Stop"',
777
+ 'Write-Host "AIES kit — scaffolding IDE-native harness into $(Get-Location)"',
778
+ '',
779
+ ];
780
+ for (const [relPath, content] of Object.entries(bundle.files)) {
781
+ const dir = relPath.includes('/') ? relPath.slice(0, relPath.lastIndexOf('/')) : '';
782
+ const psPath = relPath.replace(/\//g, '\\');
783
+ if (dir) {
784
+ lines.push(`New-Item -ItemType Directory -Force -Path "${dir.replace(/\//g, '\\')}" | Out-Null`);
785
+ }
786
+ const b64 = Buffer.from(content, 'utf8').toString('base64');
787
+ lines.push(
788
+ `[System.IO.File]::WriteAllText((Join-Path (Get-Location) "${psPath}"), [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String("${b64}")))`,
789
+ );
790
+ }
791
+ lines.push('Write-Host "Done. Read AIES.md — then: npx @grvmithas/create-aies-kit enhance"');
792
+ lines.push(`Write-Host "Open: ${SITE_URL}/quickstart"`);
793
+ return lines.join('\n');
794
+ }