truecourse 0.7.0-next.1 → 0.7.0-next.2
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/README.md +23 -0
- package/cli.mjs +311 -123
- package/package.json +1 -1
- package/public/assets/{index-BR55uq7e.js → index-B4R8yF4j.js} +101 -101
- package/public/index.html +1 -1
- package/server.mjs +302 -123
package/server.mjs
CHANGED
|
@@ -28079,7 +28079,7 @@ function parseBlockedOnCapabilities(reason) {
|
|
|
28079
28079
|
return [];
|
|
28080
28080
|
return m[1].split(",").map((s) => s.trim()).filter(Boolean);
|
|
28081
28081
|
}
|
|
28082
|
-
var GuardWrittenScenarioSchema, GuardCoverageGapKindSchema, GuardCoverageGapSchema, GuardBirthFindingSchema, GuardGenerateErrorSchema, GuardExtractionFailureSchema, GuardOrphanedSectionSchema, GuardRecipeReportSchema, GuardGenerateUsageSchema, GuardGenerateReportSchema;
|
|
28082
|
+
var GuardWrittenScenarioSchema, GuardCoverageGapKindSchema, GuardCoverageGapSchema, GuardBirthFindingSchema, GuardGenerateErrorSchema, GuardEntryPreflightSchema, GuardExtractionFailureSchema, GuardOrphanedSectionSchema, GuardRecipeReportSchema, GuardGenerateUsageSchema, GuardGenerateReportSchema;
|
|
28083
28083
|
var init_report = __esm({
|
|
28084
28084
|
"packages/shared/dist/guard/report.js"() {
|
|
28085
28085
|
"use strict";
|
|
@@ -28132,6 +28132,14 @@ var init_report = __esm({
|
|
|
28132
28132
|
anchor: external_exports.string(),
|
|
28133
28133
|
message: external_exports.string()
|
|
28134
28134
|
}).strict();
|
|
28135
|
+
GuardEntryPreflightSchema = external_exports.object({
|
|
28136
|
+
/** Display form of the entry argv, e.g. `node tools/cli/dist/index.js`. */
|
|
28137
|
+
entry: external_exports.string(),
|
|
28138
|
+
/** The recipe build command, for the rebuild hint. */
|
|
28139
|
+
buildCommand: external_exports.string(),
|
|
28140
|
+
/** The full, UNTRUNCATED startup output the dead entry produced. */
|
|
28141
|
+
stderr: external_exports.string()
|
|
28142
|
+
}).strict();
|
|
28135
28143
|
GuardExtractionFailureSchema = external_exports.object({
|
|
28136
28144
|
doc: external_exports.string(),
|
|
28137
28145
|
reason: external_exports.string()
|
|
@@ -28177,7 +28185,13 @@ var init_report = __esm({
|
|
|
28177
28185
|
*/
|
|
28178
28186
|
birthPassed: external_exports.number().int().nonnegative().optional(),
|
|
28179
28187
|
manifestPath: external_exports.string().optional(),
|
|
28180
|
-
usage: GuardGenerateUsageSchema.optional()
|
|
28188
|
+
usage: GuardGenerateUsageSchema.optional(),
|
|
28189
|
+
/**
|
|
28190
|
+
* Present ONLY when the built entry failed to start — the whole birth phase was
|
|
28191
|
+
* short-circuited, so every changed section stayed unsettled. Optional so older
|
|
28192
|
+
* reports (written before this field existed) keep parsing.
|
|
28193
|
+
*/
|
|
28194
|
+
entryPreflight: GuardEntryPreflightSchema.optional()
|
|
28181
28195
|
}).strict();
|
|
28182
28196
|
}
|
|
28183
28197
|
});
|
|
@@ -194710,6 +194724,129 @@ function listSandboxFiles(dir) {
|
|
|
194710
194724
|
return out.sort();
|
|
194711
194725
|
}
|
|
194712
194726
|
|
|
194727
|
+
// packages/guard-runner/dist/executor.js
|
|
194728
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
194729
|
+
var DEFAULT_STEP_TIMEOUT_MS = 3e4;
|
|
194730
|
+
function executeStep(opts) {
|
|
194731
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_STEP_TIMEOUT_MS;
|
|
194732
|
+
const [command, ...args] = opts.argv;
|
|
194733
|
+
const start = Date.now();
|
|
194734
|
+
return new Promise((resolve11) => {
|
|
194735
|
+
const child = spawn3(command, args, {
|
|
194736
|
+
cwd: opts.cwd,
|
|
194737
|
+
env: opts.env,
|
|
194738
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
194739
|
+
});
|
|
194740
|
+
let stdout = "";
|
|
194741
|
+
let stderr = "";
|
|
194742
|
+
let timedOut = false;
|
|
194743
|
+
let settled = false;
|
|
194744
|
+
const timer = setTimeout(() => {
|
|
194745
|
+
timedOut = true;
|
|
194746
|
+
child.kill("SIGKILL");
|
|
194747
|
+
}, timeoutMs);
|
|
194748
|
+
const finish = (capture) => {
|
|
194749
|
+
if (settled)
|
|
194750
|
+
return;
|
|
194751
|
+
settled = true;
|
|
194752
|
+
clearTimeout(timer);
|
|
194753
|
+
resolve11(capture);
|
|
194754
|
+
};
|
|
194755
|
+
child.stdout.on("data", (chunk3) => {
|
|
194756
|
+
stdout += chunk3.toString("utf-8");
|
|
194757
|
+
});
|
|
194758
|
+
child.stderr.on("data", (chunk3) => {
|
|
194759
|
+
stderr += chunk3.toString("utf-8");
|
|
194760
|
+
});
|
|
194761
|
+
child.on("error", (err) => {
|
|
194762
|
+
finish({
|
|
194763
|
+
exitCode: null,
|
|
194764
|
+
signal: null,
|
|
194765
|
+
stdout,
|
|
194766
|
+
stderr,
|
|
194767
|
+
timedOut,
|
|
194768
|
+
spawnError: err.message,
|
|
194769
|
+
durationMs: Date.now() - start
|
|
194770
|
+
});
|
|
194771
|
+
});
|
|
194772
|
+
child.on("close", (code, signal) => {
|
|
194773
|
+
finish({
|
|
194774
|
+
exitCode: code,
|
|
194775
|
+
signal,
|
|
194776
|
+
stdout,
|
|
194777
|
+
stderr,
|
|
194778
|
+
timedOut,
|
|
194779
|
+
durationMs: Date.now() - start
|
|
194780
|
+
});
|
|
194781
|
+
});
|
|
194782
|
+
if (opts.stdin !== void 0)
|
|
194783
|
+
child.stdin.write(opts.stdin);
|
|
194784
|
+
child.stdin.end();
|
|
194785
|
+
});
|
|
194786
|
+
}
|
|
194787
|
+
|
|
194788
|
+
// packages/guard-runner/dist/preflight.js
|
|
194789
|
+
var ENTRY_PROBE_ARGVS = [[], ["--help"]];
|
|
194790
|
+
var ENTRY_PREFLIGHT_TIMEOUT_MS = 2e4;
|
|
194791
|
+
var defaultEntryProbeExecutor = async (fullArgv, recipeEnv, timeoutMs) => {
|
|
194792
|
+
const sandbox = createSandbox({ recipeEnv });
|
|
194793
|
+
try {
|
|
194794
|
+
return await executeStep({ argv: fullArgv, cwd: sandbox.cwd, env: sandbox.env, timeoutMs });
|
|
194795
|
+
} finally {
|
|
194796
|
+
sandbox.cleanup();
|
|
194797
|
+
}
|
|
194798
|
+
};
|
|
194799
|
+
async function preflightEntry(opts) {
|
|
194800
|
+
const exec = opts.exec ?? defaultEntryProbeExecutor;
|
|
194801
|
+
const timeoutMs = opts.timeoutMs ?? ENTRY_PREFLIGHT_TIMEOUT_MS;
|
|
194802
|
+
const entry = opts.displayEntry.join(" ");
|
|
194803
|
+
const probes = await Promise.all(ENTRY_PROBE_ARGVS.map(async (argv) => ({
|
|
194804
|
+
argv: [...argv],
|
|
194805
|
+
capture: await exec([...opts.resolvedEntry, ...argv], opts.recipeEnv, timeoutMs)
|
|
194806
|
+
})));
|
|
194807
|
+
const ok = entryStarts(probes);
|
|
194808
|
+
return { ok, entry, stderr: ok ? "" : startupOutput(probes[0].capture, timeoutMs), probes };
|
|
194809
|
+
}
|
|
194810
|
+
function entryStarts(probes) {
|
|
194811
|
+
if (probes.some((p) => startedCleanly(p.capture)))
|
|
194812
|
+
return true;
|
|
194813
|
+
const shapes = probes.map((p) => failureShape(p.capture));
|
|
194814
|
+
return shapes.some((s) => s !== shapes[0]);
|
|
194815
|
+
}
|
|
194816
|
+
function startedCleanly(c) {
|
|
194817
|
+
return !c.spawnError && !c.timedOut && c.signal === null && c.exitCode === 0;
|
|
194818
|
+
}
|
|
194819
|
+
function failureShape(c) {
|
|
194820
|
+
return JSON.stringify({
|
|
194821
|
+
spawnError: c.spawnError ?? null,
|
|
194822
|
+
signal: c.signal ?? null,
|
|
194823
|
+
timedOut: c.timedOut,
|
|
194824
|
+
exitCode: c.exitCode,
|
|
194825
|
+
stdout: c.stdout,
|
|
194826
|
+
stderr: c.stderr
|
|
194827
|
+
});
|
|
194828
|
+
}
|
|
194829
|
+
function startupOutput(c, timeoutMs) {
|
|
194830
|
+
const parts = [];
|
|
194831
|
+
const primary = c.stderr || c.stdout;
|
|
194832
|
+
if (primary)
|
|
194833
|
+
parts.push(primary.trimEnd());
|
|
194834
|
+
if (c.spawnError)
|
|
194835
|
+
parts.push(`failed to spawn: ${c.spawnError}`);
|
|
194836
|
+
if (c.timedOut)
|
|
194837
|
+
parts.push(`(the entry produced no output within ${timeoutMs}ms and was killed)`);
|
|
194838
|
+
if (parts.length === 0) {
|
|
194839
|
+
parts.push(c.exitCode !== null ? `(the entry exited ${c.exitCode} with no output)` : `(the entry was killed by ${c.signal})`);
|
|
194840
|
+
}
|
|
194841
|
+
return parts.join("\n");
|
|
194842
|
+
}
|
|
194843
|
+
function entryPreflightHeadline(entry, buildCommand) {
|
|
194844
|
+
return `The recipe entry \`${entry}\` failed to start \u2014 it crashes before it runs, so every scenario would fail identically. Rebuild it with \`${buildCommand}\` (its build output is likely stale or incomplete), then retry.`;
|
|
194845
|
+
}
|
|
194846
|
+
function formatEntryPreflightError(opts) {
|
|
194847
|
+
return [entryPreflightHeadline(opts.entry, opts.buildCommand), "", "Startup output:", opts.stderr].join("\n");
|
|
194848
|
+
}
|
|
194849
|
+
|
|
194713
194850
|
// packages/guard-runner/dist/capabilities/git.js
|
|
194714
194851
|
import { spawnSync } from "node:child_process";
|
|
194715
194852
|
import fs15 from "node:fs";
|
|
@@ -194790,67 +194927,6 @@ function applyCapabilities(setup, ctx) {
|
|
|
194790
194927
|
}
|
|
194791
194928
|
}
|
|
194792
194929
|
|
|
194793
|
-
// packages/guard-runner/dist/executor.js
|
|
194794
|
-
import { spawn as spawn3 } from "node:child_process";
|
|
194795
|
-
var DEFAULT_STEP_TIMEOUT_MS = 3e4;
|
|
194796
|
-
function executeStep(opts) {
|
|
194797
|
-
const timeoutMs = opts.timeoutMs ?? DEFAULT_STEP_TIMEOUT_MS;
|
|
194798
|
-
const [command, ...args] = opts.argv;
|
|
194799
|
-
const start = Date.now();
|
|
194800
|
-
return new Promise((resolve11) => {
|
|
194801
|
-
const child = spawn3(command, args, {
|
|
194802
|
-
cwd: opts.cwd,
|
|
194803
|
-
env: opts.env,
|
|
194804
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
194805
|
-
});
|
|
194806
|
-
let stdout = "";
|
|
194807
|
-
let stderr = "";
|
|
194808
|
-
let timedOut = false;
|
|
194809
|
-
let settled = false;
|
|
194810
|
-
const timer = setTimeout(() => {
|
|
194811
|
-
timedOut = true;
|
|
194812
|
-
child.kill("SIGKILL");
|
|
194813
|
-
}, timeoutMs);
|
|
194814
|
-
const finish = (capture) => {
|
|
194815
|
-
if (settled)
|
|
194816
|
-
return;
|
|
194817
|
-
settled = true;
|
|
194818
|
-
clearTimeout(timer);
|
|
194819
|
-
resolve11(capture);
|
|
194820
|
-
};
|
|
194821
|
-
child.stdout.on("data", (chunk3) => {
|
|
194822
|
-
stdout += chunk3.toString("utf-8");
|
|
194823
|
-
});
|
|
194824
|
-
child.stderr.on("data", (chunk3) => {
|
|
194825
|
-
stderr += chunk3.toString("utf-8");
|
|
194826
|
-
});
|
|
194827
|
-
child.on("error", (err) => {
|
|
194828
|
-
finish({
|
|
194829
|
-
exitCode: null,
|
|
194830
|
-
signal: null,
|
|
194831
|
-
stdout,
|
|
194832
|
-
stderr,
|
|
194833
|
-
timedOut,
|
|
194834
|
-
spawnError: err.message,
|
|
194835
|
-
durationMs: Date.now() - start
|
|
194836
|
-
});
|
|
194837
|
-
});
|
|
194838
|
-
child.on("close", (code, signal) => {
|
|
194839
|
-
finish({
|
|
194840
|
-
exitCode: code,
|
|
194841
|
-
signal,
|
|
194842
|
-
stdout,
|
|
194843
|
-
stderr,
|
|
194844
|
-
timedOut,
|
|
194845
|
-
durationMs: Date.now() - start
|
|
194846
|
-
});
|
|
194847
|
-
});
|
|
194848
|
-
if (opts.stdin !== void 0)
|
|
194849
|
-
child.stdin.write(opts.stdin);
|
|
194850
|
-
child.stdin.end();
|
|
194851
|
-
});
|
|
194852
|
-
}
|
|
194853
|
-
|
|
194854
194930
|
// packages/guard-runner/dist/normalizers.js
|
|
194855
194931
|
var CANONICAL_ORDER = [
|
|
194856
194932
|
"abs-paths",
|
|
@@ -195481,16 +195557,27 @@ async function runGuard(opts) {
|
|
|
195481
195557
|
}));
|
|
195482
195558
|
const executable = planned.filter((p) => p.resolution.kind === "match" || p.resolution.kind === "remap");
|
|
195483
195559
|
const nonExecutable = planned.filter((p) => p.resolution.kind === "stale" || p.resolution.kind === "orphaned");
|
|
195484
|
-
|
|
195560
|
+
const buildsOwnEntry = !opts.skipBuild && executable.length > 0;
|
|
195561
|
+
if (buildsOwnEntry) {
|
|
195485
195562
|
opts.onPhase?.("build");
|
|
195486
195563
|
const build8 = await runBuild(repoRoot, loaded.recipe.build, loaded.recipe.env);
|
|
195487
195564
|
if (!build8.ok)
|
|
195488
195565
|
return { status: "build-failed", build: build8, loadErrors };
|
|
195489
195566
|
}
|
|
195567
|
+
const resolvedEntry = resolveEntry(repoRoot, loaded.recipe.entry);
|
|
195568
|
+
if (buildsOwnEntry) {
|
|
195569
|
+
const preflight = await preflightEntry({
|
|
195570
|
+
resolvedEntry,
|
|
195571
|
+
displayEntry: loaded.recipe.entry,
|
|
195572
|
+
recipeEnv: loaded.recipe.env
|
|
195573
|
+
});
|
|
195574
|
+
if (!preflight.ok) {
|
|
195575
|
+
return { status: "entry-preflight-failed", preflight, buildCommand: loaded.recipe.build, loadErrors };
|
|
195576
|
+
}
|
|
195577
|
+
}
|
|
195490
195578
|
opts.onPhase?.("run", selected.length);
|
|
195491
195579
|
const runId = buildRunId();
|
|
195492
195580
|
const ranAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
195493
|
-
const resolvedEntry = resolveEntry(repoRoot, loaded.recipe.entry);
|
|
195494
195581
|
const stepTimeoutMs = opts.stepTimeoutMs ?? DEFAULT_STEP_TIMEOUT_MS;
|
|
195495
195582
|
const concurrency = opts.concurrency ?? defaultRunConcurrency();
|
|
195496
195583
|
const results = [];
|
|
@@ -197279,35 +197366,49 @@ function prefilterDocs(docs, manualIncludes = []) {
|
|
|
197279
197366
|
skipped: [...reasons].map(([path73, reason]) => ({ path: path73, reason }))
|
|
197280
197367
|
};
|
|
197281
197368
|
}
|
|
197369
|
+
async function planRelevanceWork(repoRoot, docs, manualIncludes = []) {
|
|
197370
|
+
const manualSet = new Set(manualIncludes);
|
|
197371
|
+
const { toClassify, skipped } = prefilterDocs(docs, manualIncludes);
|
|
197372
|
+
const needsCall = [];
|
|
197373
|
+
const known = /* @__PURE__ */ new Map();
|
|
197374
|
+
await Promise.all(toClassify.map(async (doc) => {
|
|
197375
|
+
if (manualSet.has(doc.path)) {
|
|
197376
|
+
known.set(doc.path, { path: doc.path, include: true, reason: "manual include" });
|
|
197377
|
+
return;
|
|
197378
|
+
}
|
|
197379
|
+
const cached = await readCache4(repoRoot, computeCacheKey5(doc));
|
|
197380
|
+
if (cached)
|
|
197381
|
+
known.set(doc.path, cached);
|
|
197382
|
+
else
|
|
197383
|
+
needsCall.push(doc);
|
|
197384
|
+
}));
|
|
197385
|
+
return { toClassify, prefilterSkipped: skipped, needsCall, known };
|
|
197386
|
+
}
|
|
197282
197387
|
async function filterByRelevance(repoRoot, docs, opts = {}) {
|
|
197283
197388
|
if (opts.enabled === false || docs.length === 0) {
|
|
197284
197389
|
return { included: docs, skipped: [] };
|
|
197285
197390
|
}
|
|
197286
|
-
const manualSet = new Set(opts.manualIncludes ?? []);
|
|
197287
197391
|
const runner2 = opts.runner ?? spawnRelevanceRunner({ transport: opts.transport, model: opts.model, fallbackModel: opts.fallbackModel });
|
|
197288
197392
|
const concurrency = opts.concurrency ?? defaultConcurrency();
|
|
197289
|
-
const
|
|
197290
|
-
const prefilterReason = new Map(prefilterSkipped.map((s) => [s.path, s.reason]));
|
|
197393
|
+
const plan = await planRelevanceWork(repoRoot, docs, opts.manualIncludes ?? []);
|
|
197394
|
+
const prefilterReason = new Map(plan.prefilterSkipped.map((s) => [s.path, s.reason]));
|
|
197291
197395
|
const total = docs.length;
|
|
197292
197396
|
let done = 0;
|
|
197293
197397
|
const markDone = () => opts.onProgress?.(++done, total);
|
|
197294
197398
|
opts.onProgress?.(0, total);
|
|
197295
|
-
|
|
197399
|
+
const resolvedUpfront = prefilterReason.size + plan.known.size;
|
|
197400
|
+
for (let i = 0; i < resolvedUpfront; i++)
|
|
197296
197401
|
markDone();
|
|
197297
|
-
const verdicts =
|
|
197402
|
+
const verdicts = new Map(plan.known);
|
|
197403
|
+
const pending = plan.needsCall;
|
|
197298
197404
|
let cursor = 0;
|
|
197299
197405
|
let active12 = 0;
|
|
197300
197406
|
await new Promise((resolve11) => {
|
|
197407
|
+
if (pending.length === 0)
|
|
197408
|
+
return resolve11();
|
|
197301
197409
|
const launch = () => {
|
|
197302
|
-
while (active12 < concurrency && cursor <
|
|
197303
|
-
const doc =
|
|
197304
|
-
if (manualSet.has(doc.path)) {
|
|
197305
|
-
verdicts.set(doc.path, { path: doc.path, include: true, reason: "manual include" });
|
|
197306
|
-
markDone();
|
|
197307
|
-
if (cursor >= toClassify.length && active12 === 0)
|
|
197308
|
-
resolve11();
|
|
197309
|
-
continue;
|
|
197310
|
-
}
|
|
197410
|
+
while (active12 < concurrency && cursor < pending.length) {
|
|
197411
|
+
const doc = pending[cursor++];
|
|
197311
197412
|
active12++;
|
|
197312
197413
|
classifyOne(repoRoot, doc, runner2).then((verdict) => {
|
|
197313
197414
|
verdicts.set(doc.path, verdict);
|
|
@@ -197320,14 +197421,12 @@ async function filterByRelevance(repoRoot, docs, opts = {}) {
|
|
|
197320
197421
|
}).finally(() => {
|
|
197321
197422
|
markDone();
|
|
197322
197423
|
active12--;
|
|
197323
|
-
if (cursor >=
|
|
197424
|
+
if (cursor >= pending.length && active12 === 0)
|
|
197324
197425
|
resolve11();
|
|
197325
197426
|
else
|
|
197326
197427
|
launch();
|
|
197327
197428
|
});
|
|
197328
197429
|
}
|
|
197329
|
-
if (cursor >= toClassify.length && active12 === 0)
|
|
197330
|
-
resolve11();
|
|
197331
197430
|
};
|
|
197332
197431
|
launch();
|
|
197333
197432
|
});
|
|
@@ -197524,9 +197623,6 @@ async function readCache4(scope, cacheKey) {
|
|
|
197524
197623
|
async function writeCache4(scope, cacheKey, verdict) {
|
|
197525
197624
|
await setCacheEntry(scope, CACHE_NAME5, cacheKey, verdict);
|
|
197526
197625
|
}
|
|
197527
|
-
async function readRelevanceCache(repoRoot, doc) {
|
|
197528
|
-
return readCache4(repoRoot, computeCacheKey5(doc));
|
|
197529
|
-
}
|
|
197530
197626
|
|
|
197531
197627
|
// packages/spec-consolidator/dist/curate.js
|
|
197532
197628
|
async function curate(repoRoot, opts = {}) {
|
|
@@ -224323,6 +224419,9 @@ var STAGE_DEFAULTS = {
|
|
|
224323
224419
|
// Authoring an executable scenario faithful to a spec claim is the hard,
|
|
224324
224420
|
// load-bearing call (a weak scenario is false confidence) — opus.
|
|
224325
224421
|
"guard.generate": "opus",
|
|
224422
|
+
// The one evidence-retry per birth-failed claim — the same authoring task, so
|
|
224423
|
+
// the same tier; a distinct stage so retry spend is attributed to the birth line.
|
|
224424
|
+
"guard.retry": "opus",
|
|
224326
224425
|
// Proposing a build/entry recipe is a modest structured task — sonnet.
|
|
224327
224426
|
"guard.recipe": "sonnet",
|
|
224328
224427
|
"rules.violationGen": "opus"
|
|
@@ -225024,11 +225123,11 @@ function spawnGenerateRunner2(opts = {}) {
|
|
|
225024
225123
|
return async (ctx) => {
|
|
225025
225124
|
const refs = ctx.claims.map((c) => c.ref).join(",");
|
|
225026
225125
|
const isRetry = ctx.claims.some((c) => c.retry);
|
|
225027
|
-
const
|
|
225126
|
+
const stage = isRetry ? "guard.retry" : "guard.generate";
|
|
225028
225127
|
const raw = await transport({
|
|
225029
|
-
id:
|
|
225030
|
-
stage
|
|
225031
|
-
model: opts.model,
|
|
225128
|
+
id: `${stage}:${ctx.doc}:${refs}${ctx.correction ? ":correction" : ""}`,
|
|
225129
|
+
stage,
|
|
225130
|
+
model: isRetry ? opts.retryModel ?? opts.model : opts.model,
|
|
225032
225131
|
fallbackModel: opts.fallbackModel,
|
|
225033
225132
|
system: GENERATE_SYSTEM_PROMPT,
|
|
225034
225133
|
user: buildAuthorUserPrompt(ctx),
|
|
@@ -225340,12 +225439,15 @@ async function captureProbes(opts) {
|
|
|
225340
225439
|
const cached = await getCacheEntry(opts.repoRoot, GROUND_CACHE_NAME, key4);
|
|
225341
225440
|
if (cached) {
|
|
225342
225441
|
const parsed = ProbeTranscriptSchema.safeParse(cached);
|
|
225343
|
-
if (parsed.success)
|
|
225442
|
+
if (parsed.success) {
|
|
225443
|
+
opts.onProbeCaptured?.();
|
|
225344
225444
|
return parsed.data;
|
|
225445
|
+
}
|
|
225345
225446
|
}
|
|
225346
225447
|
const capture = await exec([...opts.resolvedEntry, ...argv], opts.recipeEnv);
|
|
225347
225448
|
const transcript = toTranscript(argv, [...opts.displayEntry, ...argv], capture);
|
|
225348
225449
|
await setCacheEntry(opts.repoRoot, GROUND_CACHE_NAME, key4, transcript);
|
|
225450
|
+
opts.onProbeCaptured?.();
|
|
225349
225451
|
return transcript;
|
|
225350
225452
|
}));
|
|
225351
225453
|
}
|
|
@@ -225610,6 +225712,7 @@ function deleteScenarioFiles(repoRoot, ids) {
|
|
|
225610
225712
|
|
|
225611
225713
|
// packages/guard-generator/dist/generate.js
|
|
225612
225714
|
var GENERATE_CACHE_NAME = "guard/generate";
|
|
225715
|
+
var ENTRY_PREFLIGHT_ANCHOR = "(entry preflight)";
|
|
225613
225716
|
function defaultConcurrency3() {
|
|
225614
225717
|
const env = process.env.TRUECOURSE_MAX_CONCURRENCY;
|
|
225615
225718
|
if (env) {
|
|
@@ -225679,7 +225782,12 @@ async function generateGuards(options) {
|
|
|
225679
225782
|
const limit = pLimit(Math.max(1, options.concurrency ?? defaultConcurrency3()));
|
|
225680
225783
|
const batchSize = Math.max(1, options.batchSize ?? defaultGenerateBatch2());
|
|
225681
225784
|
const extractRunner = options.extractRunner ?? spawnExtractRunner({ transport: options.transport, model: options.models?.extract, fallbackModel: options.models?.fallback });
|
|
225682
|
-
const generateRunner = options.generateRunner ?? spawnGenerateRunner2({
|
|
225785
|
+
const generateRunner = options.generateRunner ?? spawnGenerateRunner2({
|
|
225786
|
+
transport: options.transport,
|
|
225787
|
+
model: options.models?.generate,
|
|
225788
|
+
retryModel: options.models?.retry,
|
|
225789
|
+
fallbackModel: options.models?.fallback
|
|
225790
|
+
});
|
|
225683
225791
|
const coverageGaps = [];
|
|
225684
225792
|
const errors = [];
|
|
225685
225793
|
const extractionFailures = [];
|
|
@@ -225750,11 +225858,15 @@ async function generateGuards(options) {
|
|
|
225750
225858
|
return buildPromise;
|
|
225751
225859
|
};
|
|
225752
225860
|
let resolvedEntryMemo = null;
|
|
225861
|
+
let groundPlanned = 0;
|
|
225862
|
+
let groundCaptured = 0;
|
|
225753
225863
|
const groundClaims = async (claimTexts) => {
|
|
225754
225864
|
const probes = deriveProbes(claimTexts, recipe.entry);
|
|
225755
225865
|
const build8 = await buildPromise;
|
|
225756
|
-
if (!build8.ok)
|
|
225866
|
+
if (!build8.ok || probes.length === 0)
|
|
225757
225867
|
return [];
|
|
225868
|
+
groundPlanned += probes.length;
|
|
225869
|
+
options.onGroundProgress?.(groundCaptured, groundPlanned);
|
|
225758
225870
|
resolvedEntryMemo ??= resolveEntry(repoRoot, recipe.entry);
|
|
225759
225871
|
return captureProbes({
|
|
225760
225872
|
repoRoot,
|
|
@@ -225762,9 +225874,21 @@ async function generateGuards(options) {
|
|
|
225762
225874
|
resolvedEntry: resolvedEntryMemo,
|
|
225763
225875
|
displayEntry: recipe.entry,
|
|
225764
225876
|
recipeFingerprint,
|
|
225765
|
-
recipeEnv: recipe.env
|
|
225877
|
+
recipeEnv: recipe.env,
|
|
225878
|
+
onProbeCaptured: () => options.onGroundProgress?.(++groundCaptured, groundPlanned)
|
|
225766
225879
|
});
|
|
225767
225880
|
};
|
|
225881
|
+
let entryPreflightMemo = null;
|
|
225882
|
+
const preflightEntryOnce = () => {
|
|
225883
|
+
entryPreflightMemo ??= (async () => {
|
|
225884
|
+
const build8 = await buildPromise;
|
|
225885
|
+
if (!build8.ok)
|
|
225886
|
+
return null;
|
|
225887
|
+
resolvedEntryMemo ??= resolveEntry(repoRoot, recipe.entry);
|
|
225888
|
+
return preflightEntry({ resolvedEntry: resolvedEntryMemo, displayEntry: recipe.entry, recipeEnv: recipe.env });
|
|
225889
|
+
})();
|
|
225890
|
+
return entryPreflightMemo;
|
|
225891
|
+
};
|
|
225768
225892
|
const priorSections = readPriorManifest(repoRoot);
|
|
225769
225893
|
const manifestByKey = new Map(priorSections.map((e) => [`${e.doc}\0${e.anchor}`, e]));
|
|
225770
225894
|
const usedIds = existingScenarioIds(repoRoot);
|
|
@@ -225788,9 +225912,11 @@ async function generateGuards(options) {
|
|
|
225788
225912
|
});
|
|
225789
225913
|
settledKeys.add(k);
|
|
225790
225914
|
writeWorkingManifest();
|
|
225915
|
+
options.onSectionSettled?.(settledKeys.size, plan.work.length);
|
|
225791
225916
|
};
|
|
225792
225917
|
const written = [];
|
|
225793
225918
|
const birthFindings = [];
|
|
225919
|
+
let entryPreflightFailure = null;
|
|
225794
225920
|
let birthTotal = 0;
|
|
225795
225921
|
let birthSettled = 0;
|
|
225796
225922
|
let birthPassed = 0;
|
|
@@ -225837,6 +225963,20 @@ async function generateGuards(options) {
|
|
|
225837
225963
|
return;
|
|
225838
225964
|
settleChain = settleChain.then(() => settleCliSection(sectionByKey.get(k), refsBySection.get(k)));
|
|
225839
225965
|
};
|
|
225966
|
+
const deadEntry = async () => {
|
|
225967
|
+
const preflight = await preflightEntryOnce();
|
|
225968
|
+
if (!preflight || preflight.ok)
|
|
225969
|
+
return false;
|
|
225970
|
+
if (!entryPreflightFailure) {
|
|
225971
|
+
entryPreflightFailure = { entry: preflight.entry, buildCommand: recipe.build, stderr: preflight.stderr };
|
|
225972
|
+
errors.push({
|
|
225973
|
+
doc: preflight.entry,
|
|
225974
|
+
anchor: ENTRY_PREFLIGHT_ANCHOR,
|
|
225975
|
+
message: formatEntryPreflightError(entryPreflightFailure)
|
|
225976
|
+
});
|
|
225977
|
+
}
|
|
225978
|
+
return true;
|
|
225979
|
+
};
|
|
225840
225980
|
async function settleCliSection(section, refs) {
|
|
225841
225981
|
const k = key2(section);
|
|
225842
225982
|
for (const id of priorIdsOf(k))
|
|
@@ -225871,6 +226011,8 @@ async function generateGuards(options) {
|
|
|
225871
226011
|
const message = `build failed (\`${build8.command}\`)${build8.timedOut ? " \u2014 timed out" : ""}`;
|
|
225872
226012
|
for (const c of round1)
|
|
225873
226013
|
localErrors.push(errorFrom({ candidate: c, result: { failure: { actual: message } } }));
|
|
226014
|
+
} else if (await deadEntry()) {
|
|
226015
|
+
return;
|
|
225874
226016
|
} else {
|
|
225875
226017
|
birthTotal += round1.length;
|
|
225876
226018
|
const r1 = await birthValidate(repoRoot, round1, { skipBuild: true, onPhase: options.onBirthPhase, onScenarioSettled: bumpBirth });
|
|
@@ -225947,6 +226089,8 @@ async function generateGuards(options) {
|
|
|
225947
226089
|
const authorTotal = authTasks.length;
|
|
225948
226090
|
let authorDone = 0;
|
|
225949
226091
|
const bumpAuthor = (n) => options.onAuthorProgress?.(authorDone += n, authorTotal);
|
|
226092
|
+
if (authorTotal > 0)
|
|
226093
|
+
options.onAuthorProgress?.(authorDone, authorTotal);
|
|
225950
226094
|
const missTasks = [];
|
|
225951
226095
|
for (const t of authTasks) {
|
|
225952
226096
|
const cached = await readAuthorCache(repoRoot, t.claim, t.section, recipeFingerprint);
|
|
@@ -226018,7 +226162,8 @@ async function generateGuards(options) {
|
|
|
226018
226162
|
extractionFailures,
|
|
226019
226163
|
orphaned,
|
|
226020
226164
|
birthPassed,
|
|
226021
|
-
manifestPath: manifestPath(repoRoot)
|
|
226165
|
+
manifestPath: manifestPath(repoRoot),
|
|
226166
|
+
...entryPreflightFailure ? { entryPreflight: entryPreflightFailure } : {}
|
|
226022
226167
|
};
|
|
226023
226168
|
}
|
|
226024
226169
|
var key2 = (s) => `${s.doc}\0${s.anchor}`;
|
|
@@ -226829,12 +226974,14 @@ function previewChars() {
|
|
|
226829
226974
|
return 60 * 50;
|
|
226830
226975
|
}
|
|
226831
226976
|
async function estimateScanTokens(repoRoot, prices) {
|
|
226977
|
+
const decisions = readCorpusDecisions(repoRoot);
|
|
226978
|
+
const manualIncludes = decisions.manualIncludes ?? [];
|
|
226979
|
+
const manualExcludes = new Set(decisions.manualExcludes ?? []);
|
|
226832
226980
|
const docs = discoverDocs(repoRoot);
|
|
226833
|
-
const
|
|
226834
|
-
const nClassify = toClassify.length;
|
|
226835
|
-
const
|
|
226836
|
-
const
|
|
226837
|
-
const cachedKeptDocs = toClassify.filter((_, i) => relevance[i]?.include === true);
|
|
226981
|
+
const plan = await planRelevanceWork(repoRoot, docs, manualIncludes);
|
|
226982
|
+
const nClassify = plan.toClassify.length;
|
|
226983
|
+
const relevanceMissDocs = plan.needsCall;
|
|
226984
|
+
const cachedKeptDocs = plan.toClassify.filter((d) => plan.known.get(d.path)?.include === true && !manualExcludes.has(d.path));
|
|
226838
226985
|
const cachedKeptTagged = await Promise.all(cachedKeptDocs.map((d) => isAreaTagCached(repoRoot, d)));
|
|
226839
226986
|
const cachedKeptTagMisses = cachedKeptTagged.filter((cached) => !cached).length;
|
|
226840
226987
|
const estChangedKept = Math.round(relevanceMissDocs.length * KEEP_RATE);
|
|
@@ -231252,7 +231399,7 @@ function readToolVersion() {
|
|
|
231252
231399
|
if (cachedVersion)
|
|
231253
231400
|
return cachedVersion;
|
|
231254
231401
|
if (true) {
|
|
231255
|
-
cachedVersion = "0.7.0-next.
|
|
231402
|
+
cachedVersion = "0.7.0-next.2";
|
|
231256
231403
|
return cachedVersion;
|
|
231257
231404
|
}
|
|
231258
231405
|
try {
|
|
@@ -238876,7 +239023,8 @@ var GUARD_GENERATE_STEPS = [
|
|
|
238876
239023
|
var GUARD_STEP_STAGES = {
|
|
238877
239024
|
index: ["guard.recipe"],
|
|
238878
239025
|
extract: ["guard.extract"],
|
|
238879
|
-
author: ["guard.generate"]
|
|
239026
|
+
author: ["guard.generate"],
|
|
239027
|
+
validate: ["guard.retry"]
|
|
238880
239028
|
};
|
|
238881
239029
|
async function estimateGuard(repoRoot) {
|
|
238882
239030
|
return estimateGuardTokens(repoRoot, await getModelPrices());
|
|
@@ -238885,6 +239033,7 @@ function resolveGuardModels(repoRoot) {
|
|
|
238885
239033
|
return {
|
|
238886
239034
|
extract: resolveModel("guard.extract", void 0, repoRoot),
|
|
238887
239035
|
generate: resolveModel("guard.generate", void 0, repoRoot),
|
|
239036
|
+
retry: resolveModel("guard.retry", void 0, repoRoot),
|
|
238888
239037
|
recipe: resolveModel("guard.recipe", void 0, repoRoot),
|
|
238889
239038
|
fallback: resolveFallbackModel(repoRoot) ?? void 0
|
|
238890
239039
|
};
|
|
@@ -238926,10 +239075,20 @@ async function guardGenerateInProcess(repoRoot, options = {}) {
|
|
|
238926
239075
|
cur = ni;
|
|
238927
239076
|
};
|
|
238928
239077
|
const withUsage = (key4, base) => `${base}${stageUsageTag(GUARD_STEP_STAGES[key4] ?? [], repoRoot)}`;
|
|
239078
|
+
let authorDone = 0;
|
|
239079
|
+
let authorTotal = 0;
|
|
239080
|
+
let authorFinished = false;
|
|
239081
|
+
let groundCaptured = 0;
|
|
239082
|
+
let groundPlanned = 0;
|
|
239083
|
+
const authorDetail = () => {
|
|
239084
|
+
const claims = `${authorDone}/${authorTotal} claim${authorTotal === 1 ? "" : "s"}`;
|
|
239085
|
+
const base = groundPlanned > 0 ? `grounding probes ${groundCaptured}/${groundPlanned} \xB7 authoring ${claims}` : claims;
|
|
239086
|
+
return withUsage("author", base);
|
|
239087
|
+
};
|
|
238929
239088
|
let building = false;
|
|
238930
|
-
let birthSeen = false;
|
|
238931
239089
|
let birthDone = 0;
|
|
238932
|
-
let
|
|
239090
|
+
let sectionsDone = 0;
|
|
239091
|
+
let sectionsTotal = 0;
|
|
238933
239092
|
let retrySeen = false;
|
|
238934
239093
|
let retryDone = 0;
|
|
238935
239094
|
let retryTotal = 0;
|
|
@@ -238940,10 +239099,10 @@ async function guardGenerateInProcess(repoRoot, options = {}) {
|
|
|
238940
239099
|
tracker?.start("validate");
|
|
238941
239100
|
validateStarted = true;
|
|
238942
239101
|
}
|
|
238943
|
-
const parts = [building ? "building\u2026" : `birth ${birthDone}
|
|
239102
|
+
const parts = [`sections ${sectionsDone}/${sectionsTotal}`, building ? "building\u2026" : `birth ${birthDone}`];
|
|
238944
239103
|
if (retrySeen)
|
|
238945
|
-
parts.push(`retrying
|
|
238946
|
-
tracker?.detail("validate", parts.join(" \xB7 "));
|
|
239104
|
+
parts.push(`retrying ${retryDone}/${retryTotal}`);
|
|
239105
|
+
tracker?.detail("validate", withUsage("validate", parts.join(" \xB7 ")));
|
|
238947
239106
|
};
|
|
238948
239107
|
tracker?.start("index");
|
|
238949
239108
|
try {
|
|
@@ -238955,6 +239114,7 @@ async function guardGenerateInProcess(repoRoot, options = {}) {
|
|
|
238955
239114
|
generateRunner: options.generateRunner,
|
|
238956
239115
|
recipeRunner: options.recipeRunner,
|
|
238957
239116
|
onPlan: (total, work) => {
|
|
239117
|
+
sectionsTotal = work;
|
|
238958
239118
|
tracker?.done("index", withUsage("index", `${work} of ${total} section${total === 1 ? "" : "s"} changed`));
|
|
238959
239119
|
cur = STEPS.indexOf("extract");
|
|
238960
239120
|
tracker?.start("extract", `0 views`);
|
|
@@ -238971,27 +239131,30 @@ async function guardGenerateInProcess(repoRoot, options = {}) {
|
|
|
238971
239131
|
},
|
|
238972
239132
|
onAuthorProgress: (done, total) => {
|
|
238973
239133
|
advanceTo("author");
|
|
238974
|
-
|
|
238975
|
-
|
|
238976
|
-
|
|
238977
|
-
|
|
238978
|
-
tracker?.
|
|
238979
|
-
},
|
|
238980
|
-
onBirthPhase: (phase, total) => {
|
|
238981
|
-
if (phase === "build") {
|
|
238982
|
-
building = true;
|
|
239134
|
+
authorDone = done;
|
|
239135
|
+
authorTotal = total;
|
|
239136
|
+
if (done >= total) {
|
|
239137
|
+
authorFinished = true;
|
|
239138
|
+
tracker?.done("author", withUsage("author", `${done}/${total} claim${total === 1 ? "" : "s"}`));
|
|
238983
239139
|
} else {
|
|
238984
|
-
|
|
238985
|
-
if (!birthSeen && total !== void 0)
|
|
238986
|
-
birthTotal = total;
|
|
239140
|
+
tracker?.detail("author", authorDetail());
|
|
238987
239141
|
}
|
|
239142
|
+
},
|
|
239143
|
+
onGroundProgress: (captured, planned) => {
|
|
239144
|
+
groundCaptured = captured;
|
|
239145
|
+
groundPlanned = planned;
|
|
239146
|
+
if (authorFinished)
|
|
239147
|
+
return;
|
|
239148
|
+
advanceTo("author");
|
|
239149
|
+
tracker?.detail("author", authorDetail());
|
|
239150
|
+
},
|
|
239151
|
+
onBirthPhase: (phase) => {
|
|
239152
|
+
building = phase === "build";
|
|
238988
239153
|
renderValidate();
|
|
238989
239154
|
},
|
|
238990
|
-
onBirthProgress: (done
|
|
239155
|
+
onBirthProgress: (done) => {
|
|
238991
239156
|
building = false;
|
|
238992
|
-
birthSeen = true;
|
|
238993
239157
|
birthDone = done;
|
|
238994
|
-
birthTotal = total;
|
|
238995
239158
|
renderValidate();
|
|
238996
239159
|
},
|
|
238997
239160
|
onRetryProgress: (done, total) => {
|
|
@@ -238999,6 +239162,12 @@ async function guardGenerateInProcess(repoRoot, options = {}) {
|
|
|
238999
239162
|
retryDone = done;
|
|
239000
239163
|
retryTotal = total;
|
|
239001
239164
|
renderValidate();
|
|
239165
|
+
},
|
|
239166
|
+
onSectionSettled: (settled, total) => {
|
|
239167
|
+
sectionsDone = settled;
|
|
239168
|
+
sectionsTotal = total;
|
|
239169
|
+
if (validateStarted)
|
|
239170
|
+
renderValidate();
|
|
239002
239171
|
}
|
|
239003
239172
|
});
|
|
239004
239173
|
for (let i = cur; i < STEPS.length; i++)
|
|
@@ -239022,7 +239191,7 @@ async function guardGenerateInProcess(repoRoot, options = {}) {
|
|
|
239022
239191
|
}
|
|
239023
239192
|
}
|
|
239024
239193
|
}
|
|
239025
|
-
var GUARD_USAGE_STAGES = ["guard.recipe", "guard.extract", "guard.generate"];
|
|
239194
|
+
var GUARD_USAGE_STAGES = ["guard.recipe", "guard.extract", "guard.generate", "guard.retry"];
|
|
239026
239195
|
function sumGuardUsage() {
|
|
239027
239196
|
const usage = getStageUsage();
|
|
239028
239197
|
let calls = 0;
|
|
@@ -239070,6 +239239,8 @@ async function guardRunInProcess(repoRoot, options = {}) {
|
|
|
239070
239239
|
tracker?.done("run", `${n} scenario${n === 1 ? "" : "s"}`);
|
|
239071
239240
|
} else if (result.status === "build-failed") {
|
|
239072
239241
|
tracker?.error("build", `Build failed (\`${result.build.command}\`)${result.build.timedOut ? " \u2014 timed out" : ""}`);
|
|
239242
|
+
} else if (result.status === "entry-preflight-failed") {
|
|
239243
|
+
tracker?.error("build", `Entry failed to start: \`${result.preflight.entry}\` (rebuild via \`${result.buildCommand}\`)`);
|
|
239073
239244
|
}
|
|
239074
239245
|
return result;
|
|
239075
239246
|
}
|
|
@@ -239150,7 +239321,9 @@ router14.post("/:id/guard/run", async (req, res, next) => {
|
|
|
239150
239321
|
res.json({ status: "ok", summary: result.latest.summary });
|
|
239151
239322
|
return;
|
|
239152
239323
|
}
|
|
239153
|
-
if (result.status !== "build-failed"
|
|
239324
|
+
if (result.status !== "build-failed" && result.status !== "entry-preflight-failed") {
|
|
239325
|
+
emitSpecComplete(repoId, "guard-run");
|
|
239326
|
+
}
|
|
239154
239327
|
res.json({ status: result.status, message: runFailureMessage(result) });
|
|
239155
239328
|
} catch (e) {
|
|
239156
239329
|
emitSpecProgress(repoId, { step: "error", percent: 100, detail: e.message });
|
|
@@ -239169,6 +239342,12 @@ function runFailureMessage(result) {
|
|
|
239169
239342
|
return "No scenarios found under .truecourse/scenarios/. Generate scenarios first.";
|
|
239170
239343
|
case "build-failed":
|
|
239171
239344
|
return `Build failed (\`${result.build.command}\`)${result.build.timedOut ? " \u2014 timed out" : ""}. No scenarios ran.`;
|
|
239345
|
+
case "entry-preflight-failed":
|
|
239346
|
+
return formatEntryPreflightError({
|
|
239347
|
+
entry: result.preflight.entry,
|
|
239348
|
+
buildCommand: result.buildCommand,
|
|
239349
|
+
stderr: result.preflight.stderr
|
|
239350
|
+
});
|
|
239172
239351
|
}
|
|
239173
239352
|
}
|
|
239174
239353
|
var guard_actions_default = router14;
|