@opengroundplan/core 0.1.1 → 0.2.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.
Files changed (64) hide show
  1. package/README.md +1 -1
  2. package/dist/agent-runtime.d.ts +81 -0
  3. package/dist/agent-runtime.js +108 -0
  4. package/dist/agent-runtime.js.map +1 -0
  5. package/dist/analysis.d.ts +36 -0
  6. package/dist/analysis.js +106 -0
  7. package/dist/analysis.js.map +1 -0
  8. package/dist/analyze.d.ts +26 -0
  9. package/dist/analyze.js +155 -0
  10. package/dist/analyze.js.map +1 -0
  11. package/dist/assessment.d.ts +39 -0
  12. package/dist/assessment.js +81 -0
  13. package/dist/assessment.js.map +1 -0
  14. package/dist/autoplan.d.ts +60 -0
  15. package/dist/autoplan.js +219 -0
  16. package/dist/autoplan.js.map +1 -0
  17. package/dist/blueprint.d.ts +102 -0
  18. package/dist/blueprint.js +490 -0
  19. package/dist/blueprint.js.map +1 -0
  20. package/dist/config.d.ts +11 -0
  21. package/dist/config.js +18 -0
  22. package/dist/config.js.map +1 -1
  23. package/dist/graph.d.ts +20 -0
  24. package/dist/graph.js +84 -0
  25. package/dist/graph.js.map +1 -0
  26. package/dist/improve.d.ts +20 -0
  27. package/dist/improve.js +50 -0
  28. package/dist/improve.js.map +1 -0
  29. package/dist/index.d.ts +15 -0
  30. package/dist/index.js +15 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/infer-llm.d.ts +29 -0
  33. package/dist/infer-llm.js +114 -0
  34. package/dist/infer-llm.js.map +1 -0
  35. package/dist/intent.js +24 -1
  36. package/dist/intent.js.map +1 -1
  37. package/dist/knowledge.d.ts +23 -0
  38. package/dist/knowledge.js +61 -0
  39. package/dist/knowledge.js.map +1 -0
  40. package/dist/library.d.ts +25 -0
  41. package/dist/library.js +89 -0
  42. package/dist/library.js.map +1 -0
  43. package/dist/loader.js +23 -5
  44. package/dist/loader.js.map +1 -1
  45. package/dist/pipeline.d.ts +25 -0
  46. package/dist/pipeline.js +37 -0
  47. package/dist/pipeline.js.map +1 -0
  48. package/dist/schema.d.ts +113 -113
  49. package/dist/simulate.d.ts +15 -0
  50. package/dist/simulate.js +89 -0
  51. package/dist/simulate.js.map +1 -0
  52. package/dist/variables.d.ts +7 -0
  53. package/dist/variables.js +37 -0
  54. package/dist/variables.js.map +1 -0
  55. package/dist/verification.d.ts +23 -0
  56. package/dist/verification.js +61 -0
  57. package/dist/verification.js.map +1 -0
  58. package/package.json +7 -4
  59. package/templates/bases/fastapi-service/blueprint.yaml +2 -3
  60. package/templates/layers/auth-jwt/blueprint.yaml +3 -0
  61. package/templates/layers/auth-oidc/blueprint.yaml +1 -0
  62. package/templates/layers/db-mongo/blueprint.yaml +1 -0
  63. package/templates/layers/db-postgres/blueprint.yaml +3 -0
  64. package/templates/layers/db-sqlite/blueprint.yaml +1 -0
