truecourse 0.7.0-next.1 → 0.7.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -0
- package/cli.mjs +311 -123
- package/package.json +1 -1
- package/public/assets/{index-BR55uq7e.js → index-B4R8yF4j.js} +101 -101
- package/public/index.html +1 -1
- package/server.mjs +302 -123
package/cli.mjs
CHANGED
|
@@ -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, GuardExtractionFailureSchema, GuardOrphanedSectionSchema, GuardRecipeReportSchema, GuardGenerateUsageSchema, GuardGenerateReportSchema;
|
|
105221
|
+
var GuardWrittenScenarioSchema, GuardCoverageGapKindSchema, GuardCoverageGapSchema, GuardBirthFindingSchema, GuardGenerateErrorSchema, GuardEntryPreflightSchema, GuardExtractionFailureSchema, GuardOrphanedSectionSchema, GuardRecipeReportSchema, GuardGenerateUsageSchema, GuardGenerateReportSchema;
|
|
105222
105222
|
var init_report = __esm({
|
|
105223
105223
|
"packages/shared/dist/guard/report.js"() {
|
|
105224
105224
|
"use strict";
|
|
@@ -105271,6 +105271,14 @@ var init_report = __esm({
|
|
|
105271
105271
|
anchor: external_exports.string(),
|
|
105272
105272
|
message: external_exports.string()
|
|
105273
105273
|
}).strict();
|
|
105274
|
+
GuardEntryPreflightSchema = external_exports.object({
|
|
105275
|
+
/** Display form of the entry argv, e.g. `node tools/cli/dist/index.js`. */
|
|
105276
|
+
entry: external_exports.string(),
|
|
105277
|
+
/** The recipe build command, for the rebuild hint. */
|
|
105278
|
+
buildCommand: external_exports.string(),
|
|
105279
|
+
/** The full, UNTRUNCATED startup output the dead entry produced. */
|
|
105280
|
+
stderr: external_exports.string()
|
|
105281
|
+
}).strict();
|
|
105274
105282
|
GuardExtractionFailureSchema = external_exports.object({
|
|
105275
105283
|
doc: external_exports.string(),
|
|
105276
105284
|
reason: external_exports.string()
|
|
@@ -105316,7 +105324,13 @@ var init_report = __esm({
|
|
|
105316
105324
|
*/
|
|
105317
105325
|
birthPassed: external_exports.number().int().nonnegative().optional(),
|
|
105318
105326
|
manifestPath: external_exports.string().optional(),
|
|
105319
|
-
usage: GuardGenerateUsageSchema.optional()
|
|
105327
|
+
usage: GuardGenerateUsageSchema.optional(),
|
|
105328
|
+
/**
|
|
105329
|
+
* Present ONLY when the built entry failed to start — the whole birth phase was
|
|
105330
|
+
* short-circuited, so every changed section stayed unsettled. Optional so older
|
|
105331
|
+
* reports (written before this field existed) keep parsing.
|
|
105332
|
+
*/
|
|
105333
|
+
entryPreflight: GuardEntryPreflightSchema.optional()
|
|
105320
105334
|
}).strict();
|
|
105321
105335
|
}
|
|
105322
105336
|
});
|
|
@@ -170270,7 +170284,7 @@ function readToolVersion() {
|
|
|
170270
170284
|
if (cachedVersion)
|
|
170271
170285
|
return cachedVersion;
|
|
170272
170286
|
if (true) {
|
|
170273
|
-
cachedVersion = "0.7.0-next.
|
|
170287
|
+
cachedVersion = "0.7.0-next.2";
|
|
170274
170288
|
return cachedVersion;
|
|
170275
170289
|
}
|
|
170276
170290
|
try {
|
|
@@ -197480,35 +197494,49 @@ function prefilterDocs(docs, manualIncludes = []) {
|
|
|
197480
197494
|
skipped: [...reasons].map(([path79, reason]) => ({ path: path79, reason }))
|
|
197481
197495
|
};
|
|
197482
197496
|
}
|
|
197497
|
+
async function planRelevanceWork(repoRoot5, docs, manualIncludes = []) {
|
|
197498
|
+
const manualSet = new Set(manualIncludes);
|
|
197499
|
+
const { toClassify, skipped } = prefilterDocs(docs, manualIncludes);
|
|
197500
|
+
const needsCall = [];
|
|
197501
|
+
const known = /* @__PURE__ */ new Map();
|
|
197502
|
+
await Promise.all(toClassify.map(async (doc) => {
|
|
197503
|
+
if (manualSet.has(doc.path)) {
|
|
197504
|
+
known.set(doc.path, { path: doc.path, include: true, reason: "manual include" });
|
|
197505
|
+
return;
|
|
197506
|
+
}
|
|
197507
|
+
const cached = await readCache4(repoRoot5, computeCacheKey5(doc));
|
|
197508
|
+
if (cached)
|
|
197509
|
+
known.set(doc.path, cached);
|
|
197510
|
+
else
|
|
197511
|
+
needsCall.push(doc);
|
|
197512
|
+
}));
|
|
197513
|
+
return { toClassify, prefilterSkipped: skipped, needsCall, known };
|
|
197514
|
+
}
|
|
197483
197515
|
async function filterByRelevance(repoRoot5, docs, opts = {}) {
|
|
197484
197516
|
if (opts.enabled === false || docs.length === 0) {
|
|
197485
197517
|
return { included: docs, skipped: [] };
|
|
197486
197518
|
}
|
|
197487
|
-
const manualSet = new Set(opts.manualIncludes ?? []);
|
|
197488
197519
|
const runner = opts.runner ?? spawnRelevanceRunner({ transport: opts.transport, model: opts.model, fallbackModel: opts.fallbackModel });
|
|
197489
197520
|
const concurrency = opts.concurrency ?? defaultConcurrency();
|
|
197490
|
-
const
|
|
197491
|
-
const prefilterReason = new Map(prefilterSkipped.map((s) => [s.path, s.reason]));
|
|
197521
|
+
const plan = await planRelevanceWork(repoRoot5, docs, opts.manualIncludes ?? []);
|
|
197522
|
+
const prefilterReason = new Map(plan.prefilterSkipped.map((s) => [s.path, s.reason]));
|
|
197492
197523
|
const total = docs.length;
|
|
197493
197524
|
let done = 0;
|
|
197494
197525
|
const markDone = () => opts.onProgress?.(++done, total);
|
|
197495
197526
|
opts.onProgress?.(0, total);
|
|
197496
|
-
|
|
197527
|
+
const resolvedUpfront = prefilterReason.size + plan.known.size;
|
|
197528
|
+
for (let i = 0; i < resolvedUpfront; i++)
|
|
197497
197529
|
markDone();
|
|
197498
|
-
const verdicts =
|
|
197530
|
+
const verdicts = new Map(plan.known);
|
|
197531
|
+
const pending = plan.needsCall;
|
|
197499
197532
|
let cursor = 0;
|
|
197500
197533
|
let active11 = 0;
|
|
197501
197534
|
await new Promise((resolve12) => {
|
|
197535
|
+
if (pending.length === 0)
|
|
197536
|
+
return resolve12();
|
|
197502
197537
|
const launch = () => {
|
|
197503
|
-
while (active11 < concurrency && cursor <
|
|
197504
|
-
const doc =
|
|
197505
|
-
if (manualSet.has(doc.path)) {
|
|
197506
|
-
verdicts.set(doc.path, { path: doc.path, include: true, reason: "manual include" });
|
|
197507
|
-
markDone();
|
|
197508
|
-
if (cursor >= toClassify.length && active11 === 0)
|
|
197509
|
-
resolve12();
|
|
197510
|
-
continue;
|
|
197511
|
-
}
|
|
197538
|
+
while (active11 < concurrency && cursor < pending.length) {
|
|
197539
|
+
const doc = pending[cursor++];
|
|
197512
197540
|
active11++;
|
|
197513
197541
|
classifyOne(repoRoot5, doc, runner).then((verdict) => {
|
|
197514
197542
|
verdicts.set(doc.path, verdict);
|
|
@@ -197521,14 +197549,12 @@ async function filterByRelevance(repoRoot5, docs, opts = {}) {
|
|
|
197521
197549
|
}).finally(() => {
|
|
197522
197550
|
markDone();
|
|
197523
197551
|
active11--;
|
|
197524
|
-
if (cursor >=
|
|
197552
|
+
if (cursor >= pending.length && active11 === 0)
|
|
197525
197553
|
resolve12();
|
|
197526
197554
|
else
|
|
197527
197555
|
launch();
|
|
197528
197556
|
});
|
|
197529
197557
|
}
|
|
197530
|
-
if (cursor >= toClassify.length && active11 === 0)
|
|
197531
|
-
resolve12();
|
|
197532
197558
|
};
|
|
197533
197559
|
launch();
|
|
197534
197560
|
});
|
|
@@ -197725,9 +197751,6 @@ async function readCache4(scope, cacheKey) {
|
|
|
197725
197751
|
async function writeCache4(scope, cacheKey, verdict) {
|
|
197726
197752
|
await setCacheEntry(scope, CACHE_NAME5, cacheKey, verdict);
|
|
197727
197753
|
}
|
|
197728
|
-
async function readRelevanceCache(repoRoot5, doc) {
|
|
197729
|
-
return readCache4(repoRoot5, computeCacheKey5(doc));
|
|
197730
|
-
}
|
|
197731
197754
|
|
|
197732
197755
|
// packages/spec-consolidator/dist/curate.js
|
|
197733
197756
|
async function curate(repoRoot5, opts = {}) {
|
|
@@ -201835,6 +201858,9 @@ var STAGE_DEFAULTS = {
|
|
|
201835
201858
|
// Authoring an executable scenario faithful to a spec claim is the hard,
|
|
201836
201859
|
// load-bearing call (a weak scenario is false confidence) — opus.
|
|
201837
201860
|
"guard.generate": "opus",
|
|
201861
|
+
// The one evidence-retry per birth-failed claim — the same authoring task, so
|
|
201862
|
+
// the same tier; a distinct stage so retry spend is attributed to the birth line.
|
|
201863
|
+
"guard.retry": "opus",
|
|
201838
201864
|
// Proposing a build/entry recipe is a modest structured task — sonnet.
|
|
201839
201865
|
"guard.recipe": "sonnet",
|
|
201840
201866
|
"rules.violationGen": "opus"
|
|
@@ -205125,6 +205151,129 @@ function listSandboxFiles(dir) {
|
|
|
205125
205151
|
return out.sort();
|
|
205126
205152
|
}
|
|
205127
205153
|
|
|
205154
|
+
// packages/guard-runner/dist/executor.js
|
|
205155
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
205156
|
+
var DEFAULT_STEP_TIMEOUT_MS = 3e4;
|
|
205157
|
+
function executeStep(opts) {
|
|
205158
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_STEP_TIMEOUT_MS;
|
|
205159
|
+
const [command, ...args] = opts.argv;
|
|
205160
|
+
const start = Date.now();
|
|
205161
|
+
return new Promise((resolve12) => {
|
|
205162
|
+
const child = spawn9(command, args, {
|
|
205163
|
+
cwd: opts.cwd,
|
|
205164
|
+
env: opts.env,
|
|
205165
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
205166
|
+
});
|
|
205167
|
+
let stdout = "";
|
|
205168
|
+
let stderr = "";
|
|
205169
|
+
let timedOut = false;
|
|
205170
|
+
let settled = false;
|
|
205171
|
+
const timer = setTimeout(() => {
|
|
205172
|
+
timedOut = true;
|
|
205173
|
+
child.kill("SIGKILL");
|
|
205174
|
+
}, timeoutMs);
|
|
205175
|
+
const finish = (capture) => {
|
|
205176
|
+
if (settled)
|
|
205177
|
+
return;
|
|
205178
|
+
settled = true;
|
|
205179
|
+
clearTimeout(timer);
|
|
205180
|
+
resolve12(capture);
|
|
205181
|
+
};
|
|
205182
|
+
child.stdout.on("data", (chunk3) => {
|
|
205183
|
+
stdout += chunk3.toString("utf-8");
|
|
205184
|
+
});
|
|
205185
|
+
child.stderr.on("data", (chunk3) => {
|
|
205186
|
+
stderr += chunk3.toString("utf-8");
|
|
205187
|
+
});
|
|
205188
|
+
child.on("error", (err) => {
|
|
205189
|
+
finish({
|
|
205190
|
+
exitCode: null,
|
|
205191
|
+
signal: null,
|
|
205192
|
+
stdout,
|
|
205193
|
+
stderr,
|
|
205194
|
+
timedOut,
|
|
205195
|
+
spawnError: err.message,
|
|
205196
|
+
durationMs: Date.now() - start
|
|
205197
|
+
});
|
|
205198
|
+
});
|
|
205199
|
+
child.on("close", (code, signal) => {
|
|
205200
|
+
finish({
|
|
205201
|
+
exitCode: code,
|
|
205202
|
+
signal,
|
|
205203
|
+
stdout,
|
|
205204
|
+
stderr,
|
|
205205
|
+
timedOut,
|
|
205206
|
+
durationMs: Date.now() - start
|
|
205207
|
+
});
|
|
205208
|
+
});
|
|
205209
|
+
if (opts.stdin !== void 0)
|
|
205210
|
+
child.stdin.write(opts.stdin);
|
|
205211
|
+
child.stdin.end();
|
|
205212
|
+
});
|
|
205213
|
+
}
|
|
205214
|
+
|
|
205215
|
+
// packages/guard-runner/dist/preflight.js
|
|
205216
|
+
var ENTRY_PROBE_ARGVS = [[], ["--help"]];
|
|
205217
|
+
var ENTRY_PREFLIGHT_TIMEOUT_MS = 2e4;
|
|
205218
|
+
var defaultEntryProbeExecutor = async (fullArgv, recipeEnv, timeoutMs) => {
|
|
205219
|
+
const sandbox = createSandbox({ recipeEnv });
|
|
205220
|
+
try {
|
|
205221
|
+
return await executeStep({ argv: fullArgv, cwd: sandbox.cwd, env: sandbox.env, timeoutMs });
|
|
205222
|
+
} finally {
|
|
205223
|
+
sandbox.cleanup();
|
|
205224
|
+
}
|
|
205225
|
+
};
|
|
205226
|
+
async function preflightEntry(opts) {
|
|
205227
|
+
const exec3 = opts.exec ?? defaultEntryProbeExecutor;
|
|
205228
|
+
const timeoutMs = opts.timeoutMs ?? ENTRY_PREFLIGHT_TIMEOUT_MS;
|
|
205229
|
+
const entry = opts.displayEntry.join(" ");
|
|
205230
|
+
const probes = await Promise.all(ENTRY_PROBE_ARGVS.map(async (argv) => ({
|
|
205231
|
+
argv: [...argv],
|
|
205232
|
+
capture: await exec3([...opts.resolvedEntry, ...argv], opts.recipeEnv, timeoutMs)
|
|
205233
|
+
})));
|
|
205234
|
+
const ok = entryStarts(probes);
|
|
205235
|
+
return { ok, entry, stderr: ok ? "" : startupOutput(probes[0].capture, timeoutMs), probes };
|
|
205236
|
+
}
|
|
205237
|
+
function entryStarts(probes) {
|
|
205238
|
+
if (probes.some((p2) => startedCleanly(p2.capture)))
|
|
205239
|
+
return true;
|
|
205240
|
+
const shapes = probes.map((p2) => failureShape(p2.capture));
|
|
205241
|
+
return shapes.some((s) => s !== shapes[0]);
|
|
205242
|
+
}
|
|
205243
|
+
function startedCleanly(c2) {
|
|
205244
|
+
return !c2.spawnError && !c2.timedOut && c2.signal === null && c2.exitCode === 0;
|
|
205245
|
+
}
|
|
205246
|
+
function failureShape(c2) {
|
|
205247
|
+
return JSON.stringify({
|
|
205248
|
+
spawnError: c2.spawnError ?? null,
|
|
205249
|
+
signal: c2.signal ?? null,
|
|
205250
|
+
timedOut: c2.timedOut,
|
|
205251
|
+
exitCode: c2.exitCode,
|
|
205252
|
+
stdout: c2.stdout,
|
|
205253
|
+
stderr: c2.stderr
|
|
205254
|
+
});
|
|
205255
|
+
}
|
|
205256
|
+
function startupOutput(c2, timeoutMs) {
|
|
205257
|
+
const parts = [];
|
|
205258
|
+
const primary = c2.stderr || c2.stdout;
|
|
205259
|
+
if (primary)
|
|
205260
|
+
parts.push(primary.trimEnd());
|
|
205261
|
+
if (c2.spawnError)
|
|
205262
|
+
parts.push(`failed to spawn: ${c2.spawnError}`);
|
|
205263
|
+
if (c2.timedOut)
|
|
205264
|
+
parts.push(`(the entry produced no output within ${timeoutMs}ms and was killed)`);
|
|
205265
|
+
if (parts.length === 0) {
|
|
205266
|
+
parts.push(c2.exitCode !== null ? `(the entry exited ${c2.exitCode} with no output)` : `(the entry was killed by ${c2.signal})`);
|
|
205267
|
+
}
|
|
205268
|
+
return parts.join("\n");
|
|
205269
|
+
}
|
|
205270
|
+
function entryPreflightHeadline(entry, buildCommand) {
|
|
205271
|
+
return `The recipe entry \`${entry}\` failed to start \u2014 it crashes before it runs, so every scenario would fail identically. Rebuild it with \`${buildCommand}\` (its build output is likely stale or incomplete), then retry.`;
|
|
205272
|
+
}
|
|
205273
|
+
function formatEntryPreflightError(opts) {
|
|
205274
|
+
return [entryPreflightHeadline(opts.entry, opts.buildCommand), "", "Startup output:", opts.stderr].join("\n");
|
|
205275
|
+
}
|
|
205276
|
+
|
|
205128
205277
|
// packages/guard-runner/dist/capabilities/git.js
|
|
205129
205278
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
205130
205279
|
import fs51 from "node:fs";
|
|
@@ -205205,67 +205354,6 @@ function applyCapabilities(setup, ctx) {
|
|
|
205205
205354
|
}
|
|
205206
205355
|
}
|
|
205207
205356
|
|
|
205208
|
-
// packages/guard-runner/dist/executor.js
|
|
205209
|
-
import { spawn as spawn9 } from "node:child_process";
|
|
205210
|
-
var DEFAULT_STEP_TIMEOUT_MS = 3e4;
|
|
205211
|
-
function executeStep(opts) {
|
|
205212
|
-
const timeoutMs = opts.timeoutMs ?? DEFAULT_STEP_TIMEOUT_MS;
|
|
205213
|
-
const [command, ...args] = opts.argv;
|
|
205214
|
-
const start = Date.now();
|
|
205215
|
-
return new Promise((resolve12) => {
|
|
205216
|
-
const child = spawn9(command, args, {
|
|
205217
|
-
cwd: opts.cwd,
|
|
205218
|
-
env: opts.env,
|
|
205219
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
205220
|
-
});
|
|
205221
|
-
let stdout = "";
|
|
205222
|
-
let stderr = "";
|
|
205223
|
-
let timedOut = false;
|
|
205224
|
-
let settled = false;
|
|
205225
|
-
const timer = setTimeout(() => {
|
|
205226
|
-
timedOut = true;
|
|
205227
|
-
child.kill("SIGKILL");
|
|
205228
|
-
}, timeoutMs);
|
|
205229
|
-
const finish = (capture) => {
|
|
205230
|
-
if (settled)
|
|
205231
|
-
return;
|
|
205232
|
-
settled = true;
|
|
205233
|
-
clearTimeout(timer);
|
|
205234
|
-
resolve12(capture);
|
|
205235
|
-
};
|
|
205236
|
-
child.stdout.on("data", (chunk3) => {
|
|
205237
|
-
stdout += chunk3.toString("utf-8");
|
|
205238
|
-
});
|
|
205239
|
-
child.stderr.on("data", (chunk3) => {
|
|
205240
|
-
stderr += chunk3.toString("utf-8");
|
|
205241
|
-
});
|
|
205242
|
-
child.on("error", (err) => {
|
|
205243
|
-
finish({
|
|
205244
|
-
exitCode: null,
|
|
205245
|
-
signal: null,
|
|
205246
|
-
stdout,
|
|
205247
|
-
stderr,
|
|
205248
|
-
timedOut,
|
|
205249
|
-
spawnError: err.message,
|
|
205250
|
-
durationMs: Date.now() - start
|
|
205251
|
-
});
|
|
205252
|
-
});
|
|
205253
|
-
child.on("close", (code, signal) => {
|
|
205254
|
-
finish({
|
|
205255
|
-
exitCode: code,
|
|
205256
|
-
signal,
|
|
205257
|
-
stdout,
|
|
205258
|
-
stderr,
|
|
205259
|
-
timedOut,
|
|
205260
|
-
durationMs: Date.now() - start
|
|
205261
|
-
});
|
|
205262
|
-
});
|
|
205263
|
-
if (opts.stdin !== void 0)
|
|
205264
|
-
child.stdin.write(opts.stdin);
|
|
205265
|
-
child.stdin.end();
|
|
205266
|
-
});
|
|
205267
|
-
}
|
|
205268
|
-
|
|
205269
205357
|
// packages/guard-runner/dist/normalizers.js
|
|
205270
205358
|
var CANONICAL_ORDER = [
|
|
205271
205359
|
"abs-paths",
|
|
@@ -205896,16 +205984,27 @@ async function runGuard(opts) {
|
|
|
205896
205984
|
}));
|
|
205897
205985
|
const executable = planned.filter((p2) => p2.resolution.kind === "match" || p2.resolution.kind === "remap");
|
|
205898
205986
|
const nonExecutable = planned.filter((p2) => p2.resolution.kind === "stale" || p2.resolution.kind === "orphaned");
|
|
205899
|
-
|
|
205987
|
+
const buildsOwnEntry = !opts.skipBuild && executable.length > 0;
|
|
205988
|
+
if (buildsOwnEntry) {
|
|
205900
205989
|
opts.onPhase?.("build");
|
|
205901
205990
|
const build8 = await runBuild(repoRoot5, loaded.recipe.build, loaded.recipe.env);
|
|
205902
205991
|
if (!build8.ok)
|
|
205903
205992
|
return { status: "build-failed", build: build8, loadErrors };
|
|
205904
205993
|
}
|
|
205994
|
+
const resolvedEntry = resolveEntry(repoRoot5, loaded.recipe.entry);
|
|
205995
|
+
if (buildsOwnEntry) {
|
|
205996
|
+
const preflight = await preflightEntry({
|
|
205997
|
+
resolvedEntry,
|
|
205998
|
+
displayEntry: loaded.recipe.entry,
|
|
205999
|
+
recipeEnv: loaded.recipe.env
|
|
206000
|
+
});
|
|
206001
|
+
if (!preflight.ok) {
|
|
206002
|
+
return { status: "entry-preflight-failed", preflight, buildCommand: loaded.recipe.build, loadErrors };
|
|
206003
|
+
}
|
|
206004
|
+
}
|
|
205905
206005
|
opts.onPhase?.("run", selected.length);
|
|
205906
206006
|
const runId = buildRunId();
|
|
205907
206007
|
const ranAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
205908
|
-
const resolvedEntry = resolveEntry(repoRoot5, loaded.recipe.entry);
|
|
205909
206008
|
const stepTimeoutMs = opts.stepTimeoutMs ?? DEFAULT_STEP_TIMEOUT_MS;
|
|
205910
206009
|
const concurrency = opts.concurrency ?? defaultRunConcurrency();
|
|
205911
206010
|
const results = [];
|
|
@@ -206450,11 +206549,11 @@ function spawnGenerateRunner2(opts = {}) {
|
|
|
206450
206549
|
return async (ctx) => {
|
|
206451
206550
|
const refs = ctx.claims.map((c2) => c2.ref).join(",");
|
|
206452
206551
|
const isRetry = ctx.claims.some((c2) => c2.retry);
|
|
206453
|
-
const
|
|
206552
|
+
const stage = isRetry ? "guard.retry" : "guard.generate";
|
|
206454
206553
|
const raw = await transport({
|
|
206455
|
-
id:
|
|
206456
|
-
stage
|
|
206457
|
-
model: opts.model,
|
|
206554
|
+
id: `${stage}:${ctx.doc}:${refs}${ctx.correction ? ":correction" : ""}`,
|
|
206555
|
+
stage,
|
|
206556
|
+
model: isRetry ? opts.retryModel ?? opts.model : opts.model,
|
|
206458
206557
|
fallbackModel: opts.fallbackModel,
|
|
206459
206558
|
system: GENERATE_SYSTEM_PROMPT,
|
|
206460
206559
|
user: buildAuthorUserPrompt(ctx),
|
|
@@ -206766,12 +206865,15 @@ async function captureProbes(opts) {
|
|
|
206766
206865
|
const cached = await getCacheEntry(opts.repoRoot, GROUND_CACHE_NAME, key4);
|
|
206767
206866
|
if (cached) {
|
|
206768
206867
|
const parsed = ProbeTranscriptSchema.safeParse(cached);
|
|
206769
|
-
if (parsed.success)
|
|
206868
|
+
if (parsed.success) {
|
|
206869
|
+
opts.onProbeCaptured?.();
|
|
206770
206870
|
return parsed.data;
|
|
206871
|
+
}
|
|
206771
206872
|
}
|
|
206772
206873
|
const capture = await exec3([...opts.resolvedEntry, ...argv], opts.recipeEnv);
|
|
206773
206874
|
const transcript = toTranscript(argv, [...opts.displayEntry, ...argv], capture);
|
|
206774
206875
|
await setCacheEntry(opts.repoRoot, GROUND_CACHE_NAME, key4, transcript);
|
|
206876
|
+
opts.onProbeCaptured?.();
|
|
206775
206877
|
return transcript;
|
|
206776
206878
|
}));
|
|
206777
206879
|
}
|
|
@@ -207036,6 +207138,7 @@ function deleteScenarioFiles(repoRoot5, ids) {
|
|
|
207036
207138
|
|
|
207037
207139
|
// packages/guard-generator/dist/generate.js
|
|
207038
207140
|
var GENERATE_CACHE_NAME = "guard/generate";
|
|
207141
|
+
var ENTRY_PREFLIGHT_ANCHOR = "(entry preflight)";
|
|
207039
207142
|
function defaultConcurrency3() {
|
|
207040
207143
|
const env = process.env.TRUECOURSE_MAX_CONCURRENCY;
|
|
207041
207144
|
if (env) {
|
|
@@ -207105,7 +207208,12 @@ async function generateGuards(options) {
|
|
|
207105
207208
|
const limit = pLimit(Math.max(1, options.concurrency ?? defaultConcurrency3()));
|
|
207106
207209
|
const batchSize = Math.max(1, options.batchSize ?? defaultGenerateBatch2());
|
|
207107
207210
|
const extractRunner = options.extractRunner ?? spawnExtractRunner({ transport: options.transport, model: options.models?.extract, fallbackModel: options.models?.fallback });
|
|
207108
|
-
const generateRunner = options.generateRunner ?? spawnGenerateRunner2({
|
|
207211
|
+
const generateRunner = options.generateRunner ?? spawnGenerateRunner2({
|
|
207212
|
+
transport: options.transport,
|
|
207213
|
+
model: options.models?.generate,
|
|
207214
|
+
retryModel: options.models?.retry,
|
|
207215
|
+
fallbackModel: options.models?.fallback
|
|
207216
|
+
});
|
|
207109
207217
|
const coverageGaps = [];
|
|
207110
207218
|
const errors = [];
|
|
207111
207219
|
const extractionFailures = [];
|
|
@@ -207176,11 +207284,15 @@ async function generateGuards(options) {
|
|
|
207176
207284
|
return buildPromise;
|
|
207177
207285
|
};
|
|
207178
207286
|
let resolvedEntryMemo = null;
|
|
207287
|
+
let groundPlanned = 0;
|
|
207288
|
+
let groundCaptured = 0;
|
|
207179
207289
|
const groundClaims = async (claimTexts) => {
|
|
207180
207290
|
const probes = deriveProbes(claimTexts, recipe.entry);
|
|
207181
207291
|
const build8 = await buildPromise;
|
|
207182
|
-
if (!build8.ok)
|
|
207292
|
+
if (!build8.ok || probes.length === 0)
|
|
207183
207293
|
return [];
|
|
207294
|
+
groundPlanned += probes.length;
|
|
207295
|
+
options.onGroundProgress?.(groundCaptured, groundPlanned);
|
|
207184
207296
|
resolvedEntryMemo ??= resolveEntry(repoRoot5, recipe.entry);
|
|
207185
207297
|
return captureProbes({
|
|
207186
207298
|
repoRoot: repoRoot5,
|
|
@@ -207188,9 +207300,21 @@ async function generateGuards(options) {
|
|
|
207188
207300
|
resolvedEntry: resolvedEntryMemo,
|
|
207189
207301
|
displayEntry: recipe.entry,
|
|
207190
207302
|
recipeFingerprint,
|
|
207191
|
-
recipeEnv: recipe.env
|
|
207303
|
+
recipeEnv: recipe.env,
|
|
207304
|
+
onProbeCaptured: () => options.onGroundProgress?.(++groundCaptured, groundPlanned)
|
|
207192
207305
|
});
|
|
207193
207306
|
};
|
|
207307
|
+
let entryPreflightMemo = null;
|
|
207308
|
+
const preflightEntryOnce = () => {
|
|
207309
|
+
entryPreflightMemo ??= (async () => {
|
|
207310
|
+
const build8 = await buildPromise;
|
|
207311
|
+
if (!build8.ok)
|
|
207312
|
+
return null;
|
|
207313
|
+
resolvedEntryMemo ??= resolveEntry(repoRoot5, recipe.entry);
|
|
207314
|
+
return preflightEntry({ resolvedEntry: resolvedEntryMemo, displayEntry: recipe.entry, recipeEnv: recipe.env });
|
|
207315
|
+
})();
|
|
207316
|
+
return entryPreflightMemo;
|
|
207317
|
+
};
|
|
207194
207318
|
const priorSections = readPriorManifest(repoRoot5);
|
|
207195
207319
|
const manifestByKey = new Map(priorSections.map((e) => [`${e.doc}\0${e.anchor}`, e]));
|
|
207196
207320
|
const usedIds = existingScenarioIds(repoRoot5);
|
|
@@ -207214,9 +207338,11 @@ async function generateGuards(options) {
|
|
|
207214
207338
|
});
|
|
207215
207339
|
settledKeys.add(k);
|
|
207216
207340
|
writeWorkingManifest();
|
|
207341
|
+
options.onSectionSettled?.(settledKeys.size, plan.work.length);
|
|
207217
207342
|
};
|
|
207218
207343
|
const written = [];
|
|
207219
207344
|
const birthFindings = [];
|
|
207345
|
+
let entryPreflightFailure = null;
|
|
207220
207346
|
let birthTotal = 0;
|
|
207221
207347
|
let birthSettled = 0;
|
|
207222
207348
|
let birthPassed = 0;
|
|
@@ -207263,6 +207389,20 @@ async function generateGuards(options) {
|
|
|
207263
207389
|
return;
|
|
207264
207390
|
settleChain = settleChain.then(() => settleCliSection(sectionByKey.get(k), refsBySection.get(k)));
|
|
207265
207391
|
};
|
|
207392
|
+
const deadEntry = async () => {
|
|
207393
|
+
const preflight = await preflightEntryOnce();
|
|
207394
|
+
if (!preflight || preflight.ok)
|
|
207395
|
+
return false;
|
|
207396
|
+
if (!entryPreflightFailure) {
|
|
207397
|
+
entryPreflightFailure = { entry: preflight.entry, buildCommand: recipe.build, stderr: preflight.stderr };
|
|
207398
|
+
errors.push({
|
|
207399
|
+
doc: preflight.entry,
|
|
207400
|
+
anchor: ENTRY_PREFLIGHT_ANCHOR,
|
|
207401
|
+
message: formatEntryPreflightError(entryPreflightFailure)
|
|
207402
|
+
});
|
|
207403
|
+
}
|
|
207404
|
+
return true;
|
|
207405
|
+
};
|
|
207266
207406
|
async function settleCliSection(section, refs) {
|
|
207267
207407
|
const k = key2(section);
|
|
207268
207408
|
for (const id of priorIdsOf(k))
|
|
@@ -207297,6 +207437,8 @@ async function generateGuards(options) {
|
|
|
207297
207437
|
const message = `build failed (\`${build8.command}\`)${build8.timedOut ? " \u2014 timed out" : ""}`;
|
|
207298
207438
|
for (const c2 of round1)
|
|
207299
207439
|
localErrors.push(errorFrom({ candidate: c2, result: { failure: { actual: message } } }));
|
|
207440
|
+
} else if (await deadEntry()) {
|
|
207441
|
+
return;
|
|
207300
207442
|
} else {
|
|
207301
207443
|
birthTotal += round1.length;
|
|
207302
207444
|
const r1 = await birthValidate(repoRoot5, round1, { skipBuild: true, onPhase: options.onBirthPhase, onScenarioSettled: bumpBirth });
|
|
@@ -207373,6 +207515,8 @@ async function generateGuards(options) {
|
|
|
207373
207515
|
const authorTotal = authTasks.length;
|
|
207374
207516
|
let authorDone = 0;
|
|
207375
207517
|
const bumpAuthor = (n) => options.onAuthorProgress?.(authorDone += n, authorTotal);
|
|
207518
|
+
if (authorTotal > 0)
|
|
207519
|
+
options.onAuthorProgress?.(authorDone, authorTotal);
|
|
207376
207520
|
const missTasks = [];
|
|
207377
207521
|
for (const t2 of authTasks) {
|
|
207378
207522
|
const cached = await readAuthorCache(repoRoot5, t2.claim, t2.section, recipeFingerprint);
|
|
@@ -207444,7 +207588,8 @@ async function generateGuards(options) {
|
|
|
207444
207588
|
extractionFailures,
|
|
207445
207589
|
orphaned,
|
|
207446
207590
|
birthPassed,
|
|
207447
|
-
manifestPath: manifestPath2(repoRoot5)
|
|
207591
|
+
manifestPath: manifestPath2(repoRoot5),
|
|
207592
|
+
...entryPreflightFailure ? { entryPreflight: entryPreflightFailure } : {}
|
|
207448
207593
|
};
|
|
207449
207594
|
}
|
|
207450
207595
|
var key2 = (s) => `${s.doc}\0${s.anchor}`;
|
|
@@ -207833,12 +207978,14 @@ function previewChars() {
|
|
|
207833
207978
|
return 60 * 50;
|
|
207834
207979
|
}
|
|
207835
207980
|
async function estimateScanTokens(repoRoot5, prices) {
|
|
207981
|
+
const decisions = readCorpusDecisions(repoRoot5);
|
|
207982
|
+
const manualIncludes = decisions.manualIncludes ?? [];
|
|
207983
|
+
const manualExcludes = new Set(decisions.manualExcludes ?? []);
|
|
207836
207984
|
const docs = discoverDocs(repoRoot5);
|
|
207837
|
-
const
|
|
207838
|
-
const nClassify = toClassify.length;
|
|
207839
|
-
const
|
|
207840
|
-
const
|
|
207841
|
-
const cachedKeptDocs = toClassify.filter((_2, i) => relevance[i]?.include === true);
|
|
207985
|
+
const plan = await planRelevanceWork(repoRoot5, docs, manualIncludes);
|
|
207986
|
+
const nClassify = plan.toClassify.length;
|
|
207987
|
+
const relevanceMissDocs = plan.needsCall;
|
|
207988
|
+
const cachedKeptDocs = plan.toClassify.filter((d3) => plan.known.get(d3.path)?.include === true && !manualExcludes.has(d3.path));
|
|
207842
207989
|
const cachedKeptTagged = await Promise.all(cachedKeptDocs.map((d3) => isAreaTagCached(repoRoot5, d3)));
|
|
207843
207990
|
const cachedKeptTagMisses = cachedKeptTagged.filter((cached) => !cached).length;
|
|
207844
207991
|
const estChangedKept = Math.round(relevanceMissDocs.length * KEEP_RATE);
|
|
@@ -210240,12 +210387,14 @@ var GUARD_GENERATE_STEPS = [
|
|
|
210240
210387
|
var GUARD_STEP_STAGES = {
|
|
210241
210388
|
index: ["guard.recipe"],
|
|
210242
210389
|
extract: ["guard.extract"],
|
|
210243
|
-
author: ["guard.generate"]
|
|
210390
|
+
author: ["guard.generate"],
|
|
210391
|
+
validate: ["guard.retry"]
|
|
210244
210392
|
};
|
|
210245
210393
|
function resolveGuardModels(repoRoot5) {
|
|
210246
210394
|
return {
|
|
210247
210395
|
extract: resolveModel("guard.extract", void 0, repoRoot5),
|
|
210248
210396
|
generate: resolveModel("guard.generate", void 0, repoRoot5),
|
|
210397
|
+
retry: resolveModel("guard.retry", void 0, repoRoot5),
|
|
210249
210398
|
recipe: resolveModel("guard.recipe", void 0, repoRoot5),
|
|
210250
210399
|
fallback: resolveFallbackModel(repoRoot5) ?? void 0
|
|
210251
210400
|
};
|
|
@@ -210287,10 +210436,20 @@ async function guardGenerateInProcess(repoRoot5, options = {}) {
|
|
|
210287
210436
|
cur = ni;
|
|
210288
210437
|
};
|
|
210289
210438
|
const withUsage = (key4, base2) => `${base2}${stageUsageTag(GUARD_STEP_STAGES[key4] ?? [], repoRoot5)}`;
|
|
210439
|
+
let authorDone = 0;
|
|
210440
|
+
let authorTotal = 0;
|
|
210441
|
+
let authorFinished = false;
|
|
210442
|
+
let groundCaptured = 0;
|
|
210443
|
+
let groundPlanned = 0;
|
|
210444
|
+
const authorDetail = () => {
|
|
210445
|
+
const claims = `${authorDone}/${authorTotal} claim${authorTotal === 1 ? "" : "s"}`;
|
|
210446
|
+
const base2 = groundPlanned > 0 ? `grounding probes ${groundCaptured}/${groundPlanned} \xB7 authoring ${claims}` : claims;
|
|
210447
|
+
return withUsage("author", base2);
|
|
210448
|
+
};
|
|
210290
210449
|
let building = false;
|
|
210291
|
-
let birthSeen = false;
|
|
210292
210450
|
let birthDone = 0;
|
|
210293
|
-
let
|
|
210451
|
+
let sectionsDone = 0;
|
|
210452
|
+
let sectionsTotal = 0;
|
|
210294
210453
|
let retrySeen = false;
|
|
210295
210454
|
let retryDone = 0;
|
|
210296
210455
|
let retryTotal = 0;
|
|
@@ -210301,10 +210460,10 @@ async function guardGenerateInProcess(repoRoot5, options = {}) {
|
|
|
210301
210460
|
tracker?.start("validate");
|
|
210302
210461
|
validateStarted = true;
|
|
210303
210462
|
}
|
|
210304
|
-
const parts = [building ? "building\u2026" : `birth ${birthDone}
|
|
210463
|
+
const parts = [`sections ${sectionsDone}/${sectionsTotal}`, building ? "building\u2026" : `birth ${birthDone}`];
|
|
210305
210464
|
if (retrySeen)
|
|
210306
|
-
parts.push(`retrying
|
|
210307
|
-
tracker?.detail("validate", parts.join(" \xB7 "));
|
|
210465
|
+
parts.push(`retrying ${retryDone}/${retryTotal}`);
|
|
210466
|
+
tracker?.detail("validate", withUsage("validate", parts.join(" \xB7 ")));
|
|
210308
210467
|
};
|
|
210309
210468
|
tracker?.start("index");
|
|
210310
210469
|
try {
|
|
@@ -210316,6 +210475,7 @@ async function guardGenerateInProcess(repoRoot5, options = {}) {
|
|
|
210316
210475
|
generateRunner: options.generateRunner,
|
|
210317
210476
|
recipeRunner: options.recipeRunner,
|
|
210318
210477
|
onPlan: (total, work) => {
|
|
210478
|
+
sectionsTotal = work;
|
|
210319
210479
|
tracker?.done("index", withUsage("index", `${work} of ${total} section${total === 1 ? "" : "s"} changed`));
|
|
210320
210480
|
cur = STEPS.indexOf("extract");
|
|
210321
210481
|
tracker?.start("extract", `0 views`);
|
|
@@ -210332,27 +210492,30 @@ async function guardGenerateInProcess(repoRoot5, options = {}) {
|
|
|
210332
210492
|
},
|
|
210333
210493
|
onAuthorProgress: (done, total) => {
|
|
210334
210494
|
advanceTo("author");
|
|
210335
|
-
|
|
210336
|
-
|
|
210337
|
-
|
|
210338
|
-
|
|
210339
|
-
tracker?.
|
|
210340
|
-
},
|
|
210341
|
-
onBirthPhase: (phase, total) => {
|
|
210342
|
-
if (phase === "build") {
|
|
210343
|
-
building = true;
|
|
210495
|
+
authorDone = done;
|
|
210496
|
+
authorTotal = total;
|
|
210497
|
+
if (done >= total) {
|
|
210498
|
+
authorFinished = true;
|
|
210499
|
+
tracker?.done("author", withUsage("author", `${done}/${total} claim${total === 1 ? "" : "s"}`));
|
|
210344
210500
|
} else {
|
|
210345
|
-
|
|
210346
|
-
if (!birthSeen && total !== void 0)
|
|
210347
|
-
birthTotal = total;
|
|
210501
|
+
tracker?.detail("author", authorDetail());
|
|
210348
210502
|
}
|
|
210503
|
+
},
|
|
210504
|
+
onGroundProgress: (captured, planned) => {
|
|
210505
|
+
groundCaptured = captured;
|
|
210506
|
+
groundPlanned = planned;
|
|
210507
|
+
if (authorFinished)
|
|
210508
|
+
return;
|
|
210509
|
+
advanceTo("author");
|
|
210510
|
+
tracker?.detail("author", authorDetail());
|
|
210511
|
+
},
|
|
210512
|
+
onBirthPhase: (phase) => {
|
|
210513
|
+
building = phase === "build";
|
|
210349
210514
|
renderValidate();
|
|
210350
210515
|
},
|
|
210351
|
-
onBirthProgress: (done
|
|
210516
|
+
onBirthProgress: (done) => {
|
|
210352
210517
|
building = false;
|
|
210353
|
-
birthSeen = true;
|
|
210354
210518
|
birthDone = done;
|
|
210355
|
-
birthTotal = total;
|
|
210356
210519
|
renderValidate();
|
|
210357
210520
|
},
|
|
210358
210521
|
onRetryProgress: (done, total) => {
|
|
@@ -210360,6 +210523,12 @@ async function guardGenerateInProcess(repoRoot5, options = {}) {
|
|
|
210360
210523
|
retryDone = done;
|
|
210361
210524
|
retryTotal = total;
|
|
210362
210525
|
renderValidate();
|
|
210526
|
+
},
|
|
210527
|
+
onSectionSettled: (settled, total) => {
|
|
210528
|
+
sectionsDone = settled;
|
|
210529
|
+
sectionsTotal = total;
|
|
210530
|
+
if (validateStarted)
|
|
210531
|
+
renderValidate();
|
|
210363
210532
|
}
|
|
210364
210533
|
});
|
|
210365
210534
|
for (let i = cur; i < STEPS.length; i++)
|
|
@@ -210383,7 +210552,7 @@ async function guardGenerateInProcess(repoRoot5, options = {}) {
|
|
|
210383
210552
|
}
|
|
210384
210553
|
}
|
|
210385
210554
|
}
|
|
210386
|
-
var GUARD_USAGE_STAGES = ["guard.recipe", "guard.extract", "guard.generate"];
|
|
210555
|
+
var GUARD_USAGE_STAGES = ["guard.recipe", "guard.extract", "guard.generate", "guard.retry"];
|
|
210387
210556
|
function sumGuardUsage() {
|
|
210388
210557
|
const usage = getStageUsage();
|
|
210389
210558
|
let calls = 0;
|
|
@@ -210431,6 +210600,8 @@ async function guardRunInProcess(repoRoot5, options = {}) {
|
|
|
210431
210600
|
tracker?.done("run", `${n} scenario${n === 1 ? "" : "s"}`);
|
|
210432
210601
|
} else if (result.status === "build-failed") {
|
|
210433
210602
|
tracker?.error("build", `Build failed (\`${result.build.command}\`)${result.build.timedOut ? " \u2014 timed out" : ""}`);
|
|
210603
|
+
} else if (result.status === "entry-preflight-failed") {
|
|
210604
|
+
tracker?.error("build", `Entry failed to start: \`${result.preflight.entry}\` (rebuild via \`${result.buildCommand}\`)`);
|
|
210434
210605
|
}
|
|
210435
210606
|
return result;
|
|
210436
210607
|
}
|
|
@@ -210494,6 +210665,15 @@ async function runGuardRun(opts = {}) {
|
|
|
210494
210665
|
process.exit(1);
|
|
210495
210666
|
return;
|
|
210496
210667
|
}
|
|
210668
|
+
case "entry-preflight-failed": {
|
|
210669
|
+
O2.error(`The recipe entry \`${result.preflight.entry}\` failed to start \u2014 every scenario would fail identically.`);
|
|
210670
|
+
for (const line of result.preflight.stderr.trimEnd().split("\n")) console.log(` ${line}`);
|
|
210671
|
+
O2.step(`Rebuild it with \`${result.buildCommand}\` (its build output is likely stale or incomplete), then re-run \`truecourse guard run\`.`);
|
|
210672
|
+
printLoadErrors(result.loadErrors);
|
|
210673
|
+
gt("Aborted \u2014 the entry could not start; no scenarios ran.");
|
|
210674
|
+
process.exit(1);
|
|
210675
|
+
return;
|
|
210676
|
+
}
|
|
210497
210677
|
case "ok":
|
|
210498
210678
|
break;
|
|
210499
210679
|
}
|
|
@@ -210576,6 +210756,13 @@ async function runGuardGenerate(opts = {}) {
|
|
|
210576
210756
|
gt("Add or fix `.truecourse/scenarios/recipe.json` and retry.");
|
|
210577
210757
|
process.exit(1);
|
|
210578
210758
|
}
|
|
210759
|
+
if (guard.entryPreflight) {
|
|
210760
|
+
O2.error(`The recipe entry \`${guard.entryPreflight.entry}\` failed to start \u2014 every scenario would fail identically, so nothing was validated.`);
|
|
210761
|
+
for (const line of guard.entryPreflight.stderr.trimEnd().split("\n")) console.log(` ${line}`);
|
|
210762
|
+
O2.step(`Rebuild it with \`${guard.entryPreflight.buildCommand}\` (its build output is likely stale or incomplete), then re-run \`truecourse guard generate\`.`);
|
|
210763
|
+
gt("Aborted \u2014 the entry could not start; no scenarios were validated.");
|
|
210764
|
+
process.exit(1);
|
|
210765
|
+
}
|
|
210579
210766
|
if (guard.recipe?.status === "discovered") {
|
|
210580
210767
|
O2.step(`recipe wrote ${guard.recipe.wrotePath} \u2014 review and commit it`);
|
|
210581
210768
|
}
|
|
@@ -210799,6 +210986,7 @@ var STAGE_LABEL = {
|
|
|
210799
210986
|
"contract.gapJudge": "Contract \xB7 gap judge",
|
|
210800
210987
|
"guard.extract": "Guard \xB7 claim extract",
|
|
210801
210988
|
"guard.generate": "Guard \xB7 scenario gen",
|
|
210989
|
+
"guard.retry": "Guard \xB7 scenario retry",
|
|
210802
210990
|
"guard.recipe": "Guard \xB7 recipe discover",
|
|
210803
210991
|
"rules.violationGen": "Rules \xB7 violation gen"
|
|
210804
210992
|
};
|
|
@@ -211107,7 +211295,7 @@ async function runHooksRun() {
|
|
|
211107
211295
|
|
|
211108
211296
|
// tools/cli/src/index.ts
|
|
211109
211297
|
var program2 = new Command();
|
|
211110
|
-
program2.name("truecourse").version("0.7.0-next.
|
|
211298
|
+
program2.name("truecourse").version("0.7.0-next.2").description("TrueCourse CLI \u2014 analyze your repository and open the dashboard");
|
|
211111
211299
|
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) => {
|
|
211112
211300
|
if (options.service && options.console) {
|
|
211113
211301
|
console.error("error: --service and --console are mutually exclusive");
|