truecourse 0.7.0-next.3 → 0.7.0-next.4
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/cli.mjs +324 -156
- package/package.json +1 -1
- package/public/assets/index-CMCPeAwv.css +1 -0
- package/public/assets/{index-B4R8yF4j.js → index-rfhWLMD4.js} +223 -218
- package/public/index.html +2 -2
- package/server.mjs +572 -303
- package/public/assets/index-D9ShQqXg.css +0 -1
package/cli.mjs
CHANGED
|
@@ -973,7 +973,7 @@ var require_command = __commonJS({
|
|
|
973
973
|
var EventEmitter2 = __require("node:events").EventEmitter;
|
|
974
974
|
var childProcess = __require("node:child_process");
|
|
975
975
|
var path80 = __require("node:path");
|
|
976
|
-
var
|
|
976
|
+
var fs70 = __require("node:fs");
|
|
977
977
|
var process2 = __require("node:process");
|
|
978
978
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
979
979
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1906,10 +1906,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1906
1906
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1907
1907
|
function findFile(baseDir, baseName) {
|
|
1908
1908
|
const localBin = path80.resolve(baseDir, baseName);
|
|
1909
|
-
if (
|
|
1909
|
+
if (fs70.existsSync(localBin)) return localBin;
|
|
1910
1910
|
if (sourceExt.includes(path80.extname(baseName))) return void 0;
|
|
1911
1911
|
const foundExt = sourceExt.find(
|
|
1912
|
-
(ext2) =>
|
|
1912
|
+
(ext2) => fs70.existsSync(`${localBin}${ext2}`)
|
|
1913
1913
|
);
|
|
1914
1914
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1915
1915
|
return void 0;
|
|
@@ -1921,7 +1921,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1921
1921
|
if (this._scriptPath) {
|
|
1922
1922
|
let resolvedScriptPath;
|
|
1923
1923
|
try {
|
|
1924
|
-
resolvedScriptPath =
|
|
1924
|
+
resolvedScriptPath = fs70.realpathSync(this._scriptPath);
|
|
1925
1925
|
} catch (err) {
|
|
1926
1926
|
resolvedScriptPath = this._scriptPath;
|
|
1927
1927
|
}
|
|
@@ -105218,7 +105218,7 @@ function parseBlockedOnCapabilities(reason) {
|
|
|
105218
105218
|
return [];
|
|
105219
105219
|
return m[1].split(",").map((s) => s.trim()).filter(Boolean);
|
|
105220
105220
|
}
|
|
105221
|
-
var GuardWrittenScenarioSchema, GuardCoverageGapKindSchema, GuardCoverageGapSchema, GuardBirthFindingSchema, GuardGenerateErrorSchema, GuardEntryPreflightSchema, GuardExtractionFailureSchema, GuardOrphanedSectionSchema, GuardRecipeReportSchema, GuardGenerateUsageSchema, GuardGenerateReportSchema;
|
|
105221
|
+
var GuardWrittenScenarioSchema, GuardCoverageGapKindSchema, GuardCoverageGapSchema, GuardBirthFindingSchema, GuardGenerateErrorSchema, GuardReadyScenarioSchema, GuardHeldSectionSchema, GuardEntryPreflightSchema, GuardExtractionFailureSchema, GuardOrphanedDismissalSchema, GuardOrphanedSectionSchema, GuardRecipeReportSchema, GuardGenerateUsageSchema, GuardGenerateReportSchema;
|
|
105222
105222
|
var init_report = __esm({
|
|
105223
105223
|
"packages/shared/dist/guard/report.js"() {
|
|
105224
105224
|
"use strict";
|
|
@@ -105236,7 +105236,8 @@ var init_report = __esm({
|
|
|
105236
105236
|
"awaiting-driver",
|
|
105237
105237
|
"untestable",
|
|
105238
105238
|
"no-claim",
|
|
105239
|
-
"blocked-on"
|
|
105239
|
+
"blocked-on",
|
|
105240
|
+
"dismissed"
|
|
105240
105241
|
]);
|
|
105241
105242
|
GuardCoverageGapSchema = external_exports.object({
|
|
105242
105243
|
doc: external_exports.string(),
|
|
@@ -105258,6 +105259,22 @@ var init_report = __esm({
|
|
|
105258
105259
|
actual: external_exports.string(),
|
|
105259
105260
|
/** Repo-relative pointer into `guard/evidence/`, when a transcript was written. */
|
|
105260
105261
|
evidencePath: external_exports.string().optional(),
|
|
105262
|
+
/**
|
|
105263
|
+
* The failed candidate's authored YAML, serialized inline AT FINDING CREATION
|
|
105264
|
+
* (same serialize-at-creation as heldSections' readyScenarios). The finding
|
|
105265
|
+
* detail renders it in the scenario-source code block so the user can judge
|
|
105266
|
+
* "defect or drift" with the exact commands the scenario ran on-screen.
|
|
105267
|
+
* Optional so older `result.json` files keep parsing.
|
|
105268
|
+
*/
|
|
105269
|
+
yaml: external_exports.string().optional(),
|
|
105270
|
+
/**
|
|
105271
|
+
* The EXTRACTED CLAIM's stable text — the claim identity a dismissal keys on
|
|
105272
|
+
* (anchor + this). The finding detail's Dismiss action writes it into
|
|
105273
|
+
* `scenarios/decisions.json`; generate then skips a matching claim before
|
|
105274
|
+
* authoring. Distinct from `title` (the scenario title). Optional so older
|
|
105275
|
+
* reports (and the internal retry-evidence findings) parse.
|
|
105276
|
+
*/
|
|
105277
|
+
claim: external_exports.string().optional(),
|
|
105261
105278
|
/**
|
|
105262
105279
|
* The bound section's human heading, joined SERVER-SIDE at report read time
|
|
105263
105280
|
* (never written to `result.json` — the enrichment is read-side). A finding's
|
|
@@ -105271,6 +105288,18 @@ var init_report = __esm({
|
|
|
105271
105288
|
anchor: external_exports.string(),
|
|
105272
105289
|
message: external_exports.string()
|
|
105273
105290
|
}).strict();
|
|
105291
|
+
GuardReadyScenarioSchema = external_exports.object({
|
|
105292
|
+
id: external_exports.string(),
|
|
105293
|
+
title: external_exports.string(),
|
|
105294
|
+
/** The committed YAML the scenario would have been written as. */
|
|
105295
|
+
yaml: external_exports.string()
|
|
105296
|
+
}).strict();
|
|
105297
|
+
GuardHeldSectionSchema = external_exports.object({
|
|
105298
|
+
doc: external_exports.string(),
|
|
105299
|
+
anchor: external_exports.string(),
|
|
105300
|
+
headingText: external_exports.string().optional(),
|
|
105301
|
+
readyScenarios: external_exports.array(GuardReadyScenarioSchema)
|
|
105302
|
+
}).strict();
|
|
105274
105303
|
GuardEntryPreflightSchema = external_exports.object({
|
|
105275
105304
|
/** Display form of the entry argv, e.g. `node tools/cli/dist/index.js`. */
|
|
105276
105305
|
entry: external_exports.string(),
|
|
@@ -105283,6 +105312,11 @@ var init_report = __esm({
|
|
|
105283
105312
|
doc: external_exports.string(),
|
|
105284
105313
|
reason: external_exports.string()
|
|
105285
105314
|
}).strict();
|
|
105315
|
+
GuardOrphanedDismissalSchema = external_exports.object({
|
|
105316
|
+
doc: external_exports.string(),
|
|
105317
|
+
anchor: external_exports.string(),
|
|
105318
|
+
title: external_exports.string()
|
|
105319
|
+
}).strict();
|
|
105286
105320
|
GuardOrphanedSectionSchema = external_exports.object({
|
|
105287
105321
|
doc: external_exports.string(),
|
|
105288
105322
|
anchor: external_exports.string(),
|
|
@@ -105323,6 +105357,19 @@ var init_report = __esm({
|
|
|
105323
105357
|
* `written.length` when a passing scenario's section didn't settle.
|
|
105324
105358
|
*/
|
|
105325
105359
|
birthPassed: external_exports.number().int().nonnegative().optional(),
|
|
105360
|
+
/**
|
|
105361
|
+
* Unsettled sections whose birth-passed candidates were withheld — the
|
|
105362
|
+
* ready-but-held scenarios, each carrying its authored YAML inline. Optional so
|
|
105363
|
+
* older reports (written before this field existed) keep parsing; absent reads
|
|
105364
|
+
* as "no held work".
|
|
105365
|
+
*/
|
|
105366
|
+
heldSections: external_exports.array(GuardHeldSectionSchema).optional(),
|
|
105367
|
+
/**
|
|
105368
|
+
* Dismissals whose claim text matched nothing in a doc this run re-extracted —
|
|
105369
|
+
* stale entries in `scenarios/decisions.json`, surfaced (never silently
|
|
105370
|
+
* honored). Optional so older reports parse; absent reads as "none".
|
|
105371
|
+
*/
|
|
105372
|
+
orphanedDismissals: external_exports.array(GuardOrphanedDismissalSchema).optional(),
|
|
105326
105373
|
manifestPath: external_exports.string().optional(),
|
|
105327
105374
|
usage: GuardGenerateUsageSchema.optional(),
|
|
105328
105375
|
/**
|
|
@@ -105373,6 +105420,35 @@ var init_manifest = __esm({
|
|
|
105373
105420
|
}
|
|
105374
105421
|
});
|
|
105375
105422
|
|
|
105423
|
+
// packages/shared/dist/guard/decisions.js
|
|
105424
|
+
function dismissedClaimKey(doc, anchor, title) {
|
|
105425
|
+
return `${doc}\0${anchor}\0${title}`;
|
|
105426
|
+
}
|
|
105427
|
+
var GuardDismissedClaimSchema, GuardDecisionsSchema, EMPTY_GUARD_DECISIONS;
|
|
105428
|
+
var init_decisions = __esm({
|
|
105429
|
+
"packages/shared/dist/guard/decisions.js"() {
|
|
105430
|
+
"use strict";
|
|
105431
|
+
init_zod();
|
|
105432
|
+
GuardDismissedClaimSchema = external_exports.object({
|
|
105433
|
+
/** Repo-relative doc path the claim's section lives in. */
|
|
105434
|
+
doc: external_exports.string().min(1),
|
|
105435
|
+
/** The section anchor (slug) the claim was extracted under. */
|
|
105436
|
+
anchor: external_exports.string().min(1),
|
|
105437
|
+
/** The extracted claim's stable text — the identity, with `anchor`. */
|
|
105438
|
+
title: external_exports.string().min(1),
|
|
105439
|
+
/** ISO timestamp the dismissal was recorded. */
|
|
105440
|
+
dismissedAt: external_exports.string(),
|
|
105441
|
+
/** Optional free-text rationale ("flaky", "won't fix", …). */
|
|
105442
|
+
note: external_exports.string().optional()
|
|
105443
|
+
});
|
|
105444
|
+
GuardDecisionsSchema = external_exports.object({
|
|
105445
|
+
version: external_exports.literal(1),
|
|
105446
|
+
dismissedClaims: external_exports.array(GuardDismissedClaimSchema).default([])
|
|
105447
|
+
});
|
|
105448
|
+
EMPTY_GUARD_DECISIONS = { version: 1, dismissedClaims: [] };
|
|
105449
|
+
}
|
|
105450
|
+
});
|
|
105451
|
+
|
|
105376
105452
|
// packages/shared/dist/guard/dashboard.js
|
|
105377
105453
|
var init_dashboard = __esm({
|
|
105378
105454
|
"packages/shared/dist/guard/dashboard.js"() {
|
|
@@ -105423,6 +105499,11 @@ function summarizeGenerate(r) {
|
|
|
105423
105499
|
}
|
|
105424
105500
|
}
|
|
105425
105501
|
}
|
|
105502
|
+
const heldSections = r.heldSections ?? [];
|
|
105503
|
+
const heldKeys = new Set(heldSections.map((h) => `${h.doc}\0${h.anchor}`));
|
|
105504
|
+
const readyButHeld = heldSections.reduce((n, h) => n + h.readyScenarios.length, 0);
|
|
105505
|
+
const heldByFindings = r.birthFindings.filter((f2) => heldKeys.has(`${f2.doc}\0${f2.anchor}`)).length;
|
|
105506
|
+
const heldByErrors = r.errors.filter((e) => heldKeys.has(`${e.doc}\0${e.anchor}`)).length;
|
|
105426
105507
|
return {
|
|
105427
105508
|
generatedAt: r.generatedAt,
|
|
105428
105509
|
status: r.status,
|
|
@@ -105433,6 +105514,9 @@ function summarizeGenerate(r) {
|
|
|
105433
105514
|
blockedOnCapabilities,
|
|
105434
105515
|
birthFindings: r.birthFindings.length,
|
|
105435
105516
|
errors: r.errors.length,
|
|
105517
|
+
readyButHeld,
|
|
105518
|
+
heldByFindings,
|
|
105519
|
+
heldByErrors,
|
|
105436
105520
|
...r.usage ? { usage: r.usage } : {}
|
|
105437
105521
|
};
|
|
105438
105522
|
}
|
|
@@ -105464,6 +105548,7 @@ var init_guard = __esm({
|
|
|
105464
105548
|
init_result();
|
|
105465
105549
|
init_report();
|
|
105466
105550
|
init_manifest();
|
|
105551
|
+
init_decisions();
|
|
105467
105552
|
init_dashboard();
|
|
105468
105553
|
init_summary();
|
|
105469
105554
|
}
|
|
@@ -146609,7 +146694,7 @@ var require_windows = __commonJS({
|
|
|
146609
146694
|
"node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/windows.js"(exports, module) {
|
|
146610
146695
|
module.exports = isexe;
|
|
146611
146696
|
isexe.sync = sync;
|
|
146612
|
-
var
|
|
146697
|
+
var fs70 = __require("fs");
|
|
146613
146698
|
function checkPathExt(path80, options) {
|
|
146614
146699
|
var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
|
|
146615
146700
|
if (!pathext) {
|
|
@@ -146634,12 +146719,12 @@ var require_windows = __commonJS({
|
|
|
146634
146719
|
return checkPathExt(path80, options);
|
|
146635
146720
|
}
|
|
146636
146721
|
function isexe(path80, options, cb) {
|
|
146637
|
-
|
|
146722
|
+
fs70.stat(path80, function(er, stat) {
|
|
146638
146723
|
cb(er, er ? false : checkStat(stat, path80, options));
|
|
146639
146724
|
});
|
|
146640
146725
|
}
|
|
146641
146726
|
function sync(path80, options) {
|
|
146642
|
-
return checkStat(
|
|
146727
|
+
return checkStat(fs70.statSync(path80), path80, options);
|
|
146643
146728
|
}
|
|
146644
146729
|
}
|
|
146645
146730
|
});
|
|
@@ -146649,14 +146734,14 @@ var require_mode = __commonJS({
|
|
|
146649
146734
|
"node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/mode.js"(exports, module) {
|
|
146650
146735
|
module.exports = isexe;
|
|
146651
146736
|
isexe.sync = sync;
|
|
146652
|
-
var
|
|
146737
|
+
var fs70 = __require("fs");
|
|
146653
146738
|
function isexe(path80, options, cb) {
|
|
146654
|
-
|
|
146739
|
+
fs70.stat(path80, function(er, stat) {
|
|
146655
146740
|
cb(er, er ? false : checkStat(stat, options));
|
|
146656
146741
|
});
|
|
146657
146742
|
}
|
|
146658
146743
|
function sync(path80, options) {
|
|
146659
|
-
return checkStat(
|
|
146744
|
+
return checkStat(fs70.statSync(path80), options);
|
|
146660
146745
|
}
|
|
146661
146746
|
function checkStat(stat, options) {
|
|
146662
146747
|
return stat.isFile() && checkMode(stat, options);
|
|
@@ -146680,7 +146765,7 @@ var require_mode = __commonJS({
|
|
|
146680
146765
|
// node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js
|
|
146681
146766
|
var require_isexe = __commonJS({
|
|
146682
146767
|
"node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js"(exports, module) {
|
|
146683
|
-
var
|
|
146768
|
+
var fs70 = __require("fs");
|
|
146684
146769
|
var core2;
|
|
146685
146770
|
if (process.platform === "win32" || global.TESTING_WINDOWS) {
|
|
146686
146771
|
core2 = require_windows();
|
|
@@ -146944,16 +147029,16 @@ var require_shebang_command = __commonJS({
|
|
|
146944
147029
|
var require_readShebang = __commonJS({
|
|
146945
147030
|
"node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js"(exports, module) {
|
|
146946
147031
|
"use strict";
|
|
146947
|
-
var
|
|
147032
|
+
var fs70 = __require("fs");
|
|
146948
147033
|
var shebangCommand = require_shebang_command();
|
|
146949
147034
|
function readShebang(command) {
|
|
146950
147035
|
const size = 150;
|
|
146951
147036
|
const buffer = Buffer.alloc(size);
|
|
146952
147037
|
let fd;
|
|
146953
147038
|
try {
|
|
146954
|
-
fd =
|
|
146955
|
-
|
|
146956
|
-
|
|
147039
|
+
fd = fs70.openSync(command, "r");
|
|
147040
|
+
fs70.readSync(fd, buffer, 0, size, 0);
|
|
147041
|
+
fs70.closeSync(fd);
|
|
146957
147042
|
} catch (e) {
|
|
146958
147043
|
}
|
|
146959
147044
|
return shebangCommand(buffer.toString());
|
|
@@ -147357,7 +147442,7 @@ var require_package = __commonJS({
|
|
|
147357
147442
|
// node_modules/.pnpm/dotenv@16.6.1/node_modules/dotenv/lib/main.js
|
|
147358
147443
|
var require_main = __commonJS({
|
|
147359
147444
|
"node_modules/.pnpm/dotenv@16.6.1/node_modules/dotenv/lib/main.js"(exports, module) {
|
|
147360
|
-
var
|
|
147445
|
+
var fs70 = __require("fs");
|
|
147361
147446
|
var path80 = __require("path");
|
|
147362
147447
|
var os15 = __require("os");
|
|
147363
147448
|
var crypto6 = __require("crypto");
|
|
@@ -147466,7 +147551,7 @@ var require_main = __commonJS({
|
|
|
147466
147551
|
if (options && options.path && options.path.length > 0) {
|
|
147467
147552
|
if (Array.isArray(options.path)) {
|
|
147468
147553
|
for (const filepath of options.path) {
|
|
147469
|
-
if (
|
|
147554
|
+
if (fs70.existsSync(filepath)) {
|
|
147470
147555
|
possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
|
|
147471
147556
|
}
|
|
147472
147557
|
}
|
|
@@ -147476,7 +147561,7 @@ var require_main = __commonJS({
|
|
|
147476
147561
|
} else {
|
|
147477
147562
|
possibleVaultPath = path80.resolve(process.cwd(), ".env.vault");
|
|
147478
147563
|
}
|
|
147479
|
-
if (
|
|
147564
|
+
if (fs70.existsSync(possibleVaultPath)) {
|
|
147480
147565
|
return possibleVaultPath;
|
|
147481
147566
|
}
|
|
147482
147567
|
return null;
|
|
@@ -147525,7 +147610,7 @@ var require_main = __commonJS({
|
|
|
147525
147610
|
const parsedAll = {};
|
|
147526
147611
|
for (const path81 of optionPaths) {
|
|
147527
147612
|
try {
|
|
147528
|
-
const parsed = DotenvModule.parse(
|
|
147613
|
+
const parsed = DotenvModule.parse(fs70.readFileSync(path81, { encoding }));
|
|
147529
147614
|
DotenvModule.populate(parsedAll, parsed, options);
|
|
147530
147615
|
} catch (e) {
|
|
147531
147616
|
if (debug2) {
|
|
@@ -161618,7 +161703,7 @@ var require_form_data = __commonJS({
|
|
|
161618
161703
|
var http = __require("http");
|
|
161619
161704
|
var https = __require("https");
|
|
161620
161705
|
var parseUrl = __require("url").parse;
|
|
161621
|
-
var
|
|
161706
|
+
var fs70 = __require("fs");
|
|
161622
161707
|
var Stream = __require("stream").Stream;
|
|
161623
161708
|
var crypto6 = __require("crypto");
|
|
161624
161709
|
var mime = require_mime_types();
|
|
@@ -161685,7 +161770,7 @@ var require_form_data = __commonJS({
|
|
|
161685
161770
|
if (value.end != void 0 && value.end != Infinity && value.start != void 0) {
|
|
161686
161771
|
callback(null, value.end + 1 - (value.start ? value.start : 0));
|
|
161687
161772
|
} else {
|
|
161688
|
-
|
|
161773
|
+
fs70.stat(value.path, function(err, stat) {
|
|
161689
161774
|
if (err) {
|
|
161690
161775
|
callback(err);
|
|
161691
161776
|
return;
|
|
@@ -162303,8 +162388,8 @@ var require_node2 = __commonJS({
|
|
|
162303
162388
|
}
|
|
162304
162389
|
break;
|
|
162305
162390
|
case "FILE":
|
|
162306
|
-
var
|
|
162307
|
-
stream2 = new
|
|
162391
|
+
var fs70 = __require("fs");
|
|
162392
|
+
stream2 = new fs70.SyncWriteStream(fd2, { autoClose: false });
|
|
162308
162393
|
stream2._type = "fs";
|
|
162309
162394
|
break;
|
|
162310
162395
|
case "PIPE":
|
|
@@ -170284,7 +170369,7 @@ function readToolVersion() {
|
|
|
170284
170369
|
if (cachedVersion)
|
|
170285
170370
|
return cachedVersion;
|
|
170286
170371
|
if (true) {
|
|
170287
|
-
cachedVersion = "0.7.0-next.
|
|
170372
|
+
cachedVersion = "0.7.0-next.4";
|
|
170288
170373
|
return cachedVersion;
|
|
170289
170374
|
}
|
|
170290
170375
|
try {
|
|
@@ -172690,13 +172775,13 @@ var init_pexprs_toFailure = __esm({
|
|
|
172690
172775
|
return new Failure(this, "a Unicode [" + this.categoryOrProp + "] character", "description");
|
|
172691
172776
|
};
|
|
172692
172777
|
Alt.prototype.toFailure = function(grammar2) {
|
|
172693
|
-
const
|
|
172694
|
-
const description = "(" +
|
|
172778
|
+
const fs70 = this.terms.map((t2) => t2.toFailure(grammar2));
|
|
172779
|
+
const description = "(" + fs70.join(" or ") + ")";
|
|
172695
172780
|
return new Failure(this, description, "description");
|
|
172696
172781
|
};
|
|
172697
172782
|
Seq.prototype.toFailure = function(grammar2) {
|
|
172698
|
-
const
|
|
172699
|
-
const description = "(" +
|
|
172783
|
+
const fs70 = this.factors.map((f2) => f2.toFailure(grammar2));
|
|
172784
|
+
const description = "(" + fs70.join(" ") + ")";
|
|
172700
172785
|
return new Failure(this, description, "description");
|
|
172701
172786
|
};
|
|
172702
172787
|
Iter.prototype.toFailure = function(grammar2) {
|
|
@@ -174533,9 +174618,9 @@ function buildGrammar2(match4, namespace, optOhmGrammarForTesting, options) {
|
|
|
174533
174618
|
decl.withSuperGrammar(namespace[superGrammarName]);
|
|
174534
174619
|
}
|
|
174535
174620
|
},
|
|
174536
|
-
Rule_define(n,
|
|
174621
|
+
Rule_define(n, fs70, d3, _2, b) {
|
|
174537
174622
|
currentRuleName = n.visit();
|
|
174538
|
-
currentRuleFormals =
|
|
174623
|
+
currentRuleFormals = fs70.children.map((c2) => c2.visit())[0] || [];
|
|
174539
174624
|
if (!decl.defaultStartRule && decl.ensureSuperGrammar() !== Grammar.ProtoBuiltInRules) {
|
|
174540
174625
|
decl.withDefaultStartRule(currentRuleName);
|
|
174541
174626
|
}
|
|
@@ -174544,9 +174629,9 @@ function buildGrammar2(match4, namespace, optOhmGrammarForTesting, options) {
|
|
|
174544
174629
|
const source = this.source.trimmed();
|
|
174545
174630
|
return decl.define(currentRuleName, currentRuleFormals, body, description, source);
|
|
174546
174631
|
},
|
|
174547
|
-
Rule_override(n,
|
|
174632
|
+
Rule_override(n, fs70, _2, b) {
|
|
174548
174633
|
currentRuleName = n.visit();
|
|
174549
|
-
currentRuleFormals =
|
|
174634
|
+
currentRuleFormals = fs70.children.map((c2) => c2.visit())[0] || [];
|
|
174550
174635
|
const source = this.source.trimmed();
|
|
174551
174636
|
decl.ensureSuperGrammarRuleForOverriding(currentRuleName, source);
|
|
174552
174637
|
overriding = true;
|
|
@@ -174554,9 +174639,9 @@ function buildGrammar2(match4, namespace, optOhmGrammarForTesting, options) {
|
|
|
174554
174639
|
overriding = false;
|
|
174555
174640
|
return decl.override(currentRuleName, currentRuleFormals, body, null, source);
|
|
174556
174641
|
},
|
|
174557
|
-
Rule_extend(n,
|
|
174642
|
+
Rule_extend(n, fs70, _2, b) {
|
|
174558
174643
|
currentRuleName = n.visit();
|
|
174559
|
-
currentRuleFormals =
|
|
174644
|
+
currentRuleFormals = fs70.children.map((c2) => c2.visit())[0] || [];
|
|
174560
174645
|
const body = b.visit();
|
|
174561
174646
|
const source = this.source.trimmed();
|
|
174562
174647
|
return decl.extend(currentRuleName, currentRuleFormals, body, null, source);
|
|
@@ -174583,8 +174668,8 @@ function buildGrammar2(match4, namespace, optOhmGrammarForTesting, options) {
|
|
|
174583
174668
|
return builder.alt(...args).withSource(this.source);
|
|
174584
174669
|
}
|
|
174585
174670
|
},
|
|
174586
|
-
Formals(opointy,
|
|
174587
|
-
return
|
|
174671
|
+
Formals(opointy, fs70, cpointy) {
|
|
174672
|
+
return fs70.visit();
|
|
174588
174673
|
},
|
|
174589
174674
|
Params(opointy, ps, cpointy) {
|
|
174590
174675
|
return ps.visit();
|
|
@@ -174746,8 +174831,8 @@ function initPrototypeParser(grammar2) {
|
|
|
174746
174831
|
formals: optFormals.children.map((c2) => c2.parse())[0] || []
|
|
174747
174832
|
};
|
|
174748
174833
|
},
|
|
174749
|
-
Formals(oparen,
|
|
174750
|
-
return
|
|
174834
|
+
Formals(oparen, fs70, cparen) {
|
|
174835
|
+
return fs70.asIteration().children.map((c2) => c2.parse());
|
|
174751
174836
|
},
|
|
174752
174837
|
name(first2, rest) {
|
|
174753
174838
|
return this.sourceString;
|
|
@@ -196095,7 +196180,7 @@ async function runRulesReset({ ruleKey }) {
|
|
|
196095
196180
|
|
|
196096
196181
|
// tools/cli/src/commands/contracts.ts
|
|
196097
196182
|
init_dist4();
|
|
196098
|
-
import
|
|
196183
|
+
import fs67 from "node:fs";
|
|
196099
196184
|
import path73 from "node:path";
|
|
196100
196185
|
|
|
196101
196186
|
// packages/spec-consolidator/dist/types.js
|
|
@@ -204900,6 +204985,7 @@ var HISTORY_FILE2 = "history.json";
|
|
|
204900
204985
|
var RESULT_FILE = "result.json";
|
|
204901
204986
|
var RECIPE_FILE = "recipe.json";
|
|
204902
204987
|
var MANIFEST_FILE = "manifest.json";
|
|
204988
|
+
var DECISIONS_FILE = "decisions.json";
|
|
204903
204989
|
function guardDir(repoRoot5) {
|
|
204904
204990
|
return path54.join(repoRoot5, TRUECOURSE_DIR3, GUARD_DIR);
|
|
204905
204991
|
}
|
|
@@ -204927,6 +205013,9 @@ function recipePath(repoRoot5) {
|
|
|
204927
205013
|
function manifestPath2(repoRoot5) {
|
|
204928
205014
|
return path54.join(scenariosDir(repoRoot5), MANIFEST_FILE);
|
|
204929
205015
|
}
|
|
205016
|
+
function guardDecisionsPath(repoRoot5) {
|
|
205017
|
+
return path54.join(scenariosDir(repoRoot5), DECISIONS_FILE);
|
|
205018
|
+
}
|
|
204930
205019
|
function evidenceRunDir(repoRoot5, runId) {
|
|
204931
205020
|
return path54.join(guardDir(repoRoot5), EVIDENCE_DIR, runId);
|
|
204932
205021
|
}
|
|
@@ -205659,6 +205748,14 @@ function writeFile(dir, name, content) {
|
|
|
205659
205748
|
|
|
205660
205749
|
// packages/guard-runner/dist/run-scenario.js
|
|
205661
205750
|
var ENV_PINS = DETERMINISM_PINS;
|
|
205751
|
+
var SANDBOX_SETUP_EXPECTED = "sandbox setup to succeed";
|
|
205752
|
+
var CAPABILITY_SETUP_EXPECTED = "setup capabilities to materialize";
|
|
205753
|
+
function isSetupDefectResult(result) {
|
|
205754
|
+
if (result.outcome !== "error")
|
|
205755
|
+
return false;
|
|
205756
|
+
const expected = result.failure?.expected;
|
|
205757
|
+
return expected === SANDBOX_SETUP_EXPECTED || expected === CAPABILITY_SETUP_EXPECTED;
|
|
205758
|
+
}
|
|
205662
205759
|
async function runScenario(scenario, ctx) {
|
|
205663
205760
|
const start = Date.now();
|
|
205664
205761
|
const base2 = {
|
|
@@ -205679,7 +205776,7 @@ async function runScenario(scenario, ctx) {
|
|
|
205679
205776
|
...base2,
|
|
205680
205777
|
outcome: "error",
|
|
205681
205778
|
durationMs: Date.now() - start,
|
|
205682
|
-
failure: { step: 1, expected:
|
|
205779
|
+
failure: { step: 1, expected: SANDBOX_SETUP_EXPECTED, actual: message }
|
|
205683
205780
|
};
|
|
205684
205781
|
}
|
|
205685
205782
|
const normCtx = { sandboxRoot: sandbox.root, repoRoot: ctx.repoRoot };
|
|
@@ -205694,7 +205791,7 @@ async function runScenario(scenario, ctx) {
|
|
|
205694
205791
|
...base2,
|
|
205695
205792
|
outcome: "error",
|
|
205696
205793
|
durationMs: Date.now() - start,
|
|
205697
|
-
failure: { step: 1, expected:
|
|
205794
|
+
failure: { step: 1, expected: CAPABILITY_SETUP_EXPECTED, actual: message }
|
|
205698
205795
|
};
|
|
205699
205796
|
}
|
|
205700
205797
|
for (let i = 0; i < scenario.steps.length; i++) {
|
|
@@ -206174,12 +206271,27 @@ async function mapWithConcurrency(items, limit, fn) {
|
|
|
206174
206271
|
return results;
|
|
206175
206272
|
}
|
|
206176
206273
|
|
|
206274
|
+
// packages/guard-runner/dist/decisions.js
|
|
206275
|
+
init_dist5();
|
|
206276
|
+
import fs57 from "node:fs";
|
|
206277
|
+
function readGuardDecisions(repoRoot5) {
|
|
206278
|
+
const file = guardDecisionsPath(repoRoot5);
|
|
206279
|
+
if (!fs57.existsSync(file))
|
|
206280
|
+
return EMPTY_GUARD_DECISIONS;
|
|
206281
|
+
try {
|
|
206282
|
+
const parsed = GuardDecisionsSchema.safeParse(JSON.parse(fs57.readFileSync(file, "utf-8")));
|
|
206283
|
+
return parsed.success ? parsed.data : EMPTY_GUARD_DECISIONS;
|
|
206284
|
+
} catch {
|
|
206285
|
+
return EMPTY_GUARD_DECISIONS;
|
|
206286
|
+
}
|
|
206287
|
+
}
|
|
206288
|
+
|
|
206177
206289
|
// packages/guard-generator/dist/generate.js
|
|
206178
206290
|
init_dist5();
|
|
206179
206291
|
|
|
206180
206292
|
// packages/guard-generator/dist/section-plan.js
|
|
206181
206293
|
init_zod();
|
|
206182
|
-
import
|
|
206294
|
+
import fs58 from "node:fs";
|
|
206183
206295
|
import path63 from "node:path";
|
|
206184
206296
|
import { createHash as createHash15 } from "node:crypto";
|
|
206185
206297
|
init_dist5();
|
|
@@ -206497,10 +206609,10 @@ var CorpusShape2 = external_exports.object({
|
|
|
206497
206609
|
function readCorpusAreaTags(repoRoot5) {
|
|
206498
206610
|
const file = path63.join(repoRoot5, ".truecourse", "specs", "corpus.json");
|
|
206499
206611
|
const map2 = /* @__PURE__ */ new Map();
|
|
206500
|
-
if (!
|
|
206612
|
+
if (!fs58.existsSync(file))
|
|
206501
206613
|
return map2;
|
|
206502
206614
|
try {
|
|
206503
|
-
const parsed = CorpusShape2.safeParse(JSON.parse(
|
|
206615
|
+
const parsed = CorpusShape2.safeParse(JSON.parse(fs58.readFileSync(file, "utf-8")));
|
|
206504
206616
|
if (!parsed.success)
|
|
206505
206617
|
return map2;
|
|
206506
206618
|
for (const d3 of parsed.data.docs ?? [])
|
|
@@ -206519,17 +206631,17 @@ function generationInputsHash(fingerprint2, recipeFingerprint) {
|
|
|
206519
206631
|
].join("\0")).digest("hex");
|
|
206520
206632
|
}
|
|
206521
206633
|
function hasGuardUniverse(repoRoot5) {
|
|
206522
|
-
return
|
|
206634
|
+
return fs58.existsSync(path63.join(repoRoot5, ".truecourse", "specs", "corpus.json"));
|
|
206523
206635
|
}
|
|
206524
206636
|
function planGuardWork(repoRoot5, recipeFingerprint) {
|
|
206525
206637
|
const recipeFp = recipeFingerprint ?? computeRecipeFingerprint(repoRoot5);
|
|
206526
|
-
const recipeMissing = !
|
|
206638
|
+
const recipeMissing = !fs58.existsSync(recipePath(repoRoot5));
|
|
206527
206639
|
const hasUniverse = hasGuardUniverse(repoRoot5);
|
|
206528
206640
|
const { indexes } = indexRepoDocs(repoRoot5, []);
|
|
206529
206641
|
const areaTags = readCorpusAreaTags(repoRoot5);
|
|
206530
206642
|
const sections = [];
|
|
206531
206643
|
for (const [doc, index] of indexes) {
|
|
206532
|
-
const texts = extractSectionTexts(doc,
|
|
206644
|
+
const texts = extractSectionTexts(doc, fs58.readFileSync(path63.resolve(repoRoot5, doc), "utf-8"));
|
|
206533
206645
|
for (const s of index.sections) {
|
|
206534
206646
|
const t2 = texts.get(s.anchor);
|
|
206535
206647
|
sections.push({
|
|
@@ -206574,7 +206686,7 @@ function collectWorkDocs(repoRoot5, plan) {
|
|
|
206574
206686
|
}
|
|
206575
206687
|
return [...byDoc].map(([doc, sections]) => ({
|
|
206576
206688
|
doc,
|
|
206577
|
-
content:
|
|
206689
|
+
content: fs58.readFileSync(path63.resolve(repoRoot5, doc), "utf-8"),
|
|
206578
206690
|
sections
|
|
206579
206691
|
}));
|
|
206580
206692
|
}
|
|
@@ -206961,7 +207073,7 @@ function truncate3(text4) {
|
|
|
206961
207073
|
}
|
|
206962
207074
|
|
|
206963
207075
|
// packages/guard-generator/dist/recipe-discovery.js
|
|
206964
|
-
import
|
|
207076
|
+
import fs59 from "node:fs";
|
|
206965
207077
|
import os13 from "node:os";
|
|
206966
207078
|
import path65 from "node:path";
|
|
206967
207079
|
import { createHash as createHash18 } from "node:crypto";
|
|
@@ -207017,8 +207129,8 @@ async function discoverRecipe(repoRoot5, runner) {
|
|
|
207017
207129
|
...proposal.env ? { env: proposal.env } : {}
|
|
207018
207130
|
};
|
|
207019
207131
|
const target = recipePath(repoRoot5);
|
|
207020
|
-
|
|
207021
|
-
|
|
207132
|
+
fs59.mkdirSync(path65.dirname(target), { recursive: true });
|
|
207133
|
+
fs59.writeFileSync(target, JSON.stringify(recipe, null, 2) + "\n");
|
|
207022
207134
|
return {
|
|
207023
207135
|
status: "discovered",
|
|
207024
207136
|
recipe,
|
|
@@ -207049,13 +207161,13 @@ async function proposeRecipeWithReask(input, runner) {
|
|
|
207049
207161
|
}
|
|
207050
207162
|
function readDiscoveryInputs(repoRoot5) {
|
|
207051
207163
|
const pkgPath = path65.join(repoRoot5, "package.json");
|
|
207052
|
-
const packageJson =
|
|
207053
|
-
const presentInputs = DISCOVERY_INPUTS.filter((f2) =>
|
|
207164
|
+
const packageJson = fs59.existsSync(pkgPath) ? fs59.readFileSync(pkgPath, "utf-8") : "(no package.json)";
|
|
207165
|
+
const presentInputs = DISCOVERY_INPUTS.filter((f2) => fs59.existsSync(path65.join(repoRoot5, f2)));
|
|
207054
207166
|
return { packageJson, presentInputs };
|
|
207055
207167
|
}
|
|
207056
207168
|
async function probeEntry(repoRoot5, entry) {
|
|
207057
207169
|
const resolved = resolveEntry(repoRoot5, entry);
|
|
207058
|
-
const cwd =
|
|
207170
|
+
const cwd = fs59.mkdtempSync(path65.join(os13.tmpdir(), "tc-guard-probe-"));
|
|
207059
207171
|
try {
|
|
207060
207172
|
for (const args of [["--help"], []]) {
|
|
207061
207173
|
const capture = await executeStep({
|
|
@@ -207072,7 +207184,7 @@ async function probeEntry(repoRoot5, entry) {
|
|
|
207072
207184
|
reason: `entrypoint ${JSON.stringify(entry)} did not answer to \`--help\` or a bare invocation`
|
|
207073
207185
|
};
|
|
207074
207186
|
} finally {
|
|
207075
|
-
|
|
207187
|
+
fs59.rmSync(cwd, { recursive: true, force: true });
|
|
207076
207188
|
}
|
|
207077
207189
|
}
|
|
207078
207190
|
|
|
@@ -207119,7 +207231,7 @@ async function birthValidate(repoRoot5, candidates, opts = {}) {
|
|
|
207119
207231
|
}
|
|
207120
207232
|
|
|
207121
207233
|
// packages/guard-generator/dist/serialize.js
|
|
207122
|
-
import
|
|
207234
|
+
import fs60 from "node:fs";
|
|
207123
207235
|
import path66 from "node:path";
|
|
207124
207236
|
init_dist5();
|
|
207125
207237
|
function anchorLeaf(anchor) {
|
|
@@ -207162,15 +207274,15 @@ function scenarioFileIndex(repoRoot5) {
|
|
|
207162
207274
|
const root2 = scenariosDir(repoRoot5);
|
|
207163
207275
|
const map2 = /* @__PURE__ */ new Map();
|
|
207164
207276
|
const walk20 = (dir) => {
|
|
207165
|
-
if (!
|
|
207277
|
+
if (!fs60.existsSync(dir))
|
|
207166
207278
|
return;
|
|
207167
|
-
for (const entry of
|
|
207279
|
+
for (const entry of fs60.readdirSync(dir, { withFileTypes: true })) {
|
|
207168
207280
|
const full = path66.join(dir, entry.name);
|
|
207169
207281
|
if (entry.isDirectory())
|
|
207170
207282
|
walk20(full);
|
|
207171
207283
|
else if (entry.isFile() && /\.ya?ml$/i.test(entry.name)) {
|
|
207172
207284
|
try {
|
|
207173
|
-
const doc = jsYaml.load(
|
|
207285
|
+
const doc = jsYaml.load(fs60.readFileSync(full, "utf-8"));
|
|
207174
207286
|
if (doc && typeof doc.id === "string")
|
|
207175
207287
|
map2.set(doc.id, full);
|
|
207176
207288
|
} catch {
|
|
@@ -207184,19 +207296,22 @@ function scenarioFileIndex(repoRoot5) {
|
|
|
207184
207296
|
function existingScenarioIds(repoRoot5) {
|
|
207185
207297
|
return new Set(loadScenarios(repoRoot5).scenarios.map((s) => s.id));
|
|
207186
207298
|
}
|
|
207299
|
+
function serializeScenarioYaml(scenario) {
|
|
207300
|
+
return jsYaml.dump(scenario, { lineWidth: -1, noRefs: true });
|
|
207301
|
+
}
|
|
207187
207302
|
function writeScenarioFile(repoRoot5, slug2, scenario) {
|
|
207188
207303
|
const dir = path66.join(scenariosDir(repoRoot5), slug2);
|
|
207189
|
-
|
|
207304
|
+
fs60.mkdirSync(dir, { recursive: true });
|
|
207190
207305
|
const file = path66.join(dir, `${scenario.id}.yaml`);
|
|
207191
|
-
|
|
207306
|
+
fs60.writeFileSync(file, serializeScenarioYaml(scenario));
|
|
207192
207307
|
return path66.relative(repoRoot5, file);
|
|
207193
207308
|
}
|
|
207194
207309
|
function deleteScenarioFiles(repoRoot5, ids) {
|
|
207195
207310
|
const index = scenarioFileIndex(repoRoot5);
|
|
207196
207311
|
for (const id of ids) {
|
|
207197
207312
|
const file = index.get(id);
|
|
207198
|
-
if (file &&
|
|
207199
|
-
|
|
207313
|
+
if (file && fs60.existsSync(file))
|
|
207314
|
+
fs60.rmSync(file);
|
|
207200
207315
|
}
|
|
207201
207316
|
}
|
|
207202
207317
|
|
|
@@ -207266,7 +207381,9 @@ async function generateGuards(options) {
|
|
|
207266
207381
|
errors: [],
|
|
207267
207382
|
extractionFailures: [],
|
|
207268
207383
|
orphaned,
|
|
207269
|
-
birthPassed: 0
|
|
207384
|
+
birthPassed: 0,
|
|
207385
|
+
heldSections: [],
|
|
207386
|
+
orphanedDismissals: []
|
|
207270
207387
|
};
|
|
207271
207388
|
}
|
|
207272
207389
|
const limit = pLimit(Math.max(1, options.concurrency ?? defaultConcurrency3()));
|
|
@@ -207281,6 +207398,10 @@ async function generateGuards(options) {
|
|
|
207281
207398
|
const coverageGaps = [];
|
|
207282
207399
|
const errors = [];
|
|
207283
207400
|
const extractionFailures = [];
|
|
207401
|
+
const decisions = readGuardDecisions(repoRoot5);
|
|
207402
|
+
const dismissalByKey = new Map(decisions.dismissedClaims.map((d3) => [dismissedClaimKey(d3.doc, d3.anchor, d3.title), d3]));
|
|
207403
|
+
const extractedClaimKeys = /* @__PURE__ */ new Set();
|
|
207404
|
+
const extractedDocs = /* @__PURE__ */ new Set();
|
|
207284
207405
|
const workDocs = collectWorkDocs(repoRoot5, plan);
|
|
207285
207406
|
const workKeys = new Set(plan.work.map(key2));
|
|
207286
207407
|
const workDocByPath = new Map(workDocs.map((d3) => [d3.doc, d3]));
|
|
@@ -207310,34 +207431,47 @@ async function generateGuards(options) {
|
|
|
207310
207431
|
reason: `${result.failedViews} extraction view(s) failed \u2014 re-run to complete coverage for affected sections`
|
|
207311
207432
|
});
|
|
207312
207433
|
}
|
|
207434
|
+
extractedDocs.add(doc.doc);
|
|
207435
|
+
for (const c2 of result.data.claims) {
|
|
207436
|
+
extractedClaimKeys.add(dismissedClaimKey(doc.doc, c2.sectionAnchor, c2.claim));
|
|
207437
|
+
}
|
|
207313
207438
|
const { claimsByAnchor, noteByAnchor } = groupExtraction(result.data);
|
|
207314
207439
|
for (const s of doc.sections) {
|
|
207315
207440
|
if (!workKeys.has(key2(s)))
|
|
207316
207441
|
continue;
|
|
207317
207442
|
const claims = claimsByAnchor.get(s.anchor) ?? [];
|
|
207318
|
-
const
|
|
207443
|
+
const cliAll = claims.filter((c2) => isRunnableDriver(c2.driver));
|
|
207319
207444
|
const others = claims.filter((c2) => !isRunnableDriver(c2.driver));
|
|
207320
207445
|
const note = noteByAnchor.get(s.anchor);
|
|
207446
|
+
const cli = cliAll.filter((c2) => !dismissalByKey.has(dismissedClaimKey(s.doc, s.anchor, c2.claim)));
|
|
207447
|
+
const dismissed = cliAll.filter((c2) => dismissalByKey.has(dismissedClaimKey(s.doc, s.anchor, c2.claim)));
|
|
207448
|
+
for (const d3 of dismissed) {
|
|
207449
|
+
const entry = dismissalByKey.get(dismissedClaimKey(s.doc, s.anchor, d3.claim));
|
|
207450
|
+
coverageGaps.push({ doc: s.doc, anchor: s.anchor, kind: "dismissed", reason: dismissedReason(d3.claim, entry?.note) });
|
|
207451
|
+
}
|
|
207321
207452
|
for (const o of others) {
|
|
207322
207453
|
coverageGaps.push({ doc: s.doc, anchor: s.anchor, kind: "awaiting-driver", driver: o.driver, reason: o.reason });
|
|
207323
207454
|
}
|
|
207324
207455
|
if (cli.length === 0 && others.length === 0) {
|
|
207325
|
-
if (
|
|
207326
|
-
|
|
207327
|
-
|
|
207456
|
+
if (dismissed.length === 0) {
|
|
207457
|
+
if (!result.complete && !note) {
|
|
207458
|
+
extractFailedKeys.add(key2(s));
|
|
207459
|
+
continue;
|
|
207460
|
+
}
|
|
207461
|
+
coverageGaps.push({
|
|
207462
|
+
doc: s.doc,
|
|
207463
|
+
anchor: s.anchor,
|
|
207464
|
+
kind: note ? "untestable" : "no-claim",
|
|
207465
|
+
reason: note?.reason ?? "the section states no CLI-assertable claim"
|
|
207466
|
+
});
|
|
207328
207467
|
}
|
|
207329
|
-
coverageGaps.push({
|
|
207330
|
-
doc: s.doc,
|
|
207331
|
-
anchor: s.anchor,
|
|
207332
|
-
kind: note ? "untestable" : "no-claim",
|
|
207333
|
-
reason: note?.reason ?? "the section states no CLI-assertable claim"
|
|
207334
|
-
});
|
|
207335
207468
|
}
|
|
207336
207469
|
classificationByKey.set(key2(s), deriveClassification(cli, others, note));
|
|
207337
207470
|
for (const c2 of cli)
|
|
207338
207471
|
authTasks.push({ ref: `c${refSeq++}`, section: s, claim: c2 });
|
|
207339
207472
|
}
|
|
207340
207473
|
}
|
|
207474
|
+
const orphanedDismissals = decisions.dismissedClaims.filter((d3) => extractedDocs.has(d3.doc) && !extractedClaimKeys.has(dismissedClaimKey(d3.doc, d3.anchor, d3.title))).map((d3) => ({ doc: d3.doc, anchor: d3.anchor, title: d3.title }));
|
|
207341
207475
|
const buildPromise = runBuild(repoRoot5, recipe.build, recipe.env);
|
|
207342
207476
|
let buildAnnounced = false;
|
|
207343
207477
|
const awaitBuild = async () => {
|
|
@@ -207406,6 +207540,7 @@ async function generateGuards(options) {
|
|
|
207406
207540
|
};
|
|
207407
207541
|
const written = [];
|
|
207408
207542
|
const birthFindings = [];
|
|
207543
|
+
const heldSections = [];
|
|
207409
207544
|
let entryPreflightFailure = null;
|
|
207410
207545
|
let birthTotal = 0;
|
|
207411
207546
|
let birthSettled = 0;
|
|
@@ -207513,9 +207648,9 @@ async function generateGuards(options) {
|
|
|
207513
207648
|
pushInto(r1ByRef, o.candidate.ref, o);
|
|
207514
207649
|
const retryEntries = [];
|
|
207515
207650
|
for (const [ref, outcomes] of r1ByRef) {
|
|
207516
|
-
const
|
|
207517
|
-
if (
|
|
207518
|
-
retryEntries.push({ task: taskByRef.get(ref), evidence: toFinding(
|
|
207651
|
+
const retriable2 = outcomes.find((o) => o.result.outcome === "fail" || isSetupDefectResult(o.result));
|
|
207652
|
+
if (retriable2) {
|
|
207653
|
+
retryEntries.push({ task: taskByRef.get(ref), evidence: toFinding(retriable2) });
|
|
207519
207654
|
continue;
|
|
207520
207655
|
}
|
|
207521
207656
|
for (const o of outcomes) {
|
|
@@ -207574,6 +207709,16 @@ async function generateGuards(options) {
|
|
|
207574
207709
|
ids.push(c2.scenario.id);
|
|
207575
207710
|
}
|
|
207576
207711
|
upsertSection(section, ids);
|
|
207712
|
+
} else if (persistedHere.length > 0) {
|
|
207713
|
+
heldSections.push({
|
|
207714
|
+
doc: section.doc,
|
|
207715
|
+
anchor: section.anchor,
|
|
207716
|
+
readyScenarios: persistedHere.map((c2) => ({
|
|
207717
|
+
id: c2.scenario.id,
|
|
207718
|
+
title: c2.scenario.title,
|
|
207719
|
+
yaml: serializeScenarioYaml(c2.scenario)
|
|
207720
|
+
}))
|
|
207721
|
+
});
|
|
207577
207722
|
}
|
|
207578
207723
|
}
|
|
207579
207724
|
const authorTotal = authTasks.length;
|
|
@@ -207652,6 +207797,8 @@ async function generateGuards(options) {
|
|
|
207652
207797
|
extractionFailures,
|
|
207653
207798
|
orphaned,
|
|
207654
207799
|
birthPassed,
|
|
207800
|
+
heldSections,
|
|
207801
|
+
orphanedDismissals,
|
|
207655
207802
|
manifestPath: manifestPath2(repoRoot5),
|
|
207656
207803
|
...entryPreflightFailure ? { entryPreflight: entryPreflightFailure } : {}
|
|
207657
207804
|
};
|
|
@@ -207698,7 +207845,9 @@ function emptyResult(status, extra) {
|
|
|
207698
207845
|
errors: [],
|
|
207699
207846
|
extractionFailures: [],
|
|
207700
207847
|
orphaned: [],
|
|
207701
|
-
birthPassed: 0
|
|
207848
|
+
birthPassed: 0,
|
|
207849
|
+
heldSections: [],
|
|
207850
|
+
orphanedDismissals: []
|
|
207702
207851
|
};
|
|
207703
207852
|
}
|
|
207704
207853
|
function readPriorManifest(repoRoot5) {
|
|
@@ -207793,9 +207942,18 @@ function toFinding(o) {
|
|
|
207793
207942
|
step: f2?.step ?? 1,
|
|
207794
207943
|
expected: f2?.expected ?? "",
|
|
207795
207944
|
actual: f2?.actual ?? "",
|
|
207796
|
-
...o.result.evidencePath ? { evidencePath: o.result.evidencePath } : {}
|
|
207945
|
+
...o.result.evidencePath ? { evidencePath: o.result.evidencePath } : {},
|
|
207946
|
+
// Judge-on-one-screen (item 19): the failed candidate's exact YAML rides inline
|
|
207947
|
+
// so the finding detail shows the commands it ran; `claim` is the dismissal
|
|
207948
|
+
// identity (item 20) so the detail's Dismiss action can key on it.
|
|
207949
|
+
yaml: serializeScenarioYaml(o.candidate.scenario),
|
|
207950
|
+
claim: o.candidate.claim.claim
|
|
207797
207951
|
};
|
|
207798
207952
|
}
|
|
207953
|
+
function dismissedReason(claim, note) {
|
|
207954
|
+
const base2 = `dismissed: ${oneLine(claim)}`;
|
|
207955
|
+
return note ? `${base2} \u2014 ${oneLine(note)}` : base2;
|
|
207956
|
+
}
|
|
207799
207957
|
function errorFrom(o) {
|
|
207800
207958
|
return {
|
|
207801
207959
|
doc: o.candidate.section.doc,
|
|
@@ -207858,7 +208016,7 @@ init_context_router();
|
|
|
207858
208016
|
|
|
207859
208017
|
// packages/core/dist/services/llm/model-prices.js
|
|
207860
208018
|
init_paths();
|
|
207861
|
-
import
|
|
208019
|
+
import fs61 from "node:fs";
|
|
207862
208020
|
import path67 from "node:path";
|
|
207863
208021
|
var OPENROUTER_URL = "https://openrouter.ai/api/v1/models";
|
|
207864
208022
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -207879,7 +208037,7 @@ function cacheFilePath() {
|
|
|
207879
208037
|
}
|
|
207880
208038
|
function readCache7() {
|
|
207881
208039
|
try {
|
|
207882
|
-
const t2 = JSON.parse(
|
|
208040
|
+
const t2 = JSON.parse(fs61.readFileSync(cacheFilePath(), "utf-8"));
|
|
207883
208041
|
if (t2 && t2.tiers && t2.byId && typeof t2.fetchedAt === "number")
|
|
207884
208042
|
return t2;
|
|
207885
208043
|
} catch {
|
|
@@ -207888,8 +208046,8 @@ function readCache7() {
|
|
|
207888
208046
|
}
|
|
207889
208047
|
function writeCache7(t2) {
|
|
207890
208048
|
try {
|
|
207891
|
-
|
|
207892
|
-
|
|
208049
|
+
fs61.mkdirSync(path67.dirname(cacheFilePath()), { recursive: true });
|
|
208050
|
+
fs61.writeFileSync(cacheFilePath(), JSON.stringify(t2));
|
|
207893
208051
|
} catch {
|
|
207894
208052
|
}
|
|
207895
208053
|
}
|
|
@@ -208268,7 +208426,7 @@ function changedSubject(total, changed, noun) {
|
|
|
208268
208426
|
|
|
208269
208427
|
// packages/core/dist/commands/spec-in-process.js
|
|
208270
208428
|
init_dist8();
|
|
208271
|
-
import
|
|
208429
|
+
import fs66 from "node:fs";
|
|
208272
208430
|
import path72 from "node:path";
|
|
208273
208431
|
init_git();
|
|
208274
208432
|
import { createHash as createHash20, randomUUID as randomUUID27 } from "node:crypto";
|
|
@@ -208276,7 +208434,7 @@ import { createHash as createHash20, randomUUID as randomUUID27 } from "node:cry
|
|
|
208276
208434
|
// packages/core/dist/lib/verify-store.js
|
|
208277
208435
|
init_atomic_write();
|
|
208278
208436
|
init_analysis_store();
|
|
208279
|
-
import
|
|
208437
|
+
import fs62 from "node:fs";
|
|
208280
208438
|
import path68 from "node:path";
|
|
208281
208439
|
|
|
208282
208440
|
// packages/core/dist/types/verify-snapshot.js
|
|
@@ -208375,7 +208533,7 @@ var FileVerifyStore = class {
|
|
|
208375
208533
|
const file = verifyLatestPath(repoPath);
|
|
208376
208534
|
let mtime;
|
|
208377
208535
|
try {
|
|
208378
|
-
mtime =
|
|
208536
|
+
mtime = fs62.statSync(file).mtimeMs;
|
|
208379
208537
|
} catch (err) {
|
|
208380
208538
|
if (err.code === "ENOENT") {
|
|
208381
208539
|
latestCache2.delete(repoPath);
|
|
@@ -208386,7 +208544,7 @@ var FileVerifyStore = class {
|
|
|
208386
208544
|
const cached = latestCache2.get(repoPath);
|
|
208387
208545
|
if (cached && cached.mtime === mtime)
|
|
208388
208546
|
return cached.data;
|
|
208389
|
-
const data = JSON.parse(
|
|
208547
|
+
const data = JSON.parse(fs62.readFileSync(file, "utf-8"));
|
|
208390
208548
|
latestCache2.set(repoPath, { mtime, data });
|
|
208391
208549
|
return data;
|
|
208392
208550
|
}
|
|
@@ -208396,7 +208554,7 @@ var FileVerifyStore = class {
|
|
|
208396
208554
|
}
|
|
208397
208555
|
async deleteVerifyLatest(repoPath) {
|
|
208398
208556
|
try {
|
|
208399
|
-
|
|
208557
|
+
fs62.unlinkSync(verifyLatestPath(repoPath));
|
|
208400
208558
|
} catch (err) {
|
|
208401
208559
|
if (err.code !== "ENOENT")
|
|
208402
208560
|
throw err;
|
|
@@ -208410,21 +208568,21 @@ var FileVerifyStore = class {
|
|
|
208410
208568
|
}
|
|
208411
208569
|
async readVerifyRun(repoPath, filename) {
|
|
208412
208570
|
const file = verifyRunPath(repoPath, filename);
|
|
208413
|
-
if (!
|
|
208571
|
+
if (!fs62.existsSync(file))
|
|
208414
208572
|
return null;
|
|
208415
|
-
return JSON.parse(
|
|
208573
|
+
return JSON.parse(fs62.readFileSync(file, "utf-8"));
|
|
208416
208574
|
}
|
|
208417
208575
|
async listVerifyRuns(repoPath) {
|
|
208418
208576
|
const dir = runsDir(repoPath);
|
|
208419
|
-
if (!
|
|
208577
|
+
if (!fs62.existsSync(dir))
|
|
208420
208578
|
return [];
|
|
208421
|
-
return
|
|
208579
|
+
return fs62.readdirSync(dir).filter((n) => n.endsWith(".json")).sort();
|
|
208422
208580
|
}
|
|
208423
208581
|
async readVerifyHistory(repoPath) {
|
|
208424
208582
|
const file = verifyHistoryPath(repoPath);
|
|
208425
|
-
if (!
|
|
208583
|
+
if (!fs62.existsSync(file))
|
|
208426
208584
|
return { runs: [] };
|
|
208427
|
-
return JSON.parse(
|
|
208585
|
+
return JSON.parse(fs62.readFileSync(file, "utf-8"));
|
|
208428
208586
|
}
|
|
208429
208587
|
async appendVerifyHistory(repoPath, entry) {
|
|
208430
208588
|
const history = await this.readVerifyHistory(repoPath);
|
|
@@ -208437,7 +208595,7 @@ var FileVerifyStore = class {
|
|
|
208437
208595
|
if (!entry)
|
|
208438
208596
|
return false;
|
|
208439
208597
|
try {
|
|
208440
|
-
|
|
208598
|
+
fs62.unlinkSync(verifyRunPath(repoPath, entry.filename));
|
|
208441
208599
|
} catch (err) {
|
|
208442
208600
|
if (err.code !== "ENOENT")
|
|
208443
208601
|
throw err;
|
|
@@ -208459,16 +208617,16 @@ var FileVerifyStore = class {
|
|
|
208459
208617
|
}
|
|
208460
208618
|
async readVerifyDiff(repoPath, scope) {
|
|
208461
208619
|
const file = verifyDiffPath(repoPath, scope);
|
|
208462
|
-
if (!
|
|
208620
|
+
if (!fs62.existsSync(file))
|
|
208463
208621
|
return null;
|
|
208464
|
-
return JSON.parse(
|
|
208622
|
+
return JSON.parse(fs62.readFileSync(file, "utf-8"));
|
|
208465
208623
|
}
|
|
208466
208624
|
async writeVerifyDiff(repoPath, diff, scope) {
|
|
208467
208625
|
atomicWriteJson(verifyDiffPath(repoPath, scope), diff);
|
|
208468
208626
|
}
|
|
208469
208627
|
async deleteVerifyDiff(repoPath, scope) {
|
|
208470
208628
|
try {
|
|
208471
|
-
|
|
208629
|
+
fs62.unlinkSync(verifyDiffPath(repoPath, scope));
|
|
208472
208630
|
} catch (err) {
|
|
208473
208631
|
if (err.code !== "ENOENT")
|
|
208474
208632
|
throw err;
|
|
@@ -208502,7 +208660,7 @@ async function repoRef(repoRoot5, commitOverride) {
|
|
|
208502
208660
|
}
|
|
208503
208661
|
|
|
208504
208662
|
// packages/core/dist/lib/contract-store.js
|
|
208505
|
-
import
|
|
208663
|
+
import fs63 from "node:fs";
|
|
208506
208664
|
import path69 from "node:path";
|
|
208507
208665
|
var KIND_REL = {
|
|
208508
208666
|
contracts: [".truecourse", "contracts"],
|
|
@@ -208513,7 +208671,7 @@ function countTcFiles(dir) {
|
|
|
208513
208671
|
let n = 0;
|
|
208514
208672
|
let entries;
|
|
208515
208673
|
try {
|
|
208516
|
-
entries =
|
|
208674
|
+
entries = fs63.readdirSync(dir, { withFileTypes: true });
|
|
208517
208675
|
} catch {
|
|
208518
208676
|
return 0;
|
|
208519
208677
|
}
|
|
@@ -208530,7 +208688,7 @@ function walkTcRel(dir, excludeInferred) {
|
|
|
208530
208688
|
const walk20 = (rel) => {
|
|
208531
208689
|
let entries;
|
|
208532
208690
|
try {
|
|
208533
|
-
entries =
|
|
208691
|
+
entries = fs63.readdirSync(path69.join(dir, rel), { withFileTypes: true });
|
|
208534
208692
|
} catch {
|
|
208535
208693
|
return;
|
|
208536
208694
|
}
|
|
@@ -208568,13 +208726,13 @@ var FileContractStore = class {
|
|
|
208568
208726
|
}
|
|
208569
208727
|
async loadContracts(ref, kind) {
|
|
208570
208728
|
const dir = path69.join(ref.repoKey, ...KIND_REL[kind]);
|
|
208571
|
-
if (!
|
|
208729
|
+
if (!fs63.existsSync(dir))
|
|
208572
208730
|
return null;
|
|
208573
208731
|
return { dir, cleanup: async () => {
|
|
208574
208732
|
} };
|
|
208575
208733
|
}
|
|
208576
208734
|
async hasContracts(ref, kind) {
|
|
208577
|
-
return
|
|
208735
|
+
return fs63.existsSync(path69.join(ref.repoKey, ...KIND_REL[kind]));
|
|
208578
208736
|
}
|
|
208579
208737
|
// The file impl reads the live repo tree, which is whatever is checked out —
|
|
208580
208738
|
// there is no per-commit history, so `commitSha` is ignored (OSS is latest).
|
|
@@ -208583,21 +208741,21 @@ var FileContractStore = class {
|
|
|
208583
208741
|
}
|
|
208584
208742
|
async readContractFile(repoKey, kind, relPath, _commitSha) {
|
|
208585
208743
|
const dest = safeResolve(path69.join(repoKey, ...KIND_REL[kind]), relPath);
|
|
208586
|
-
if (!dest || !
|
|
208744
|
+
if (!dest || !fs63.existsSync(dest) || !fs63.statSync(dest).isFile())
|
|
208587
208745
|
return null;
|
|
208588
|
-
return
|
|
208746
|
+
return fs63.readFileSync(dest, "utf-8");
|
|
208589
208747
|
}
|
|
208590
208748
|
async putContractFile(ref, kind, relPath, content) {
|
|
208591
208749
|
const dest = safeResolve(path69.join(ref.repoKey, ...KIND_REL[kind]), relPath);
|
|
208592
208750
|
if (!dest)
|
|
208593
208751
|
throw new Error(`[contract-store] unsafe contract path: ${relPath}`);
|
|
208594
|
-
|
|
208595
|
-
|
|
208752
|
+
fs63.mkdirSync(path69.dirname(dest), { recursive: true });
|
|
208753
|
+
fs63.writeFileSync(dest, content);
|
|
208596
208754
|
}
|
|
208597
208755
|
async deleteContractFile(ref, kind, relPath) {
|
|
208598
208756
|
const dest = safeResolve(path69.join(ref.repoKey, ...KIND_REL[kind]), relPath);
|
|
208599
208757
|
if (dest)
|
|
208600
|
-
|
|
208758
|
+
fs63.rmSync(dest, { force: true });
|
|
208601
208759
|
}
|
|
208602
208760
|
// OSS/local has no workspace concept (mirrors the spec store). Writing throws
|
|
208603
208761
|
// (fail loud — a caller that reached here is mis-wired); reads are empty so an
|
|
@@ -208624,7 +208782,7 @@ var loadWorkspaceContracts = (ref, kind) => active8.loadWorkspaceContracts(ref,
|
|
|
208624
208782
|
var contractsMaterializeInPlace = () => active8.materializesInPlace;
|
|
208625
208783
|
|
|
208626
208784
|
// packages/core/dist/lib/spec-store.js
|
|
208627
|
-
import
|
|
208785
|
+
import fs64 from "node:fs";
|
|
208628
208786
|
import path70 from "node:path";
|
|
208629
208787
|
function specPath(repoKey, artifact) {
|
|
208630
208788
|
return path70.join(repoKey, ".truecourse", "specs", `${artifact}.json`);
|
|
@@ -208640,18 +208798,18 @@ var FileSpecStore = class {
|
|
|
208640
208798
|
throw new Error(PR_DECISIONS_FILE_ERROR);
|
|
208641
208799
|
}
|
|
208642
208800
|
const file = specPath(ref.repoKey, artifact);
|
|
208643
|
-
|
|
208644
|
-
|
|
208801
|
+
fs64.mkdirSync(path70.dirname(file), { recursive: true });
|
|
208802
|
+
fs64.writeFileSync(file, JSON.stringify(json2, null, 2) + "\n", "utf-8");
|
|
208645
208803
|
}
|
|
208646
208804
|
async loadSpec(ref, artifact) {
|
|
208647
208805
|
if (artifact === "decisions" && isPrDecisionsRef(ref.commitSha)) {
|
|
208648
208806
|
throw new Error(PR_DECISIONS_FILE_ERROR);
|
|
208649
208807
|
}
|
|
208650
208808
|
const file = specPath(ref.repoKey, artifact);
|
|
208651
|
-
if (!
|
|
208809
|
+
if (!fs64.existsSync(file))
|
|
208652
208810
|
return null;
|
|
208653
208811
|
try {
|
|
208654
|
-
return JSON.parse(
|
|
208812
|
+
return JSON.parse(fs64.readFileSync(file, "utf-8"));
|
|
208655
208813
|
} catch {
|
|
208656
208814
|
return null;
|
|
208657
208815
|
}
|
|
@@ -208661,8 +208819,8 @@ var FileSpecStore = class {
|
|
|
208661
208819
|
throw new Error(PR_DECISIONS_FILE_ERROR);
|
|
208662
208820
|
}
|
|
208663
208821
|
const file = specPath(ref.repoKey, artifact);
|
|
208664
|
-
if (
|
|
208665
|
-
|
|
208822
|
+
if (fs64.existsSync(file))
|
|
208823
|
+
fs64.rmSync(file);
|
|
208666
208824
|
}
|
|
208667
208825
|
// The file impl is single-document-per-repo, so "latest" === read the file.
|
|
208668
208826
|
async loadLatest(repoKey, artifact) {
|
|
@@ -208689,7 +208847,7 @@ var loadLatestSpec = (repoKey, artifact) => active9.loadLatest(repoKey, artifact
|
|
|
208689
208847
|
var specsMaterializeInPlace = () => active9.materializesInPlace;
|
|
208690
208848
|
|
|
208691
208849
|
// packages/core/dist/lib/inferred-action-store.js
|
|
208692
|
-
import
|
|
208850
|
+
import fs65 from "node:fs";
|
|
208693
208851
|
import path71 from "node:path";
|
|
208694
208852
|
function actionsFile(repoKey) {
|
|
208695
208853
|
return path71.join(repoKey, ".truecourse", "specs", "inferred-actions.json");
|
|
@@ -208697,15 +208855,15 @@ function actionsFile(repoKey) {
|
|
|
208697
208855
|
var FileInferredActionStore = class {
|
|
208698
208856
|
read(repoKey) {
|
|
208699
208857
|
try {
|
|
208700
|
-
return JSON.parse(
|
|
208858
|
+
return JSON.parse(fs65.readFileSync(actionsFile(repoKey), "utf-8"));
|
|
208701
208859
|
} catch {
|
|
208702
208860
|
return [];
|
|
208703
208861
|
}
|
|
208704
208862
|
}
|
|
208705
208863
|
write(repoKey, actions) {
|
|
208706
208864
|
const file = actionsFile(repoKey);
|
|
208707
|
-
|
|
208708
|
-
|
|
208865
|
+
fs65.mkdirSync(path71.dirname(file), { recursive: true });
|
|
208866
|
+
fs65.writeFileSync(file, JSON.stringify(actions, null, 2) + "\n", "utf-8");
|
|
208709
208867
|
}
|
|
208710
208868
|
async setAction(repoKey, action) {
|
|
208711
208869
|
const next = this.read(repoKey).filter((a) => !(a.kind === action.kind && a.identity === action.identity));
|
|
@@ -208840,7 +208998,7 @@ function generatedMarkerPath(repoRoot5) {
|
|
|
208840
208998
|
}
|
|
208841
208999
|
function stampGeneratedMarker(repoRoot5, summary) {
|
|
208842
209000
|
const file = generatedMarkerPath(repoRoot5);
|
|
208843
|
-
|
|
209001
|
+
fs66.mkdirSync(path72.dirname(file), { recursive: true });
|
|
208844
209002
|
const body = {
|
|
208845
209003
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
208846
209004
|
written: summary?.written ?? 0,
|
|
@@ -208848,7 +209006,7 @@ function stampGeneratedMarker(repoRoot5, summary) {
|
|
|
208848
209006
|
validationIssues: summary?.validationIssues ?? [],
|
|
208849
209007
|
enumerateFailures: summary?.enumerateFailures ?? []
|
|
208850
209008
|
};
|
|
208851
|
-
|
|
209009
|
+
fs66.writeFileSync(file, JSON.stringify(body, null, 2) + "\n");
|
|
208852
209010
|
}
|
|
208853
209011
|
function resolveCurateModels(repoRoot5) {
|
|
208854
209012
|
return {
|
|
@@ -208973,19 +209131,19 @@ async function curateInProcess(repoRoot5, options = {}) {
|
|
|
208973
209131
|
}
|
|
208974
209132
|
function buildPriorContracts(repoRoot5) {
|
|
208975
209133
|
const dir = path72.join(repoRoot5, ".truecourse", "contracts");
|
|
208976
|
-
if (!
|
|
209134
|
+
if (!fs66.existsSync(dir))
|
|
208977
209135
|
return void 0;
|
|
208978
209136
|
const targets = [];
|
|
208979
209137
|
const bodyByKey = /* @__PURE__ */ new Map();
|
|
208980
209138
|
const walk20 = (d3) => {
|
|
208981
|
-
for (const e of
|
|
209139
|
+
for (const e of fs66.readdirSync(d3, { withFileTypes: true })) {
|
|
208982
209140
|
if (e.isDirectory()) {
|
|
208983
209141
|
if (e.name === "_inferred")
|
|
208984
209142
|
continue;
|
|
208985
209143
|
walk20(path72.join(d3, e.name));
|
|
208986
209144
|
} else if (e.name.endsWith(".tc")) {
|
|
208987
209145
|
const abs = path72.join(d3, e.name);
|
|
208988
|
-
const src =
|
|
209146
|
+
const src = fs66.readFileSync(abs, "utf-8");
|
|
208989
209147
|
try {
|
|
208990
209148
|
const file = parser_ohm_exports.parseTcFile(path72.relative(dir, abs), src);
|
|
208991
209149
|
for (const key4 of resolver_exports.resolve([file]).index.keys()) {
|
|
@@ -209158,7 +209316,7 @@ async function withContracts(repoRoot5, options, tracker, fn) {
|
|
|
209158
209316
|
try {
|
|
209159
209317
|
let recorded;
|
|
209160
209318
|
if (options.contractsDir) {
|
|
209161
|
-
if (!
|
|
209319
|
+
if (!fs66.existsSync(options.contractsDir)) {
|
|
209162
209320
|
const err = new Error(`Contracts directory not found at ${options.contractsDir}. Run \`truecourse contracts generate\` first.`);
|
|
209163
209321
|
tracker?.error("load", err.message);
|
|
209164
209322
|
throw err;
|
|
@@ -209247,7 +209405,7 @@ async function verifyInProcess(repoRoot5, options = {}) {
|
|
|
209247
209405
|
bySeverity: summary.bySeverity
|
|
209248
209406
|
});
|
|
209249
209407
|
await deleteVerifyDiff(storeKey);
|
|
209250
|
-
|
|
209408
|
+
fs66.rmSync(legacyVerifyStatePath(repoRoot5), { force: true });
|
|
209251
209409
|
}
|
|
209252
209410
|
const state = {
|
|
209253
209411
|
verifiedAt,
|
|
@@ -209465,7 +209623,7 @@ async function persistInferred(repoRoot5, options, contractsDir, codeDir, starte
|
|
|
209465
209623
|
}
|
|
209466
209624
|
function autodetectCodeDir(repoRoot5) {
|
|
209467
209625
|
const codeSubdir = path72.join(repoRoot5, "code");
|
|
209468
|
-
if (
|
|
209626
|
+
if (fs66.existsSync(codeSubdir) && fs66.statSync(codeSubdir).isDirectory()) {
|
|
209469
209627
|
return codeSubdir;
|
|
209470
209628
|
}
|
|
209471
209629
|
return repoRoot5;
|
|
@@ -209786,7 +209944,7 @@ async function runContractsGenerate(options = {}) {
|
|
|
209786
209944
|
async function runContractsList(options = {}) {
|
|
209787
209945
|
const repoRoot5 = options.cwd ?? process.cwd();
|
|
209788
209946
|
const contractsDir = path73.join(repoRoot5, ".truecourse", "contracts");
|
|
209789
|
-
if (!
|
|
209947
|
+
if (!fs67.existsSync(contractsDir)) {
|
|
209790
209948
|
O2.info("No contracts found. Run `truecourse contracts generate` first.");
|
|
209791
209949
|
return;
|
|
209792
209950
|
}
|
|
@@ -209794,12 +209952,12 @@ async function runContractsList(options = {}) {
|
|
|
209794
209952
|
const fileNodes = [];
|
|
209795
209953
|
let parseErrors = 0;
|
|
209796
209954
|
const visit = (dir) => {
|
|
209797
|
-
for (const entry of
|
|
209955
|
+
for (const entry of fs67.readdirSync(dir, { withFileTypes: true })) {
|
|
209798
209956
|
const full = path73.join(dir, entry.name);
|
|
209799
209957
|
if (entry.isDirectory()) visit(full);
|
|
209800
209958
|
else if (entry.isFile() && entry.name.endsWith(".tc")) {
|
|
209801
209959
|
try {
|
|
209802
|
-
fileNodes.push(parserOhm.parseTcFile(full,
|
|
209960
|
+
fileNodes.push(parserOhm.parseTcFile(full, fs67.readFileSync(full, "utf-8")));
|
|
209803
209961
|
} catch {
|
|
209804
209962
|
parseErrors += 1;
|
|
209805
209963
|
}
|
|
@@ -209839,7 +209997,7 @@ async function runContractsList(options = {}) {
|
|
|
209839
209997
|
async function runContractsValidate(options = {}) {
|
|
209840
209998
|
const repoRoot5 = options.cwd ?? process.cwd();
|
|
209841
209999
|
const contractsDir = path73.join(repoRoot5, ".truecourse", "contracts");
|
|
209842
|
-
if (!
|
|
210000
|
+
if (!fs67.existsSync(contractsDir)) {
|
|
209843
210001
|
O2.error("No .truecourse/contracts/ directory found.");
|
|
209844
210002
|
process.exit(1);
|
|
209845
210003
|
}
|
|
@@ -209847,12 +210005,12 @@ async function runContractsValidate(options = {}) {
|
|
|
209847
210005
|
const fileNodes = [];
|
|
209848
210006
|
const issues = [];
|
|
209849
210007
|
const visit = (dir) => {
|
|
209850
|
-
for (const entry of
|
|
210008
|
+
for (const entry of fs67.readdirSync(dir, { withFileTypes: true })) {
|
|
209851
210009
|
const full = path73.join(dir, entry.name);
|
|
209852
210010
|
if (entry.isDirectory()) visit(full);
|
|
209853
210011
|
else if (entry.isFile() && entry.name.endsWith(".tc")) {
|
|
209854
210012
|
try {
|
|
209855
|
-
fileNodes.push(parserOhm.parseTcFile(full,
|
|
210013
|
+
fileNodes.push(parserOhm.parseTcFile(full, fs67.readFileSync(full, "utf-8")));
|
|
209856
210014
|
} catch (e) {
|
|
209857
210015
|
issues.push(`${path73.relative(repoRoot5, full)}: parse error: ${e instanceof Error ? e.message : e}`);
|
|
209858
210016
|
}
|
|
@@ -210095,7 +210253,7 @@ async function runInfer(opts = {}) {
|
|
|
210095
210253
|
|
|
210096
210254
|
// tools/cli/src/commands/spec-conflicts.ts
|
|
210097
210255
|
init_dist4();
|
|
210098
|
-
import
|
|
210256
|
+
import fs68 from "node:fs";
|
|
210099
210257
|
import path75 from "node:path";
|
|
210100
210258
|
var root = (opts) => opts.cwd ?? process.cwd();
|
|
210101
210259
|
var base = (ref) => ref.split("/").pop() ?? ref;
|
|
@@ -210143,7 +210301,7 @@ async function runSpecConflictsList(opts = {}) {
|
|
|
210143
210301
|
function excerpt(repoRoot5, ref, note, max = 20) {
|
|
210144
210302
|
let text4;
|
|
210145
210303
|
try {
|
|
210146
|
-
text4 =
|
|
210304
|
+
text4 = fs68.readFileSync(path75.join(repoRoot5, ref), "utf-8");
|
|
210147
210305
|
} catch {
|
|
210148
210306
|
return ` (could not read ${ref})`;
|
|
210149
210307
|
}
|
|
@@ -210855,6 +211013,11 @@ function printGuardGenerateSummary(report4, reportPath) {
|
|
|
210855
211013
|
O2.step(`sections ${report4.sectionsChanged} changed \xB7 ${settled} settled \xB7 ${unsettled.size} unsettled \xB7 ${report4.skippedUnchanged} unchanged`);
|
|
210856
211014
|
const birth = g.birthPassed !== null ? ` \xB7 ${g.birthPassed} passed birth` : "";
|
|
210857
211015
|
O2.step(`scenarios ${g.written} written${birth}`);
|
|
211016
|
+
if (g.readyButHeld > 0) {
|
|
211017
|
+
O2.step(
|
|
211018
|
+
`held ${g.readyButHeld} ready but held (${g.heldByFindings} finding${g.heldByFindings === 1 ? "" : "s"} \xB7 ${g.heldByErrors} error${g.heldByErrors === 1 ? "" : "s"})`
|
|
211019
|
+
);
|
|
211020
|
+
}
|
|
210858
211021
|
const gapTotal = Object.values(g.coverageGapsByKind).reduce((a, b) => a + b, 0);
|
|
210859
211022
|
if (gapTotal > 0) {
|
|
210860
211023
|
const kinds = Object.entries(g.coverageGapsByKind).filter(([, n]) => n > 0).map(([k, n]) => k === "blocked-on" ? `${n} blocked-on${blockedOnBreakdown(g.blockedOnCapabilities)}` : `${n} ${k}`);
|
|
@@ -210866,6 +211029,10 @@ function printGuardGenerateSummary(report4, reportPath) {
|
|
|
210866
211029
|
if (report4.extractionFailures.length > 0) {
|
|
210867
211030
|
O2.step(`extraction ${report4.extractionFailures.length} document${report4.extractionFailures.length === 1 ? "" : "s"} failed \u2014 re-run to retry`);
|
|
210868
211031
|
}
|
|
211032
|
+
if (report4.orphanedDismissals && report4.orphanedDismissals.length > 0) {
|
|
211033
|
+
const n = report4.orphanedDismissals.length;
|
|
211034
|
+
O2.step(`dismissals ${n} orphaned \u2014 the dismissed claim no longer exists; re-dismiss the new text or drop it from decisions.json`);
|
|
211035
|
+
}
|
|
210869
211036
|
if (g.birthFindings > 0) O2.step(`findings ${g.birthFindings} birth finding${g.birthFindings === 1 ? "" : "s"}`);
|
|
210870
211037
|
if (g.errors > 0) O2.step(`errors ${g.errors} authoring error${g.errors === 1 ? "" : "s"}`);
|
|
210871
211038
|
if (g.usage) O2.step(`cost ${g.usage.calls} call${g.usage.calls === 1 ? "" : "s"} \xB7 $${g.usage.costUsd.toFixed(2)}`);
|
|
@@ -210945,6 +211112,7 @@ async function runGuardStatus(opts = {}) {
|
|
|
210945
211112
|
const kinds = Object.entries(g.coverageGapsByKind).filter(([, n]) => n > 0).map(([k, n]) => k === "blocked-on" ? `${n} blocked-on${blockedOnBreakdown(g.blockedOnCapabilities)}` : `${n} ${k}`);
|
|
210946
211113
|
detail.push(`${gapTotal} gap${gapTotal === 1 ? "" : "s"} (${kinds.join(", ")})`);
|
|
210947
211114
|
}
|
|
211115
|
+
if (g.readyButHeld > 0) detail.push(`${g.readyButHeld} ready but held`);
|
|
210948
211116
|
if (g.birthFindings > 0) detail.push(`${g.birthFindings} birth finding${g.birthFindings === 1 ? "" : "s"}`);
|
|
210949
211117
|
if (g.errors > 0) detail.push(`${g.errors} error${g.errors === 1 ? "" : "s"}`);
|
|
210950
211118
|
if (detail.length > 0) O2.message(` ${detail.join(" \xB7 ")}`);
|
|
@@ -211081,7 +211249,7 @@ async function runConfigLlmShow(options = {}) {
|
|
|
211081
211249
|
|
|
211082
211250
|
// tools/cli/src/commands/hooks.ts
|
|
211083
211251
|
import { execSync as execSync4 } from "node:child_process";
|
|
211084
|
-
import
|
|
211252
|
+
import fs69 from "node:fs";
|
|
211085
211253
|
import path79 from "node:path";
|
|
211086
211254
|
init_dist4();
|
|
211087
211255
|
init_paths();
|
|
@@ -211117,11 +211285,11 @@ function findGitDir(from) {
|
|
|
211117
211285
|
let dir = from;
|
|
211118
211286
|
while (true) {
|
|
211119
211287
|
const gitPath = path79.join(dir, ".git");
|
|
211120
|
-
if (
|
|
211121
|
-
const stat =
|
|
211288
|
+
if (fs69.existsSync(gitPath)) {
|
|
211289
|
+
const stat = fs69.statSync(gitPath);
|
|
211122
211290
|
if (stat.isDirectory()) return gitPath;
|
|
211123
211291
|
if (stat.isFile()) {
|
|
211124
|
-
const content =
|
|
211292
|
+
const content = fs69.readFileSync(gitPath, "utf-8").trim();
|
|
211125
211293
|
const match4 = content.match(/^gitdir:\s*(.+)$/);
|
|
211126
211294
|
if (match4) return path79.resolve(dir, match4[1]);
|
|
211127
211295
|
}
|
|
@@ -211134,7 +211302,7 @@ function findGitDir(from) {
|
|
|
211134
211302
|
function findProjectRoot(from) {
|
|
211135
211303
|
let dir = from;
|
|
211136
211304
|
while (true) {
|
|
211137
|
-
if (
|
|
211305
|
+
if (fs69.existsSync(path79.join(dir, ".git"))) return dir;
|
|
211138
211306
|
const parent = path79.dirname(dir);
|
|
211139
211307
|
if (parent === dir) return null;
|
|
211140
211308
|
dir = parent;
|
|
@@ -211142,10 +211310,10 @@ function findProjectRoot(from) {
|
|
|
211142
211310
|
}
|
|
211143
211311
|
function loadConfig(projectRoot) {
|
|
211144
211312
|
const configPath = path79.join(projectRoot, ".truecourse", "hooks.yaml");
|
|
211145
|
-
if (!
|
|
211313
|
+
if (!fs69.existsSync(configPath)) return null;
|
|
211146
211314
|
let parsed;
|
|
211147
211315
|
try {
|
|
211148
|
-
const raw =
|
|
211316
|
+
const raw = fs69.readFileSync(configPath, "utf-8");
|
|
211149
211317
|
parsed = jsYaml.load(raw) || {};
|
|
211150
211318
|
} catch (err) {
|
|
211151
211319
|
console.error(`Error parsing ${configPath}: ${err.message}`);
|
|
@@ -211197,10 +211365,10 @@ async function runHooksInstall() {
|
|
|
211197
211365
|
console.log(INSTALL_WARNING);
|
|
211198
211366
|
}
|
|
211199
211367
|
const hooksDir = path79.join(gitDir, "hooks");
|
|
211200
|
-
|
|
211368
|
+
fs69.mkdirSync(hooksDir, { recursive: true });
|
|
211201
211369
|
const hookPath = path79.join(hooksDir, "pre-commit");
|
|
211202
|
-
if (
|
|
211203
|
-
const existing =
|
|
211370
|
+
if (fs69.existsSync(hookPath)) {
|
|
211371
|
+
const existing = fs69.readFileSync(hookPath, "utf-8");
|
|
211204
211372
|
if (!existing.includes(HOOK_IDENTIFIER)) {
|
|
211205
211373
|
console.error(
|
|
211206
211374
|
"Error: A pre-commit hook already exists and was not installed by TrueCourse."
|
|
@@ -211210,16 +211378,16 @@ async function runHooksInstall() {
|
|
|
211210
211378
|
process.exit(1);
|
|
211211
211379
|
}
|
|
211212
211380
|
}
|
|
211213
|
-
|
|
211381
|
+
fs69.writeFileSync(hookPath, HOOK_SCRIPT, { mode: 493 });
|
|
211214
211382
|
console.log("TrueCourse pre-commit hook installed.");
|
|
211215
211383
|
console.log(` ${hookPath}`);
|
|
211216
211384
|
const projectRoot = findProjectRoot(process.cwd());
|
|
211217
211385
|
if (projectRoot) {
|
|
211218
211386
|
const cfgDir = path79.join(projectRoot, ".truecourse");
|
|
211219
211387
|
const cfgPath = path79.join(cfgDir, "hooks.yaml");
|
|
211220
|
-
if (!
|
|
211221
|
-
|
|
211222
|
-
|
|
211388
|
+
if (!fs69.existsSync(cfgPath)) {
|
|
211389
|
+
fs69.mkdirSync(cfgDir, { recursive: true });
|
|
211390
|
+
fs69.writeFileSync(cfgPath, HOOKS_YAML_TEMPLATE);
|
|
211223
211391
|
console.log(` ${cfgPath} (starter config \u2014 edit to customize, commit to share with the team)`);
|
|
211224
211392
|
}
|
|
211225
211393
|
}
|
|
@@ -211231,16 +211399,16 @@ function runHooksUninstall() {
|
|
|
211231
211399
|
process.exit(1);
|
|
211232
211400
|
}
|
|
211233
211401
|
const hookPath = path79.join(gitDir, "hooks", "pre-commit");
|
|
211234
|
-
if (!
|
|
211402
|
+
if (!fs69.existsSync(hookPath)) {
|
|
211235
211403
|
console.log("No pre-commit hook installed.");
|
|
211236
211404
|
return;
|
|
211237
211405
|
}
|
|
211238
|
-
const content =
|
|
211406
|
+
const content = fs69.readFileSync(hookPath, "utf-8");
|
|
211239
211407
|
if (!content.includes(HOOK_IDENTIFIER)) {
|
|
211240
211408
|
console.error("Error: The pre-commit hook was not installed by TrueCourse. Leaving it in place.");
|
|
211241
211409
|
process.exit(1);
|
|
211242
211410
|
}
|
|
211243
|
-
|
|
211411
|
+
fs69.unlinkSync(hookPath);
|
|
211244
211412
|
console.log("TrueCourse pre-commit hook removed.");
|
|
211245
211413
|
}
|
|
211246
211414
|
function runHooksStatus() {
|
|
@@ -211250,7 +211418,7 @@ function runHooksStatus() {
|
|
|
211250
211418
|
process.exit(1);
|
|
211251
211419
|
}
|
|
211252
211420
|
const hookPath = path79.join(gitDir, "hooks", "pre-commit");
|
|
211253
|
-
const installed =
|
|
211421
|
+
const installed = fs69.existsSync(hookPath) && fs69.readFileSync(hookPath, "utf-8").includes(HOOK_IDENTIFIER);
|
|
211254
211422
|
if (installed) {
|
|
211255
211423
|
console.log("TrueCourse pre-commit hook: installed");
|
|
211256
211424
|
console.log(` ${hookPath}`);
|
|
@@ -211359,7 +211527,7 @@ async function runHooksRun() {
|
|
|
211359
211527
|
|
|
211360
211528
|
// tools/cli/src/index.ts
|
|
211361
211529
|
var program2 = new Command();
|
|
211362
|
-
program2.name("truecourse").version("0.7.0-next.
|
|
211530
|
+
program2.name("truecourse").version("0.7.0-next.4").description("TrueCourse CLI \u2014 analyze your repository and open the dashboard");
|
|
211363
211531
|
var dashboardCmd = program2.command("dashboard").description("Start the TrueCourse dashboard and open it in your browser").option("--reconfigure", "Re-prompt for console vs background service mode").option("--service", "Run as a background service (skips mode prompt)").option("--console", "Run in this terminal (skips mode prompt)").action(async (options) => {
|
|
211364
211532
|
if (options.service && options.console) {
|
|
211365
211533
|
console.error("error: --service and --console are mutually exclusive");
|