great-cto 2.22.3 → 2.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapt.js +225 -9
- package/dist/bootstrap.js +36 -0
- package/package.json +1 -1
package/dist/adapt.js
CHANGED
|
@@ -1,16 +1,25 @@
|
|
|
1
|
-
// great-cto adapt —
|
|
1
|
+
// great-cto adapt — AI config generator.
|
|
2
2
|
//
|
|
3
3
|
// Writes CLAUDE.md + AGENTS.md from .great_cto/PROJECT.md context.
|
|
4
|
+
// Also generates cross-AI configs for Cursor, Copilot, Windsurf, Aider
|
|
5
|
+
// when ai_tools is set in PROJECT.md.
|
|
4
6
|
//
|
|
5
7
|
// Usage:
|
|
6
|
-
// great-cto adapt Generate
|
|
8
|
+
// great-cto adapt Generate all configs (reads ai_tools from PROJECT.md)
|
|
7
9
|
// great-cto adapt --dry-run Show what would be written
|
|
8
10
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
9
11
|
import { dirname, join } from "node:path";
|
|
12
|
+
const VALID_AI_TOOLS = ["claude-code", "cursor", "copilot", "windsurf", "aider"];
|
|
13
|
+
function parseAiTools(text) {
|
|
14
|
+
const line = text.match(/^ai_tools:\s*(.+)$/m)?.[1] ?? "";
|
|
15
|
+
// Support: [claude-code, cursor] or claude-code, cursor or claude-code
|
|
16
|
+
const raw = line.replace(/[\[\]]/g, "").split(/[,\s]+/).map(s => s.trim()).filter(Boolean);
|
|
17
|
+
return raw.filter((t) => VALID_AI_TOOLS.includes(t));
|
|
18
|
+
}
|
|
10
19
|
function readProjectMeta(cwd) {
|
|
11
20
|
const projectMd = join(cwd, ".great_cto", "PROJECT.md");
|
|
12
21
|
if (!existsSync(projectMd)) {
|
|
13
|
-
return { archetype: "unknown", compliance: [], owners: "", hasGreatCto: false };
|
|
22
|
+
return { archetype: "unknown", compliance: [], owners: "", hasGreatCto: false, aiTools: ["claude-code"], projectName: "project" };
|
|
14
23
|
}
|
|
15
24
|
const text = readFileSync(projectMd, "utf8");
|
|
16
25
|
const archetype = (text.match(/^primary:\s*(\S+)/m)?.[1] ?? "unknown").trim();
|
|
@@ -20,7 +29,63 @@ function readProjectMeta(cwd) {
|
|
|
20
29
|
.map(s => s.trim())
|
|
21
30
|
.filter(Boolean);
|
|
22
31
|
const owners = (text.match(/^owners?:\s*(.+)$/m)?.[1] ?? "").trim();
|
|
23
|
-
|
|
32
|
+
const aiTools = parseAiTools(text);
|
|
33
|
+
// Infer project name from first H1 heading
|
|
34
|
+
const projectName = (text.match(/^#\s+(.+)$/m)?.[1] ?? "project").trim();
|
|
35
|
+
return { archetype, compliance, owners, hasGreatCto: true, aiTools: aiTools.length > 0 ? aiTools : ["claude-code"], projectName };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Project Constitution — universal hard constraints injected into every AI config.
|
|
39
|
+
* Inspired by Spec Driven Development (FredAntB/Spec-Driven-Development).
|
|
40
|
+
*/
|
|
41
|
+
function getConstitutionBlock(meta) {
|
|
42
|
+
const hasSpec = existsSync(join(process.cwd(), "requirements.md"));
|
|
43
|
+
const specSection = hasSpec ? `
|
|
44
|
+
## Spec files (source of truth)
|
|
45
|
+
|
|
46
|
+
requirements.md — What the system must do
|
|
47
|
+
design.md — How the system is structured
|
|
48
|
+
tasks.md — Ordered implementation plan
|
|
49
|
+
|
|
50
|
+
MANDATORY BEFORE ANY ACTION:
|
|
51
|
+
0. If CONTEXT.md exists, read it first — it has session state
|
|
52
|
+
1. Read requirements.md — understand what is in scope
|
|
53
|
+
2. Read design.md — understand how it is structured
|
|
54
|
+
3. Read tasks.md — find the next incomplete [ ] task
|
|
55
|
+
` : `
|
|
56
|
+
## Session context
|
|
57
|
+
|
|
58
|
+
0. If CONTEXT.md exists, read it first — it has the active task and session state
|
|
59
|
+
1. Read .great_cto/PROJECT.md — archetype, compliance gates, team mode
|
|
60
|
+
2. Read .great_cto/lessons.md if present — past mistakes and patterns
|
|
61
|
+
`;
|
|
62
|
+
return `
|
|
63
|
+
═══════════════════════════════════════════════════════════
|
|
64
|
+
PROJECT CONSTITUTION — ${meta.projectName.toUpperCase()}
|
|
65
|
+
Generated by great-cto adapt · ${new Date().toISOString().slice(0, 10)}
|
|
66
|
+
═══════════════════════════════════════════════════════════
|
|
67
|
+
${specSection}
|
|
68
|
+
HARD CONSTRAINTS (no exceptions):
|
|
69
|
+
✗ Never implement requirements not explicitly defined in requirements.md
|
|
70
|
+
✗ Never alter the data model without updating design.md first
|
|
71
|
+
✗ Never mark a task [x] without verifying its acceptance criterion
|
|
72
|
+
✗ Never create files not listed or implied in design.md
|
|
73
|
+
✗ Never guess when a requirement is ambiguous — ask instead
|
|
74
|
+
✗ Never skip gates (security-officer, qa-engineer) — use /waiver with reason
|
|
75
|
+
|
|
76
|
+
AFTER COMPLETING A TASK:
|
|
77
|
+
1. Run the verification step listed in tasks.md (or acceptance criterion)
|
|
78
|
+
2. Mark the task [x] in tasks.md
|
|
79
|
+
3. Update CONTEXT.md resume block with the next active task
|
|
80
|
+
4. Record any divergences from design.md in CONTEXT.md
|
|
81
|
+
|
|
82
|
+
IF IMPLEMENTATION MUST DEVIATE FROM DESIGN:
|
|
83
|
+
1. Stop immediately
|
|
84
|
+
2. Describe the conflict clearly
|
|
85
|
+
3. Wait for explicit approval
|
|
86
|
+
4. Update design.md FIRST, then implement
|
|
87
|
+
═══════════════════════════════════════════════════════════
|
|
88
|
+
`;
|
|
24
89
|
}
|
|
25
90
|
/**
|
|
26
91
|
* AGENTS.md — Claude Code reads this as the cross-tool agent contract.
|
|
@@ -29,7 +94,9 @@ function getAgentsCore(meta) {
|
|
|
29
94
|
const compliance = meta.compliance.length > 0
|
|
30
95
|
? meta.compliance.map(c => `- ${c}`).join("\n")
|
|
31
96
|
: "_(none auto-detected — set in .great_cto/PROJECT.md)_";
|
|
97
|
+
const constitution = getConstitutionBlock(meta);
|
|
32
98
|
return `# AGENTS.md
|
|
99
|
+
${constitution}
|
|
33
100
|
|
|
34
101
|
> Project agent contract for Claude Code. Generated by \`great-cto adapt\` —
|
|
35
102
|
> re-run after editing \`.great_cto/PROJECT.md\`.
|
|
@@ -133,6 +200,117 @@ gates "because it's just a small change" — that's the path to incidents.
|
|
|
133
200
|
_Generated by \`great-cto@${getCliVersion()}\` adapt at ${new Date().toISOString().slice(0, 10)}_
|
|
134
201
|
`;
|
|
135
202
|
}
|
|
203
|
+
// ── Cross-AI config generators ─────────────────────────────────────────────
|
|
204
|
+
function getCursorrules(meta) {
|
|
205
|
+
const constitution = getConstitutionBlock(meta);
|
|
206
|
+
return `${constitution}
|
|
207
|
+
|
|
208
|
+
# .cursorrules — Cursor AI configuration for ${meta.projectName}
|
|
209
|
+
# Generated by great-cto adapt · ${new Date().toISOString().slice(0, 10)}
|
|
210
|
+
|
|
211
|
+
## Project context
|
|
212
|
+
|
|
213
|
+
- **Archetype:** ${meta.archetype}
|
|
214
|
+
- **Compliance:** ${meta.compliance.join(", ") || "none"}
|
|
215
|
+
- **Stack:** See .great_cto/PROJECT.md
|
|
216
|
+
|
|
217
|
+
## Coding conventions
|
|
218
|
+
|
|
219
|
+
- TypeScript strict mode — no \`any\` without explanatory comment
|
|
220
|
+
- ESM modules only (.mjs / "type":"module")
|
|
221
|
+
- Conventional commits: feat / fix / docs / refactor / test / chore
|
|
222
|
+
- Tests before implementation (RED → GREEN → REFACTOR), 80%+ coverage
|
|
223
|
+
- One concern per PR — refactors and behaviour changes are separate PRs
|
|
224
|
+
|
|
225
|
+
## Agent routing
|
|
226
|
+
|
|
227
|
+
For complex tasks, prefer the great_cto agent pipeline (via Claude Code):
|
|
228
|
+
- Architecture decisions → \`architect\` agent
|
|
229
|
+
- Feature planning → \`pm\` agent
|
|
230
|
+
- Implementation → \`senior-dev\` agent
|
|
231
|
+
- Security review → \`security-officer\` agent
|
|
232
|
+
|
|
233
|
+
See AGENTS.md for the full routing table.
|
|
234
|
+
`;
|
|
235
|
+
}
|
|
236
|
+
function getCopilotInstructions(meta) {
|
|
237
|
+
const constitution = getConstitutionBlock(meta);
|
|
238
|
+
return `${constitution}
|
|
239
|
+
|
|
240
|
+
# GitHub Copilot Instructions for ${meta.projectName}
|
|
241
|
+
# Generated by great-cto adapt · ${new Date().toISOString().slice(0, 10)}
|
|
242
|
+
|
|
243
|
+
## Project context
|
|
244
|
+
|
|
245
|
+
- **Archetype:** ${meta.archetype}
|
|
246
|
+
- **Compliance gates:** ${meta.compliance.join(", ") || "none"}
|
|
247
|
+
- **Read first:** CONTEXT.md (session state), requirements.md (scope)
|
|
248
|
+
|
|
249
|
+
## Code style
|
|
250
|
+
|
|
251
|
+
- TypeScript strict mode, ESM-only
|
|
252
|
+
- Conventional commits
|
|
253
|
+
- Test-first development — write tests before implementation
|
|
254
|
+
- No secrets in code — great-cto scan blocks ~13 patterns
|
|
255
|
+
|
|
256
|
+
## What NOT to do
|
|
257
|
+
|
|
258
|
+
- Do not implement features not in requirements.md
|
|
259
|
+
- Do not alter data models without updating design.md
|
|
260
|
+
- Do not generate placeholder files with TODO tokens
|
|
261
|
+
- Do not guess ambiguous requirements — surface them for human decision
|
|
262
|
+
`;
|
|
263
|
+
}
|
|
264
|
+
function getWindsurfrules(meta) {
|
|
265
|
+
const constitution = getConstitutionBlock(meta);
|
|
266
|
+
return `${constitution}
|
|
267
|
+
|
|
268
|
+
# .windsurfrules — Windsurf AI configuration for ${meta.projectName}
|
|
269
|
+
# Generated by great-cto adapt · ${new Date().toISOString().slice(0, 10)}
|
|
270
|
+
|
|
271
|
+
## Session startup
|
|
272
|
+
|
|
273
|
+
1. Read CONTEXT.md — resume active task from resume block
|
|
274
|
+
2. Read requirements.md — understand scope
|
|
275
|
+
3. Read design.md — understand structure
|
|
276
|
+
4. Find next incomplete [ ] task in tasks.md
|
|
277
|
+
|
|
278
|
+
## Project context
|
|
279
|
+
|
|
280
|
+
- Archetype: ${meta.archetype}
|
|
281
|
+
- Compliance: ${meta.compliance.join(", ") || "none"}
|
|
282
|
+
- Spec files: requirements.md / design.md / tasks.md
|
|
283
|
+
|
|
284
|
+
## Hard rules
|
|
285
|
+
|
|
286
|
+
- Never implement beyond requirements.md scope
|
|
287
|
+
- Never skip the CONTEXT.md update at session end
|
|
288
|
+
- Run verification step before marking any task complete
|
|
289
|
+
`;
|
|
290
|
+
}
|
|
291
|
+
function getAiderConf(meta) {
|
|
292
|
+
return `# .aider.conf.yml — Aider configuration for ${meta.projectName}
|
|
293
|
+
# Generated by great-cto adapt · ${new Date().toISOString().slice(0, 10)}
|
|
294
|
+
|
|
295
|
+
# Read these files as context at startup
|
|
296
|
+
read:
|
|
297
|
+
- CONTEXT.md
|
|
298
|
+
- requirements.md
|
|
299
|
+
- design.md
|
|
300
|
+
- tasks.md
|
|
301
|
+
- .great_cto/PROJECT.md
|
|
302
|
+
|
|
303
|
+
# Commit message format
|
|
304
|
+
commit-prompt: |
|
|
305
|
+
Write a conventional commit message (feat/fix/docs/refactor/test/chore).
|
|
306
|
+
Be specific about what changed and why.
|
|
307
|
+
Never mention private project names — use <private-project> placeholder.
|
|
308
|
+
|
|
309
|
+
# Conventions
|
|
310
|
+
auto-commits: false
|
|
311
|
+
dirty-commits: false
|
|
312
|
+
`;
|
|
313
|
+
}
|
|
136
314
|
function getCliVersion() {
|
|
137
315
|
try {
|
|
138
316
|
const here = dirname(new URL(import.meta.url).pathname);
|
|
@@ -171,8 +349,8 @@ conventions. Generated by \`great-cto adapt\`.
|
|
|
171
349
|
|
|
172
350
|
## Claude Code specifics
|
|
173
351
|
|
|
174
|
-
- The great_cto plugin orchestrates
|
|
175
|
-
through \`/start\`, \`/inbox\`, \`/save\`, etc.
|
|
352
|
+
- The great_cto plugin orchestrates specialist agents — pipeline runs
|
|
353
|
+
through \`/start\`, \`/inbox\`, \`/save\`, \`/spec\`, etc.
|
|
176
354
|
- Memory is layered: \`.great_cto/PROJECT.md\` (L1) → \`lessons.md\` (L3) →
|
|
177
355
|
\`~/.great_cto/decisions.md\` (L4 cross-project ADR log).
|
|
178
356
|
- Run \`great-cto board\` (\`http://localhost:3141\`) for the kanban + metrics
|
|
@@ -180,6 +358,7 @@ conventions. Generated by \`great-cto adapt\`.
|
|
|
180
358
|
|
|
181
359
|
## Quick links
|
|
182
360
|
|
|
361
|
+
- \`/spec\` — interview → requirements.md + design.md + tasks.md
|
|
183
362
|
- \`/start "..."\` — kick off a feature pipeline
|
|
184
363
|
- \`/inbox\` — see what needs your decision
|
|
185
364
|
- \`/agent-review\` — performance scorecard for agents
|
|
@@ -189,6 +368,38 @@ conventions. Generated by \`great-cto adapt\`.
|
|
|
189
368
|
out.push("AGENTS.md");
|
|
190
369
|
if (writeFile(join(cwd, "CLAUDE.md"), claudeBody, dryRun))
|
|
191
370
|
out.push("CLAUDE.md");
|
|
371
|
+
// Cross-AI config files based on ai_tools in PROJECT.md
|
|
372
|
+
for (const tool of meta.aiTools) {
|
|
373
|
+
switch (tool) {
|
|
374
|
+
case "cursor": {
|
|
375
|
+
const path = join(cwd, ".cursorrules");
|
|
376
|
+
if (writeFile(path, getCursorrules(meta), dryRun))
|
|
377
|
+
out.push(".cursorrules");
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
case "copilot": {
|
|
381
|
+
const path = join(cwd, ".github", "copilot-instructions.md");
|
|
382
|
+
if (writeFile(path, getCopilotInstructions(meta), dryRun))
|
|
383
|
+
out.push(".github/copilot-instructions.md");
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
386
|
+
case "windsurf": {
|
|
387
|
+
const path = join(cwd, ".windsurfrules");
|
|
388
|
+
if (writeFile(path, getWindsurfrules(meta), dryRun))
|
|
389
|
+
out.push(".windsurfrules");
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
case "aider": {
|
|
393
|
+
const path = join(cwd, ".aider.conf.yml");
|
|
394
|
+
if (writeFile(path, getAiderConf(meta), dryRun))
|
|
395
|
+
out.push(".aider.conf.yml");
|
|
396
|
+
break;
|
|
397
|
+
}
|
|
398
|
+
case "claude-code":
|
|
399
|
+
// Already handled above (CLAUDE.md + AGENTS.md)
|
|
400
|
+
break;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
192
403
|
return out;
|
|
193
404
|
}
|
|
194
405
|
// ── Main entry ─────────────────────────────────────────────────────────────
|
|
@@ -199,14 +410,19 @@ export async function runAdapt(args) {
|
|
|
199
410
|
console.error("Run `npx great-cto init` first to bootstrap the project.");
|
|
200
411
|
return 1;
|
|
201
412
|
}
|
|
202
|
-
|
|
413
|
+
const toolsList = meta.aiTools.join(", ");
|
|
414
|
+
console.log(`great-cto adapt → ${toolsList}${args.dryRun ? " (dry-run)" : ""}`);
|
|
203
415
|
console.log(` archetype: ${meta.archetype} compliance: ${meta.compliance.join(", ") || "none"}`);
|
|
416
|
+
console.log(` ai_tools: ${toolsList}`);
|
|
204
417
|
console.log("");
|
|
205
418
|
const written = adaptClaude(args.cwd, meta, args.dryRun);
|
|
206
419
|
if (!args.dryRun) {
|
|
207
420
|
console.log("");
|
|
208
|
-
console.log(`✓ generated ${written.length} file(s)
|
|
209
|
-
console.log(` Re-run after editing .great_cto/PROJECT.md to refresh.`);
|
|
421
|
+
console.log(`✓ generated ${written.length} file(s): ${written.join(", ")}`);
|
|
422
|
+
console.log(` Re-run after editing .great_cto/PROJECT.md or adding tools to ai_tools: [] to refresh.`);
|
|
423
|
+
if (!meta.aiTools.includes("cursor") && !meta.aiTools.includes("copilot") && !meta.aiTools.includes("windsurf")) {
|
|
424
|
+
console.log(` Tip: add other AI tools to ai_tools: [] in PROJECT.md to generate .cursorrules, copilot-instructions.md, etc.`);
|
|
425
|
+
}
|
|
210
426
|
}
|
|
211
427
|
return 0;
|
|
212
428
|
}
|
package/dist/bootstrap.js
CHANGED
|
@@ -22,6 +22,38 @@ export function bootstrap(dir, detection, archetype, compliance, detectionMeta)
|
|
|
22
22
|
: "unknown";
|
|
23
23
|
const teamSize = 1; // MVP default — user edits later
|
|
24
24
|
const approvalLevel = "gates-only"; // default per README
|
|
25
|
+
// Write CONTEXT.md in the project root (resume-block for all AI agents).
|
|
26
|
+
const contextMdPath = join(dir, "CONTEXT.md");
|
|
27
|
+
if (!existsSync(contextMdPath)) {
|
|
28
|
+
const contextContent = `# CONTEXT.md
|
|
29
|
+
|
|
30
|
+
> AI session state for all agents. Updated at the end of each session.
|
|
31
|
+
> All AI coding tools (Claude Code, Cursor, Copilot, Windsurf, Aider) read this
|
|
32
|
+
> before starting work.
|
|
33
|
+
|
|
34
|
+
## Resume block
|
|
35
|
+
|
|
36
|
+
**Current task:** _(none — project just initialized)_
|
|
37
|
+
**Last session:** ${new Date().toISOString().slice(0, 10)}
|
|
38
|
+
**Status:** 🟢 ready to start
|
|
39
|
+
|
|
40
|
+
## Session log
|
|
41
|
+
|
|
42
|
+
| Session | Date | Summary | Files changed |
|
|
43
|
+
|---------|------|---------|---------------|
|
|
44
|
+
| 1 | ${new Date().toISOString().slice(0, 10)} | Project initialized | CONTEXT.md, .great_cto/PROJECT.md |
|
|
45
|
+
|
|
46
|
+
## Open questions
|
|
47
|
+
|
|
48
|
+
_(none yet — add questions that need founder/team input before implementation can proceed)_
|
|
49
|
+
|
|
50
|
+
## Divergences from spec
|
|
51
|
+
|
|
52
|
+
_(none — record any deviations from design.md here with rationale)_
|
|
53
|
+
`;
|
|
54
|
+
writeFileSync(contextMdPath, contextContent, "utf-8");
|
|
55
|
+
success(`created CONTEXT.md ${dim("(session resume block for all AI tools)")}`);
|
|
56
|
+
}
|
|
25
57
|
const content = `# ${title}
|
|
26
58
|
|
|
27
59
|
> Auto-generated by \`great-cto init\` on ${new Date().toISOString().slice(0, 10)}.
|
|
@@ -55,8 +87,12 @@ phase: implementation
|
|
|
55
87
|
team-size: ${teamSize}
|
|
56
88
|
mode: solo
|
|
57
89
|
approval-level: ${approvalLevel}
|
|
90
|
+
ai_tools: [claude-code]
|
|
58
91
|
|
|
59
92
|
> \`team-size:\` is read at root level (not nested) by /rfc and other commands.
|
|
93
|
+
> \`ai_tools:\` controls which config files \`great-cto adapt\` generates.
|
|
94
|
+
> Supported values: claude-code, cursor, copilot, windsurf, aider
|
|
95
|
+
> Example: ai_tools: [claude-code, cursor, copilot]
|
|
60
96
|
|
|
61
97
|
## Compliance
|
|
62
98
|
|
package/package.json
CHANGED