truecourse 0.7.0-next.10 → 0.7.0-next.11
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 +1 -0
- package/cli.mjs +83 -26
- package/package.json +1 -1
- package/roslyn-host/csharp-roslyn-host.dll +0 -0
- package/roslyn-host/csharp-roslyn-host.pdb +0 -0
- package/server.mjs +13 -5
package/README.md
CHANGED
|
@@ -301,6 +301,7 @@ truecourse spec docs unexclude <path> # Remove a force-exclude overr
|
|
|
301
301
|
truecourse guard generate # Author scenarios from spec sections (classify → generate → birth-validate)
|
|
302
302
|
truecourse guard run # Build via the recipe + run committed scenarios; exits non-zero on any drift (CI gate)
|
|
303
303
|
truecourse guard run --scenario <id> # Run a single scenario
|
|
304
|
+
truecourse guard run --verbose # List every scenario result (one ✓ line per pass; default shows failures only)
|
|
304
305
|
truecourse guard status # Compact summary: section coverage, last run, last generate (LLM-free, no re-run)
|
|
305
306
|
truecourse guard drifts # List the latest run's non-pass scenarios, most severe first (paginated; --all / --offset / --json)
|
|
306
307
|
```
|
package/cli.mjs
CHANGED
|
@@ -171204,7 +171204,7 @@ function readToolVersion() {
|
|
|
171204
171204
|
if (cachedVersion)
|
|
171205
171205
|
return cachedVersion;
|
|
171206
171206
|
if (true) {
|
|
171207
|
-
cachedVersion = "0.7.0-next.
|
|
171207
|
+
cachedVersion = "0.7.0-next.11";
|
|
171208
171208
|
return cachedVersion;
|
|
171209
171209
|
}
|
|
171210
171210
|
try {
|
|
@@ -208858,6 +208858,7 @@ async function generateGuards(options) {
|
|
|
208858
208858
|
let extractDone = 0;
|
|
208859
208859
|
const viewTotal = workDocs.reduce((n, d3) => n + countExtractViews(d3), 0);
|
|
208860
208860
|
let viewDone = 0;
|
|
208861
|
+
options.onExtractViewProgress?.(0, viewTotal);
|
|
208861
208862
|
const extracted = await Promise.all(workDocs.map(async (doc) => {
|
|
208862
208863
|
const result = await extractDocClaims(repoRoot5, doc, extractRunner, limit, () => options.onExtractViewProgress?.(++viewDone, viewTotal));
|
|
208863
208864
|
options.onExtractProgress?.(++extractDone, workDocs.length);
|
|
@@ -211414,15 +211415,43 @@ init_registry();
|
|
|
211414
211415
|
|
|
211415
211416
|
// tools/cli/src/lib/stdout-step-renderer.ts
|
|
211416
211417
|
var SPINNER_FRAMES2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
211418
|
+
var ANSI_SGR_GLOBAL = /\x1b\[[0-9;]*m/g;
|
|
211419
|
+
function visibleLength(s) {
|
|
211420
|
+
return [...s.replace(ANSI_SGR_GLOBAL, "")].length;
|
|
211421
|
+
}
|
|
211422
|
+
function clampToWidth(s, maxWidth) {
|
|
211423
|
+
if (maxWidth <= 0 || visibleLength(s) <= maxWidth) return s;
|
|
211424
|
+
const budget = maxWidth - 1;
|
|
211425
|
+
const tokens = s.match(/\x1b\[[0-9;]*m|[\s\S]/gu) ?? [];
|
|
211426
|
+
let out = "";
|
|
211427
|
+
let visible = 0;
|
|
211428
|
+
for (const tok of tokens) {
|
|
211429
|
+
if (tok.charCodeAt(0) === 27) {
|
|
211430
|
+
out += tok;
|
|
211431
|
+
continue;
|
|
211432
|
+
}
|
|
211433
|
+
if (visible >= budget) break;
|
|
211434
|
+
out += tok;
|
|
211435
|
+
visible++;
|
|
211436
|
+
}
|
|
211437
|
+
return `${out}\u2026`;
|
|
211438
|
+
}
|
|
211439
|
+
function terminalWidth() {
|
|
211440
|
+
if (!process.stderr.isTTY) return null;
|
|
211441
|
+
return process.stdout.columns || process.stderr.columns || 80;
|
|
211442
|
+
}
|
|
211417
211443
|
function createStdoutStepRenderer() {
|
|
211418
211444
|
let spinnerFrame2 = 0;
|
|
211419
211445
|
let spinnerInterval2 = null;
|
|
211420
211446
|
let renderedLineCount2 = 0;
|
|
211421
211447
|
let latestSteps2 = null;
|
|
211448
|
+
let lastPainted = null;
|
|
211422
211449
|
function paint(steps) {
|
|
211450
|
+
lastPainted = steps;
|
|
211423
211451
|
if (renderedLineCount2 > 0) {
|
|
211424
211452
|
process.stderr.write(`\x1B[${renderedLineCount2}A`);
|
|
211425
211453
|
}
|
|
211454
|
+
const width = terminalWidth();
|
|
211426
211455
|
for (const step of steps) {
|
|
211427
211456
|
const detail = step.detail && step.status !== "pending" ? ` \u2014 ${step.detail}` : "";
|
|
211428
211457
|
let icon;
|
|
@@ -211449,7 +211478,9 @@ function createStdoutStepRenderer() {
|
|
|
211449
211478
|
icon = "\u25CB";
|
|
211450
211479
|
color = "";
|
|
211451
211480
|
}
|
|
211452
|
-
|
|
211481
|
+
const content = ` ${icon} ${step.label}${detail}`;
|
|
211482
|
+
const line = width === null ? content : clampToWidth(content, width);
|
|
211483
|
+
process.stderr.write(`\x1B[2K${color}${line}${reset}
|
|
211453
211484
|
`);
|
|
211454
211485
|
}
|
|
211455
211486
|
renderedLineCount2 = steps.length;
|
|
@@ -211472,6 +211503,20 @@ function createStdoutStepRenderer() {
|
|
|
211472
211503
|
onProgress(payload) {
|
|
211473
211504
|
if (payload.steps) paint(payload.steps);
|
|
211474
211505
|
},
|
|
211506
|
+
log(line) {
|
|
211507
|
+
if (!process.stderr.isTTY) {
|
|
211508
|
+
process.stderr.write(`${line}
|
|
211509
|
+
`);
|
|
211510
|
+
return;
|
|
211511
|
+
}
|
|
211512
|
+
if (renderedLineCount2 > 0) {
|
|
211513
|
+
process.stderr.write(`\x1B[${renderedLineCount2}A\x1B[0J`);
|
|
211514
|
+
renderedLineCount2 = 0;
|
|
211515
|
+
}
|
|
211516
|
+
process.stderr.write(`${line}
|
|
211517
|
+
`);
|
|
211518
|
+
if (lastPainted) paint(lastPainted);
|
|
211519
|
+
},
|
|
211475
211520
|
dispose() {
|
|
211476
211521
|
if (spinnerInterval2) {
|
|
211477
211522
|
clearInterval(spinnerInterval2);
|
|
@@ -212379,6 +212424,7 @@ async function guardGenerateInProcess(repoRoot5, options = {}) {
|
|
|
212379
212424
|
cur = ni;
|
|
212380
212425
|
};
|
|
212381
212426
|
const withUsage = (key4, base2) => `${base2}${stageUsageTag(GUARD_STEP_STAGES[key4] ?? [], repoRoot5)}`;
|
|
212427
|
+
let extractViewsTotal = 0;
|
|
212382
212428
|
let authorDone = 0;
|
|
212383
212429
|
let authorTotal = 0;
|
|
212384
212430
|
let authorFinished = false;
|
|
@@ -212426,16 +212472,19 @@ async function guardGenerateInProcess(repoRoot5, options = {}) {
|
|
|
212426
212472
|
sectionsTotal = work;
|
|
212427
212473
|
tracker?.done("index", withUsage("index", `${work} of ${total} section${total === 1 ? "" : "s"} changed`));
|
|
212428
212474
|
cur = STEPS.indexOf("extract");
|
|
212429
|
-
tracker?.start("extract"
|
|
212475
|
+
tracker?.start("extract");
|
|
212430
212476
|
},
|
|
212431
212477
|
onExtractViewProgress: (done, total) => {
|
|
212478
|
+
extractViewsTotal = total;
|
|
212432
212479
|
advanceTo("extract");
|
|
212433
|
-
tracker?.detail("extract", withUsage("extract",
|
|
212480
|
+
tracker?.detail("extract", withUsage("extract", `views ${done}/${total}`));
|
|
212434
212481
|
},
|
|
212435
212482
|
onExtractProgress: (done, total) => {
|
|
212436
212483
|
advanceTo("extract");
|
|
212437
212484
|
if (done >= total) {
|
|
212438
|
-
|
|
212485
|
+
const docs = `${total} doc${total === 1 ? "" : "s"}`;
|
|
212486
|
+
const views = `${extractViewsTotal} view${extractViewsTotal === 1 ? "" : "s"}`;
|
|
212487
|
+
tracker?.done("extract", withUsage("extract", `${docs} \xB7 ${views}`));
|
|
212439
212488
|
}
|
|
212440
212489
|
},
|
|
212441
212490
|
onAuthorProgress: (done, total) => {
|
|
@@ -212547,7 +212596,10 @@ async function guardRunInProcess(repoRoot5, options = {}) {
|
|
|
212547
212596
|
tracker?.start("run", `0/${total} scenarios`);
|
|
212548
212597
|
}
|
|
212549
212598
|
},
|
|
212550
|
-
onScenarioSettled: (done, total) =>
|
|
212599
|
+
onScenarioSettled: (done, total, scenarioResult) => {
|
|
212600
|
+
tracker?.detail("run", `${done}/${total} scenarios`);
|
|
212601
|
+
options.onScenarioResult?.(scenarioResult);
|
|
212602
|
+
}
|
|
212551
212603
|
});
|
|
212552
212604
|
if (result.status === "ok") {
|
|
212553
212605
|
const n = result.latest.summary.total;
|
|
@@ -212580,13 +212632,26 @@ var MARK2 = {
|
|
|
212580
212632
|
stale: "~",
|
|
212581
212633
|
orphaned: "\u25CB"
|
|
212582
212634
|
};
|
|
212635
|
+
function scenarioLine(s) {
|
|
212636
|
+
const suffix = s.outcome === "stale" || s.outcome === "orphaned" ? ` \u2014 ${BINDING_REASON[s.outcome]}` : ` (${Math.round(s.durationMs)}ms)`;
|
|
212637
|
+
return `${MARK2[s.outcome]} ${s.id} \u2014 ${s.title}${suffix}`;
|
|
212638
|
+
}
|
|
212583
212639
|
async function runGuardRun(opts = {}) {
|
|
212584
212640
|
const repoRoot5 = opts.cwd ?? process.cwd();
|
|
212585
212641
|
mt("Guard");
|
|
212586
212642
|
await requireGitRepo(repoRoot5);
|
|
212587
212643
|
const renderer = createStdoutStepRenderer();
|
|
212588
212644
|
const tracker = new StepTracker(renderer.onProgress, GUARD_RUN_STEPS.map((s) => ({ ...s })));
|
|
212589
|
-
const result = await guardRunInProcess(repoRoot5, {
|
|
212645
|
+
const result = await guardRunInProcess(repoRoot5, {
|
|
212646
|
+
scenario: opts.scenario,
|
|
212647
|
+
tracker,
|
|
212648
|
+
// Non-pass results surface the moment they settle — a full line each,
|
|
212649
|
+
// printed above the live counter so they are never buried under pass
|
|
212650
|
+
// output. Passes ride the counter only (`--verbose` lists them at the end).
|
|
212651
|
+
onScenarioResult: (s) => {
|
|
212652
|
+
if (s.outcome !== "pass") renderer.log(scenarioLine(s));
|
|
212653
|
+
}
|
|
212654
|
+
});
|
|
212590
212655
|
renderer.dispose();
|
|
212591
212656
|
switch (result.status) {
|
|
212592
212657
|
case "no-recipe":
|
|
@@ -212632,22 +212697,8 @@ async function runGuardRun(opts = {}) {
|
|
|
212632
212697
|
break;
|
|
212633
212698
|
}
|
|
212634
212699
|
const { latest, loadErrors, manifest } = result;
|
|
212635
|
-
|
|
212636
|
-
const
|
|
212637
|
-
O2.message(`${MARK2[s.outcome]} ${s.id} \u2014 ${s.title}${suffix}`);
|
|
212638
|
-
}
|
|
212639
|
-
const failing = latest.scenarios.filter((s) => s.outcome === "fail" || s.outcome === "error");
|
|
212640
|
-
if (failing.length > 0) {
|
|
212641
|
-
O2.message("");
|
|
212642
|
-
for (const s of failing) {
|
|
212643
|
-
O2.message(`${MARK2[s.outcome]} ${s.id}`);
|
|
212644
|
-
if (s.failure) {
|
|
212645
|
-
O2.message(` step ${s.failure.step}`);
|
|
212646
|
-
O2.message(` expected: ${s.failure.expected}`);
|
|
212647
|
-
O2.message(` actual: ${s.failure.actual}`);
|
|
212648
|
-
}
|
|
212649
|
-
if (s.evidencePath) O2.message(` evidence: ${s.evidencePath}`);
|
|
212650
|
-
}
|
|
212700
|
+
if (opts.verbose) {
|
|
212701
|
+
for (const s of latest.scenarios) O2.message(scenarioLine(s));
|
|
212651
212702
|
}
|
|
212652
212703
|
printLoadErrors(loadErrors);
|
|
212653
212704
|
if (manifest) O2.info(`manifest: ${manifest.sections.length} section${manifest.sections.length === 1 ? "" : "s"} recorded`);
|
|
@@ -212661,6 +212712,12 @@ async function runGuardRun(opts = {}) {
|
|
|
212661
212712
|
const bad = fail4 > 0 || error > 0 || stale > 0 || orphaned > 0 || loadErrors.length > 0;
|
|
212662
212713
|
if (bad) {
|
|
212663
212714
|
O2.error(parts.join(" \xB7 "));
|
|
212715
|
+
O2.info(
|
|
212716
|
+
[
|
|
212717
|
+
"`truecourse guard drifts` \u2014 inspect failures (expected/actual/evidence)",
|
|
212718
|
+
"`truecourse guard status` \u2014 coverage"
|
|
212719
|
+
].join("\n")
|
|
212720
|
+
);
|
|
212664
212721
|
gt("Guard found drift.");
|
|
212665
212722
|
process.exit(1);
|
|
212666
212723
|
}
|
|
@@ -213270,7 +213327,7 @@ async function runHooksRun() {
|
|
|
213270
213327
|
|
|
213271
213328
|
// tools/cli/src/index.ts
|
|
213272
213329
|
var program2 = new Command();
|
|
213273
|
-
program2.name("truecourse").version("0.7.0-next.
|
|
213330
|
+
program2.name("truecourse").version("0.7.0-next.11").description("TrueCourse CLI \u2014 analyze your repository and open the dashboard");
|
|
213274
213331
|
function warnDiscontinued(command) {
|
|
213275
213332
|
process.stderr.write(
|
|
213276
213333
|
`\u26A0 \`${command}\` is discontinued in favor of \`truecourse guard\` \u2014 see the README. Planned removal: 0.8.
|
|
@@ -213424,8 +213481,8 @@ driftsCmd.command("list").description("List drifts from the latest verify (pagin
|
|
|
213424
213481
|
});
|
|
213425
213482
|
});
|
|
213426
213483
|
var guardCmd = program2.command("guard").description("Run spec-section-bound scenario tests");
|
|
213427
|
-
guardCmd.command("run").description("Build via the recipe and run the committed scenarios").option("--scenario <id>", "Run only the scenario with this id").action(async (options) => {
|
|
213428
|
-
await runGuardRun({ scenario: options.scenario });
|
|
213484
|
+
guardCmd.command("run").description("Build via the recipe and run the committed scenarios").option("--scenario <id>", "Run only the scenario with this id").option("--verbose", "List every scenario result (one \u2713 line per pass)").action(async (options) => {
|
|
213485
|
+
await runGuardRun({ scenario: options.scenario, verbose: !!options.verbose });
|
|
213429
213486
|
});
|
|
213430
213487
|
guardCmd.command("generate").description("Author spec-section-bound scenarios (classify \u2192 generate \u2192 birth-validate)").option("-y, --yes", "Skip the pre-flight cost-estimate confirmation").option("--llm-transport <mode>", "LLM transport: cli (default) or agent").option("--io <dir>", "Request/response mailbox dir for --llm-transport agent").action(async (options) => {
|
|
213431
213488
|
await runGuardGenerate({
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
package/server.mjs
CHANGED
|
@@ -227399,6 +227399,7 @@ async function generateGuards(options) {
|
|
|
227399
227399
|
let extractDone = 0;
|
|
227400
227400
|
const viewTotal = workDocs.reduce((n, d) => n + countExtractViews(d), 0);
|
|
227401
227401
|
let viewDone = 0;
|
|
227402
|
+
options.onExtractViewProgress?.(0, viewTotal);
|
|
227402
227403
|
const extracted = await Promise.all(workDocs.map(async (doc) => {
|
|
227403
227404
|
const result = await extractDocClaims(repoRoot, doc, extractRunner, limit, () => options.onExtractViewProgress?.(++viewDone, viewTotal));
|
|
227404
227405
|
options.onExtractProgress?.(++extractDone, workDocs.length);
|
|
@@ -233154,7 +233155,7 @@ function readToolVersion() {
|
|
|
233154
233155
|
if (cachedVersion)
|
|
233155
233156
|
return cachedVersion;
|
|
233156
233157
|
if (true) {
|
|
233157
|
-
cachedVersion = "0.7.0-next.
|
|
233158
|
+
cachedVersion = "0.7.0-next.11";
|
|
233158
233159
|
return cachedVersion;
|
|
233159
233160
|
}
|
|
233160
233161
|
try {
|
|
@@ -241105,6 +241106,7 @@ async function guardGenerateInProcess(repoRoot, options = {}) {
|
|
|
241105
241106
|
cur = ni;
|
|
241106
241107
|
};
|
|
241107
241108
|
const withUsage = (key4, base) => `${base}${stageUsageTag(GUARD_STEP_STAGES[key4] ?? [], repoRoot)}`;
|
|
241109
|
+
let extractViewsTotal = 0;
|
|
241108
241110
|
let authorDone = 0;
|
|
241109
241111
|
let authorTotal = 0;
|
|
241110
241112
|
let authorFinished = false;
|
|
@@ -241152,16 +241154,19 @@ async function guardGenerateInProcess(repoRoot, options = {}) {
|
|
|
241152
241154
|
sectionsTotal = work;
|
|
241153
241155
|
tracker?.done("index", withUsage("index", `${work} of ${total} section${total === 1 ? "" : "s"} changed`));
|
|
241154
241156
|
cur = STEPS.indexOf("extract");
|
|
241155
|
-
tracker?.start("extract"
|
|
241157
|
+
tracker?.start("extract");
|
|
241156
241158
|
},
|
|
241157
241159
|
onExtractViewProgress: (done, total) => {
|
|
241160
|
+
extractViewsTotal = total;
|
|
241158
241161
|
advanceTo("extract");
|
|
241159
|
-
tracker?.detail("extract", withUsage("extract",
|
|
241162
|
+
tracker?.detail("extract", withUsage("extract", `views ${done}/${total}`));
|
|
241160
241163
|
},
|
|
241161
241164
|
onExtractProgress: (done, total) => {
|
|
241162
241165
|
advanceTo("extract");
|
|
241163
241166
|
if (done >= total) {
|
|
241164
|
-
|
|
241167
|
+
const docs = `${total} doc${total === 1 ? "" : "s"}`;
|
|
241168
|
+
const views = `${extractViewsTotal} view${extractViewsTotal === 1 ? "" : "s"}`;
|
|
241169
|
+
tracker?.done("extract", withUsage("extract", `${docs} \xB7 ${views}`));
|
|
241165
241170
|
}
|
|
241166
241171
|
},
|
|
241167
241172
|
onAuthorProgress: (done, total) => {
|
|
@@ -241273,7 +241278,10 @@ async function guardRunInProcess(repoRoot, options = {}) {
|
|
|
241273
241278
|
tracker?.start("run", `0/${total} scenarios`);
|
|
241274
241279
|
}
|
|
241275
241280
|
},
|
|
241276
|
-
onScenarioSettled: (done, total) =>
|
|
241281
|
+
onScenarioSettled: (done, total, scenarioResult) => {
|
|
241282
|
+
tracker?.detail("run", `${done}/${total} scenarios`);
|
|
241283
|
+
options.onScenarioResult?.(scenarioResult);
|
|
241284
|
+
}
|
|
241277
241285
|
});
|
|
241278
241286
|
if (result.status === "ok") {
|
|
241279
241287
|
const n = result.latest.summary.total;
|