great-cto 2.20.0 → 2.21.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/bootstrap.js CHANGED
@@ -4,12 +4,13 @@ import { existsSync, mkdirSync, writeFileSync, readFileSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import { dim, success, warn } from "./ui.js";
6
6
  import { suggestJurisdictions } from "./jurisdictions.js";
7
+ import { compileFlow, renderFlowMd } from "./flow.js";
7
8
  export function bootstrap(dir, detection, archetype, compliance, detectionMeta) {
8
9
  const greatCtoDir = join(dir, ".great_cto");
9
10
  const projectMd = join(greatCtoDir, "PROJECT.md");
10
11
  if (existsSync(projectMd)) {
11
12
  warn(`.great_cto/PROJECT.md already exists — not overwriting.`);
12
- return { projectMdPath: projectMd, created: false, skippedReason: "already exists" };
13
+ return { projectMdPath: projectMd, created: false, skippedReason: "already exists", flow: null };
13
14
  }
14
15
  mkdirSync(greatCtoDir, { recursive: true });
15
16
  const title = inferProjectTitle(dir);
@@ -120,7 +121,14 @@ when you actually start work:
120
121
  `;
121
122
  writeFileSync(projectMd, content, "utf-8");
122
123
  success(`created .great_cto/PROJECT.md ${dim(`(archetype: ${archetype})`)}`);
123
- return { projectMdPath: projectMd, created: true, skippedReason: null };
124
+ // Write FLOW.md compiled delivery flow for agents and user
125
+ const confidence = detectionMeta?.confidence ?? "medium";
126
+ const size = (detection.projectSize ?? "medium");
127
+ const flow = compileFlow(archetype, size, detection, compliance, confidence);
128
+ const flowMdPath = join(greatCtoDir, "FLOW.md");
129
+ const generatedAt = new Date().toISOString().slice(0, 10);
130
+ writeFileSync(flowMdPath, renderFlowMd(flow, generatedAt), "utf-8");
131
+ return { projectMdPath: projectMd, created: true, skippedReason: null, flow };
124
132
  }
125
133
  /**
126
134
  * Slugify a project title into a tenant-id safe for HTTP headers and audit
package/dist/flow.js ADDED
@@ -0,0 +1,188 @@
1
+ // flow.ts — compiles all detection outputs into a single user-facing FlowResult.
2
+ // Pure function: no I/O, no side effects.
3
+ // Called by bootstrap.ts (writes FLOW.md) and main.ts (prints summary).
4
+ import { reviewersFor, gatesFor } from "./archetypes.js";
5
+ import { suggestPackReviewers, suggestPackGates, suggestPacks } from "./packs.js";
6
+ import { suggestJurisdictions, suggestJurisdictionReviewers, suggestJurisdictionGates } from "./jurisdictions.js";
7
+ // ── Human-readable titles ─────────────────────────────────────────────────
8
+ const ARCHETYPE_TITLE = {
9
+ "fintech": "Fintech",
10
+ "healthcare": "Healthcare",
11
+ "enterprise-saas": "Enterprise SaaS",
12
+ "agent-product": "AI agent",
13
+ "ai-system": "AI system",
14
+ "mlops": "MLOps pipeline",
15
+ "commerce": "E-commerce",
16
+ "marketplace": "Marketplace",
17
+ "mobile-app": "Mobile app",
18
+ "web-service": "Web service",
19
+ "library": "Library / SDK",
20
+ "cli-tool": "CLI tool",
21
+ "data-platform": "Data platform",
22
+ "streaming": "Streaming system",
23
+ "infra": "Infrastructure",
24
+ "devtools": "Developer tool",
25
+ "browser-extension": "Browser extension",
26
+ "game": "Game",
27
+ "web3": "Web3 / DeFi",
28
+ "iot-embedded": "IoT / embedded",
29
+ "cms": "CMS",
30
+ "edtech": "EdTech",
31
+ "gov-public": "Government",
32
+ "insurance": "Insurance",
33
+ "regulated": "Regulated system",
34
+ "greenfield": "New project",
35
+ };
36
+ // Gate id (StandardGate) → user label
37
+ const GATE_LABEL = {
38
+ "plan": "gate:plan",
39
+ "arch": "gate:arch",
40
+ "code": "gate:code",
41
+ "qa": "gate:qa",
42
+ "security": "gate:security",
43
+ "compliance": "gate:compliance",
44
+ "ship": "gate:ship",
45
+ "cost": "gate:cost-forecast",
46
+ "oracle-review": "gate:oracle-review",
47
+ "edtech-review": "gate:edtech-review",
48
+ "gov-review": "gate:gov-review",
49
+ "insurance-review": "gate:insurance-review",
50
+ };
51
+ // Cost (low, high) per feature cycle by archetype tier
52
+ const ARCHETYPE_COST = {
53
+ "fintech": [8, 18],
54
+ "healthcare": [8, 18],
55
+ "agent-product": [8, 18],
56
+ "mlops": [8, 18],
57
+ "marketplace": [8, 18],
58
+ "enterprise-saas": [8, 18],
59
+ "regulated": [8, 18],
60
+ "edtech": [8, 18],
61
+ "gov-public": [8, 18],
62
+ "insurance": [8, 18],
63
+ "web3": [8, 18],
64
+ "commerce": [3, 8],
65
+ "mobile-app": [3, 8],
66
+ "web-service": [3, 8],
67
+ "data-platform": [3, 8],
68
+ "streaming": [3, 8],
69
+ "devtools": [3, 8],
70
+ "browser-extension": [3, 8],
71
+ "game": [3, 8],
72
+ "cms": [3, 8],
73
+ "ai-system": [3, 8],
74
+ "iot-embedded": [3, 8],
75
+ "infra": [3, 8],
76
+ "library": [0.5, 3],
77
+ "cli-tool": [0.5, 3],
78
+ "greenfield": [0.5, 3],
79
+ };
80
+ // ── Main export ───────────────────────────────────────────────────────────
81
+ /**
82
+ * Compile all detection outputs into a single FlowResult.
83
+ *
84
+ * Pure function — no file I/O. Called by bootstrap.ts (FLOW.md) and
85
+ * main.ts (summary output).
86
+ */
87
+ export function compileFlow(archetype, size, detection, compliance, confidence) {
88
+ // ── Agents ──────────────────────────────────────────────────────────────
89
+ const agentSet = new Set(reviewersFor(archetype));
90
+ for (const r of suggestPackReviewers(detection))
91
+ agentSet.add(r);
92
+ for (const r of suggestJurisdictionReviewers(detection))
93
+ agentSet.add(r);
94
+ // Always include base orchestration agents
95
+ agentSet.add("architect");
96
+ agentSet.add("senior-dev");
97
+ agentSet.add("qa-engineer");
98
+ // ── Gates ────────────────────────────────────────────────────────────────
99
+ const gateSet = new Set(gatesFor(archetype, size).map((g) => GATE_LABEL[g] ?? `gate:${g}`));
100
+ for (const g of suggestPackGates(detection))
101
+ gateSet.add(g);
102
+ for (const g of suggestJurisdictionGates(detection))
103
+ gateSet.add(g);
104
+ // ── Packs + jurisdictions for routing block ──────────────────────────────
105
+ const packs = suggestPacks(detection);
106
+ const jurisdictions = suggestJurisdictions(detection);
107
+ // ── Title ────────────────────────────────────────────────────────────────
108
+ const productLabel = ARCHETYPE_TITLE[archetype] ?? archetype;
109
+ const jCodes = jurisdictions
110
+ .slice(0, 3)
111
+ .map((j) => j.jurisdiction.toUpperCase())
112
+ .join(" + ");
113
+ const title = jCodes ? `${productLabel} · ${jCodes}` : productLabel;
114
+ // ── ID ───────────────────────────────────────────────────────────────────
115
+ const id = [archetype, ...jurisdictions.map((j) => j.jurisdiction)]
116
+ .join("-")
117
+ .toLowerCase();
118
+ // ── Cost range ────────────────────────────────────────────────────────────
119
+ const costEntry = ARCHETYPE_COST[archetype] ?? [3, 8];
120
+ const [low, high] = costEntry;
121
+ return {
122
+ id,
123
+ title,
124
+ agents: Array.from(agentSet).sort(),
125
+ gates: Array.from(gateSet).sort(),
126
+ compliance: [...new Set(compliance)].sort(),
127
+ costRange: { low, high },
128
+ routing: {
129
+ archetype,
130
+ packs: packs.map((p) => p.pack),
131
+ jurisdictions: jurisdictions.map((j) => j.jurisdiction),
132
+ confidence,
133
+ },
134
+ };
135
+ }
136
+ /**
137
+ * Render FLOW.md content from a FlowResult.
138
+ * Exported separately so bootstrap.ts can call it without depending on main.ts.
139
+ */
140
+ export function renderFlowMd(flow, generatedAt) {
141
+ const agentLines = flow.agents.map((a) => `- ${a}`).join("\n");
142
+ const gateLines = flow.gates.map((g) => `- ${g}`).join("\n");
143
+ const complianceLines = flow.compliance.length > 0
144
+ ? flow.compliance.map((c) => `- ${c}`).join("\n")
145
+ : "- none";
146
+ const packLines = flow.routing.packs.length > 0
147
+ ? flow.routing.packs.join(", ")
148
+ : "none";
149
+ const jLines = flow.routing.jurisdictions.length > 0
150
+ ? flow.routing.jurisdictions.join(", ")
151
+ : "none";
152
+ return `# Delivery Flow
153
+
154
+ > Auto-generated by \`great-cto init\` on ${generatedAt}.
155
+ > This file tells agents how to orchestrate your SDLC.
156
+ > Regenerates on \`npx great-cto init --force\`. Edit \`_routing:\` to tune.
157
+
158
+ ## Detected
159
+
160
+ ${flow.title}
161
+
162
+ ## Agents
163
+
164
+ ${agentLines}
165
+
166
+ ## Human gates
167
+
168
+ ${gateLines}
169
+
170
+ ## Compliance
171
+
172
+ ${complianceLines}
173
+
174
+ ## Cost estimate
175
+
176
+ $${flow.costRange.low}–$${flow.costRange.high} per feature cycle
177
+
178
+ ---
179
+
180
+ <!-- Internal routing — view with: great-cto flow explain -->
181
+ _routing:
182
+ id: ${flow.id}
183
+ archetype: ${flow.routing.archetype}
184
+ packs: [${packLines}]
185
+ jurisdictions: [${jLines}]
186
+ confidence: ${flow.routing.confidence}
187
+ `;
188
+ }
package/dist/main.js CHANGED
@@ -18,6 +18,7 @@ import { install, findInstalledVersions } from "./installer.js";
18
18
  import { enableGreatCto } from "./settings.js";
19
19
  import { installAllCompanions } from "./companion.js";
20
20
  import { bootstrap } from "./bootstrap.js";
21
+ import { compileFlow } from "./flow.js";
21
22
  import { shouldUseLlmFallback, suggestArchetypeFromLlm } from "./llm-fallback.js";
22
23
  import { readFileSync, copyFileSync, chmodSync, existsSync as fsExistsSync } from "node:fs";
23
24
  import { dirname, join } from "node:path";
@@ -576,23 +577,26 @@ async function runInit(args) {
576
577
  }
577
578
  }
