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 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.10";
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
- process.stderr.write(`\x1B[2K${color} ${icon} ${step.label}${detail}${reset}
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", `0 views`);
212475
+ tracker?.start("extract");
212430
212476
  },
212431
212477
  onExtractViewProgress: (done, total) => {
212478
+ extractViewsTotal = total;
212432
212479
  advanceTo("extract");
212433
- tracker?.detail("extract", withUsage("extract", `${done}/${total} view${total === 1 ? "" : "s"}`));
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
- tracker?.done("extract", withUsage("extract", `${total} doc${total === 1 ? "" : "s"}`));
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) => tracker?.detail("run", `${done}/${total} scenarios`)
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, { scenario: opts.scenario, tracker });
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
- for (const s of latest.scenarios) {
212636
- const suffix = s.outcome === "stale" || s.outcome === "orphaned" ? ` \u2014 ${BINDING_REASON[s.outcome]}` : ` (${Math.round(s.durationMs)}ms)`;
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.10").description("TrueCourse CLI \u2014 analyze your repository and open the dashboard");
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "truecourse",
3
- "version": "0.7.0-next.10",
3
+ "version": "0.7.0-next.11",
4
4
  "description": "Visualize your codebase architecture as an interactive graph",
5
5
  "type": "module",
6
6
  "bin": {
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.10";
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", `0 views`);
241157
+ tracker?.start("extract");
241156
241158
  },
241157
241159
  onExtractViewProgress: (done, total) => {
241160
+ extractViewsTotal = total;
241158
241161
  advanceTo("extract");
241159
- tracker?.detail("extract", withUsage("extract", `${done}/${total} view${total === 1 ? "" : "s"}`));
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
- tracker?.done("extract", withUsage("extract", `${total} doc${total === 1 ? "" : "s"}`));
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) => tracker?.detail("run", `${done}/${total} scenarios`)
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;