@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
package/README.md CHANGED
@@ -21,6 +21,6 @@ Two things worth knowing before writing a template:
21
21
  - A file that must land as `.gitignore` or `.npmrc` is stored undotted, because npm strips
22
22
  those names from any package tarball. The engine restores the dot.
23
23
 
24
- Full documentation is in the [repository](https://github.com/groundplan/groundplan#readme).
24
+ Full documentation is in the [repository](https://github.com/groundplan/opengroundplan#readme).
25
25
 
26
26
  MIT licensed.
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Provider-neutral agent runtime. Every AI coding tool that declares a verified headless
3
+ * `invoke` block ([adapters]) is a dispatchable agent behind one interface — Claude Code,
4
+ * Codex, Gemini, Aider, Cursor and the rest are described by data, not special-cased in code.
5
+ *
6
+ * This layer does not spawn anything. It answers two questions deterministically: which agents
7
+ * are available, and what exact command dispatches a prompt to one. Execution is the caller's
8
+ * (the CLI, a hook, an orchestrator) — keeping the boundary that templates and plans are data.
9
+ */
10
+ import type { Adapter } from './schema.js';
11
+ import type { Catalog } from './loader.js';
12
+ export interface AgentDescriptor {
13
+ id: string;
14
+ name: string;
15
+ /** How to run it headlessly; absent means it cannot be dispatched to. */
16
+ invoke?: Adapter['invoke'];
17
+ readsAgentsMd: boolean;
18
+ deprecated: boolean;
19
+ }
20
+ /** A concrete command line, ready for the caller to spawn. `promptVia` says where the prompt goes. */
21
+ export interface Dispatch {
22
+ binary: string;
23
+ args: string[];
24
+ promptVia: 'arg' | 'stdin';
25
+ }
26
+ /** Agents with a verified headless mode, most-preferred first (non-deprecated before deprecated). */
27
+ export declare function availableAgents(catalog: Catalog): AgentDescriptor[];
28
+ /**
29
+ * Substitute a task into an agent's invoke template. `{prompt}` and `{model}` are the only
30
+ * tokens replaced; everything else is literal, exactly as the delegation dispatcher does it.
31
+ */
32
+ export declare function dispatch(agent: AgentDescriptor, task: {
33
+ prompt: string;
34
+ model?: string;
35
+ autoApprove?: boolean;
36
+ }): Dispatch | null;
37
+ export interface AgentRole {
38
+ role: string;
39
+ responsibility: string;
40
+ /** Lifecycle phases and task keywords this role owns, used to route tasks. */
41
+ phases: string[];
42
+ keywords: string[];
43
+ }
44
+ /** The engineering roles an orchestrator assigns work to. A taxonomy, not configuration. */
45
+ export declare const AGENT_ROLES: AgentRole[];
46
+ /**
47
+ * Route a task to the role that owns it. Every lifecycle phase except Implementation maps to a
48
+ * single role, so those go by phase. Implementation tasks all share a phase, so they route by
49
+ * keyword — matched on word boundaries, or "test suite" lands on Frontend because "suite" ends
50
+ * in "ui".
51
+ */
52
+ export declare function roleFor(task: {
53
+ title: string;
54
+ phase: string;
55
+ }): AgentRole;
56
+ export interface RoleAssignment {
57
+ role: string;
58
+ responsibility: string;
59
+ /** The available agent this role dispatches to, or null when none is installed. */
60
+ agent: string | null;
61
+ tasks: string[];
62
+ }
63
+ /**
64
+ * Assign every task to a role, then bind each role to an available agent. Roles are distributed
65
+ * round-robin across agents so parallel work fans out; with one agent everything routes to it.
66
+ */
67
+ export declare function orchestrate(tasks: {
68
+ id: string;
69
+ title: string;
70
+ phase: string;
71
+ }[], agents: AgentDescriptor[]): RoleAssignment[];
72
+ /**
73
+ * Group tasks into waves that can run in parallel (Phase 7). Each wave holds every task whose
74
+ * dependencies are all satisfied by earlier waves — a topological levelling. A dependency cycle,
75
+ * or a reference to an unknown task, leaves the remaining tasks in a final "blocked" wave rather
76
+ * than looping forever.
77
+ */
78
+ export declare function executionWaves(tasks: {
79
+ id: string;
80
+ dependsOn: string[];
81
+ }[]): string[][];
@@ -0,0 +1,108 @@
1
+ /** Agents with a verified headless mode, most-preferred first (non-deprecated before deprecated). */
2
+ export function availableAgents(catalog) {
3
+ return [...catalog.adapters.values()]
4
+ .map((a) => ({
5
+ id: a.id,
6
+ name: a.name,
7
+ invoke: a.invoke,
8
+ readsAgentsMd: a.readsAgentsMd,
9
+ deprecated: Boolean(a.invoke?.deprecated),
10
+ }))
11
+ .filter((a) => a.invoke !== undefined)
12
+ .sort((a, b) => Number(a.deprecated) - Number(b.deprecated) || a.id.localeCompare(b.id));
13
+ }
14
+ /**
15
+ * Substitute a task into an agent's invoke template. `{prompt}` and `{model}` are the only
16
+ * tokens replaced; everything else is literal, exactly as the delegation dispatcher does it.
17
+ */
18
+ export function dispatch(agent, task) {
19
+ const invoke = agent.invoke;
20
+ if (!invoke)
21
+ return null;
22
+ const fill = (arg) => arg.replace('{prompt}', task.prompt).replace('{model}', task.model ?? '');
23
+ const args = invoke.args.map(fill);
24
+ if (task.model && invoke.modelFlag.length)
25
+ args.push(...invoke.modelFlag.map(fill));
26
+ if (task.autoApprove)
27
+ args.push(...invoke.autoApprove);
28
+ return { binary: invoke.binary, args, promptVia: invoke.promptVia };
29
+ }
30
+ /** The engineering roles an orchestrator assigns work to. A taxonomy, not configuration. */
31
+ export const AGENT_ROLES = [
32
+ { role: 'Product Manager', responsibility: 'Requirements, scope, and acceptance criteria', phases: ['Discovery', 'Planning'], keywords: ['requirement', 'scope', 'backlog'] },
33
+ { role: 'Architect', responsibility: 'System boundaries, contracts, and the data model', phases: ['Architecture'], keywords: ['architecture', 'boundary', 'contract', 'scaffold', 'layout'] },
34
+ { role: 'Backend', responsibility: 'Services, APIs, and business logic', phases: ['Implementation'], keywords: ['api', 'service', 'auth', 'queue', 'cache', 'audit', 'versioning'] },
35
+ { role: 'Frontend', responsibility: 'UI, components, and client state', phases: ['Implementation'], keywords: ['ui', 'frontend', 'component', 'page'] },
36
+ { role: 'Database', responsibility: 'Schema, migrations, and access layer', phases: ['Implementation'], keywords: ['database', 'db', 'postgres', 'mongo', 'sqlite', 'migration', 'persistence'] },
37
+ { role: 'DevOps', responsibility: 'CI/CD, containers, and infrastructure', phases: ['Deployment'], keywords: ['ci', 'cd', 'docker', 'deploy', 'infrastructure', 'pipeline'] },
38
+ { role: 'Security', responsibility: 'Threat model, secrets, and dependency hygiene', phases: ['Security review'], keywords: ['security', 'threat', 'secret', 'supply-chain', 'auth'] },
39
+ { role: 'QA', responsibility: 'Test coverage across the pyramid', phases: ['Testing'], keywords: ['test', 'e2e', 'coverage', 'qa'] },
40
+ { role: 'Performance', responsibility: 'Load, latency, and cost against targets', phases: ['Performance review'], keywords: ['performance', 'load', 'latency', 'cache'] },
41
+ { role: 'Documentation', responsibility: 'READMEs, ADRs, and runbooks', phases: ['Monitoring'], keywords: ['doc', 'readme', 'adr', 'runbook', 'observability', 'monitoring'] },
42
+ ];
43
+ /**
44
+ * Route a task to the role that owns it. Every lifecycle phase except Implementation maps to a
45
+ * single role, so those go by phase. Implementation tasks all share a phase, so they route by
46
+ * keyword — matched on word boundaries, or "test suite" lands on Frontend because "suite" ends
47
+ * in "ui".
48
+ */
49
+ export function roleFor(task) {
50
+ if (task.phase !== 'Implementation') {
51
+ const byPhase = AGENT_ROLES.find((r) => r.phases.includes(task.phase) && !r.phases.includes('Implementation'));
52
+ if (byPhase)
53
+ return byPhase;
54
+ }
55
+ // Anchor at a word start (not both ends) so "postgres" matches "PostgreSQL" while "ui" still
56
+ // won't match the "ui" buried in "suite".
57
+ const text = task.title.toLowerCase();
58
+ const keyworded = AGENT_ROLES.find((r) => r.keywords.some((k) => new RegExp(`\\b${k}`).test(text)));
59
+ if (keyworded)
60
+ return keyworded;
61
+ return AGENT_ROLES.find((r) => r.phases.includes(task.phase)) ?? AGENT_ROLES.find((r) => r.role === 'Backend');
62
+ }
63
+ /**
64
+ * Assign every task to a role, then bind each role to an available agent. Roles are distributed
65
+ * round-robin across agents so parallel work fans out; with one agent everything routes to it.
66
+ */
67
+ export function orchestrate(tasks, agents) {
68
+ const byRole = new Map();
69
+ for (const task of tasks) {
70
+ const role = roleFor(task);
71
+ const entry = byRole.get(role.role) ?? { role, tasks: [] };
72
+ entry.tasks.push(`${task.id} ${task.title}`);
73
+ byRole.set(role.role, entry);
74
+ }
75
+ const assignments = [...byRole.values()];
76
+ return assignments.map((a, i) => ({
77
+ role: a.role.role,
78
+ responsibility: a.role.responsibility,
79
+ agent: agents.length ? agents[i % agents.length].id : null,
80
+ tasks: a.tasks,
81
+ }));
82
+ }
83
+ /**
84
+ * Group tasks into waves that can run in parallel (Phase 7). Each wave holds every task whose
85
+ * dependencies are all satisfied by earlier waves — a topological levelling. A dependency cycle,
86
+ * or a reference to an unknown task, leaves the remaining tasks in a final "blocked" wave rather
87
+ * than looping forever.
88
+ */
89
+ export function executionWaves(tasks) {
90
+ const ids = new Set(tasks.map((t) => t.id));
91
+ const done = new Set();
92
+ const remaining = [...tasks];
93
+ const waves = [];
94
+ while (remaining.length > 0) {
95
+ const ready = remaining.filter((t) => t.dependsOn.every((d) => done.has(d) || !ids.has(d)));
96
+ if (ready.length === 0) {
97
+ waves.push(remaining.map((t) => t.id)); // cycle or dangling dep — surface, don't hang
98
+ break;
99
+ }
100
+ waves.push(ready.map((t) => t.id));
101
+ for (const t of ready) {
102
+ done.add(t.id);
103
+ remaining.splice(remaining.indexOf(t), 1);
104
+ }
105
+ }
106
+ return waves;
107
+ }
108
+ //# sourceMappingURL=agent-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-runtime.js","sourceRoot":"","sources":["../src/agent-runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Architecture review before any code is generated — the "would a staff engineer sign off on
3
+ * this?" pass. Deterministic rules over the selected layers, the matched intent signals, and the
4
+ * stated priorities flag the gaps that sink production systems: no auth on a system with users,
5
+ * no observability, an unscalable datastore for a multi-tenant load, no test strategy, no CI.
6
+ *
7
+ * It also answers two questions every plan should: what to buy instead of build, and roughly
8
+ * what the infrastructure costs. Nothing here calls a model — every finding traces to a rule.
9
+ */
10
+ import type { AutoSelection } from './autoplan.js';
11
+ export interface Finding {
12
+ severity: 'high' | 'medium' | 'low';
13
+ area: string;
14
+ message: string;
15
+ recommendation: string;
16
+ }
17
+ export interface BuildVsBuy {
18
+ capability: string;
19
+ verdict: 'buy' | 'build';
20
+ option: string;
21
+ reason: string;
22
+ }
23
+ export interface CostBand {
24
+ item: string;
25
+ monthly: string;
26
+ }
27
+ /** Review the selection for the gaps that break production systems. High severity blocks sign-off. */
28
+ export declare function reviewArchitecture(selection: AutoSelection): Finding[];
29
+ /** The security-specific view of the review, for the Security Guardian section. */
30
+ export declare function securityReview(selection: AutoSelection): Finding[];
31
+ /** Capabilities better bought than built — with the reason a team usually regrets building them. */
32
+ export declare function buildVsBuy(selection: AutoSelection): BuildVsBuy[];
33
+ /** A rough monthly infrastructure estimate at a small production scale, from the selected layers. */
34
+ export declare function costEstimate(selection: AutoSelection): CostBand[];
35
+ /** The review as a single document for the blueprint. */
36
+ export declare function renderReview(selection: AutoSelection): string;
@@ -0,0 +1,106 @@
1
+ const has = (layers, prefix) => layers.some((l) => l === prefix || l.startsWith(`${prefix}`));
2
+ const signal = (s, id) => s.intent.matched.some((m) => m.signal === id);
3
+ const priority = (s, c) => s.intent.priorities[c] ?? 0;
4
+ /** A project has real users when it is multi-tenant, regulated, admin-facing, or an app/AI product. */
5
+ const hasUsers = (s) => signal(s, 'multi-tenant') || signal(s, 'regulated') || signal(s, 'crud-admin') || s.intent.family === 'ai' || s.intent.family === 'application';
6
+ /** Review the selection for the gaps that break production systems. High severity blocks sign-off. */
7
+ export function reviewArchitecture(selection) {
8
+ const layers = selection.layers;
9
+ const out = [];
10
+ if (hasUsers(selection) && !has(layers, 'auth')) {
11
+ out.push({ severity: 'high', area: 'security', message: 'No authentication layer for a system that has users.', recommendation: 'Add auth-jwt (self-issued) or auth-oidc (external IdP).' });
12
+ }
13
+ if (!layers.some((l) => l.startsWith('testing'))) {
14
+ out.push({ severity: 'high', area: 'testing', message: 'No test strategy selected — nothing proves the system works.', recommendation: 'Add testing-unit at minimum; testing-e2e for user-facing flows.' });
15
+ }
16
+ if ((signal(selection, 'multi-tenant') || signal(selection, 'high-traffic')) && layers.includes('db-sqlite')) {
17
+ out.push({ severity: 'high', area: 'scaling', message: 'SQLite backs a multi-tenant or high-traffic system; it does not scale past a single node.', recommendation: 'Use db-postgres for concurrent, multi-tenant workloads.' });
18
+ }
19
+ if (!has(layers, 'observability')) {
20
+ out.push({ severity: 'medium', area: 'observability', message: 'No observability layer — production failures will be invisible.', recommendation: 'Add observability-otel for traces, metrics, and structured logs.' });
21
+ }
22
+ if (!layers.includes('security-supply-chain')) {
23
+ out.push({ severity: 'medium', area: 'security', message: 'No dependency or secret scanning (OWASP A03:2025 is supply-chain).', recommendation: 'Add security-supply-chain (Dependabot/Renovate, CodeQL, gitleaks, SBOM).' });
24
+ }
25
+ if (!layers.includes('ci-github-actions')) {
26
+ out.push({ severity: 'medium', area: 'ci', message: 'No CI pipeline — nothing gates a broken change from merging.', recommendation: 'Add ci-github-actions to run build, lint, and tests on every push.' });
27
+ }
28
+ if ((priority(selection, 'scalability') >= 3 || signal(selection, 'high-traffic')) && !has(layers, 'cache')) {
29
+ out.push({ severity: 'medium', area: 'scaling', message: 'Scalability is a stated priority but there is no caching layer.', recommendation: 'Add cache-redis to absorb read load and protect the datastore.' });
30
+ }
31
+ if (priority(selection, 'fault-tolerance') >= 3 && !layers.includes('health-checks')) {
32
+ out.push({ severity: 'low', area: 'resilience', message: 'Fault tolerance matters here but no health checks are selected.', recommendation: 'Add health-checks so an orchestrator can detect and replace a bad instance.' });
33
+ }
34
+ if (layers.some((l) => l.startsWith('db-'))) {
35
+ out.push({ severity: 'low', area: 'data', message: 'A datastore is selected; automated backups are not scaffolded.', recommendation: 'Configure managed backups / point-in-time recovery before launch.' });
36
+ }
37
+ return out;
38
+ }
39
+ /** The security-specific view of the review, for the Security Guardian section. */
40
+ export function securityReview(selection) {
41
+ return reviewArchitecture(selection).filter((f) => f.area === 'security');
42
+ }
43
+ /** Capabilities better bought than built — with the reason a team usually regrets building them. */
44
+ export function buildVsBuy(selection) {
45
+ const out = [];
46
+ const text = selection.intent.matched.map((m) => m.signal).join(' ') + ' ' + (selection.architecture ?? '');
47
+ const idea = selection.assumptions.join(' ').toLowerCase();
48
+ const wants = (t) => idea.includes(t) || text.includes(t);
49
+ if (wants('payment') || wants('billing') || wants('marketplace') || wants('subscription') || selection.layers.includes('audit-log')) {
50
+ out.push({ capability: 'Payments & billing', verdict: 'buy', option: 'Stripe', reason: 'PCI scope, fraud, tax, and dunning are a product on their own — building them rarely pays off.' });
51
+ }
52
+ if (selection.layers.some((l) => l.startsWith('auth'))) {
53
+ out.push({ capability: 'Authentication', verdict: selection.layers.includes('auth-oidc') ? 'buy' : 'build', option: selection.layers.includes('auth-oidc') ? 'Auth0 / Clerk / Cognito (OIDC)' : 'Self-issued JWT (in-repo)', reason: selection.layers.includes('auth-oidc') ? 'An external IdP is already the chosen approach; managed keeps you off the critical-security path.' : 'A first-party JWT layer is fine for a single service; move to a managed IdP when SSO or social login is needed.' });
54
+ }
55
+ if (selection.intent.family === 'ai') {
56
+ out.push({ capability: 'LLM inference', verdict: 'buy', option: 'Anthropic / OpenAI API', reason: 'Hosting and serving a frontier model is not the product; call a provider and spend effort on the app.' });
57
+ }
58
+ out.push({ capability: 'Email / notifications', verdict: 'buy', option: 'Resend / Postmark / SES', reason: 'Deliverability and compliance are a moving target; a provider handles both.' });
59
+ return out;
60
+ }
61
+ /** A rough monthly infrastructure estimate at a small production scale, from the selected layers. */
62
+ export function costEstimate(selection) {
63
+ const bands = [{ item: 'App hosting (small instance / serverless)', monthly: '$5–25' }];
64
+ if (selection.layers.some((l) => l.startsWith('db-')))
65
+ bands.push({ item: 'Managed database', monthly: '$15–60' });
66
+ if (selection.layers.some((l) => l.startsWith('cache')))
67
+ bands.push({ item: 'Managed cache (Redis)', monthly: '$10–40' });
68
+ if (selection.layers.includes('queue-broker'))
69
+ bands.push({ item: 'Message broker', monthly: '$10–40' });
70
+ if (selection.layers.includes('observability-otel'))
71
+ bands.push({ item: 'Observability (traces/metrics/logs)', monthly: '$0–50' });
72
+ if (selection.intent.family === 'ai')
73
+ bands.push({ item: 'LLM API usage (variable)', monthly: '$20–500+' });
74
+ return bands;
75
+ }
76
+ /** The review as a single document for the blueprint. */
77
+ export function renderReview(selection) {
78
+ const findings = reviewArchitecture(selection);
79
+ const blocking = findings.filter((f) => f.severity === 'high');
80
+ const badge = (s) => (s === 'high' ? '🔴' : s === 'medium' ? '🟡' : '⚪');
81
+ const lines = [
82
+ `# Architecture review`,
83
+ ``,
84
+ blocking.length
85
+ ? `**${blocking.length} blocking issue(s)** must be resolved before this is production-ready.`
86
+ : `No blocking issues — review the medium/low findings before launch.`,
87
+ ``,
88
+ `## Findings`,
89
+ ``,
90
+ ];
91
+ if (findings.length === 0)
92
+ lines.push(`_None. The selection covers the production baseline._`, ``);
93
+ for (const f of findings) {
94
+ lines.push(`- ${badge(f.severity)} **${f.area}** — ${f.message}`, ` - ${f.recommendation}`);
95
+ }
96
+ lines.push(``, `## Build vs buy`, ``);
97
+ for (const b of buildVsBuy(selection)) {
98
+ lines.push(`- **${b.capability}** → **${b.verdict.toUpperCase()}** (${b.option}) — ${b.reason}`);
99
+ }
100
+ lines.push(``, `## Rough monthly cost (small production scale)`, ``);
101
+ for (const c of costEstimate(selection))
102
+ lines.push(`- ${c.item}: ${c.monthly}`);
103
+ lines.push(``);
104
+ return lines.join('\n');
105
+ }
106
+ //# sourceMappingURL=analysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analysis.js","sourceRoot":"","sources":["../src/analysis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { type Finding } from './analysis.js';
2
+ import { type CtoReview, type Score } from './assessment.js';
3
+ import type { Stack } from './schema.js';
4
+ export interface RepoFacts {
5
+ stack: Stack;
6
+ /** Catalog capability ids detected in the repo. */
7
+ present: string[];
8
+ /** Baseline capabilities a production repo should have but this one lacks. */
9
+ missing: string[];
10
+ dependencies: number;
11
+ }
12
+ export interface RepoAnalysis {
13
+ dir: string;
14
+ facts: RepoFacts;
15
+ scores: Score[];
16
+ overall: number;
17
+ findings: Finding[];
18
+ cto: CtoReview;
19
+ }
20
+ /** Detect the stack and present capabilities from manifests and marker files. */
21
+ export declare function detectRepo(dir: string): RepoFacts;
22
+ /** Run the shared review/scoring/CTO engine over a set of repo facts. Reused by analyze and improve. */
23
+ export declare function assessFacts(facts: RepoFacts): Omit<RepoAnalysis, 'dir' | 'facts'>;
24
+ export declare function analyzeRepo(dir: string): RepoAnalysis;
25
+ /** The analysis as files (filename → content) for the caller to write. */
26
+ export declare function renderAnalysis(a: RepoAnalysis): Record<string, string>;
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Repository intelligence — point Groundplan at an existing repo and get the same review it
3
+ * gives a new one. It detects the stack and which capabilities are already present, projects
4
+ * those onto a selection, and runs the one review/scoring/CTO engine over it. No parallel
5
+ * analysis logic: an existing repo and a planned one are judged by identical rules.
6
+ */
7
+ import fs from 'node:fs';
8
+ import path from 'node:path';
9
+ import { reviewArchitecture } from './analysis.js';
10
+ import { ctoReview, overallScore, qualityScores } from './assessment.js';
11
+ const readIfExists = (file) => {
12
+ try {
13
+ return fs.readFileSync(file, 'utf8');
14
+ }
15
+ catch {
16
+ return '';
17
+ }
18
+ };
19
+ const exists = (dir, rel) => fs.existsSync(path.join(dir, rel));
20
+ /** What a production repo is expected to have, by capability id. */
21
+ const BASELINE = ['auth', 'testing', 'observability-otel', 'security-supply-chain', 'ci-github-actions'];
22
+ /** Detect the stack and present capabilities from manifests and marker files. */
23
+ export function detectRepo(dir) {
24
+ const pkgRaw = readIfExists(path.join(dir, 'package.json'));
25
+ let deps = new Set();
26
+ let manifest = '';
27
+ let stack = 'polyglot';
28
+ if (pkgRaw) {
29
+ try {
30
+ const pkg = JSON.parse(pkgRaw);
31
+ deps = new Set([...Object.keys(pkg.dependencies ?? {}), ...Object.keys(pkg.devDependencies ?? {})]);
32
+ }
33
+ catch {
34
+ /* a malformed package.json still counts as a node project */
35
+ }
36
+ manifest = pkgRaw;
37
+ stack = exists(dir, 'tsconfig.json') ? 'typescript' : 'node';
38
+ }
39
+ else if (exists(dir, 'pyproject.toml') || exists(dir, 'requirements.txt')) {
40
+ manifest = readIfExists(path.join(dir, 'pyproject.toml')) + readIfExists(path.join(dir, 'requirements.txt'));
41
+ stack = 'python';
42
+ }
43
+ else if (exists(dir, 'go.mod')) {
44
+ manifest = readIfExists(path.join(dir, 'go.mod'));
45
+ stack = 'go';
46
+ }
47
+ else {
48
+ const proj = fs.existsSync(dir) ? fs.readdirSync(dir).find((f) => f.endsWith('.csproj') || f.endsWith('.slnx')) : undefined;
49
+ if (proj) {
50
+ manifest = readIfExists(path.join(dir, proj));
51
+ stack = 'dotnet';
52
+ }
53
+ }
54
+ const dep = (name) => deps.has(name) || manifest.toLowerCase().includes(name.toLowerCase());
55
+ const present = [];
56
+ if (exists(dir, '.github/workflows'))
57
+ present.push('ci-github-actions');
58
+ if (exists(dir, 'Dockerfile') || exists(dir, 'compose.yaml') || exists(dir, 'docker-compose.yml'))
59
+ present.push('docker');
60
+ if (dep('vitest') || dep('jest') || dep('pytest') || dep('mocha') || exists(dir, 'tests') || exists(dir, 'test'))
61
+ present.push('testing-unit');
62
+ if (dep('jsonwebtoken') || dep('jose') || dep('passport') || dep('argon2') || dep('bcrypt'))
63
+ present.push('auth-jwt');
64
+ if (dep('pg') || dep('postgres') || dep('psycopg'))
65
+ present.push('db-postgres');
66
+ else if (dep('mongoose') || dep('mongodb') || dep('pymongo'))
67
+ present.push('db-mongo');
68
+ else if (dep('better-sqlite3') || dep('sqlite'))
69
+ present.push('db-sqlite');
70
+ if (dep('redis') || dep('ioredis'))
71
+ present.push('cache-redis');
72
+ if (dep('bullmq') || dep('amqplib') || dep('kafkajs') || dep('celery'))
73
+ present.push('queue-broker');
74
+ if (dep('opentelemetry'))
75
+ present.push('observability-otel');
76
+ if (exists(dir, '.gitleaks.toml') || dep('gitleaks') || exists(dir, '.github/dependabot.yml'))
77
+ present.push('security-supply-chain');
78
+ if (dep('eslint') || dep('prettier') || dep('ruff') || dep('golangci'))
79
+ present.push('lint-format');
80
+ const missing = BASELINE.filter((id) => !present.some((l) => l === id || l.startsWith(id)));
81
+ return { stack, present, missing, dependencies: deps.size };
82
+ }
83
+ /** Project the detected facts onto a selection so the one review engine can judge the repo. */
84
+ function asSelection(facts) {
85
+ return {
86
+ intent: { priorities: {}, family: 'application', stack: facts.stack, teamSize: 4, impliedLayers: [], matched: [], confidence: 1 },
87
+ stack: facts.stack,
88
+ teamSize: 4,
89
+ architecture: undefined,
90
+ base: '',
91
+ layers: facts.present,
92
+ adapters: [],
93
+ ranked: [],
94
+ confidence: 1,
95
+ assumptions: [],
96
+ questions: [],
97
+ };
98
+ }
99
+ /** Run the shared review/scoring/CTO engine over a set of repo facts. Reused by analyze and improve. */
100
+ export function assessFacts(facts) {
101
+ const selection = asSelection(facts);
102
+ const findings = reviewArchitecture(selection);
103
+ const scores = qualityScores(selection, findings);
104
+ return { scores, overall: overallScore(scores), findings, cto: ctoReview(selection, findings, scores) };
105
+ }
106
+ export function analyzeRepo(dir) {
107
+ const facts = detectRepo(dir);
108
+ return { dir, facts, ...assessFacts(facts) };
109
+ }
110
+ /** The analysis as files (filename → content) for the caller to write. */
111
+ export function renderAnalysis(a) {
112
+ const bar = (n) => '█'.repeat(Math.round(n / 10)) + '░'.repeat(10 - Math.round(n / 10));
113
+ const report = [
114
+ `# Repository analysis`,
115
+ ``,
116
+ `Stack: **${a.facts.stack}** · Dependencies: **${a.facts.dependencies}** · Overall quality: **${a.overall}/100**`,
117
+ ``,
118
+ `## Detected capabilities`,
119
+ ``,
120
+ ...(a.facts.present.length ? a.facts.present.map((c) => `- ${c}`) : ['- (none detected)']),
121
+ ``,
122
+ `## Missing baseline`,
123
+ ``,
124
+ ...(a.facts.missing.length ? a.facts.missing.map((c) => `- ${c}`) : ['- None — the production baseline is covered.']),
125
+ ``,
126
+ `## Quality scores`,
127
+ ``,
128
+ `| Dimension | Score | |`,
129
+ `|---|---|---|`,
130
+ ...a.scores.map((s) => `| ${s.dimension} | ${s.score} | \`${bar(s.score)}\` |`),
131
+ ``,
132
+ `## CTO verdict: ${a.cto.verdict.toUpperCase().replace(/-/g, ' ')}`,
133
+ ``,
134
+ a.cto.summary,
135
+ ``,
136
+ ].join('\n');
137
+ const roadmap = [
138
+ `# Improvement roadmap`,
139
+ ``,
140
+ `Ordered by severity — the highest-impact fixes first.`,
141
+ ``,
142
+ ...['high', 'medium', 'low'].flatMap((sev) => {
143
+ const items = a.findings.filter((f) => f.severity === sev);
144
+ if (items.length === 0)
145
+ return [];
146
+ return [`## ${sev[0].toUpperCase() + sev.slice(1)} priority`, ``, ...items.map((f) => `- [ ] **${f.area}** — ${f.recommendation}`), ``];
147
+ }),
148
+ ].join('\n');
149
+ return {
150
+ 'analysis-report.md': report,
151
+ 'improvement-roadmap.md': roadmap,
152
+ 'analysis.json': JSON.stringify({ facts: a.facts, overall: a.overall, scores: a.scores, findings: a.findings, cto: a.cto }, null, 2) + '\n',
153
+ };
154
+ }
155
+ //# sourceMappingURL=analyze.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.js","sourceRoot":"","sources":["../src/analyze.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * The review layer over a blueprint: quality scores, Architecture Decision Records, and an
3
+ * independent "AI CTO" pass. All derived deterministically from the selection and the
4
+ * architecture review — the CTO review challenges the plan using the same findings a staff
5
+ * engineer would raise, so a low score and a blocking finding tell one consistent story.
6
+ */
7
+ import type { AutoSelection } from './autoplan.js';
8
+ import type { Finding } from './analysis.js';
9
+ export interface Score {
10
+ dimension: string;
11
+ score: number;
12
+ note: string;
13
+ }
14
+ export interface ADR {
15
+ number: number;
16
+ title: string;
17
+ status: 'accepted' | 'proposed';
18
+ context: string;
19
+ decision: string;
20
+ alternatives: string[];
21
+ consequences: string[];
22
+ }
23
+ export interface CtoReview {
24
+ verdict: 'approved' | 'approved-with-conditions' | 'needs-work';
25
+ summary: string;
26
+ challenges: string[];
27
+ conditions: string[];
28
+ }
29
+ /**
30
+ * Ten quality dimensions, each scored from the selection and the review. A high-severity finding
31
+ * in a dimension's area caps it low; a covered baseline scores high. Deterministic, not vibes.
32
+ */
33
+ export declare function qualityScores(selection: AutoSelection, findings: Finding[]): Score[];
34
+ /** The overall score is the mean of the dimensions. */
35
+ export declare function overallScore(scores: Score[]): number;
36
+ /** One ADR per major decision — architecture and each choice-set layer (database, auth). */
37
+ export declare function generateADRs(selection: AutoSelection): ADR[];
38
+ /** The independent CTO pass — it challenges the plan using the review's high/medium findings. */
39
+ export declare function ctoReview(selection: AutoSelection, findings: Finding[], scores: Score[]): CtoReview;