578
579
  const compliance = suggestCompliance(detection, archetype);
579
- log(` ${dim("archetype:")} ${cyan(archetype)} ${dim(`(confidence: ${confidence})`)}`);
580
- log(` ${dim("rationale:")} ${rationale}`);
581
- if (alternatives.length > 0) {
582
- log(` ${dim("alternatives:")} ${alternatives.join(", ")}`);
580
+ // Compile flow — used for user-facing summary AND written to FLOW.md by bootstrap()
581
+ const compiledFlow = compileFlow(archetype, (detection.projectSize ?? "medium"), detection, compliance, confidence);
582
+ // ── User-facing "Compiled flow" summary ──────────────────────────────────
583
+ log("");
584
+ log(`${bold("Compiled flow:")} ${cyan(compiledFlow.title)}`);
585
+ log(` ${dim("Agents:")} ${compiledFlow.agents.join(" · ")}`);
586
+ log(` ${dim("Gates:")} ${compiledFlow.gates.join(" · ")}`);
587
+ if (compiledFlow.compliance.length > 0) {
588
+ log(` ${dim("Compliance:")} ${compiledFlow.compliance.join(", ")}`);
583
589
  }
584
- log(` ${dim("suggested compliance:")} ${compliance.length > 0 ? compliance.join(", ") : "none"}`);
585
- // v1.0.144+: ask user to confirm archetype if confidence is low
586
- // OR if alternatives are present and not user-specified
590
+ log(` ${dim("Cost:")} ~$${compiledFlow.costRange.low}–$${compiledFlow.costRange.high} per feature cycle`);
591
+ log("");
592
+ // Low-confidence notice show only when actionable
587
593
  if (!args.yes && !args.archetype && (confidence === "low" || (confidence === "medium" && alternatives.length >= 2))) {
588
- log("");
589
- log(`${bold("⚠ Archetype detection confidence:")} ${cyan(confidence)}`);
590
- log(` Top candidate: ${cyan(archetype)} — ${dim(rationale)}`);
594
+ log(` ${yellow("")} ${dim(`Detected as ${cyan(archetype)} (${confidence} confidence).`)}`);
591
595
  if (alternatives.length > 0) {
592
- log(` Alternatives: ${alternatives.map(a => cyan(a)).join(", ")}`);
596
+ log(` ${dim("Alternatives: " + alternatives.join(", "))}`);
593
597
  }
594
- log(` ${dim("If wrong, override with: --archetype " + (alternatives[0] ?? "<name>"))}`);
595
- log(` ${dim("Or edit .great_cto/PROJECT.md after install — agents read 'archetype:' field.")}`);
598
+ log(` ${dim("Override: npx great-cto init --archetype <name>")}`);
599
+ log("");
596
600
  }
597
601
  // Confirmation
598
602
  if (!args.yes) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "great-cto",
3
- "version": "2.20.0",
3
+ "version": "2.21.0",
4
4
  "description": "One command install for the great_cto Claude Code plugin. Auto-detects your stack, picks the right archetype, bootstraps PROJECT.md.",
5
5
  "keywords": [
6
6
  "claude-code",