@@ -0,0 +1,81 @@
1
+ const has = (layers, prefix) => layers.some((l) => l === prefix || l.startsWith(prefix));
2
+ /**
3
+ * Ten quality dimensions, each scored from the selection and the review. A high-severity finding
4
+ * in a dimension's area caps it low; a covered baseline scores high. Deterministic, not vibes.
5
+ */
6
+ export function qualityScores(selection, findings) {
7
+ const layers = selection.layers;
8
+ const highIn = (area) => findings.some((f) => f.area === area && f.severity === 'high');
9
+ const anyIn = (area) => findings.some((f) => f.area === area);
10
+ const band = (present, area) => (highIn(area) ? 35 : anyIn(area) ? 60 : present ? 90 : 70);
11
+ return [
12
+ { dimension: 'Architecture', score: selection.architecture ? 85 : 60, note: selection.architecture ? `${selection.architecture} overlay applied` : 'no architecture overlay' },
13
+ { dimension: 'Security', score: band(has(layers, 'auth') && layers.includes('security-supply-chain'), 'security'), note: has(layers, 'auth') ? 'auth present' : 'no auth layer' },
14
+ { dimension: 'Scalability', score: band(has(layers, 'cache') || has(layers, 'queue'), 'scaling'), note: has(layers, 'cache') ? 'caching in place' : 'no caching layer' },
15
+ { dimension: 'Maintainability', score: Math.round(((selection.intent.priorities.maintainability ?? 3) / 5) * 100), note: 'from stated priority' },
16
+ { dimension: 'Performance', score: has(layers, 'cache') ? 80 : 65, note: has(layers, 'cache') ? 'cache reduces read load' : 'no cache' },
17
+ { dimension: 'Documentation', score: 80, note: 'blueprint docs generated; keep them current' },
18
+ { dimension: 'Developer experience', score: layers.includes('lint-format') ? 85 : 70, note: layers.includes('lint-format') ? 'lint/format configured' : 'add lint-format' },
19
+ { dimension: 'Operational readiness', score: band(has(layers, 'observability') && layers.includes('health-checks'), 'observability'), note: has(layers, 'observability') ? 'observability present' : 'no observability' },
20
+ { dimension: 'Testing', score: band(layers.some((l) => l.startsWith('testing')), 'testing'), note: layers.some((l) => l.startsWith('testing')) ? 'tests selected' : 'no test strategy' },
21
+ { dimension: 'Infrastructure', score: layers.includes('ci-github-actions') ? 85 : band(false, 'ci'), note: layers.includes('ci-github-actions') ? 'CI configured' : 'no CI pipeline' },
22
+ ];
23
+ }
24
+ /** The overall score is the mean of the dimensions. */
25
+ export function overallScore(scores) {
26
+ if (scores.length === 0)
27
+ return 0;
28
+ return Math.round(scores.reduce((sum, s) => sum + s.score, 0) / scores.length);
29
+ }
30
+ /** One ADR per major decision — architecture and each choice-set layer (database, auth). */
31
+ export function generateADRs(selection) {
32
+ const adrs = [];
33
+ let n = 1;
34
+ const top = selection.ranked.find((r) => r.architecture.id === selection.architecture) ?? selection.ranked[0];
35
+ if (top) {
36
+ adrs.push({
37
+ number: n++,
38
+ title: `Adopt ${top.architecture.name}`,
39
+ status: 'accepted',
40
+ context: `A ${selection.intent.family ?? 'general'} project on ${selection.stack}, weighed against the stated priorities.`,
41
+ decision: `Use ${top.architecture.name}.`,
42
+ alternatives: selection.ranked.filter((r) => r.architecture.id !== top.architecture.id).slice(0, 3).map((r) => `${r.architecture.name} (${Math.round(r.fit * 100)}% fit)`),
43
+ consequences: [top.architecture.keyTradeoff ?? 'See the architecture review for trade-offs.', ...top.concerns],
44
+ });
45
+ }
46
+ for (const id of selection.layers.filter((l) => l.startsWith('db-') || l.startsWith('auth'))) {
47
+ adrs.push({
48
+ number: n++,
49
+ title: `Use ${id}`,
50
+ status: 'accepted',
51
+ context: `The project implied this capability; ${id} is the default for the chosen stack.`,
52
+ decision: `Adopt ${id}.`,
53
+ alternatives: id.startsWith('db-') ? ['db-postgres', 'db-mongo', 'db-sqlite'].filter((x) => x !== id) : ['auth-jwt', 'auth-oidc'].filter((x) => x !== id),
54
+ consequences: ['Migrating away later is a schema/contract change — decide deliberately now.'],
55
+ });
56
+ }
57
+ return adrs;
58
+ }
59
+ /** The independent CTO pass — it challenges the plan using the review's high/medium findings. */
60
+ export function ctoReview(selection, findings, scores) {
61
+ const blocking = findings.filter((f) => f.severity === 'high');
62
+ const medium = findings.filter((f) => f.severity === 'medium');
63
+ const overall = overallScore(scores);
64
+ const challenges = [...blocking, ...medium].map((f) => `${f.message} → ${f.recommendation}`);
65
+ if (selection.confidence < 0.4)
66
+ challenges.push('Inference confidence is low — validate the architecture with the team before building.');
67
+ for (const q of selection.questions)
68
+ challenges.push(`Unresolved: ${q.reason} (${q.field}).`);
69
+ const verdict = blocking.length ? 'needs-work' : medium.length || overall < 75 ? 'approved-with-conditions' : 'approved';
70
+ return {
71
+ verdict,
72
+ summary: verdict === 'needs-work'
73
+ ? `Not ready: ${blocking.length} blocking issue(s) would ship an unsafe or unproven system.`
74
+ : verdict === 'approved-with-conditions'
75
+ ? `Sound direction (${overall}/100), conditional on closing the items below before launch.`
76
+ : `Approved (${overall}/100) — a solid production baseline.`,
77
+ challenges,
78
+ conditions: [...blocking, ...medium].map((f) => f.recommendation),
79
+ };
80
+ }
81
+ //# sourceMappingURL=assessment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assessment.js","sourceRoot":"","sources":["../src/assessment.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * From one paragraph to a complete selection — the layer that makes Groundplan an architect
3
+ * rather than a questionnaire. It infers intent, ranks architectures, and picks the base,
4
+ * layers, and tools deterministically, asking nothing it can decide with confidence.
5
+ *
6
+ * Everything is inferred from the description plus the catalog; nothing here is a hardcoded id.
7
+ * When a genuine fork has no basis for a choice — an unstated stack, a near-tie between
8
+ * architectures — it surfaces a `question` instead of guessing, so the one prompt the user
9
+ * sees is always one that changes the outcome.
10
+ */
11
+ import { type Intent } from './intent.js';
12
+ import { type Recommendation } from './recommend.js';
13
+ import type { Catalog } from './loader.js';
14
+ import type { Blueprint, Characteristic, Stack } from './schema.js';
15
+ export interface AutoOverrides {
16
+ stack?: Stack;
17
+ architecture?: string;
18
+ base?: string;
19
+ layers?: string[];
20
+ adapters?: string[];
21
+ teamSize?: number;
22
+ priorities?: Partial<Record<Characteristic, number>>;
23
+ }
24
+ /** A fork the planner could not decide with confidence. Blocking: worth one interactive prompt. */
25
+ export interface AutoQuestion {
26
+ /** 'stack' | 'priorities' | 'architecture' | 'base' | a choiceSet name (e.g. 'database'). */
27
+ field: string;
28
+ reason: string;
29
+ options: {
30
+ id: string;
31
+ label: string;
32
+ hint?: string;
33
+ }[];
34
+ /** The default applied when the question is not asked (--yes / non-interactive). */
35
+ chosen?: string;
36
+ }
37
+ export interface AutoSelection {
38
+ intent: Intent;
39
+ stack: Stack;
40
+ teamSize: number;
41
+ architecture?: string;
42
+ base: string;
43
+ layers: string[];
44
+ adapters: string[];
45
+ ranked: Recommendation[];
46
+ /** 0..1 — how much of this selection was decided rather than defaulted. */
47
+ confidence: number;
48
+ /** Human-readable "chose X because Y" notes for everything inferred. */
49
+ assumptions: string[];
50
+ /** Forks worth asking about; empty means the brief is enough to generate zero-question. */
51
+ questions: AutoQuestion[];
52
+ }
53
+ /** Bases for a stack that also support the architecture — the CLI reuses this when it must ask. */
54
+ export declare function basesFor(catalog: Catalog, stack: Stack, architecture: string | undefined): Blueprint[];
55
+ /** Layers that apply to a stack (stack-agnostic ones included). */
56
+ export declare function layersFor(catalog: Catalog, stack: Stack): Blueprint[];
57
+ export declare function autoSelect(description: string, catalog: Catalog, opts: {
58
+ defaultAdapters: string[];
59
+ overrides?: AutoOverrides;
60
+ }): AutoSelection;
@@ -0,0 +1,219 @@
1
+ /**
2
+ * From one paragraph to a complete selection — the layer that makes Groundplan an architect
3
+ * rather than a questionnaire. It infers intent, ranks architectures, and picks the base,
4
+ * layers, and tools deterministically, asking nothing it can decide with confidence.
5
+ *
6
+ * Everything is inferred from the description plus the catalog; nothing here is a hardcoded id.
7
+ * When a genuine fork has no basis for a choice — an unstated stack, a near-tie between
8
+ * architectures — it surfaces a `question` instead of guessing, so the one prompt the user
9
+ * sees is always one that changes the outcome.
10
+ */
11
+ import { inferIntent } from './intent.js';
12
+ import { recommend } from './recommend.js';
13
+ import { resolve, ResolveError } from './resolve.js';
14
+ /** Ranking heuristics — design constants for the inference, not deployment configuration. */
15
+ const DEFAULT_TEAM_SIZE = 4;
16
+ /** A runner-up within this fraction of the top score is a genuine tie worth asking about. */
17
+ const NEAR_TIE_RATIO = 0.12;
18
+ /** Used only when the description states no priority at all, so the ranker has something to weigh. */
19
+ const NEUTRAL_PRIORITIES = {
20
+ simplicity: 4,
21
+ maintainability: 3,
22
+ testability: 2,
23
+ };
24
+ const FAMILY_STACK = {
25
+ ai: 'python',
26
+ data: 'python',
27
+ frontend: 'typescript',
28
+ };
29
+ const FALLBACK_STACK = 'typescript';
30
+ /** Bases for a stack that also support the architecture — the CLI reuses this when it must ask. */
31
+ export function basesFor(catalog, stack, architecture) {
32
+ return [...catalog.blueprints.values()].filter((b) => b.kind === 'base' &&
33
+ b.stack === stack &&
34
+ (!architecture ||
35
+ b.supportsArchitectures.length === 0 ||
36
+ b.supportsArchitectures.includes(architecture)));
37
+ }
38
+ /** Layers that apply to a stack (stack-agnostic ones included). */
39
+ export function layersFor(catalog, stack) {
40
+ return [...catalog.blueprints.values()].filter((b) => b.kind === 'layer' && (!b.stack || b.stack === stack));
41
+ }
42
+ export function autoSelect(description, catalog, opts) {
43
+ const overrides = opts.overrides ?? {};
44
+ const text = description.toLowerCase();
45
+ const intent = inferIntent(description);
46
+ const assumptions = [];
47
+ const questions = [];
48
+ // Stack — stated wins, then the family convention (a real inference), then a blind fallback we ask about.
49
+ let stack = overrides.stack ?? intent.stack;
50
+ if (stack) {
51
+ assumptions.push(`Stack ${stack}${overrides.stack ? ' (you set it)' : ' inferred from the description'}`);
52
+ }
53
+ else if (intent.family && FAMILY_STACK[intent.family]) {
54
+ stack = FAMILY_STACK[intent.family];
55
+ assumptions.push(`Stack ${stack} — the default for an ${intent.family} project`);
56
+ }
57
+ else {
58
+ stack = FALLBACK_STACK;
59
+ questions.push({ field: 'stack', reason: 'no language or framework was named', options: STACK_OPTIONS, chosen: stack });
60
+ assumptions.push(`Assumed ${stack} — the description named no stack`);
61
+ }
62
+ const priorities = overrides.priorities ?? (hasWeight(intent.priorities) ? intent.priorities : NEUTRAL_PRIORITIES);
63
+ if (!overrides.priorities && !hasWeight(intent.priorities)) {
64
+ questions.push({
65
+ field: 'priorities',
66
+ reason: 'the description implied no clear priority',
67
+ options: [],
68
+ });
69
+ }
70
+ const teamSize = overrides.teamSize ?? intent.teamSize ?? DEFAULT_TEAM_SIZE;
71
+ // Architecture — rank, retry without the family filter if it excluded everything.
72
+ let ranked = rank(catalog.architectures.values(), { priorities, teamSize, stack, family: intent.family });
73
+ if (ranked.length === 0)
74
+ ranked = rank(catalog.architectures.values(), { priorities, teamSize, stack });
75
+ // Prefer the highest-ranked architecture the chosen stack can actually build — a top pick with
76
+ // no base on this stack is not a recommendation, it is a dead end.
77
+ let architecture = overrides.architecture;
78
+ if (!architecture && ranked.length > 0) {
79
+ const viable = ranked.find((r) => basesFor(catalog, stack, r.architecture.id).length > 0) ?? ranked[0];
80
+ architecture = viable.architecture.id;
81
+ assumptions.push(`Architecture ${viable.architecture.name} — ${Math.round(viable.fit * 100)}% fit`);
82
+ const alt = ranked.find((r) => r.architecture.id !== architecture && basesFor(catalog, stack, r.architecture.id).length > 0);
83
+ if (alt && viable.score > 0 && (viable.score - alt.score) / viable.score < NEAR_TIE_RATIO) {
84
+ questions.push({
85
+ field: 'architecture',
86
+ reason: `${alt.architecture.name} scores nearly as well`,
87
+ options: ranked
88
+ .filter((r) => basesFor(catalog, stack, r.architecture.id).length > 0)
89
+ .slice(0, 4)
90
+ .map((r) => ({ id: r.architecture.id, label: r.architecture.name, hint: `${Math.round(r.fit * 100)}% fit` })),
91
+ chosen: architecture,
92
+ });
93
+ }
94
+ }
95
+ // Base — narrowed by stack and architecture support. If the overlay has no base on this stack,
96
+ // drop the overlay rather than fail: a repo with no architecture layout still builds.
97
+ let bases = basesFor(catalog, stack, architecture);
98
+ if (bases.length === 0 && architecture && !overrides.base) {
99
+ assumptions.push(`No ${stack} base builds "${architecture}" — generating without an architecture overlay`);
100
+ architecture = undefined;
101
+ bases = basesFor(catalog, stack, undefined);
102
+ }
103
+ // A base that names the architecture is specialized for it; a generic base (empty list) is a
104
+ // fallback. Prefer the specialist, and only ask when more than one is equally specialized.
105
+ const explicit = architecture ? bases.filter((b) => b.supportsArchitectures.includes(architecture)) : [];
106
+ const preferred = explicit.length > 0 ? explicit : bases;
107
+ const base = overrides.base ?? preferred[0]?.id;
108
+ if (!base)
109
+ throw baseError(catalog, stack, architecture);
110
+ if (!overrides.base && preferred.length > 1) {
111
+ questions.push({
112
+ field: 'base',
113
+ reason: `${preferred.length} bases fit ${stack} and ${architecture ?? 'no overlay'}`,
114
+ options: preferred.map((b) => ({ id: b.id, label: b.name, hint: b.description })),
115
+ chosen: base,
116
+ });
117
+ }
118
+ assumptions.push(`Base ${catalog.blueprints.get(base)?.name ?? base}`);
119
+ // Layers — map each implied capability to a concrete layer, defaulting inside a choice set.
120
+ const layers = overrides.layers ?? impliedLayers(intent.impliedLayers, catalog, stack, text, assumptions);
121
+ const adapters = (overrides.adapters ?? opts.defaultAdapters).filter((id) => catalog.adapters.has(id));
122
+ assumptions.push(`AI tools: ${adapters.join(', ') || 'none'}`);
123
+ // Prove the combination holds before returning it as a plan.
124
+ try {
125
+ const selected = resolve({ base, architecture, layers }, catalog.blueprints);
126
+ for (const w of selected.warnings)
127
+ assumptions.push(w);
128
+ }
129
+ catch (error) {
130
+ if (error instanceof ResolveError)
131
+ assumptions.push(`Adjust needed: ${error.message}`);
132
+ else
133
+ throw error;
134
+ }
135
+ return {
136
+ intent,
137
+ stack,
138
+ teamSize,
139
+ architecture,
140
+ base,
141
+ layers,
142
+ adapters,
143
+ ranked,
144
+ confidence: score(intent, ranked, questions),
145
+ assumptions,
146
+ questions,
147
+ };
148
+ }
149
+ const STACK_OPTIONS = [
150
+ { id: 'typescript', label: 'TypeScript / Next.js / React' },
151
+ { id: 'python', label: 'Python / FastAPI / AI-ML' },
152
+ { id: 'dotnet', label: '.NET / C#' },
153
+ { id: 'node', label: 'Node backend / NestJS' },
154
+ { id: 'go', label: 'Go' },
155
+ { id: 'polyglot', label: 'Polyglot / monorepo' },
156
+ ];
157
+ function rank(candidates, req) {
158
+ return recommend(candidates, req);
159
+ }
160
+ /**
161
+ * Resolve an inferred capability ("db", "auth", "cache") to a concrete layer. Candidates are
162
+ * matched on `provides`, `tags`, and id shape so an inconsistent catalog token still resolves;
163
+ * a mutually-exclusive group collapses to the choiceDefault, or to whichever member the
164
+ * description actually named.
165
+ */
166
+ function impliedLayers(implied, catalog, stack, text, assumptions) {
167
+ const layers = layersFor(catalog, stack);
168
+ const chosen = new Set();
169
+ for (const capability of implied) {
170
+ // A layer that IS the capability (by id or `provides`) beats one that merely touches it in
171
+ // `tags` — docker-compose tags "queue" because it can run one, but queue-broker is the layer.
172
+ const strong = layers.filter((l) => l.id === capability || l.id.startsWith(`${capability}-`) || l.provides.includes(capability));
173
+ const candidates = strong.length > 0 ? strong : layers.filter((l) => l.tags.includes(capability));
174
+ if (candidates.length === 0) {
175
+ assumptions.push(`No layer provides "${capability}" — skipped`);
176
+ continue;
177
+ }
178
+ const inSet = candidates.filter((c) => c.choiceSet);
179
+ if (inSet.length === 0) {
180
+ // A single concrete capability (cache, observability, evals…).
181
+ chosen.add(candidates[0].id);
182
+ continue;
183
+ }
184
+ for (const set of new Set(inSet.map((c) => c.choiceSet))) {
185
+ const members = inSet.filter((c) => c.choiceSet === set);
186
+ const named = members.find((m) => m.tags.some((t) => text.includes(t)));
187
+ const pick = named ?? members.find((m) => m.choiceDefault) ?? members[0];
188
+ chosen.add(pick.id);
189
+ if (named)
190
+ assumptions.push(`${set}: ${pick.name} — you named it`);
191
+ else
192
+ assumptions.push(`${set}: ${pick.name} (default)`);
193
+ }
194
+ }
195
+ return [...chosen];
196
+ }
197
+ function score(intent, ranked, questions) {
198
+ const archConfidence = ranked.length === 0 ? 0 : ranked.length === 1 ? 1 : gap(ranked[0].score, ranked[1].score);
199
+ const blocking = questions.filter((q) => q.field === 'stack' || q.field === 'priorities').length;
200
+ const raw = intent.confidence * archConfidence * Math.pow(0.6, blocking);
201
+ return Math.round(raw * 100) / 100;
202
+ }
203
+ function gap(top, next) {
204
+ if (top <= 0)
205
+ return 0;
206
+ return Math.min(1, 0.5 + (top - next) / top);
207
+ }
208
+ function hasWeight(priorities) {
209
+ return Object.values(priorities).some((w) => (w ?? 0) > 0);
210
+ }
211
+ /** The interactive base picker and the auto picker should fail with the same explanation. */
212
+ function baseError(catalog, stack, architecture) {
213
+ const forStack = [...catalog.blueprints.values()].filter((b) => b.kind === 'base' && b.stack === stack);
214
+ return new Error(forStack.length === 0
215
+ ? `No base template for stack "${stack}" yet.`
216
+ : `No ${stack} base supports the "${architecture}" architecture. ` +
217
+ `Bases for this stack: ${forStack.map((b) => b.id).join(', ')}.`);
218
+ }
219
+ //# sourceMappingURL=autoplan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autoplan.js","sourceRoot":"","sources":["../src/autoplan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * From a selection to an engineering blueprint — the documents a team would write by hand before
3
+ * a line of code: understanding, requirements, architecture decisions, a roadmap, and tasks.
4
+ *
5
+ * Deterministic and catalog-driven. Everything here is derived from the `AutoSelection` (which
6
+ * already carries the ranked architecture, its reasons, the inferred layers, matched intent
7
+ * signals, confidence, and gaps) plus the catalog's own names and descriptions — no prose is
8
+ * invented that can't be traced to a signal or a blueprint. When a model produced the selection
9
+ * its reasoning rides along in `assumptions`; the blueprint reads the same either way.
10
+ */
11
+ import { type AgentDescriptor, type RoleAssignment } from './agent-runtime.js';
12
+ import { type BuildVsBuy, type CostBand, type Finding } from './analysis.js';
13
+ import { type ADR, type CtoReview, type Score } from './assessment.js';
14
+ import { type Simulation } from './simulate.js';
15
+ import { type IndustryBlueprint } from './library.js';
16
+ import type { AutoSelection } from './autoplan.js';
17
+ import type { Catalog } from './loader.js';
18
+ export interface Decision {
19
+ topic: string;
20
+ choice: string;
21
+ reason: string;
22
+ /** 0..1 — how firmly the selection settled this. */
23
+ confidence: number;
24
+ alternatives: string[];
25
+ }
26
+ export interface Requirement {
27
+ id: string;
28
+ kind: 'functional' | 'non-functional' | 'inferred';
29
+ text: string;
30
+ because?: string;
31
+ }
32
+ export interface Task {
33
+ id: string;
34
+ title: string;
35
+ phase: string;
36
+ dependsOn: string[];
37
+ fromBlueprint?: string;
38
+ }
39
+ /**
40
+ * The structured essence of a project — its DNA — derived once and carried through every
41
+ * document, so requirements, architecture, and roadmap all reason from the same facts.
42
+ */
43
+ export interface ProjectDNA {
44
+ industry: string;
45
+ productType: string;
46
+ businessModel: string;
47
+ expectedScale: 'small' | 'growing' | 'large';
48
+ security: 'standard' | 'elevated';
49
+ compliance: 'none' | 'regulated';
50
+ riskLevel: 'low' | 'medium' | 'high';
51
+ }
52
+ export interface ProjectBlueprint {
53
+ idea: string;
54
+ domain: string;
55
+ dna: ProjectDNA;
56
+ /** The matched industry pattern from the library, when the idea maps to one. */
57
+ industry: IndustryBlueprint | null;
58
+ confidence: number;
59
+ understanding: string[];
60
+ assumptions: string[];
61
+ requirements: Requirement[];
62
+ decisions: Decision[];
63
+ architecture: {
64
+ id?: string;
65
+ name: string;
66
+ oneLine: string;
67
+ reasons: string[];
68
+ concerns: string[];
69
+ alternatives: {
70
+ name: string;
71
+ fit: number;
72
+ }[];
73
+ };
74
+ layers: {
75
+ id: string;
76
+ name: string;
77
+ description: string;
78
+ }[];
79
+ roadmap: {
80
+ phase: string;
81
+ goal: string;
82
+ items: string[];
83
+ }[];
84
+ risks: string[];
85
+ gaps: string[];
86
+ tasks: Task[];
87
+ /** Production-readiness findings — high severity blocks sign-off. */
88
+ review: Finding[];
89
+ buildVsBuy: BuildVsBuy[];
90
+ cost: CostBand[];
91
+ quality: Score[];
92
+ adrs: ADR[];
93
+ ctoReview: CtoReview;
94
+ simulation: Simulation;
95
+ /** Role → agent → tasks, when an agent roster is provided. */
96
+ orchestration: RoleAssignment[];
97
+ /** Task ids grouped into waves that can run in parallel (dependencies satisfied by earlier waves). */
98
+ executionWaves: string[][];
99
+ }
100
+ export declare function buildBlueprint(idea: string, selection: AutoSelection, catalog: Catalog, gaps?: string[], agents?: AgentDescriptor[]): ProjectBlueprint;
101
+ /** The blueprint as a set of files (filename → content), ready to write into a repo. */
102
+ export declare function renderBlueprint(bp: ProjectBlueprint): Record<string, string>;