@riddledc/riddle-proof 0.7.218 → 0.7.220
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/dist/cli.cjs +235 -4
- package/dist/cli.js +235 -4
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -16332,6 +16332,92 @@ function extractRiddleProofProfileResult(input) {
|
|
|
16332
16332
|
|
|
16333
16333
|
// src/cli.ts
|
|
16334
16334
|
var RIDDLE_PROFILE_BALANCE_PREFLIGHT_MIN_SECONDS_PER_JOB = 30;
|
|
16335
|
+
var KNOWN_CLI_OPTIONS = /* @__PURE__ */ new Set([
|
|
16336
|
+
"agent",
|
|
16337
|
+
"apiBaseUrl",
|
|
16338
|
+
"apiKey",
|
|
16339
|
+
"apiKeyFile",
|
|
16340
|
+
"artifact",
|
|
16341
|
+
"attempts",
|
|
16342
|
+
"balancePreflight",
|
|
16343
|
+
"baseUrl",
|
|
16344
|
+
"candidateJson",
|
|
16345
|
+
"candidatesJson",
|
|
16346
|
+
"checkpointMode",
|
|
16347
|
+
"checkpointVisibility",
|
|
16348
|
+
"codexCommand",
|
|
16349
|
+
"codexFullAuto",
|
|
16350
|
+
"codexHome",
|
|
16351
|
+
"codexModel",
|
|
16352
|
+
"codexSandbox",
|
|
16353
|
+
"codexTimeoutMs",
|
|
16354
|
+
"command",
|
|
16355
|
+
"continueWithStage",
|
|
16356
|
+
"createdAt",
|
|
16357
|
+
"decision",
|
|
16358
|
+
"defaultReviewer",
|
|
16359
|
+
"defaultShipMode",
|
|
16360
|
+
"exclude",
|
|
16361
|
+
"format",
|
|
16362
|
+
"framework",
|
|
16363
|
+
"help",
|
|
16364
|
+
"image",
|
|
16365
|
+
"input",
|
|
16366
|
+
"inputDir",
|
|
16367
|
+
"inputFile",
|
|
16368
|
+
"inputFiles",
|
|
16369
|
+
"inputs",
|
|
16370
|
+
"intervalMs",
|
|
16371
|
+
"job",
|
|
16372
|
+
"jobId",
|
|
16373
|
+
"maxIterations",
|
|
16374
|
+
"navigationTimeout",
|
|
16375
|
+
"output",
|
|
16376
|
+
"outputDir",
|
|
16377
|
+
"path",
|
|
16378
|
+
"payloadJson",
|
|
16379
|
+
"pollAttempts",
|
|
16380
|
+
"pollIntervalMs",
|
|
16381
|
+
"port",
|
|
16382
|
+
"profile",
|
|
16383
|
+
"progressEveryMs",
|
|
16384
|
+
"quiet",
|
|
16385
|
+
"readinessPath",
|
|
16386
|
+
"readinessTimeout",
|
|
16387
|
+
"reasonsJson",
|
|
16388
|
+
"requestJson",
|
|
16389
|
+
"requiredJson",
|
|
16390
|
+
"responseJson",
|
|
16391
|
+
"resultFormat",
|
|
16392
|
+
"resultsDir",
|
|
16393
|
+
"riddleEngineModuleUrl",
|
|
16394
|
+
"riddleProofDir",
|
|
16395
|
+
"route",
|
|
16396
|
+
"runDir",
|
|
16397
|
+
"runner",
|
|
16398
|
+
"scriptFile",
|
|
16399
|
+
"sourceKind",
|
|
16400
|
+
"splitViewports",
|
|
16401
|
+
"stateDir",
|
|
16402
|
+
"statePath",
|
|
16403
|
+
"strict",
|
|
16404
|
+
"submitRetries",
|
|
16405
|
+
"submitTimeoutMs",
|
|
16406
|
+
"summary",
|
|
16407
|
+
"sync",
|
|
16408
|
+
"timeout",
|
|
16409
|
+
"url",
|
|
16410
|
+
"unsubmittedJobRetries",
|
|
16411
|
+
"unsubmittedJobTimeoutMs",
|
|
16412
|
+
"unsubmittedRetries",
|
|
16413
|
+
"unsubmittedTimeoutMs",
|
|
16414
|
+
"viewport",
|
|
16415
|
+
"viewportName",
|
|
16416
|
+
"viewportNames",
|
|
16417
|
+
"viewports",
|
|
16418
|
+
"wait",
|
|
16419
|
+
"waitForSelector"
|
|
16420
|
+
]);
|
|
16335
16421
|
function usage() {
|
|
16336
16422
|
return [
|
|
16337
16423
|
"Usage:",
|
|
@@ -16340,9 +16426,9 @@ function usage() {
|
|
|
16340
16426
|
" riddle-proof-loop respond --state-path <path> --response-json <file|json|->",
|
|
16341
16427
|
" riddle-proof-loop respond --state-path <path> --decision <decision> --summary <text> [--payload-json <file|json|->]",
|
|
16342
16428
|
" riddle-proof-loop status --state-path <path>",
|
|
16343
|
-
" riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--runner riddle] [--viewport-name <name[,name...]>] [--strict true|false; default false] [--split-viewports true|false; default false] [--balance-preflight true|false; default true] [--poll-attempts n] [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json] [--quiet]",
|
|
16344
|
-
" riddle-proof-loop run-profile aggregate --profile <file|json|-> --url <base-url> --input-dir <dir>|--inputs <path[,path...]> [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
|
|
16345
|
-
" riddle-proof-loop run-profile recover --profile <file|json|-> --url <base-url> --job <job-id> [--viewport-name <name[,name...]>] [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
|
|
16429
|
+
" riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--base-url <base-url>] [--runner riddle] [--viewport-name <name[,name...]>] [--strict true|false; default false] [--split-viewports true|false; default false] [--balance-preflight true|false; default true] [--poll-attempts n] [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json] [--quiet]",
|
|
16430
|
+
" riddle-proof-loop run-profile aggregate --profile <file|json|-> --url <base-url> [--base-url <base-url>] --input-dir <dir>|--inputs <path[,path...]> [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
|
|
16431
|
+
" riddle-proof-loop run-profile recover --profile <file|json|-> --url <base-url> [--base-url <base-url>] --job <job-id> [--viewport-name <name[,name...]>] [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
|
|
16346
16432
|
" riddle-proof-loop profile-body-assertions --artifact <file|url|-> --candidates-json <file|json|-> [--required-json <file|json|->] [--format json|body-contains]",
|
|
16347
16433
|
" riddle-proof-loop profile-http-status-preflight --profile <file|json|-> --url <base-url> [--format json|summary]",
|
|
16348
16434
|
" riddle-proof-loop riddle-preview-deploy <build-dir> <label> [--framework spa|static]",
|
|
@@ -16382,6 +16468,15 @@ function parseArgs(argv) {
|
|
|
16382
16468
|
}
|
|
16383
16469
|
return { positional, options };
|
|
16384
16470
|
}
|
|
16471
|
+
function optionKeyToFlagName(key) {
|
|
16472
|
+
return key.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
|
|
16473
|
+
}
|
|
16474
|
+
function validateCliOptions(options) {
|
|
16475
|
+
const unknown = Object.keys(options).filter((key) => !KNOWN_CLI_OPTIONS.has(key));
|
|
16476
|
+
if (!unknown.length) return;
|
|
16477
|
+
const flags = unknown.map((key) => `--${optionKeyToFlagName(key)}`).join(", ");
|
|
16478
|
+
throw new Error(`Unknown option${unknown.length === 1 ? "" : "s"}: ${flags}. Run riddle-proof-loop help for usage.`);
|
|
16479
|
+
}
|
|
16385
16480
|
function optionString(options, key) {
|
|
16386
16481
|
const value = options[key];
|
|
16387
16482
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
@@ -16703,7 +16798,7 @@ function parseProfileViewports(value) {
|
|
|
16703
16798
|
function normalizeProfileForCli(options) {
|
|
16704
16799
|
const rawProfile = readJsonValue(optionString(options, "profile"), "--profile");
|
|
16705
16800
|
return normalizeRiddleProofProfile(rawProfile, {
|
|
16706
|
-
url: optionString(options, "url"),
|
|
16801
|
+
url: optionString(options, "url") ?? optionString(options, "baseUrl"),
|
|
16707
16802
|
route: optionString(options, "route"),
|
|
16708
16803
|
viewports: parseProfileViewports(optionString(options, "viewports") || optionString(options, "viewport"))
|
|
16709
16804
|
});
|
|
@@ -17380,6 +17475,137 @@ function profileHasGeneratedOutputReceipt(receipts) {
|
|
|
17380
17475
|
}
|
|
17381
17476
|
return outputReady && outputChanged;
|
|
17382
17477
|
}
|
|
17478
|
+
function profileSemanticReceiptPassed(receipt) {
|
|
17479
|
+
if (receipt.ok === false) return false;
|
|
17480
|
+
return setupReturnSummaryValue(receipt, ["ok", "success", "passed", "completed", "valid"]) === true;
|
|
17481
|
+
}
|
|
17482
|
+
function profileSemanticArrayEvidence(value) {
|
|
17483
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
17484
|
+
const text = cliString(value);
|
|
17485
|
+
return Boolean(text && text.trim());
|
|
17486
|
+
}
|
|
17487
|
+
function profileSemanticTruthyField(receipt, names) {
|
|
17488
|
+
return names.some((name) => setupReturnSummaryValue(receipt, [name]) === true);
|
|
17489
|
+
}
|
|
17490
|
+
function profileHasBoardEvidence(receipt) {
|
|
17491
|
+
return [
|
|
17492
|
+
"board",
|
|
17493
|
+
"beforeBoard",
|
|
17494
|
+
"afterBoard",
|
|
17495
|
+
"cells",
|
|
17496
|
+
"grid",
|
|
17497
|
+
"state"
|
|
17498
|
+
].some((name) => setupReturnSummaryValue(receipt, [name]) !== void 0);
|
|
17499
|
+
}
|
|
17500
|
+
function profileHasTurnEvidence(receipt) {
|
|
17501
|
+
return [
|
|
17502
|
+
"activeX",
|
|
17503
|
+
"activeO",
|
|
17504
|
+
"turn",
|
|
17505
|
+
"currentTurn",
|
|
17506
|
+
"nextTurn",
|
|
17507
|
+
"currentPlayer",
|
|
17508
|
+
"nextPlayer",
|
|
17509
|
+
"isXNext"
|
|
17510
|
+
].some((name) => setupReturnSummaryValue(receipt, [name]) !== void 0);
|
|
17511
|
+
}
|
|
17512
|
+
function profileSemanticInvalidStateReason(receipts, text) {
|
|
17513
|
+
const asksInvalidOrBlocked = text.includes("invalid") || text.includes("blocked") || text.includes("occupied") || text.includes("replay") || text.includes("ignored") || text.includes("reject") || text.includes("same board") || text.includes("unchanged");
|
|
17514
|
+
if (!asksInvalidOrBlocked) return void 0;
|
|
17515
|
+
const asksTurn = text.includes("turn") || text.includes("player");
|
|
17516
|
+
for (const receipt of receipts) {
|
|
17517
|
+
if (!profileSemanticReceiptPassed(receipt)) continue;
|
|
17518
|
+
const unchanged = profileSemanticTruthyField(receipt, [
|
|
17519
|
+
"sameBoard",
|
|
17520
|
+
"same_board",
|
|
17521
|
+
"boardUnchanged",
|
|
17522
|
+
"stateUnchanged",
|
|
17523
|
+
"unchanged",
|
|
17524
|
+
"noMutation",
|
|
17525
|
+
"no_mutation"
|
|
17526
|
+
]);
|
|
17527
|
+
const blocked = profileSemanticTruthyField(receipt, [
|
|
17528
|
+
"blocked",
|
|
17529
|
+
"invalid",
|
|
17530
|
+
"rejected",
|
|
17531
|
+
"ignored",
|
|
17532
|
+
"prevented"
|
|
17533
|
+
]);
|
|
17534
|
+
if (!(unchanged || blocked)) continue;
|
|
17535
|
+
if (!profileHasBoardEvidence(receipt)) continue;
|
|
17536
|
+
if (asksTurn && !profileHasTurnEvidence(receipt)) continue;
|
|
17537
|
+
const parts = [
|
|
17538
|
+
unchanged ? "unchanged=true" : "",
|
|
17539
|
+
blocked ? "blocked=true" : "",
|
|
17540
|
+
profileHasTurnEvidence(receipt) ? "turn evidence present" : ""
|
|
17541
|
+
].filter(Boolean);
|
|
17542
|
+
return `semantic invalid-state receipt present${parts.length ? `: ${parts.join(", ")}` : ""}`;
|
|
17543
|
+
}
|
|
17544
|
+
return void 0;
|
|
17545
|
+
}
|
|
17546
|
+
function profileSemanticTerminalLockReason(receipts, text) {
|
|
17547
|
+
const asksLock = text.includes("lock") || text.includes("cannot mutate") || text.includes("can not mutate") || text.includes("can't mutate") || text.includes("cannot change") || text.includes("unchanged after") || text.includes("post-winner") && text.includes("click") || text.includes("post winner") && text.includes("click");
|
|
17548
|
+
if (!asksLock) return void 0;
|
|
17549
|
+
for (const receipt of receipts) {
|
|
17550
|
+
if (!profileSemanticReceiptPassed(receipt)) continue;
|
|
17551
|
+
const unchanged = profileSemanticTruthyField(receipt, [
|
|
17552
|
+
"sameBoard",
|
|
17553
|
+
"same_board",
|
|
17554
|
+
"boardUnchanged",
|
|
17555
|
+
"stateUnchanged",
|
|
17556
|
+
"unchanged",
|
|
17557
|
+
"noMutation",
|
|
17558
|
+
"no_mutation",
|
|
17559
|
+
"locked"
|
|
17560
|
+
]);
|
|
17561
|
+
if (!unchanged) continue;
|
|
17562
|
+
const hasTerminal = profileSemanticTruthyField(receipt, ["hasWinner", "winner", "won", "gameWon", "terminal", "locked"]) || profileSemanticArrayEvidence(setupReturnSummaryValue(receipt, ["winCells", "winningCells", "winningLine"])) || Boolean(cliString(setupReturnSummaryValue(receipt, ["winCellsCsv", "winnerText", "terminalText", "statusText"])));
|
|
17563
|
+
if (!hasTerminal) continue;
|
|
17564
|
+
return "semantic terminal-lock receipt present: unchanged=true";
|
|
17565
|
+
}
|
|
17566
|
+
return void 0;
|
|
17567
|
+
}
|
|
17568
|
+
function profileSemanticWinnerReason(receipts, text) {
|
|
17569
|
+
const asksWinner = text.includes("winner") || text.includes("win-cell") || text.includes("winning") || /\bwin\b/.test(text);
|
|
17570
|
+
if (!asksWinner) return void 0;
|
|
17571
|
+
const asksCounts = text.includes("count");
|
|
17572
|
+
const asksWinCells = text.includes("win-cell") || text.includes("winning") || text.includes("inventory") || text.includes("top-row");
|
|
17573
|
+
const asksPlayAgain = text.includes("play again") || text.includes("play-again") || text.includes("playagain");
|
|
17574
|
+
for (const receipt of receipts) {
|
|
17575
|
+
if (!profileSemanticReceiptPassed(receipt)) continue;
|
|
17576
|
+
const winnerText = (cliString(setupReturnSummaryValue(receipt, ["winnerText", "terminalText", "statusText"])) || "").toLowerCase();
|
|
17577
|
+
const hasWinner = profileSemanticTruthyField(receipt, ["hasWinner", "winner", "won", "gameWon"]) || winnerText.includes("win") || profileSemanticArrayEvidence(setupReturnSummaryValue(receipt, ["winCells", "winningCells", "winningLine"])) || Boolean(cliString(setupReturnSummaryValue(receipt, ["winCellsCsv"])));
|
|
17578
|
+
if (!hasWinner) continue;
|
|
17579
|
+
const hasCounts = [
|
|
17580
|
+
"xCount",
|
|
17581
|
+
"oCount",
|
|
17582
|
+
"count",
|
|
17583
|
+
"filledCount",
|
|
17584
|
+
"winnerCount",
|
|
17585
|
+
"score"
|
|
17586
|
+
].some((name) => setupReturnSummaryValue(receipt, [name]) !== void 0);
|
|
17587
|
+
const hasWinCells = profileSemanticArrayEvidence(setupReturnSummaryValue(receipt, ["winCells", "winningCells", "winningLine"])) || Boolean(cliString(setupReturnSummaryValue(receipt, ["winCellsCsv"])));
|
|
17588
|
+
const hasPlayAgain = profileSemanticTruthyField(receipt, [
|
|
17589
|
+
"playAgainVisible",
|
|
17590
|
+
"play_again_visible",
|
|
17591
|
+
"restartVisible",
|
|
17592
|
+
"resetVisible"
|
|
17593
|
+
]);
|
|
17594
|
+
if (asksCounts && !hasCounts) continue;
|
|
17595
|
+
if (asksWinCells && !hasWinCells) continue;
|
|
17596
|
+
if (asksPlayAgain && !hasPlayAgain) continue;
|
|
17597
|
+
const parts = [
|
|
17598
|
+
hasCounts ? "counts present" : "",
|
|
17599
|
+
hasWinCells ? "win cells present" : "",
|
|
17600
|
+
hasPlayAgain ? "play-again visible" : ""
|
|
17601
|
+
].filter(Boolean);
|
|
17602
|
+
return `semantic winner receipt present${parts.length ? `: ${parts.join(", ")}` : ""}`;
|
|
17603
|
+
}
|
|
17604
|
+
return void 0;
|
|
17605
|
+
}
|
|
17606
|
+
function profileSemanticStateReceiptReason(receipts, text) {
|
|
17607
|
+
return profileSemanticTerminalLockReason(receipts, text) || profileSemanticInvalidStateReason(receipts, text) || profileSemanticWinnerReason(receipts, text);
|
|
17608
|
+
}
|
|
17383
17609
|
function profilePackReceiptStatus(result, metadata, receipt) {
|
|
17384
17610
|
const text = receipt.toLowerCase();
|
|
17385
17611
|
const setupSummary = profileSetupSummaryRecord(result);
|
|
@@ -17838,6 +18064,10 @@ function profilePackReceiptStatus(result, metadata, receipt) {
|
|
|
17838
18064
|
if (text.includes("measured") || text.includes("state-change") || text.includes("pixel delta") || text.includes("movement receipt") || text.includes("canvas hash")) {
|
|
17839
18065
|
return profileReceiptSignalStatus(hasMeasuredStateChange, "measured-change evidence present", "measured-change evidence missing");
|
|
17840
18066
|
}
|
|
18067
|
+
const semanticStateReason = profileSemanticStateReceiptReason(valueReceipts, text);
|
|
18068
|
+
if (semanticStateReason) {
|
|
18069
|
+
return { status: "present", reason: semanticStateReason };
|
|
18070
|
+
}
|
|
17841
18071
|
return { status: "manual", reason: "semantic receipt requires audit review" };
|
|
17842
18072
|
}
|
|
17843
18073
|
function profilePackMetadataMarkdown(result) {
|
|
@@ -19955,6 +20185,7 @@ async function main() {
|
|
|
19955
20185
|
`);
|
|
19956
20186
|
return;
|
|
19957
20187
|
}
|
|
20188
|
+
validateCliOptions(options);
|
|
19958
20189
|
if (command === "doctor") {
|
|
19959
20190
|
const subject = positional[1];
|
|
19960
20191
|
if (!isLocalAgentMode(subject)) throw new Error("Only `doctor local` is supported.");
|
package/dist/cli.js
CHANGED
|
@@ -41,6 +41,92 @@ import "./chunk-VY4Y5U57.js";
|
|
|
41
41
|
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
|
42
42
|
import path from "path";
|
|
43
43
|
var RIDDLE_PROFILE_BALANCE_PREFLIGHT_MIN_SECONDS_PER_JOB = 30;
|
|
44
|
+
var KNOWN_CLI_OPTIONS = /* @__PURE__ */ new Set([
|
|
45
|
+
"agent",
|
|
46
|
+
"apiBaseUrl",
|
|
47
|
+
"apiKey",
|
|
48
|
+
"apiKeyFile",
|
|
49
|
+
"artifact",
|
|
50
|
+
"attempts",
|
|
51
|
+
"balancePreflight",
|
|
52
|
+
"baseUrl",
|
|
53
|
+
"candidateJson",
|
|
54
|
+
"candidatesJson",
|
|
55
|
+
"checkpointMode",
|
|
56
|
+
"checkpointVisibility",
|
|
57
|
+
"codexCommand",
|
|
58
|
+
"codexFullAuto",
|
|
59
|
+
"codexHome",
|
|
60
|
+
"codexModel",
|
|
61
|
+
"codexSandbox",
|
|
62
|
+
"codexTimeoutMs",
|
|
63
|
+
"command",
|
|
64
|
+
"continueWithStage",
|
|
65
|
+
"createdAt",
|
|
66
|
+
"decision",
|
|
67
|
+
"defaultReviewer",
|
|
68
|
+
"defaultShipMode",
|
|
69
|
+
"exclude",
|
|
70
|
+
"format",
|
|
71
|
+
"framework",
|
|
72
|
+
"help",
|
|
73
|
+
"image",
|
|
74
|
+
"input",
|
|
75
|
+
"inputDir",
|
|
76
|
+
"inputFile",
|
|
77
|
+
"inputFiles",
|
|
78
|
+
"inputs",
|
|
79
|
+
"intervalMs",
|
|
80
|
+
"job",
|
|
81
|
+
"jobId",
|
|
82
|
+
"maxIterations",
|
|
83
|
+
"navigationTimeout",
|
|
84
|
+
"output",
|
|
85
|
+
"outputDir",
|
|
86
|
+
"path",
|
|
87
|
+
"payloadJson",
|
|
88
|
+
"pollAttempts",
|
|
89
|
+
"pollIntervalMs",
|
|
90
|
+
"port",
|
|
91
|
+
"profile",
|
|
92
|
+
"progressEveryMs",
|
|
93
|
+
"quiet",
|
|
94
|
+
"readinessPath",
|
|
95
|
+
"readinessTimeout",
|
|
96
|
+
"reasonsJson",
|
|
97
|
+
"requestJson",
|
|
98
|
+
"requiredJson",
|
|
99
|
+
"responseJson",
|
|
100
|
+
"resultFormat",
|
|
101
|
+
"resultsDir",
|
|
102
|
+
"riddleEngineModuleUrl",
|
|
103
|
+
"riddleProofDir",
|
|
104
|
+
"route",
|
|
105
|
+
"runDir",
|
|
106
|
+
"runner",
|
|
107
|
+
"scriptFile",
|
|
108
|
+
"sourceKind",
|
|
109
|
+
"splitViewports",
|
|
110
|
+
"stateDir",
|
|
111
|
+
"statePath",
|
|
112
|
+
"strict",
|
|
113
|
+
"submitRetries",
|
|
114
|
+
"submitTimeoutMs",
|
|
115
|
+
"summary",
|
|
116
|
+
"sync",
|
|
117
|
+
"timeout",
|
|
118
|
+
"url",
|
|
119
|
+
"unsubmittedJobRetries",
|
|
120
|
+
"unsubmittedJobTimeoutMs",
|
|
121
|
+
"unsubmittedRetries",
|
|
122
|
+
"unsubmittedTimeoutMs",
|
|
123
|
+
"viewport",
|
|
124
|
+
"viewportName",
|
|
125
|
+
"viewportNames",
|
|
126
|
+
"viewports",
|
|
127
|
+
"wait",
|
|
128
|
+
"waitForSelector"
|
|
129
|
+
]);
|
|
44
130
|
function usage() {
|
|
45
131
|
return [
|
|
46
132
|
"Usage:",
|
|
@@ -49,9 +135,9 @@ function usage() {
|
|
|
49
135
|
" riddle-proof-loop respond --state-path <path> --response-json <file|json|->",
|
|
50
136
|
" riddle-proof-loop respond --state-path <path> --decision <decision> --summary <text> [--payload-json <file|json|->]",
|
|
51
137
|
" riddle-proof-loop status --state-path <path>",
|
|
52
|
-
" riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--runner riddle] [--viewport-name <name[,name...]>] [--strict true|false; default false] [--split-viewports true|false; default false] [--balance-preflight true|false; default true] [--poll-attempts n] [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json] [--quiet]",
|
|
53
|
-
" riddle-proof-loop run-profile aggregate --profile <file|json|-> --url <base-url> --input-dir <dir>|--inputs <path[,path...]> [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
|
|
54
|
-
" riddle-proof-loop run-profile recover --profile <file|json|-> --url <base-url> --job <job-id> [--viewport-name <name[,name...]>] [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
|
|
138
|
+
" riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--base-url <base-url>] [--runner riddle] [--viewport-name <name[,name...]>] [--strict true|false; default false] [--split-viewports true|false; default false] [--balance-preflight true|false; default true] [--poll-attempts n] [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json] [--quiet]",
|
|
139
|
+
" riddle-proof-loop run-profile aggregate --profile <file|json|-> --url <base-url> [--base-url <base-url>] --input-dir <dir>|--inputs <path[,path...]> [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
|
|
140
|
+
" riddle-proof-loop run-profile recover --profile <file|json|-> --url <base-url> [--base-url <base-url>] --job <job-id> [--viewport-name <name[,name...]>] [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
|
|
55
141
|
" riddle-proof-loop profile-body-assertions --artifact <file|url|-> --candidates-json <file|json|-> [--required-json <file|json|->] [--format json|body-contains]",
|
|
56
142
|
" riddle-proof-loop profile-http-status-preflight --profile <file|json|-> --url <base-url> [--format json|summary]",
|
|
57
143
|
" riddle-proof-loop riddle-preview-deploy <build-dir> <label> [--framework spa|static]",
|
|
@@ -91,6 +177,15 @@ function parseArgs(argv) {
|
|
|
91
177
|
}
|
|
92
178
|
return { positional, options };
|
|
93
179
|
}
|
|
180
|
+
function optionKeyToFlagName(key) {
|
|
181
|
+
return key.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
|
|
182
|
+
}
|
|
183
|
+
function validateCliOptions(options) {
|
|
184
|
+
const unknown = Object.keys(options).filter((key) => !KNOWN_CLI_OPTIONS.has(key));
|
|
185
|
+
if (!unknown.length) return;
|
|
186
|
+
const flags = unknown.map((key) => `--${optionKeyToFlagName(key)}`).join(", ");
|
|
187
|
+
throw new Error(`Unknown option${unknown.length === 1 ? "" : "s"}: ${flags}. Run riddle-proof-loop help for usage.`);
|
|
188
|
+
}
|
|
94
189
|
function optionString(options, key) {
|
|
95
190
|
const value = options[key];
|
|
96
191
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
@@ -412,7 +507,7 @@ function parseProfileViewports(value) {
|
|
|
412
507
|
function normalizeProfileForCli(options) {
|
|
413
508
|
const rawProfile = readJsonValue(optionString(options, "profile"), "--profile");
|
|
414
509
|
return normalizeRiddleProofProfile(rawProfile, {
|
|
415
|
-
url: optionString(options, "url"),
|
|
510
|
+
url: optionString(options, "url") ?? optionString(options, "baseUrl"),
|
|
416
511
|
route: optionString(options, "route"),
|
|
417
512
|
viewports: parseProfileViewports(optionString(options, "viewports") || optionString(options, "viewport"))
|
|
418
513
|
});
|
|
@@ -1089,6 +1184,137 @@ function profileHasGeneratedOutputReceipt(receipts) {
|
|
|
1089
1184
|
}
|
|
1090
1185
|
return outputReady && outputChanged;
|
|
1091
1186
|
}
|
|
1187
|
+
function profileSemanticReceiptPassed(receipt) {
|
|
1188
|
+
if (receipt.ok === false) return false;
|
|
1189
|
+
return setupReturnSummaryValue(receipt, ["ok", "success", "passed", "completed", "valid"]) === true;
|
|
1190
|
+
}
|
|
1191
|
+
function profileSemanticArrayEvidence(value) {
|
|
1192
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
1193
|
+
const text = cliString(value);
|
|
1194
|
+
return Boolean(text && text.trim());
|
|
1195
|
+
}
|
|
1196
|
+
function profileSemanticTruthyField(receipt, names) {
|
|
1197
|
+
return names.some((name) => setupReturnSummaryValue(receipt, [name]) === true);
|
|
1198
|
+
}
|
|
1199
|
+
function profileHasBoardEvidence(receipt) {
|
|
1200
|
+
return [
|
|
1201
|
+
"board",
|
|
1202
|
+
"beforeBoard",
|
|
1203
|
+
"afterBoard",
|
|
1204
|
+
"cells",
|
|
1205
|
+
"grid",
|
|
1206
|
+
"state"
|
|
1207
|
+
].some((name) => setupReturnSummaryValue(receipt, [name]) !== void 0);
|
|
1208
|
+
}
|
|
1209
|
+
function profileHasTurnEvidence(receipt) {
|
|
1210
|
+
return [
|
|
1211
|
+
"activeX",
|
|
1212
|
+
"activeO",
|
|
1213
|
+
"turn",
|
|
1214
|
+
"currentTurn",
|
|
1215
|
+
"nextTurn",
|
|
1216
|
+
"currentPlayer",
|
|
1217
|
+
"nextPlayer",
|
|
1218
|
+
"isXNext"
|
|
1219
|
+
].some((name) => setupReturnSummaryValue(receipt, [name]) !== void 0);
|
|
1220
|
+
}
|
|
1221
|
+
function profileSemanticInvalidStateReason(receipts, text) {
|
|
1222
|
+
const asksInvalidOrBlocked = text.includes("invalid") || text.includes("blocked") || text.includes("occupied") || text.includes("replay") || text.includes("ignored") || text.includes("reject") || text.includes("same board") || text.includes("unchanged");
|
|
1223
|
+
if (!asksInvalidOrBlocked) return void 0;
|
|
1224
|
+
const asksTurn = text.includes("turn") || text.includes("player");
|
|
1225
|
+
for (const receipt of receipts) {
|
|
1226
|
+
if (!profileSemanticReceiptPassed(receipt)) continue;
|
|
1227
|
+
const unchanged = profileSemanticTruthyField(receipt, [
|
|
1228
|
+
"sameBoard",
|
|
1229
|
+
"same_board",
|
|
1230
|
+
"boardUnchanged",
|
|
1231
|
+
"stateUnchanged",
|
|
1232
|
+
"unchanged",
|
|
1233
|
+
"noMutation",
|
|
1234
|
+
"no_mutation"
|
|
1235
|
+
]);
|
|
1236
|
+
const blocked = profileSemanticTruthyField(receipt, [
|
|
1237
|
+
"blocked",
|
|
1238
|
+
"invalid",
|
|
1239
|
+
"rejected",
|
|
1240
|
+
"ignored",
|
|
1241
|
+
"prevented"
|
|
1242
|
+
]);
|
|
1243
|
+
if (!(unchanged || blocked)) continue;
|
|
1244
|
+
if (!profileHasBoardEvidence(receipt)) continue;
|
|
1245
|
+
if (asksTurn && !profileHasTurnEvidence(receipt)) continue;
|
|
1246
|
+
const parts = [
|
|
1247
|
+
unchanged ? "unchanged=true" : "",
|
|
1248
|
+
blocked ? "blocked=true" : "",
|
|
1249
|
+
profileHasTurnEvidence(receipt) ? "turn evidence present" : ""
|
|
1250
|
+
].filter(Boolean);
|
|
1251
|
+
return `semantic invalid-state receipt present${parts.length ? `: ${parts.join(", ")}` : ""}`;
|
|
1252
|
+
}
|
|
1253
|
+
return void 0;
|
|
1254
|
+
}
|
|
1255
|
+
function profileSemanticTerminalLockReason(receipts, text) {
|
|
1256
|
+
const asksLock = text.includes("lock") || text.includes("cannot mutate") || text.includes("can not mutate") || text.includes("can't mutate") || text.includes("cannot change") || text.includes("unchanged after") || text.includes("post-winner") && text.includes("click") || text.includes("post winner") && text.includes("click");
|
|
1257
|
+
if (!asksLock) return void 0;
|
|
1258
|
+
for (const receipt of receipts) {
|
|
1259
|
+
if (!profileSemanticReceiptPassed(receipt)) continue;
|
|
1260
|
+
const unchanged = profileSemanticTruthyField(receipt, [
|
|
1261
|
+
"sameBoard",
|
|
1262
|
+
"same_board",
|
|
1263
|
+
"boardUnchanged",
|
|
1264
|
+
"stateUnchanged",
|
|
1265
|
+
"unchanged",
|
|
1266
|
+
"noMutation",
|
|
1267
|
+
"no_mutation",
|
|
1268
|
+
"locked"
|
|
1269
|
+
]);
|
|
1270
|
+
if (!unchanged) continue;
|
|
1271
|
+
const hasTerminal = profileSemanticTruthyField(receipt, ["hasWinner", "winner", "won", "gameWon", "terminal", "locked"]) || profileSemanticArrayEvidence(setupReturnSummaryValue(receipt, ["winCells", "winningCells", "winningLine"])) || Boolean(cliString(setupReturnSummaryValue(receipt, ["winCellsCsv", "winnerText", "terminalText", "statusText"])));
|
|
1272
|
+
if (!hasTerminal) continue;
|
|
1273
|
+
return "semantic terminal-lock receipt present: unchanged=true";
|
|
1274
|
+
}
|
|
1275
|
+
return void 0;
|
|
1276
|
+
}
|
|
1277
|
+
function profileSemanticWinnerReason(receipts, text) {
|
|
1278
|
+
const asksWinner = text.includes("winner") || text.includes("win-cell") || text.includes("winning") || /\bwin\b/.test(text);
|
|
1279
|
+
if (!asksWinner) return void 0;
|
|
1280
|
+
const asksCounts = text.includes("count");
|
|
1281
|
+
const asksWinCells = text.includes("win-cell") || text.includes("winning") || text.includes("inventory") || text.includes("top-row");
|
|
1282
|
+
const asksPlayAgain = text.includes("play again") || text.includes("play-again") || text.includes("playagain");
|
|
1283
|
+
for (const receipt of receipts) {
|
|
1284
|
+
if (!profileSemanticReceiptPassed(receipt)) continue;
|
|
1285
|
+
const winnerText = (cliString(setupReturnSummaryValue(receipt, ["winnerText", "terminalText", "statusText"])) || "").toLowerCase();
|
|
1286
|
+
const hasWinner = profileSemanticTruthyField(receipt, ["hasWinner", "winner", "won", "gameWon"]) || winnerText.includes("win") || profileSemanticArrayEvidence(setupReturnSummaryValue(receipt, ["winCells", "winningCells", "winningLine"])) || Boolean(cliString(setupReturnSummaryValue(receipt, ["winCellsCsv"])));
|
|
1287
|
+
if (!hasWinner) continue;
|
|
1288
|
+
const hasCounts = [
|
|
1289
|
+
"xCount",
|
|
1290
|
+
"oCount",
|
|
1291
|
+
"count",
|
|
1292
|
+
"filledCount",
|
|
1293
|
+
"winnerCount",
|
|
1294
|
+
"score"
|
|
1295
|
+
].some((name) => setupReturnSummaryValue(receipt, [name]) !== void 0);
|
|
1296
|
+
const hasWinCells = profileSemanticArrayEvidence(setupReturnSummaryValue(receipt, ["winCells", "winningCells", "winningLine"])) || Boolean(cliString(setupReturnSummaryValue(receipt, ["winCellsCsv"])));
|
|
1297
|
+
const hasPlayAgain = profileSemanticTruthyField(receipt, [
|
|
1298
|
+
"playAgainVisible",
|
|
1299
|
+
"play_again_visible",
|
|
1300
|
+
"restartVisible",
|
|
1301
|
+
"resetVisible"
|
|
1302
|
+
]);
|
|
1303
|
+
if (asksCounts && !hasCounts) continue;
|
|
1304
|
+
if (asksWinCells && !hasWinCells) continue;
|
|
1305
|
+
if (asksPlayAgain && !hasPlayAgain) continue;
|
|
1306
|
+
const parts = [
|
|
1307
|
+
hasCounts ? "counts present" : "",
|
|
1308
|
+
hasWinCells ? "win cells present" : "",
|
|
1309
|
+
hasPlayAgain ? "play-again visible" : ""
|
|
1310
|
+
].filter(Boolean);
|
|
1311
|
+
return `semantic winner receipt present${parts.length ? `: ${parts.join(", ")}` : ""}`;
|
|
1312
|
+
}
|
|
1313
|
+
return void 0;
|
|
1314
|
+
}
|
|
1315
|
+
function profileSemanticStateReceiptReason(receipts, text) {
|
|
1316
|
+
return profileSemanticTerminalLockReason(receipts, text) || profileSemanticInvalidStateReason(receipts, text) || profileSemanticWinnerReason(receipts, text);
|
|
1317
|
+
}
|
|
1092
1318
|
function profilePackReceiptStatus(result, metadata, receipt) {
|
|
1093
1319
|
const text = receipt.toLowerCase();
|
|
1094
1320
|
const setupSummary = profileSetupSummaryRecord(result);
|
|
@@ -1547,6 +1773,10 @@ function profilePackReceiptStatus(result, metadata, receipt) {
|
|
|
1547
1773
|
if (text.includes("measured") || text.includes("state-change") || text.includes("pixel delta") || text.includes("movement receipt") || text.includes("canvas hash")) {
|
|
1548
1774
|
return profileReceiptSignalStatus(hasMeasuredStateChange, "measured-change evidence present", "measured-change evidence missing");
|
|
1549
1775
|
}
|
|
1776
|
+
const semanticStateReason = profileSemanticStateReceiptReason(valueReceipts, text);
|
|
1777
|
+
if (semanticStateReason) {
|
|
1778
|
+
return { status: "present", reason: semanticStateReason };
|
|
1779
|
+
}
|
|
1550
1780
|
return { status: "manual", reason: "semantic receipt requires audit review" };
|
|
1551
1781
|
}
|
|
1552
1782
|
function profilePackMetadataMarkdown(result) {
|
|
@@ -3664,6 +3894,7 @@ async function main() {
|
|
|
3664
3894
|
`);
|
|
3665
3895
|
return;
|
|
3666
3896
|
}
|
|
3897
|
+
validateCliOptions(options);
|
|
3667
3898
|
if (command === "doctor") {
|
|
3668
3899
|
const subject = positional[1];
|
|
3669
3900
|
if (!isLocalAgentMode(subject)) throw new Error("Only `doctor local` is supported.");
|