@maintainabilityai/research-runner 0.1.1
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/LICENSE +21 -0
- package/README.md +82 -0
- package/bin/research-runner.js +2 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +209 -0
- package/dist/llm/anthropic-client.d.ts +39 -0
- package/dist/llm/anthropic-client.js +74 -0
- package/dist/llm/github-models-client.d.ts +46 -0
- package/dist/llm/github-models-client.js +78 -0
- package/dist/llm/llm-router.d.ts +46 -0
- package/dist/llm/llm-router.js +60 -0
- package/dist/mesh/get-mesh-sha.d.ts +1 -0
- package/dist/mesh/get-mesh-sha.js +27 -0
- package/dist/mesh/mesh-reader.d.ts +14 -0
- package/dist/mesh/mesh-reader.js +392 -0
- package/dist/mesh/prompt-loader.d.ts +22 -0
- package/dist/mesh/prompt-loader.js +119 -0
- package/dist/mesh/threat-model-reader.d.ts +33 -0
- package/dist/mesh/threat-model-reader.js +123 -0
- package/dist/runner/archeologist.d.ts +39 -0
- package/dist/runner/archeologist.js +620 -0
- package/dist/runner/audit-emitter.d.ts +62 -0
- package/dist/runner/audit-emitter.js +210 -0
- package/dist/runner/hatters-tag-builder.d.ts +52 -0
- package/dist/runner/hatters-tag-builder.js +40 -0
- package/dist/runner/nodes/analyze-architecture.d.ts +10 -0
- package/dist/runner/nodes/analyze-architecture.js +447 -0
- package/dist/runner/nodes/arxiv-search.d.ts +12 -0
- package/dist/runner/nodes/arxiv-search.js +52 -0
- package/dist/runner/nodes/clone-and-index.d.ts +32 -0
- package/dist/runner/nodes/clone-and-index.js +158 -0
- package/dist/runner/nodes/dedupe-and-rank.d.ts +27 -0
- package/dist/runner/nodes/dedupe-and-rank.js +98 -0
- package/dist/runner/nodes/deterministic-review.d.ts +55 -0
- package/dist/runner/nodes/deterministic-review.js +206 -0
- package/dist/runner/nodes/expert-review.d.ts +68 -0
- package/dist/runner/nodes/expert-review.js +197 -0
- package/dist/runner/nodes/gap-analysis.d.ts +48 -0
- package/dist/runner/nodes/gap-analysis.js +153 -0
- package/dist/runner/nodes/generate-prd-manifest.d.ts +53 -0
- package/dist/runner/nodes/generate-prd-manifest.js +209 -0
- package/dist/runner/nodes/hackernews-search.d.ts +12 -0
- package/dist/runner/nodes/hackernews-search.js +63 -0
- package/dist/runner/nodes/identify-gaps.d.ts +33 -0
- package/dist/runner/nodes/identify-gaps.js +185 -0
- package/dist/runner/nodes/plan-queries.d.ts +28 -0
- package/dist/runner/nodes/plan-queries.js +120 -0
- package/dist/runner/nodes/prd-validator.d.ts +51 -0
- package/dist/runner/nodes/prd-validator.js +203 -0
- package/dist/runner/nodes/synthesis-archaeology-validator.d.ts +22 -0
- package/dist/runner/nodes/synthesis-archaeology-validator.js +131 -0
- package/dist/runner/nodes/synthesis-validator.d.ts +51 -0
- package/dist/runner/nodes/synthesis-validator.js +185 -0
- package/dist/runner/nodes/synthesize-prd.d.ts +84 -0
- package/dist/runner/nodes/synthesize-prd.js +202 -0
- package/dist/runner/nodes/synthesize-report.d.ts +53 -0
- package/dist/runner/nodes/synthesize-report.js +188 -0
- package/dist/runner/nodes/tavily-search.d.ts +21 -0
- package/dist/runner/nodes/tavily-search.js +57 -0
- package/dist/runner/nodes/uspto-search.d.ts +13 -0
- package/dist/runner/nodes/uspto-search.js +62 -0
- package/dist/runner/nodes/verify-grounding.d.ts +54 -0
- package/dist/runner/nodes/verify-grounding.js +134 -0
- package/dist/runner/prd.d.ts +28 -0
- package/dist/runner/prd.js +494 -0
- package/dist/schemas/audit-event.d.ts +1151 -0
- package/dist/schemas/audit-event.js +141 -0
- package/dist/schemas/index.d.ts +17 -0
- package/dist/schemas/index.js +33 -0
- package/dist/schemas/mesh-context.d.ts +415 -0
- package/dist/schemas/mesh-context.js +95 -0
- package/dist/schemas/observed-architecture.d.ts +262 -0
- package/dist/schemas/observed-architecture.js +90 -0
- package/dist/schemas/prd-brief.d.ts +111 -0
- package/dist/schemas/prd-brief.js +37 -0
- package/dist/schemas/prd-doc.d.ts +249 -0
- package/dist/schemas/prd-doc.js +42 -0
- package/dist/schemas/prd-manifest.d.ts +171 -0
- package/dist/schemas/prd-manifest.js +73 -0
- package/dist/schemas/primitives.d.ts +47 -0
- package/dist/schemas/primitives.js +41 -0
- package/dist/schemas/query-plan.d.ts +33 -0
- package/dist/schemas/query-plan.js +25 -0
- package/dist/schemas/ranked-source.d.ts +82 -0
- package/dist/schemas/ranked-source.js +29 -0
- package/dist/schemas/research-brief.d.ts +114 -0
- package/dist/schemas/research-brief.js +49 -0
- package/dist/schemas/research-doc.d.ts +104 -0
- package/dist/schemas/research-doc.js +37 -0
- package/dist/search/arxiv-client.d.ts +41 -0
- package/dist/search/arxiv-client.js +88 -0
- package/dist/search/hackernews-client.d.ts +33 -0
- package/dist/search/hackernews-client.js +44 -0
- package/dist/search/provider-result.d.ts +25 -0
- package/dist/search/provider-result.js +2 -0
- package/dist/search/tavily-client.d.ts +38 -0
- package/dist/search/tavily-client.js +53 -0
- package/dist/search/uspto-client.d.ts +50 -0
- package/dist/search/uspto-client.js +112 -0
- package/dist/utils/run-id.d.ts +2 -0
- package/dist/utils/run-id.js +22 -0
- package/package.json +53 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MeshContext = exports.MeshGapKind = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* MeshContext — what `gather_mesh_context` produces for every LLM node.
|
|
6
|
+
*
|
|
7
|
+
* Mirrors the shape defined in the design doc (§"gather_mesh_context — the
|
|
8
|
+
* mesh IS the expert"). Every LLM call in both the Archeologist and PRD
|
|
9
|
+
* pipelines receives this as its grounding payload.
|
|
10
|
+
*/
|
|
11
|
+
const zod_1 = require("zod");
|
|
12
|
+
const primitives_1 = require("./primitives");
|
|
13
|
+
/** A small projection of a research doc that lives in scope. */
|
|
14
|
+
const RelatedResearchSummary = zod_1.z.object({
|
|
15
|
+
research_id: zod_1.z.string(),
|
|
16
|
+
topic: zod_1.z.string(),
|
|
17
|
+
published_at: zod_1.z.string(),
|
|
18
|
+
});
|
|
19
|
+
/** Structural gap kinds the GovernanceScorer detects per BAR. */
|
|
20
|
+
exports.MeshGapKind = zod_1.z.enum([
|
|
21
|
+
'no_threat_model',
|
|
22
|
+
'no_controls_mapping',
|
|
23
|
+
'no_adrs',
|
|
24
|
+
'stale_research',
|
|
25
|
+
'missing_prd_for_planned_feature',
|
|
26
|
+
'low_architecture_pillar',
|
|
27
|
+
'low_security_pillar',
|
|
28
|
+
]);
|
|
29
|
+
const PillarScores = zod_1.z.object({
|
|
30
|
+
architecture: zod_1.z.number(),
|
|
31
|
+
security: zod_1.z.number(),
|
|
32
|
+
info_risk: zod_1.z.number(),
|
|
33
|
+
operations: zod_1.z.number(),
|
|
34
|
+
});
|
|
35
|
+
const Adr = zod_1.z.object({
|
|
36
|
+
id: zod_1.z.string(),
|
|
37
|
+
title: zod_1.z.string(),
|
|
38
|
+
status: zod_1.z.string(),
|
|
39
|
+
decision: zod_1.z.string(),
|
|
40
|
+
});
|
|
41
|
+
exports.MeshContext = zod_1.z.object({
|
|
42
|
+
scope: zod_1.z.object({
|
|
43
|
+
level: primitives_1.ScopeLevel,
|
|
44
|
+
bar_id: zod_1.z.string().optional(), // present when level === 'bar'
|
|
45
|
+
platform_id: zod_1.z.string().optional(), // present when level === 'platform' OR 'bar' (parent)
|
|
46
|
+
}),
|
|
47
|
+
/** Git SHA of the mesh repo at the moment context was read. */
|
|
48
|
+
mesh_sha: primitives_1.GitSha,
|
|
49
|
+
/** Always populated. */
|
|
50
|
+
portfolio: zod_1.z.object({
|
|
51
|
+
name: zod_1.z.string(),
|
|
52
|
+
governance_policy: zod_1.z.unknown(),
|
|
53
|
+
capability_models: zod_1.z.array(zod_1.z.unknown()),
|
|
54
|
+
related_research_summaries: zod_1.z.array(RelatedResearchSummary),
|
|
55
|
+
}),
|
|
56
|
+
/** Populated when level is platform OR bar. */
|
|
57
|
+
platform: zod_1.z.object({
|
|
58
|
+
platform_id: zod_1.z.string(),
|
|
59
|
+
architecture: zod_1.z.unknown(),
|
|
60
|
+
sibling_bars: zod_1.z.array(zod_1.z.object({
|
|
61
|
+
bar_id: zod_1.z.string(),
|
|
62
|
+
name: zod_1.z.string(),
|
|
63
|
+
composite_score: zod_1.z.number(),
|
|
64
|
+
/** owner/repo entries parsed from each sibling BAR's app.yaml. */
|
|
65
|
+
linked_repos: zod_1.z.array(zod_1.z.string().regex(/^[\w.-]+\/[\w.-]+$/)).default([]),
|
|
66
|
+
/** CALM node ids the BAR owns. Used by generate-prd-manifest's
|
|
67
|
+
* impact classification to decide whether a sibling is HIGH
|
|
68
|
+
* confidence (one of these nodes is referenced by an endpoint)
|
|
69
|
+
* or LOW (no citation overlap). */
|
|
70
|
+
calm_node_ids: zod_1.z.array(zod_1.z.string()).default([]),
|
|
71
|
+
/** Threat ids declared in the BAR's threat-model.yaml. Used by the
|
|
72
|
+
* same impact classification to flag siblings whose threats are
|
|
73
|
+
* cited by the PRD's security requirements. */
|
|
74
|
+
threat_ids: zod_1.z.array(zod_1.z.string()).default([]),
|
|
75
|
+
})),
|
|
76
|
+
related_research_summaries: zod_1.z.array(RelatedResearchSummary),
|
|
77
|
+
}).nullable(),
|
|
78
|
+
/** Populated only when level is bar. */
|
|
79
|
+
bar: zod_1.z.object({
|
|
80
|
+
bar_id: zod_1.z.string(),
|
|
81
|
+
name: zod_1.z.string(),
|
|
82
|
+
composite_score: zod_1.z.number(),
|
|
83
|
+
tier: zod_1.z.enum(['restricted', 'supervised', 'autonomous']),
|
|
84
|
+
calm_model: zod_1.z.unknown(),
|
|
85
|
+
threats: zod_1.z.unknown().nullable(),
|
|
86
|
+
controls: zod_1.z.unknown().nullable(),
|
|
87
|
+
adrs: zod_1.z.array(Adr),
|
|
88
|
+
pillar_scores: PillarScores,
|
|
89
|
+
related_research: zod_1.z.array(RelatedResearchSummary),
|
|
90
|
+
related_prds: zod_1.z.array(RelatedResearchSummary),
|
|
91
|
+
mesh_gaps: zod_1.z.array(exports.MeshGapKind),
|
|
92
|
+
/** owner/repo entries parsed from app.yaml application.repos — drives PrdManifest.target_repos. */
|
|
93
|
+
linked_repos: zod_1.z.array(zod_1.z.string().regex(/^[\w.-]+\/[\w.-]+$/)).default([]),
|
|
94
|
+
}).nullable(),
|
|
95
|
+
});
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObservedArchitecture — what analyze_architecture extracts from a cloned
|
|
3
|
+
* target repo (archaeology path).
|
|
4
|
+
*
|
|
5
|
+
* Phase 3a is file-based: no AST parsing, no tree-sitter. We extract what
|
|
6
|
+
* we can from filenames, manifest files, and regex-detected route handlers.
|
|
7
|
+
* Phase 3b will add tree-sitter for deeper symbol-level analysis.
|
|
8
|
+
*
|
|
9
|
+
* The shape mirrors the spec in docs/design/research-and-prd-agents.md
|
|
10
|
+
* §"What `analyze_architecture` extracts" but pares back depth we can't
|
|
11
|
+
* deliver without an AST.
|
|
12
|
+
*/
|
|
13
|
+
import { z } from 'zod';
|
|
14
|
+
export declare const ObservedLayer: z.ZodEnum<["api", "web", "data", "worker", "shared", "unknown"]>;
|
|
15
|
+
export type ObservedLayer = z.infer<typeof ObservedLayer>;
|
|
16
|
+
export declare const Endpoint: z.ZodObject<{
|
|
17
|
+
/** HTTP method like "GET" / "POST". */
|
|
18
|
+
method: z.ZodString;
|
|
19
|
+
/** Path template, e.g. "/users/:id". */
|
|
20
|
+
path: z.ZodString;
|
|
21
|
+
/** File the endpoint lives in (relative to repo root). */
|
|
22
|
+
file: z.ZodString;
|
|
23
|
+
/** Framework that surfaced it, e.g. "express" / "fastapi" / "flask" / "spring". */
|
|
24
|
+
framework: z.ZodString;
|
|
25
|
+
}, "strip", z.ZodTypeAny, {
|
|
26
|
+
path: string;
|
|
27
|
+
method: string;
|
|
28
|
+
file: string;
|
|
29
|
+
framework: string;
|
|
30
|
+
}, {
|
|
31
|
+
path: string;
|
|
32
|
+
method: string;
|
|
33
|
+
file: string;
|
|
34
|
+
framework: string;
|
|
35
|
+
}>;
|
|
36
|
+
export type Endpoint = z.infer<typeof Endpoint>;
|
|
37
|
+
export declare const Module: z.ZodObject<{
|
|
38
|
+
/** Top-level directory or src/<name> identifier. */
|
|
39
|
+
name: z.ZodString;
|
|
40
|
+
/** Inferred layer per the heuristics in analyze_architecture. */
|
|
41
|
+
layer: z.ZodEnum<["api", "web", "data", "worker", "shared", "unknown"]>;
|
|
42
|
+
/** File counts that landed in this module (excluding test files). */
|
|
43
|
+
fileCount: z.ZodNumber;
|
|
44
|
+
/** Endpoints declared in this module. */
|
|
45
|
+
endpointCount: z.ZodNumber;
|
|
46
|
+
}, "strip", z.ZodTypeAny, {
|
|
47
|
+
name: string;
|
|
48
|
+
layer: "unknown" | "web" | "api" | "data" | "worker" | "shared";
|
|
49
|
+
fileCount: number;
|
|
50
|
+
endpointCount: number;
|
|
51
|
+
}, {
|
|
52
|
+
name: string;
|
|
53
|
+
layer: "unknown" | "web" | "api" | "data" | "worker" | "shared";
|
|
54
|
+
fileCount: number;
|
|
55
|
+
endpointCount: number;
|
|
56
|
+
}>;
|
|
57
|
+
export type Module = z.infer<typeof Module>;
|
|
58
|
+
export declare const RepositoryProfile: z.ZodObject<{
|
|
59
|
+
/** owner/repo at the time of clone. */
|
|
60
|
+
slug: z.ZodString;
|
|
61
|
+
/** Git SHA of the clone HEAD. */
|
|
62
|
+
cloneSha: z.ZodString;
|
|
63
|
+
/** Total tracked files (skips .git, node_modules, build, dist). */
|
|
64
|
+
totalFiles: z.ZodNumber;
|
|
65
|
+
/** Bytes counted across tracked files. */
|
|
66
|
+
totalBytes: z.ZodNumber;
|
|
67
|
+
/** File counts by extension (sorted desc by count in serialised form). */
|
|
68
|
+
byExtension: z.ZodRecord<z.ZodString, z.ZodNumber>;
|
|
69
|
+
/** Detected primary language(s) — derived from extension counts + manifests. */
|
|
70
|
+
languages: z.ZodArray<z.ZodString, "many">;
|
|
71
|
+
/** Detected primary framework(s) (express, fastapi, react, next, vue, …). */
|
|
72
|
+
frameworks: z.ZodArray<z.ZodString, "many">;
|
|
73
|
+
/** Manifest files present (package.json, pyproject.toml, Cargo.toml, …). */
|
|
74
|
+
manifests: z.ZodArray<z.ZodString, "many">;
|
|
75
|
+
}, "strip", z.ZodTypeAny, {
|
|
76
|
+
slug: string;
|
|
77
|
+
cloneSha: string;
|
|
78
|
+
totalFiles: number;
|
|
79
|
+
totalBytes: number;
|
|
80
|
+
byExtension: Record<string, number>;
|
|
81
|
+
languages: string[];
|
|
82
|
+
frameworks: string[];
|
|
83
|
+
manifests: string[];
|
|
84
|
+
}, {
|
|
85
|
+
slug: string;
|
|
86
|
+
cloneSha: string;
|
|
87
|
+
totalFiles: number;
|
|
88
|
+
totalBytes: number;
|
|
89
|
+
byExtension: Record<string, number>;
|
|
90
|
+
languages: string[];
|
|
91
|
+
frameworks: string[];
|
|
92
|
+
manifests: string[];
|
|
93
|
+
}>;
|
|
94
|
+
export type RepositoryProfile = z.infer<typeof RepositoryProfile>;
|
|
95
|
+
export declare const ObservedArchitecture: z.ZodObject<{
|
|
96
|
+
profile: z.ZodObject<{
|
|
97
|
+
/** owner/repo at the time of clone. */
|
|
98
|
+
slug: z.ZodString;
|
|
99
|
+
/** Git SHA of the clone HEAD. */
|
|
100
|
+
cloneSha: z.ZodString;
|
|
101
|
+
/** Total tracked files (skips .git, node_modules, build, dist). */
|
|
102
|
+
totalFiles: z.ZodNumber;
|
|
103
|
+
/** Bytes counted across tracked files. */
|
|
104
|
+
totalBytes: z.ZodNumber;
|
|
105
|
+
/** File counts by extension (sorted desc by count in serialised form). */
|
|
106
|
+
byExtension: z.ZodRecord<z.ZodString, z.ZodNumber>;
|
|
107
|
+
/** Detected primary language(s) — derived from extension counts + manifests. */
|
|
108
|
+
languages: z.ZodArray<z.ZodString, "many">;
|
|
109
|
+
/** Detected primary framework(s) (express, fastapi, react, next, vue, …). */
|
|
110
|
+
frameworks: z.ZodArray<z.ZodString, "many">;
|
|
111
|
+
/** Manifest files present (package.json, pyproject.toml, Cargo.toml, …). */
|
|
112
|
+
manifests: z.ZodArray<z.ZodString, "many">;
|
|
113
|
+
}, "strip", z.ZodTypeAny, {
|
|
114
|
+
slug: string;
|
|
115
|
+
cloneSha: string;
|
|
116
|
+
totalFiles: number;
|
|
117
|
+
totalBytes: number;
|
|
118
|
+
byExtension: Record<string, number>;
|
|
119
|
+
languages: string[];
|
|
120
|
+
frameworks: string[];
|
|
121
|
+
manifests: string[];
|
|
122
|
+
}, {
|
|
123
|
+
slug: string;
|
|
124
|
+
cloneSha: string;
|
|
125
|
+
totalFiles: number;
|
|
126
|
+
totalBytes: number;
|
|
127
|
+
byExtension: Record<string, number>;
|
|
128
|
+
languages: string[];
|
|
129
|
+
frameworks: string[];
|
|
130
|
+
manifests: string[];
|
|
131
|
+
}>;
|
|
132
|
+
modules: z.ZodArray<z.ZodObject<{
|
|
133
|
+
/** Top-level directory or src/<name> identifier. */
|
|
134
|
+
name: z.ZodString;
|
|
135
|
+
/** Inferred layer per the heuristics in analyze_architecture. */
|
|
136
|
+
layer: z.ZodEnum<["api", "web", "data", "worker", "shared", "unknown"]>;
|
|
137
|
+
/** File counts that landed in this module (excluding test files). */
|
|
138
|
+
fileCount: z.ZodNumber;
|
|
139
|
+
/** Endpoints declared in this module. */
|
|
140
|
+
endpointCount: z.ZodNumber;
|
|
141
|
+
}, "strip", z.ZodTypeAny, {
|
|
142
|
+
name: string;
|
|
143
|
+
layer: "unknown" | "web" | "api" | "data" | "worker" | "shared";
|
|
144
|
+
fileCount: number;
|
|
145
|
+
endpointCount: number;
|
|
146
|
+
}, {
|
|
147
|
+
name: string;
|
|
148
|
+
layer: "unknown" | "web" | "api" | "data" | "worker" | "shared";
|
|
149
|
+
fileCount: number;
|
|
150
|
+
endpointCount: number;
|
|
151
|
+
}>, "many">;
|
|
152
|
+
endpoints: z.ZodArray<z.ZodObject<{
|
|
153
|
+
/** HTTP method like "GET" / "POST". */
|
|
154
|
+
method: z.ZodString;
|
|
155
|
+
/** Path template, e.g. "/users/:id". */
|
|
156
|
+
path: z.ZodString;
|
|
157
|
+
/** File the endpoint lives in (relative to repo root). */
|
|
158
|
+
file: z.ZodString;
|
|
159
|
+
/** Framework that surfaced it, e.g. "express" / "fastapi" / "flask" / "spring". */
|
|
160
|
+
framework: z.ZodString;
|
|
161
|
+
}, "strip", z.ZodTypeAny, {
|
|
162
|
+
path: string;
|
|
163
|
+
method: string;
|
|
164
|
+
file: string;
|
|
165
|
+
framework: string;
|
|
166
|
+
}, {
|
|
167
|
+
path: string;
|
|
168
|
+
method: string;
|
|
169
|
+
file: string;
|
|
170
|
+
framework: string;
|
|
171
|
+
}>, "many">;
|
|
172
|
+
/**
|
|
173
|
+
* Direct external dependencies (production only, not dev). Source: the
|
|
174
|
+
* detected manifests. Up to 60 dependencies, sorted alphabetically; the
|
|
175
|
+
* runner truncates to keep audit payload sane.
|
|
176
|
+
*/
|
|
177
|
+
dependencies: z.ZodArray<z.ZodString, "many">;
|
|
178
|
+
/**
|
|
179
|
+
* Tier-3 (CALM-relative) deviations the analyzer flagged. Populated by
|
|
180
|
+
* `identify_gaps` after comparison — empty here.
|
|
181
|
+
*/
|
|
182
|
+
deviations: z.ZodArray<z.ZodString, "many">;
|
|
183
|
+
}, "strip", z.ZodTypeAny, {
|
|
184
|
+
endpoints: {
|
|
185
|
+
path: string;
|
|
186
|
+
method: string;
|
|
187
|
+
file: string;
|
|
188
|
+
framework: string;
|
|
189
|
+
}[];
|
|
190
|
+
profile: {
|
|
191
|
+
slug: string;
|
|
192
|
+
cloneSha: string;
|
|
193
|
+
totalFiles: number;
|
|
194
|
+
totalBytes: number;
|
|
195
|
+
byExtension: Record<string, number>;
|
|
196
|
+
languages: string[];
|
|
197
|
+
frameworks: string[];
|
|
198
|
+
manifests: string[];
|
|
199
|
+
};
|
|
200
|
+
modules: {
|
|
201
|
+
name: string;
|
|
202
|
+
layer: "unknown" | "web" | "api" | "data" | "worker" | "shared";
|
|
203
|
+
fileCount: number;
|
|
204
|
+
endpointCount: number;
|
|
205
|
+
}[];
|
|
206
|
+
dependencies: string[];
|
|
207
|
+
deviations: string[];
|
|
208
|
+
}, {
|
|
209
|
+
endpoints: {
|
|
210
|
+
path: string;
|
|
211
|
+
method: string;
|
|
212
|
+
file: string;
|
|
213
|
+
framework: string;
|
|
214
|
+
}[];
|
|
215
|
+
profile: {
|
|
216
|
+
slug: string;
|
|
217
|
+
cloneSha: string;
|
|
218
|
+
totalFiles: number;
|
|
219
|
+
totalBytes: number;
|
|
220
|
+
byExtension: Record<string, number>;
|
|
221
|
+
languages: string[];
|
|
222
|
+
frameworks: string[];
|
|
223
|
+
manifests: string[];
|
|
224
|
+
};
|
|
225
|
+
modules: {
|
|
226
|
+
name: string;
|
|
227
|
+
layer: "unknown" | "web" | "api" | "data" | "worker" | "shared";
|
|
228
|
+
fileCount: number;
|
|
229
|
+
endpointCount: number;
|
|
230
|
+
}[];
|
|
231
|
+
dependencies: string[];
|
|
232
|
+
deviations: string[];
|
|
233
|
+
}>;
|
|
234
|
+
export type ObservedArchitecture = z.infer<typeof ObservedArchitecture>;
|
|
235
|
+
/** A single gap surfaced by identify_gaps. */
|
|
236
|
+
export declare const ArchaeologyGap: z.ZodObject<{
|
|
237
|
+
/** Stable id like "G1", "G2", … assigned in the order signals were detected. */
|
|
238
|
+
id: z.ZodString;
|
|
239
|
+
kind: z.ZodEnum<["missing_module", "orphan_module", "endpoint_not_in_calm", "missing_security_control", "framework_choice_undeclared"]>;
|
|
240
|
+
severity: z.ZodEnum<["HIGH", "MEDIUM", "LOW"]>;
|
|
241
|
+
/** Human-readable summary the synthesis prompt cites. */
|
|
242
|
+
summary: z.ZodString;
|
|
243
|
+
/** Pointers into observed architecture — `OA[<module>]` / `OA[<endpoint>]`. */
|
|
244
|
+
observedEvidence: z.ZodArray<z.ZodString, "many">;
|
|
245
|
+
/** Pointers into mesh CALM — node ids, ADR refs, control ids. */
|
|
246
|
+
meshReferences: z.ZodArray<z.ZodString, "many">;
|
|
247
|
+
}, "strip", z.ZodTypeAny, {
|
|
248
|
+
id: string;
|
|
249
|
+
kind: "missing_module" | "orphan_module" | "endpoint_not_in_calm" | "missing_security_control" | "framework_choice_undeclared";
|
|
250
|
+
severity: "HIGH" | "MEDIUM" | "LOW";
|
|
251
|
+
summary: string;
|
|
252
|
+
observedEvidence: string[];
|
|
253
|
+
meshReferences: string[];
|
|
254
|
+
}, {
|
|
255
|
+
id: string;
|
|
256
|
+
kind: "missing_module" | "orphan_module" | "endpoint_not_in_calm" | "missing_security_control" | "framework_choice_undeclared";
|
|
257
|
+
severity: "HIGH" | "MEDIUM" | "LOW";
|
|
258
|
+
summary: string;
|
|
259
|
+
observedEvidence: string[];
|
|
260
|
+
meshReferences: string[];
|
|
261
|
+
}>;
|
|
262
|
+
export type ArchaeologyGap = z.infer<typeof ArchaeologyGap>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ArchaeologyGap = exports.ObservedArchitecture = exports.RepositoryProfile = exports.Module = exports.Endpoint = exports.ObservedLayer = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* ObservedArchitecture — what analyze_architecture extracts from a cloned
|
|
6
|
+
* target repo (archaeology path).
|
|
7
|
+
*
|
|
8
|
+
* Phase 3a is file-based: no AST parsing, no tree-sitter. We extract what
|
|
9
|
+
* we can from filenames, manifest files, and regex-detected route handlers.
|
|
10
|
+
* Phase 3b will add tree-sitter for deeper symbol-level analysis.
|
|
11
|
+
*
|
|
12
|
+
* The shape mirrors the spec in docs/design/research-and-prd-agents.md
|
|
13
|
+
* §"What `analyze_architecture` extracts" but pares back depth we can't
|
|
14
|
+
* deliver without an AST.
|
|
15
|
+
*/
|
|
16
|
+
const zod_1 = require("zod");
|
|
17
|
+
exports.ObservedLayer = zod_1.z.enum(['api', 'web', 'data', 'worker', 'shared', 'unknown']);
|
|
18
|
+
exports.Endpoint = zod_1.z.object({
|
|
19
|
+
/** HTTP method like "GET" / "POST". */
|
|
20
|
+
method: zod_1.z.string(),
|
|
21
|
+
/** Path template, e.g. "/users/:id". */
|
|
22
|
+
path: zod_1.z.string(),
|
|
23
|
+
/** File the endpoint lives in (relative to repo root). */
|
|
24
|
+
file: zod_1.z.string(),
|
|
25
|
+
/** Framework that surfaced it, e.g. "express" / "fastapi" / "flask" / "spring". */
|
|
26
|
+
framework: zod_1.z.string(),
|
|
27
|
+
});
|
|
28
|
+
exports.Module = zod_1.z.object({
|
|
29
|
+
/** Top-level directory or src/<name> identifier. */
|
|
30
|
+
name: zod_1.z.string(),
|
|
31
|
+
/** Inferred layer per the heuristics in analyze_architecture. */
|
|
32
|
+
layer: exports.ObservedLayer,
|
|
33
|
+
/** File counts that landed in this module (excluding test files). */
|
|
34
|
+
fileCount: zod_1.z.number().int().nonnegative(),
|
|
35
|
+
/** Endpoints declared in this module. */
|
|
36
|
+
endpointCount: zod_1.z.number().int().nonnegative(),
|
|
37
|
+
});
|
|
38
|
+
exports.RepositoryProfile = zod_1.z.object({
|
|
39
|
+
/** owner/repo at the time of clone. */
|
|
40
|
+
slug: zod_1.z.string().regex(/^[\w.-]+\/[\w.-]+$/),
|
|
41
|
+
/** Git SHA of the clone HEAD. */
|
|
42
|
+
cloneSha: zod_1.z.string(),
|
|
43
|
+
/** Total tracked files (skips .git, node_modules, build, dist). */
|
|
44
|
+
totalFiles: zod_1.z.number().int().nonnegative(),
|
|
45
|
+
/** Bytes counted across tracked files. */
|
|
46
|
+
totalBytes: zod_1.z.number().int().nonnegative(),
|
|
47
|
+
/** File counts by extension (sorted desc by count in serialised form). */
|
|
48
|
+
byExtension: zod_1.z.record(zod_1.z.string(), zod_1.z.number().int()),
|
|
49
|
+
/** Detected primary language(s) — derived from extension counts + manifests. */
|
|
50
|
+
languages: zod_1.z.array(zod_1.z.string()),
|
|
51
|
+
/** Detected primary framework(s) (express, fastapi, react, next, vue, …). */
|
|
52
|
+
frameworks: zod_1.z.array(zod_1.z.string()),
|
|
53
|
+
/** Manifest files present (package.json, pyproject.toml, Cargo.toml, …). */
|
|
54
|
+
manifests: zod_1.z.array(zod_1.z.string()),
|
|
55
|
+
});
|
|
56
|
+
exports.ObservedArchitecture = zod_1.z.object({
|
|
57
|
+
profile: exports.RepositoryProfile,
|
|
58
|
+
modules: zod_1.z.array(exports.Module),
|
|
59
|
+
endpoints: zod_1.z.array(exports.Endpoint),
|
|
60
|
+
/**
|
|
61
|
+
* Direct external dependencies (production only, not dev). Source: the
|
|
62
|
+
* detected manifests. Up to 60 dependencies, sorted alphabetically; the
|
|
63
|
+
* runner truncates to keep audit payload sane.
|
|
64
|
+
*/
|
|
65
|
+
dependencies: zod_1.z.array(zod_1.z.string()),
|
|
66
|
+
/**
|
|
67
|
+
* Tier-3 (CALM-relative) deviations the analyzer flagged. Populated by
|
|
68
|
+
* `identify_gaps` after comparison — empty here.
|
|
69
|
+
*/
|
|
70
|
+
deviations: zod_1.z.array(zod_1.z.string()),
|
|
71
|
+
});
|
|
72
|
+
/** A single gap surfaced by identify_gaps. */
|
|
73
|
+
exports.ArchaeologyGap = zod_1.z.object({
|
|
74
|
+
/** Stable id like "G1", "G2", … assigned in the order signals were detected. */
|
|
75
|
+
id: zod_1.z.string().regex(/^G\d+$/),
|
|
76
|
+
kind: zod_1.z.enum([
|
|
77
|
+
'missing_module', // CALM mentions X; code has no module
|
|
78
|
+
'orphan_module', // code has Y; no matching CALM node
|
|
79
|
+
'endpoint_not_in_calm', // observed endpoint isn't represented as a CALM node
|
|
80
|
+
'missing_security_control', // CALM mentions a control; nothing in code suggests it
|
|
81
|
+
'framework_choice_undeclared', // code uses a framework not mentioned in mesh decisions
|
|
82
|
+
]),
|
|
83
|
+
severity: zod_1.z.enum(['HIGH', 'MEDIUM', 'LOW']),
|
|
84
|
+
/** Human-readable summary the synthesis prompt cites. */
|
|
85
|
+
summary: zod_1.z.string(),
|
|
86
|
+
/** Pointers into observed architecture — `OA[<module>]` / `OA[<endpoint>]`. */
|
|
87
|
+
observedEvidence: zod_1.z.array(zod_1.z.string()),
|
|
88
|
+
/** Pointers into mesh CALM — node ids, ADR refs, control ids. */
|
|
89
|
+
meshReferences: zod_1.z.array(zod_1.z.string()),
|
|
90
|
+
});
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PrdBrief — validated input to the PRD pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Produced when the PRD agent is triggered: either by a merged research PR
|
|
5
|
+
* (via label-on-merge.yml creating a prd-pending issue), by a prd-request
|
|
6
|
+
* label, or by workflow_dispatch.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
export declare const PrdBrief: z.ZodObject<{
|
|
10
|
+
/** Where the upstream research lives: a merged PR url OR a relative doc path. */
|
|
11
|
+
research_source: z.ZodUnion<[z.ZodObject<{
|
|
12
|
+
kind: z.ZodLiteral<"pr">;
|
|
13
|
+
url: z.ZodString;
|
|
14
|
+
}, "strip", z.ZodTypeAny, {
|
|
15
|
+
kind: "pr";
|
|
16
|
+
url: string;
|
|
17
|
+
}, {
|
|
18
|
+
kind: "pr";
|
|
19
|
+
url: string;
|
|
20
|
+
}>, z.ZodObject<{
|
|
21
|
+
kind: z.ZodLiteral<"path">;
|
|
22
|
+
relative_path: z.ZodString;
|
|
23
|
+
}, "strip", z.ZodTypeAny, {
|
|
24
|
+
kind: "path";
|
|
25
|
+
relative_path: string;
|
|
26
|
+
}, {
|
|
27
|
+
kind: "path";
|
|
28
|
+
relative_path: string;
|
|
29
|
+
}>]>;
|
|
30
|
+
scope: z.ZodObject<{
|
|
31
|
+
level: z.ZodEnum<["platform", "bar"]>;
|
|
32
|
+
/** Required: platform slug (e.g. `imdb-lite`) or BAR id (e.g. `APP-IMDB-002`). */
|
|
33
|
+
id: z.ZodString;
|
|
34
|
+
}, "strip", z.ZodTypeAny, {
|
|
35
|
+
level: "platform" | "bar";
|
|
36
|
+
id: string;
|
|
37
|
+
}, {
|
|
38
|
+
level: "platform" | "bar";
|
|
39
|
+
id: string;
|
|
40
|
+
}>;
|
|
41
|
+
mode: z.ZodDefault<z.ZodEnum<["shallow", "deep"]>>;
|
|
42
|
+
grounding: z.ZodDefault<z.ZodEnum<["strict", "default", "lenient"]>>;
|
|
43
|
+
/** Minimum expert score (0.5-1.0) required to publish without iterating. */
|
|
44
|
+
grounding_threshold: z.ZodDefault<z.ZodNumber>;
|
|
45
|
+
max_iterations: z.ZodDefault<z.ZodNumber>;
|
|
46
|
+
guardrails: z.ZodDefault<z.ZodEnum<["strict", "default", "lenient"]>>;
|
|
47
|
+
llm_provider: z.ZodDefault<z.ZodEnum<["anthropic", "openai", "azure-openai", "github-models"]>>;
|
|
48
|
+
cost_cap_tokens: z.ZodDefault<z.ZodNumber>;
|
|
49
|
+
trigger: z.ZodObject<{
|
|
50
|
+
kind: z.ZodEnum<["workflow_dispatch", "issue_label", "merged_research_pr", "local_dev"]>;
|
|
51
|
+
issue_number: z.ZodOptional<z.ZodNumber>;
|
|
52
|
+
actor: z.ZodOptional<z.ZodString>;
|
|
53
|
+
}, "strip", z.ZodTypeAny, {
|
|
54
|
+
kind: "workflow_dispatch" | "issue_label" | "local_dev" | "merged_research_pr";
|
|
55
|
+
issue_number?: number | undefined;
|
|
56
|
+
actor?: string | undefined;
|
|
57
|
+
}, {
|
|
58
|
+
kind: "workflow_dispatch" | "issue_label" | "local_dev" | "merged_research_pr";
|
|
59
|
+
issue_number?: number | undefined;
|
|
60
|
+
actor?: string | undefined;
|
|
61
|
+
}>;
|
|
62
|
+
}, "strip", z.ZodTypeAny, {
|
|
63
|
+
scope: {
|
|
64
|
+
level: "platform" | "bar";
|
|
65
|
+
id: string;
|
|
66
|
+
};
|
|
67
|
+
guardrails: "strict" | "default" | "lenient";
|
|
68
|
+
llm_provider: "anthropic" | "openai" | "azure-openai" | "github-models";
|
|
69
|
+
cost_cap_tokens: number;
|
|
70
|
+
trigger: {
|
|
71
|
+
kind: "workflow_dispatch" | "issue_label" | "local_dev" | "merged_research_pr";
|
|
72
|
+
issue_number?: number | undefined;
|
|
73
|
+
actor?: string | undefined;
|
|
74
|
+
};
|
|
75
|
+
research_source: {
|
|
76
|
+
kind: "pr";
|
|
77
|
+
url: string;
|
|
78
|
+
} | {
|
|
79
|
+
kind: "path";
|
|
80
|
+
relative_path: string;
|
|
81
|
+
};
|
|
82
|
+
mode: "shallow" | "deep";
|
|
83
|
+
grounding: "strict" | "default" | "lenient";
|
|
84
|
+
grounding_threshold: number;
|
|
85
|
+
max_iterations: number;
|
|
86
|
+
}, {
|
|
87
|
+
scope: {
|
|
88
|
+
level: "platform" | "bar";
|
|
89
|
+
id: string;
|
|
90
|
+
};
|
|
91
|
+
trigger: {
|
|
92
|
+
kind: "workflow_dispatch" | "issue_label" | "local_dev" | "merged_research_pr";
|
|
93
|
+
issue_number?: number | undefined;
|
|
94
|
+
actor?: string | undefined;
|
|
95
|
+
};
|
|
96
|
+
research_source: {
|
|
97
|
+
kind: "pr";
|
|
98
|
+
url: string;
|
|
99
|
+
} | {
|
|
100
|
+
kind: "path";
|
|
101
|
+
relative_path: string;
|
|
102
|
+
};
|
|
103
|
+
guardrails?: "strict" | "default" | "lenient" | undefined;
|
|
104
|
+
llm_provider?: "anthropic" | "openai" | "azure-openai" | "github-models" | undefined;
|
|
105
|
+
cost_cap_tokens?: number | undefined;
|
|
106
|
+
mode?: "shallow" | "deep" | undefined;
|
|
107
|
+
grounding?: "strict" | "default" | "lenient" | undefined;
|
|
108
|
+
grounding_threshold?: number | undefined;
|
|
109
|
+
max_iterations?: number | undefined;
|
|
110
|
+
}>;
|
|
111
|
+
export type PrdBrief = z.infer<typeof PrdBrief>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PrdBrief = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* PrdBrief — validated input to the PRD pipeline.
|
|
6
|
+
*
|
|
7
|
+
* Produced when the PRD agent is triggered: either by a merged research PR
|
|
8
|
+
* (via label-on-merge.yml creating a prd-pending issue), by a prd-request
|
|
9
|
+
* label, or by workflow_dispatch.
|
|
10
|
+
*/
|
|
11
|
+
const zod_1 = require("zod");
|
|
12
|
+
const primitives_1 = require("./primitives");
|
|
13
|
+
exports.PrdBrief = zod_1.z.object({
|
|
14
|
+
/** Where the upstream research lives: a merged PR url OR a relative doc path. */
|
|
15
|
+
research_source: zod_1.z.union([
|
|
16
|
+
zod_1.z.object({ kind: zod_1.z.literal('pr'), url: zod_1.z.string().url() }),
|
|
17
|
+
zod_1.z.object({ kind: zod_1.z.literal('path'), relative_path: zod_1.z.string().min(1) }),
|
|
18
|
+
]),
|
|
19
|
+
scope: zod_1.z.object({
|
|
20
|
+
level: primitives_1.ScopeLevel,
|
|
21
|
+
/** Required: platform slug (e.g. `imdb-lite`) or BAR id (e.g. `APP-IMDB-002`). */
|
|
22
|
+
id: zod_1.z.string().min(1),
|
|
23
|
+
}),
|
|
24
|
+
mode: primitives_1.PrdMode.default('deep'),
|
|
25
|
+
grounding: primitives_1.GroundingMode.default('default'),
|
|
26
|
+
/** Minimum expert score (0.5-1.0) required to publish without iterating. */
|
|
27
|
+
grounding_threshold: zod_1.z.number().min(0.5).max(1).default(0.85),
|
|
28
|
+
max_iterations: zod_1.z.number().int().min(1).max(5).default(3),
|
|
29
|
+
guardrails: primitives_1.GuardrailMode.default('default'),
|
|
30
|
+
llm_provider: primitives_1.LlmProvider.default('anthropic'),
|
|
31
|
+
cost_cap_tokens: zod_1.z.number().int().positive().default(200_000),
|
|
32
|
+
trigger: zod_1.z.object({
|
|
33
|
+
kind: zod_1.z.enum(['workflow_dispatch', 'issue_label', 'merged_research_pr', 'local_dev']),
|
|
34
|
+
issue_number: zod_1.z.number().int().optional(),
|
|
35
|
+
actor: zod_1.z.string().optional(),
|
|
36
|
+
}),
|
|
37
|
+
});
|