@ramplab/generator 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +23 -0
- package/dist/agentSdkRunner.d.ts +64 -0
- package/dist/agentSdkRunner.d.ts.map +1 -0
- package/dist/agentSdkRunner.js +158 -0
- package/dist/agentSdkRunner.js.map +1 -0
- package/dist/assembleStage.d.ts +41 -0
- package/dist/assembleStage.d.ts.map +1 -0
- package/dist/assembleStage.js +33 -0
- package/dist/assembleStage.js.map +1 -0
- package/dist/authorStage.d.ts +123 -0
- package/dist/authorStage.d.ts.map +1 -0
- package/dist/authorStage.js +284 -0
- package/dist/authorStage.js.map +1 -0
- package/dist/cloneRepo.d.ts +72 -0
- package/dist/cloneRepo.d.ts.map +1 -0
- package/dist/cloneRepo.js +104 -0
- package/dist/cloneRepo.js.map +1 -0
- package/dist/flagship.d.ts +62 -0
- package/dist/flagship.d.ts.map +1 -0
- package/dist/flagship.js +216 -0
- package/dist/flagship.js.map +1 -0
- package/dist/generateLab.d.ts +151 -0
- package/dist/generateLab.d.ts.map +1 -0
- package/dist/generateLab.js +291 -0
- package/dist/generateLab.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/intake.d.ts +31 -0
- package/dist/intake.d.ts.map +1 -0
- package/dist/intake.js +45 -0
- package/dist/intake.js.map +1 -0
- package/dist/live.d.ts +2 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +213 -0
- package/dist/live.js.map +1 -0
- package/dist/mapStage.d.ts +84 -0
- package/dist/mapStage.d.ts.map +1 -0
- package/dist/mapStage.js +241 -0
- package/dist/mapStage.js.map +1 -0
- package/dist/pass1.d.ts +85 -0
- package/dist/pass1.d.ts.map +1 -0
- package/dist/pass1.js +81 -0
- package/dist/pass1.js.map +1 -0
- package/dist/pipeline.d.ts +73 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +70 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/planStage.d.ts +141 -0
- package/dist/planStage.d.ts.map +1 -0
- package/dist/planStage.js +275 -0
- package/dist/planStage.js.map +1 -0
- package/dist/progress.d.ts +45 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +2 -0
- package/dist/progress.js.map +1 -0
- package/dist/repoCommit.d.ts +41 -0
- package/dist/repoCommit.d.ts.map +1 -0
- package/dist/repoCommit.js +84 -0
- package/dist/repoCommit.js.map +1 -0
- package/dist/repoSize.d.ts +23 -0
- package/dist/repoSize.d.ts.map +1 -0
- package/dist/repoSize.js +74 -0
- package/dist/repoSize.js.map +1 -0
- package/dist/resolveAnchors.d.ts +142 -0
- package/dist/resolveAnchors.d.ts.map +1 -0
- package/dist/resolveAnchors.js +242 -0
- package/dist/resolveAnchors.js.map +1 -0
- package/dist/verifyStage.d.ts +150 -0
- package/dist/verifyStage.d.ts.map +1 -0
- package/dist/verifyStage.js +461 -0
- package/dist/verifyStage.js.map +1 -0
- package/package.json +47 -0
package/dist/flagship.js
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { hasIntakeAnswers } from './intake.js';
|
|
2
|
+
import { LANDING_MODULE_ID, plannedModuleSchema, } from './planStage.js';
|
|
3
|
+
/** Raised when the map offers nothing teachable to author. */
|
|
4
|
+
export class FlagshipSelectionError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(`Flagship selection failed: ${message}`);
|
|
7
|
+
this.name = 'FlagshipSelectionError';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export function selectFlagshipModule(mapSpec, intake, traceCandidates) {
|
|
11
|
+
const fromTrace = selectTraceFlagship(traceCandidates, intake);
|
|
12
|
+
if (fromTrace !== undefined)
|
|
13
|
+
return fromTrace;
|
|
14
|
+
return selectCentralityFlagship(mapSpec, intake);
|
|
15
|
+
}
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Trace-based selection (the primary path)
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
/**
|
|
20
|
+
* Select the flagship trace from the map's candidate actions, or `undefined`
|
|
21
|
+
* when there are no candidates (callers fall back to centrality). Exported
|
|
22
|
+
* separately because pass 2 uses it too: the plan stage pins its module 1 to
|
|
23
|
+
* the same selection pass 1 previewed.
|
|
24
|
+
*/
|
|
25
|
+
export function selectTraceFlagship(traceCandidates, intake) {
|
|
26
|
+
if (traceCandidates === undefined || traceCandidates.length === 0)
|
|
27
|
+
return undefined;
|
|
28
|
+
const searchable = traceCandidates.map((candidate) => ({
|
|
29
|
+
candidate,
|
|
30
|
+
searchText: [
|
|
31
|
+
candidate.id,
|
|
32
|
+
candidate.action,
|
|
33
|
+
candidate.description ?? '',
|
|
34
|
+
...candidate.keyFiles,
|
|
35
|
+
]
|
|
36
|
+
.join(' ')
|
|
37
|
+
.toLowerCase(),
|
|
38
|
+
}));
|
|
39
|
+
const fromIntake = matchIntakeHints(searchable, intake);
|
|
40
|
+
if (fromIntake !== undefined) {
|
|
41
|
+
return toTraceSelection(fromIntake.matched.candidate, 'trace-intake', intake, fromIntake.hint);
|
|
42
|
+
}
|
|
43
|
+
// Map order is the representativeness ranking (see the map prompt).
|
|
44
|
+
const first = traceCandidates[0];
|
|
45
|
+
return toTraceSelection(first, 'trace', intake);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Ids owned by other parts of the pipeline: the map stage's overview module
|
|
49
|
+
* and the plan stage's mandated landing module. A colliding candidate id is
|
|
50
|
+
* suffixed rather than rejected.
|
|
51
|
+
*/
|
|
52
|
+
function traceModuleId(candidateId) {
|
|
53
|
+
return candidateId === 'repo-overview' || candidateId === LANDING_MODULE_ID
|
|
54
|
+
? `${candidateId}-trace`
|
|
55
|
+
: candidateId;
|
|
56
|
+
}
|
|
57
|
+
function toTraceSelection(candidate, basis, intake, matchedHint) {
|
|
58
|
+
const focusParts = [
|
|
59
|
+
`This module is the lab's opening trace: follow ONE real user action end to ` +
|
|
60
|
+
`end through the code. The action: ${candidate.action}.`,
|
|
61
|
+
];
|
|
62
|
+
if (candidate.description !== undefined) {
|
|
63
|
+
focusParts.push(candidate.description);
|
|
64
|
+
}
|
|
65
|
+
focusParts.push(`Start at the entry point and walk the exact path the action takes — file by ` +
|
|
66
|
+
`file, layer by layer — teaching each mechanism concretely as the action ` +
|
|
67
|
+
`reaches it, before naming any abstraction it exemplifies.`, `Widget order is part of the pedagogy: the module MUST open with a ` +
|
|
68
|
+
`code-walkthrough stepping through this action's entry point — the learner's ` +
|
|
69
|
+
`first contact is real code being walked, never a diagram. A system-map of ` +
|
|
70
|
+
`the path may appear only after the walkthroughs, as a recap of ground ` +
|
|
71
|
+
`already covered.`, basis === 'trace-intake'
|
|
72
|
+
? `The onboarding lead's intake singled this area out ("${matchedHint ?? ''}").`
|
|
73
|
+
: `The map stage judged this the most representative front-door action of this codebase.`);
|
|
74
|
+
const intakeLine = renderIntakeFocusLine(intake);
|
|
75
|
+
if (intakeLine !== undefined)
|
|
76
|
+
focusParts.push(intakeLine);
|
|
77
|
+
const plannedModule = plannedModuleSchema.parse({
|
|
78
|
+
id: traceModuleId(candidate.id),
|
|
79
|
+
title: `End to end: ${candidate.action}`,
|
|
80
|
+
focus: focusParts.join(' '),
|
|
81
|
+
keyFiles: candidate.keyFiles,
|
|
82
|
+
assumes: [],
|
|
83
|
+
teaches: [
|
|
84
|
+
`how "${candidate.action}" flows end to end through this codebase`,
|
|
85
|
+
'the files and layers along that path, and why each exists',
|
|
86
|
+
],
|
|
87
|
+
});
|
|
88
|
+
return {
|
|
89
|
+
basis,
|
|
90
|
+
traceAction: candidate.action,
|
|
91
|
+
...(matchedHint !== undefined ? { matchedHint } : {}),
|
|
92
|
+
plannedModule,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function selectCentralityFlagship(mapSpec, intake) {
|
|
96
|
+
const systemMap = findSystemMap(mapSpec);
|
|
97
|
+
if (systemMap === undefined) {
|
|
98
|
+
throw new FlagshipSelectionError('the map spec contains no system-map widget.');
|
|
99
|
+
}
|
|
100
|
+
const candidates = systemMap.nodes
|
|
101
|
+
.map((node) => toNodeCandidate(node, systemMap.edges))
|
|
102
|
+
.filter((candidate) => candidate.keyFiles.length > 0);
|
|
103
|
+
if (candidates.length === 0) {
|
|
104
|
+
throw new FlagshipSelectionError('no system-map node carries an anchor (directly or via an incident edge), ' +
|
|
105
|
+
'so there are no key files to author from.');
|
|
106
|
+
}
|
|
107
|
+
const fromIntake = matchIntakeHints(candidates, intake);
|
|
108
|
+
if (fromIntake !== undefined) {
|
|
109
|
+
return toNodeSelection(fromIntake.matched, 'intake', intake, fromIntake.hint);
|
|
110
|
+
}
|
|
111
|
+
let best = candidates[0];
|
|
112
|
+
for (const candidate of candidates) {
|
|
113
|
+
if (candidate.degree > best.degree)
|
|
114
|
+
best = candidate; // ties keep map order
|
|
115
|
+
}
|
|
116
|
+
return toNodeSelection(best, 'centrality', intake);
|
|
117
|
+
}
|
|
118
|
+
function findSystemMap(mapSpec) {
|
|
119
|
+
for (const module of mapSpec.base.modules) {
|
|
120
|
+
for (const widget of module.widgets) {
|
|
121
|
+
if (widget.type === 'system-map')
|
|
122
|
+
return widget;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
function toNodeCandidate(node, edges) {
|
|
128
|
+
const incident = edges.filter((edge) => edge.from === node.id || edge.to === node.id);
|
|
129
|
+
const keyFiles = [
|
|
130
|
+
...new Set([...(node.anchors ?? []), ...incident.flatMap((edge) => edge.anchors ?? [])].map((anchor) => anchor.file)),
|
|
131
|
+
];
|
|
132
|
+
const searchText = [node.id, node.label, node.description ?? '', ...keyFiles]
|
|
133
|
+
.join(' ')
|
|
134
|
+
.toLowerCase();
|
|
135
|
+
return { node, degree: incident.length, keyFiles, searchText };
|
|
136
|
+
}
|
|
137
|
+
/** The map stage owns `repo-overview`; a colliding node id gets suffixed. */
|
|
138
|
+
function flagshipModuleId(nodeId) {
|
|
139
|
+
return nodeId === 'repo-overview' ? 'repo-overview-flagship' : nodeId;
|
|
140
|
+
}
|
|
141
|
+
function toNodeSelection(candidate, basis, intake, matchedHint) {
|
|
142
|
+
const { node, degree, keyFiles } = candidate;
|
|
143
|
+
const focusParts = [
|
|
144
|
+
`Teach "${node.label}" as this repository's flagship subsystem — the single ` +
|
|
145
|
+
`deepest first look a new engineer gets.`,
|
|
146
|
+
];
|
|
147
|
+
if (node.description !== undefined) {
|
|
148
|
+
focusParts.push(node.description);
|
|
149
|
+
}
|
|
150
|
+
focusParts.push(basis === 'intake'
|
|
151
|
+
? `The onboarding lead's intake singled this area out ("${matchedHint ?? ''}").`
|
|
152
|
+
: `It was chosen by subsystem centrality: ${degree} edge${degree === 1 ? '' : 's'} ` +
|
|
153
|
+
`of the system map touch it.`);
|
|
154
|
+
const intakeLine = renderIntakeFocusLine(intake);
|
|
155
|
+
if (intakeLine !== undefined)
|
|
156
|
+
focusParts.push(intakeLine);
|
|
157
|
+
const plannedModule = plannedModuleSchema.parse({
|
|
158
|
+
id: flagshipModuleId(node.id),
|
|
159
|
+
title: node.label,
|
|
160
|
+
focus: focusParts.join(' '),
|
|
161
|
+
keyFiles,
|
|
162
|
+
assumes: [],
|
|
163
|
+
teaches: [`how the "${node.label}" subsystem works and its role in the system`],
|
|
164
|
+
});
|
|
165
|
+
return {
|
|
166
|
+
basis,
|
|
167
|
+
nodeId: node.id,
|
|
168
|
+
degree,
|
|
169
|
+
...(matchedHint !== undefined ? { matchedHint } : {}),
|
|
170
|
+
plannedModule,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
// Shared intake-hint matching
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
/**
|
|
177
|
+
* A hint matches an item when any of its words (4+ characters, so "the"/"a"
|
|
178
|
+
* never match) appears in the item's search text. Hints are scanned in
|
|
179
|
+
* intake priority order; items in map order.
|
|
180
|
+
*/
|
|
181
|
+
function matchIntakeHints(items, intake) {
|
|
182
|
+
if (!hasIntakeAnswers(intake))
|
|
183
|
+
return undefined;
|
|
184
|
+
const hints = [...(intake.weekOneMastery ?? []), ...(intake.activeDevelopment ?? [])];
|
|
185
|
+
for (const hint of hints) {
|
|
186
|
+
const words = hint
|
|
187
|
+
.toLowerCase()
|
|
188
|
+
.split(/[^a-z0-9]+/)
|
|
189
|
+
.filter((word) => word.length >= 4);
|
|
190
|
+
if (words.length === 0)
|
|
191
|
+
continue;
|
|
192
|
+
for (const matched of items) {
|
|
193
|
+
if (words.some((word) => matched.searchText.includes(word))) {
|
|
194
|
+
return { matched, hint };
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return undefined;
|
|
199
|
+
}
|
|
200
|
+
/** The intake summary appended to every flagship brief, when present. */
|
|
201
|
+
function renderIntakeFocusLine(intake) {
|
|
202
|
+
if (!hasIntakeAnswers(intake))
|
|
203
|
+
return undefined;
|
|
204
|
+
const inline = [];
|
|
205
|
+
if ((intake.weekOneMastery?.length ?? 0) > 0) {
|
|
206
|
+
inline.push(`week-one hires must master: ${intake.weekOneMastery.join('; ')}`);
|
|
207
|
+
}
|
|
208
|
+
if ((intake.activeDevelopment?.length ?? 0) > 0) {
|
|
209
|
+
inline.push(`under active development: ${intake.activeDevelopment.join('; ')}`);
|
|
210
|
+
}
|
|
211
|
+
if ((intake.gotchas?.length ?? 0) > 0) {
|
|
212
|
+
inline.push(`known gotchas to call out: ${intake.gotchas.join('; ')}`);
|
|
213
|
+
}
|
|
214
|
+
return `Lead intake — ${inline.join('. ')}.`;
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=flagship.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flagship.js","sourceRoot":"","sources":["../src/flagship.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import type { LabSpec } from '@ramplab/spec';
|
|
2
|
+
import type { LeadIntake } from './intake.js';
|
|
3
|
+
import { type MapStageResult } from './mapStage.js';
|
|
4
|
+
import { type GenerationStageName, type ModelRunner, type StageModelConfig } from './pipeline.js';
|
|
5
|
+
import { type CurriculumBudget, type CurriculumPlan, type PlannedModule } from './planStage.js';
|
|
6
|
+
import type { ProgressCallback } from './progress.js';
|
|
7
|
+
import { type ResolutionPolicy, type ResolutionReport } from './resolveAnchors.js';
|
|
8
|
+
import { type VerificationReport } from './verifyStage.js';
|
|
9
|
+
/**
|
|
10
|
+
* `generateLab(repoDir, config)` — the generator entry point (PLAN.md §4).
|
|
11
|
+
*
|
|
12
|
+
* Two modes on the same config/runner plumbing:
|
|
13
|
+
*
|
|
14
|
+
* - **Tracer (default, `full` unset/false):** the map stage only — agent
|
|
15
|
+
* explores the repo (read-only), emits a system-map widget plus one module
|
|
16
|
+
* of anchored callouts. Predates the two-pass runtime; for the streamed
|
|
17
|
+
* pass-1 preview (map + flagship module) use `generateLabPass1` in
|
|
18
|
+
* `pass1.ts`. The tracer emits no progress events.
|
|
19
|
+
* - **Full pipeline (`full: true`) — pass 2 of the two-pass runtime:**
|
|
20
|
+
* map → curriculum plan → author (parallel per planned module,
|
|
21
|
+
* concurrency-capped) → assemble → verify. The plan stage plans a
|
|
22
|
+
* dependency-ordered journey (issue #18) within `config.budget` (a config
|
|
23
|
+
* cap, never repo size), steered by the lead's `config.intake` answers
|
|
24
|
+
* when present: module 1 is pinned to the flagship trace when the map
|
|
25
|
+
* proposed candidates, every module carries an `assumes`/`teaches`
|
|
26
|
+
* learner-state ledger, and the final module is always "your first
|
|
27
|
+
* contribution". Each planned module is authored by its own agent call
|
|
28
|
+
* (with its ledger slice and the style contract in the prompt); assembly
|
|
29
|
+
* merges everything into one spec, revalidates, and runs anchor resolution
|
|
30
|
+
* per policy; the verify stage then adversarially checks every surviving
|
|
31
|
+
* claim against its anchored code and drops what it cannot verify
|
|
32
|
+
* (PLAN.md §3).
|
|
33
|
+
*
|
|
34
|
+
* **Map reuse (`config.mapResult`):** pass 2 normally runs right after pass 1
|
|
35
|
+
* on the same repo snapshot, so callers hand pass 1's `mapResult` in and the
|
|
36
|
+
* map stage is skipped entirely — no second map agent call. The reused map's
|
|
37
|
+
* cost is NOT re-counted in this run's `costUsd` (it was paid in pass 1).
|
|
38
|
+
* The pass-1 **flagship module is deliberately re-authored, not reused**:
|
|
39
|
+
* the plan stage owns pass 2's curriculum (ids, ordering, briefs), and
|
|
40
|
+
* splicing a module authored against pass 1's ad-hoc brief into it would
|
|
41
|
+
* make the draft's shape depend on which pass wrote which module. Pass 1 is
|
|
42
|
+
* a preview; pass 2 is the canonical draft.
|
|
43
|
+
*
|
|
44
|
+
* **Progress (`config.onProgress`):** full-pipeline runs emit typed events
|
|
45
|
+
* (see `progress.ts`) tagged `pass: 'pass2'` — stage boundaries,
|
|
46
|
+
* per-module authoring, and `spec-updated` snapshots that are always valid
|
|
47
|
+
* and anchor-resolved, so a caller can render each one as it lands.
|
|
48
|
+
*
|
|
49
|
+
* Zero infra assumptions: the input is a plain local directory. No cloning,
|
|
50
|
+
* no network beyond the model API (and none at all with an injected fake
|
|
51
|
+
* runner).
|
|
52
|
+
*/
|
|
53
|
+
export interface GenerateLabConfig {
|
|
54
|
+
/**
|
|
55
|
+
* Run the full pipeline (map → plan → author → assemble → verify) instead
|
|
56
|
+
* of the map-only tracer.
|
|
57
|
+
* @default false
|
|
58
|
+
*/
|
|
59
|
+
full?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Per-stage model map. Every stage defaults to `claude-sonnet-5`;
|
|
62
|
+
* overrides are honored per stage (PLAN.md §10).
|
|
63
|
+
*/
|
|
64
|
+
models?: StageModelConfig;
|
|
65
|
+
/**
|
|
66
|
+
* Curriculum budget for the plan stage (full pipeline only): max module
|
|
67
|
+
* count and scope hints. Caps lab scope by config, not repo size.
|
|
68
|
+
*/
|
|
69
|
+
budget?: CurriculumBudget;
|
|
70
|
+
/**
|
|
71
|
+
* The lead's 2-minute intake (PLAN.md §4 curation loop). Threaded into the
|
|
72
|
+
* curriculum-plan prompt so the answers steer module selection/ordering,
|
|
73
|
+
* and into pass 1's flagship choice (see `flagship.ts`).
|
|
74
|
+
*/
|
|
75
|
+
intake?: LeadIntake;
|
|
76
|
+
/**
|
|
77
|
+
* Progress-event callback — the streaming seam (see `progress.ts`).
|
|
78
|
+
* Full-pipeline runs emit `pass: 'pass2'` events; the tracer emits none.
|
|
79
|
+
*/
|
|
80
|
+
onProgress?: ProgressCallback;
|
|
81
|
+
/**
|
|
82
|
+
* A previous map-stage result (typically pass 1's `result.mapResult`).
|
|
83
|
+
* When present, the map stage is skipped and this output is used verbatim;
|
|
84
|
+
* its cost is not re-counted. Full pipeline only.
|
|
85
|
+
*/
|
|
86
|
+
mapResult?: MapStageResult;
|
|
87
|
+
/**
|
|
88
|
+
* Millisecond clock for timing measurements, injectable for tests.
|
|
89
|
+
* Only the live path should rely on the `Date.now` default.
|
|
90
|
+
* @default Date.now
|
|
91
|
+
*/
|
|
92
|
+
clock?: () => number;
|
|
93
|
+
/**
|
|
94
|
+
* Max authoring agents in flight at once (full pipeline only).
|
|
95
|
+
* @default 4
|
|
96
|
+
*/
|
|
97
|
+
concurrency?: number;
|
|
98
|
+
/**
|
|
99
|
+
* What to do with teachable units whose anchors fail to resolve:
|
|
100
|
+
* `drop` (default) removes them; `flag` keeps them and only reports.
|
|
101
|
+
*/
|
|
102
|
+
resolutionPolicy?: ResolutionPolicy;
|
|
103
|
+
/**
|
|
104
|
+
* The agent-invocation boundary. Defaults to the real Claude Agent SDK
|
|
105
|
+
* runner; tests inject a fake so CI never makes live API calls.
|
|
106
|
+
*/
|
|
107
|
+
runner?: ModelRunner;
|
|
108
|
+
/**
|
|
109
|
+
* Bounded retries per stage (and per authored module) when the model's
|
|
110
|
+
* output is schema-invalid.
|
|
111
|
+
* @default 1
|
|
112
|
+
*/
|
|
113
|
+
maxRetries?: number;
|
|
114
|
+
/** Lab id override; defaults to a slug of the repo directory name. */
|
|
115
|
+
labId?: string;
|
|
116
|
+
}
|
|
117
|
+
export interface GenerateLabResult {
|
|
118
|
+
/** The validated, anchor-resolved lab spec. */
|
|
119
|
+
spec: LabSpec;
|
|
120
|
+
/** Full anchor-resolution report (what resolved, dropped, or flagged). */
|
|
121
|
+
resolution: ResolutionReport;
|
|
122
|
+
/** The fully-resolved per-stage model map used for this run. */
|
|
123
|
+
models: Record<GenerationStageName, string>;
|
|
124
|
+
/** Total model cost in USD across all stages, when the runner reports cost. */
|
|
125
|
+
costUsd: number | undefined;
|
|
126
|
+
/** Map-stage attempts (1 = first output was already valid). */
|
|
127
|
+
attempts: number;
|
|
128
|
+
/** The curriculum plan, present only on full-pipeline runs. */
|
|
129
|
+
plan?: CurriculumPlan;
|
|
130
|
+
/** Per-module authoring attempts, present only on full-pipeline runs. */
|
|
131
|
+
authorAttempts?: Record<string, number>;
|
|
132
|
+
/**
|
|
133
|
+
* Adversarial verification report (per-claim verdicts, pass rate, drops),
|
|
134
|
+
* present only on full-pipeline runs.
|
|
135
|
+
*/
|
|
136
|
+
verification?: VerificationReport;
|
|
137
|
+
/** Per-module verifier attempts, present only on full-pipeline runs. */
|
|
138
|
+
verifyAttempts?: Record<string, number>;
|
|
139
|
+
}
|
|
140
|
+
export declare function generateLab(repoDir: string, config?: GenerateLabConfig): Promise<GenerateLabResult>;
|
|
141
|
+
/** The map stage's zoom-out chapter — a stable id learner progress keys off. */
|
|
142
|
+
export declare const OVERVIEW_MODULE_ID = "repo-overview";
|
|
143
|
+
/**
|
|
144
|
+
* Build the planned-module brief for the zoom-out chapter: what the reader
|
|
145
|
+
* already walked (the flagship trace's `teaches`), and what this chapter owes
|
|
146
|
+
* them. Exported for tests — the brief IS the fix, so it is worth pinning.
|
|
147
|
+
*/
|
|
148
|
+
export declare function plannedOverviewModule(mapSpec: LabSpec, plan: CurriculumPlan): PlannedModule | undefined;
|
|
149
|
+
export declare function sumCosts(...costs: (number | undefined)[]): number | undefined;
|
|
150
|
+
export declare function assertDirectory(repoDir: string): void;
|
|
151
|
+
//# sourceMappingURL=generateLab.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateLab.d.ts","sourceRoot":"","sources":["../src/generateLab.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAK7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAe,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B;;;OAGG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B;;;;OAIG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;;;OAGG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B;;;;OAIG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,+CAA+C;IAC/C,IAAI,EAAE,OAAO,CAAC;IACd,0EAA0E;IAC1E,UAAU,EAAE,gBAAgB,CAAC;IAC7B,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;IAC5C,+EAA+E;IAC/E,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC;;;OAGG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,wEAAwE;IACxE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,iBAAsB,GAC7B,OAAO,CAAC,iBAAiB,CAAC,CAsM5B;AAED,gFAAgF;AAChF,eAAO,MAAM,kBAAkB,kBAAkB,CAAC;AAkBlD;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,cAAc,GACnB,aAAa,GAAG,SAAS,CAkC3B;AAyDD,wBAAgB,QAAQ,CAAC,GAAG,KAAK,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,GAAG,MAAM,GAAG,SAAS,CAQ7E;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAUrD"}
|