@cassiomc1/forgeloop 0.1.14 → 0.1.16
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/.forgeloop/forgeloop.gitignore +1 -0
- package/DOCS_INDEX.md +60 -0
- package/EXECUTION_STATE.md +9 -0
- package/LOOP_ENGINEERING.md +44 -6
- package/LOOP_SYSTEM_DESIGN.md +8 -0
- package/PROTOCOL_INTEGRATION.md +41 -0
- package/QUALITY_SCORECARD.md +2 -0
- package/README.md +183 -643
- package/TERMINOLOGY.md +4 -0
- package/THREAT_MODEL.md +14 -0
- package/docs/assets/forgeloop-flow.svg +1 -0
- package/docs/forgeloop-flow.mmd +51 -0
- package/package.json +16 -3
- package/schemas/check.schema.json +2 -0
- package/schemas/continuity.schema.json +57 -0
- package/schemas/execution.schema.json +63 -0
- package/scripts/CI_VALIDATORS.md +32 -0
- package/src/cli.js +351 -196
- package/src/commands/clear-continuity.js +9 -0
- package/src/commands/continuity.js +25 -0
- package/src/commands/doctor.js +17 -2
- package/src/commands/reconcile-continuity.js +23 -0
- package/src/commands/record-continuity.js +63 -0
- package/src/commands/run-check.js +83 -0
- package/src/commands/status.js +14 -1
- package/src/commands/update.js +12 -13
- package/src/commands/validate-protocol.js +37 -0
- package/src/core/artifacts.js +9 -0
- package/src/core/bundles.js +78 -0
- package/src/core/checks.js +16 -0
- package/src/core/command-resolution.js +295 -0
- package/src/core/command-tokenizer.js +122 -0
- package/src/core/completion-artifacts.js +229 -47
- package/src/core/completion.js +19 -1
- package/src/core/conformance.js +8 -2
- package/src/core/continuity-cli-options.js +58 -0
- package/src/core/continuity-conformance.js +46 -0
- package/src/core/continuity-observability.js +20 -0
- package/src/core/continuity-reconciliation.js +224 -0
- package/src/core/continuity.js +245 -0
- package/src/core/evidence-readiness.js +26 -1
- package/src/core/execution.js +185 -0
- package/src/core/inspect.js +9 -1
- package/src/core/installation-authority.js +178 -0
- package/src/core/json-safety.js +17 -13
- package/src/core/next-action-artifacts.js +118 -0
- package/src/core/next-action-continuity.js +65 -0
- package/src/core/next-action-model.js +127 -0
- package/src/core/next-action-phases.js +12 -0
- package/src/core/next-action.js +22 -249
- package/src/core/npm-classifier.js +343 -0
- package/src/core/package-manager-classifiers.js +37 -0
- package/src/core/preflight-consistency.js +221 -0
- package/src/core/preflight-loaders.js +112 -0
- package/src/core/preflight-model.js +83 -0
- package/src/core/preflight.js +34 -444
- package/src/core/protocol.js +7 -0
- package/src/core/schema-validation.js +16 -1
- package/src/core/templates.js +3 -0
- package/src/core/verification-capability.js +31 -495
- package/src/core/verification-constants.js +61 -0
package/src/cli.js
CHANGED
|
@@ -24,14 +24,54 @@ import { formatPolicyResult, runPolicy } from "./commands/policy.js";
|
|
|
24
24
|
import { formatBundleResult, runBundle } from "./commands/bundle.js";
|
|
25
25
|
import { formatPrepareCompletionResult, runPrepareCompletion } from "./commands/prepare-completion.js";
|
|
26
26
|
import { formatRecordCheckResult, runRecordCheck } from "./commands/record-check.js";
|
|
27
|
+
import { formatRunCheckResult, runCheck } from "./commands/run-check.js";
|
|
27
28
|
import { formatRecordTerminalResult, runRecordTerminalResult } from "./commands/record-terminal-result.js";
|
|
28
29
|
import { formatNextActionResult, runNext } from "./commands/next.js";
|
|
30
|
+
import { formatContinuityResult, runContinuity } from "./commands/continuity.js";
|
|
31
|
+
import { formatRecordContinuityResult, runRecordContinuity } from "./commands/record-continuity.js";
|
|
32
|
+
import { formatReconcileContinuityResult, runReconcileContinuity } from "./commands/reconcile-continuity.js";
|
|
33
|
+
import { formatClearContinuityResult, runClearContinuity } from "./commands/clear-continuity.js";
|
|
34
|
+
import { continuityOptionDefaults, consumeContinuityOption, validateContinuityOptions } from "./core/continuity-cli-options.js";
|
|
29
35
|
import { resolveTarget } from "./core/filesystem.js";
|
|
30
36
|
import { getPackageRoot } from "./core/templates.js";
|
|
31
37
|
import { ARTIFACT_PATHS } from "./core/artifacts.js";
|
|
32
38
|
|
|
39
|
+
export const COMMANDS = Object.freeze([
|
|
40
|
+
"init",
|
|
41
|
+
"doctor",
|
|
42
|
+
"update",
|
|
43
|
+
"activate",
|
|
44
|
+
"route",
|
|
45
|
+
"preflight",
|
|
46
|
+
"advance",
|
|
47
|
+
"next",
|
|
48
|
+
"continuity",
|
|
49
|
+
"record-continuity",
|
|
50
|
+
"reconcile-continuity",
|
|
51
|
+
"clear-continuity",
|
|
52
|
+
"prepare-completion",
|
|
53
|
+
"run-check",
|
|
54
|
+
"record-check",
|
|
55
|
+
"record-terminal-result",
|
|
56
|
+
"complete",
|
|
57
|
+
"audit",
|
|
58
|
+
"report",
|
|
59
|
+
"policy",
|
|
60
|
+
"bundle",
|
|
61
|
+
"inspect",
|
|
62
|
+
"status",
|
|
63
|
+
"validate-state",
|
|
64
|
+
"clear-state",
|
|
65
|
+
"validate-receipt",
|
|
66
|
+
"validate-protocol",
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
// Commands whose usage blocks already describe --json (doctor, route) or that
|
|
70
|
+
// accept no --json at all (init, update).
|
|
71
|
+
const GENERIC_JSON_EXCLUDED_COMMANDS = new Set(["init", "doctor", "update", "route"]);
|
|
72
|
+
|
|
33
73
|
function usage(command = null) {
|
|
34
|
-
const commands = "
|
|
74
|
+
const commands = COMMANDS.join("|");
|
|
35
75
|
const options = [" --path <directory> target project directory (default: current directory)"];
|
|
36
76
|
if (!command || command === "init" || command === "update") {
|
|
37
77
|
options.push(" --dry-run show planned writes without changing files");
|
|
@@ -39,6 +79,7 @@ function usage(command = null) {
|
|
|
39
79
|
if (!command || command === "doctor") {
|
|
40
80
|
options.push(" --json emit doctor findings as JSON");
|
|
41
81
|
options.push(" --strict treat warnings as unhealthy");
|
|
82
|
+
options.push(" --fix restore missing managed template files");
|
|
42
83
|
options.push(" --adopt <path> preserve an existing adapter in the manifest");
|
|
43
84
|
}
|
|
44
85
|
if (!command || command === "route") {
|
|
@@ -53,7 +94,16 @@ function usage(command = null) {
|
|
|
53
94
|
if (!command || command === "advance") {
|
|
54
95
|
options.push(" --to <phase> destination workflow phase");
|
|
55
96
|
}
|
|
56
|
-
if (!command ||
|
|
97
|
+
if (!command || command === "record-continuity") {
|
|
98
|
+
options.push(" --focus-id <id> current implementation focus ID");
|
|
99
|
+
options.push(" --focus-summary <text> current implementation focus summary");
|
|
100
|
+
options.push(" --remaining <id:summary> remaining implementation item (repeatable)");
|
|
101
|
+
options.push(" --known-issue <id:summary> known implementation issue (repeatable)");
|
|
102
|
+
options.push(" --changed-area <path> changed project area (repeatable)");
|
|
103
|
+
options.push(" --inspect-first <path> suggested inspection path (repeatable)");
|
|
104
|
+
options.push(" --resume-note <text> bounded operational resume note");
|
|
105
|
+
}
|
|
106
|
+
if (!command || !GENERIC_JSON_EXCLUDED_COMMANDS.has(command)) {
|
|
57
107
|
options.push(" --json emit structured output as JSON");
|
|
58
108
|
}
|
|
59
109
|
if (!command || ["preflight", "complete", "audit", "report"].includes(command)) {
|
|
@@ -72,22 +122,30 @@ function usage(command = null) {
|
|
|
72
122
|
options.push(" --route-file <path> routing-result JSON relative to target");
|
|
73
123
|
options.push(" --state-file <path> work-state JSON relative to target");
|
|
74
124
|
options.push(" --receipt-file <path> execution-receipt JSON relative to target");
|
|
125
|
+
options.push(" --continuity-file <path> optional execution-continuity JSON relative to target");
|
|
75
126
|
options.push(" --task-brief-file <path> task brief JSON (repeatable)");
|
|
76
127
|
options.push(" --delegated-result-file <path> delegated result JSON (repeatable)");
|
|
77
128
|
}
|
|
78
129
|
if (!command || command === "validate-receipt") {
|
|
79
130
|
options.push(" --file <path> receipt file relative to target");
|
|
80
131
|
}
|
|
81
|
-
if (!command || command === "record-check") {
|
|
132
|
+
if (!command || command === "record-check" || command === "run-check") {
|
|
82
133
|
options.push(" --id <id> stable check identifier");
|
|
83
|
-
options.push(" --kind <kind> check kind (default: command)");
|
|
84
134
|
options.push(" --requirement <id> completion requirement covered by the check");
|
|
135
|
+
options.push(" --details <json> additional structured check details");
|
|
136
|
+
}
|
|
137
|
+
if (!command || command === "record-check") {
|
|
138
|
+
options.push(" --kind <kind> check kind (default: command; use manual-review for manual evidence)");
|
|
85
139
|
options.push(" --status <status> passed, failed, blocked, or not-run");
|
|
86
140
|
options.push(" --evidence-kind <kind> OBSERVED, INFERRED, NOT_VERIFIED, or BLOCKED");
|
|
87
|
-
options.push(" --command <text>
|
|
88
|
-
options.push(" --result <text> observed result supplied by the
|
|
141
|
+
options.push(" --command <text> recorded only as metadata; it is never executed");
|
|
142
|
+
options.push(" --result <text> observed result supplied by the actor");
|
|
89
143
|
options.push(" --exit-code <number> observed process exit code");
|
|
90
|
-
options.push(" --
|
|
144
|
+
options.push(" --execution-ref <id> ForgeLoop execution artifact reference");
|
|
145
|
+
options.push(" --provenance <value> FORGELOOP_EXECUTED, ACTOR_REPORTED, or MANUAL_OBSERVATION");
|
|
146
|
+
}
|
|
147
|
+
if (!command || command === "run-check") {
|
|
148
|
+
options.push(" -- <argv> exact command argv to classify, execute, and attest");
|
|
91
149
|
}
|
|
92
150
|
if (!command || command === "record-terminal-result") {
|
|
93
151
|
options.push(" --requirement <id> terminal requirement covered by the result");
|
|
@@ -109,6 +167,7 @@ export function parseArgs(argv) {
|
|
|
109
167
|
dryRun: false,
|
|
110
168
|
json: false,
|
|
111
169
|
strict: false,
|
|
170
|
+
fix: false,
|
|
112
171
|
adopt: [],
|
|
113
172
|
work: null,
|
|
114
173
|
surfaces: [],
|
|
@@ -122,6 +181,8 @@ export function parseArgs(argv) {
|
|
|
122
181
|
routeFile: null,
|
|
123
182
|
stateFile: null,
|
|
124
183
|
receiptFile: null,
|
|
184
|
+
continuityFile: null,
|
|
185
|
+
...continuityOptionDefaults(),
|
|
125
186
|
taskBriefFiles: [],
|
|
126
187
|
delegatedResultFiles: [],
|
|
127
188
|
checkId: null,
|
|
@@ -133,6 +194,9 @@ export function parseArgs(argv) {
|
|
|
133
194
|
checkResult: null,
|
|
134
195
|
checkExitCode: null,
|
|
135
196
|
checkDetails: null,
|
|
197
|
+
checkExecutionRef: null,
|
|
198
|
+
checkProvenance: null,
|
|
199
|
+
commandArgv: [],
|
|
136
200
|
checkType: null,
|
|
137
201
|
checkSource: null,
|
|
138
202
|
policy: null,
|
|
@@ -144,7 +208,7 @@ export function parseArgs(argv) {
|
|
|
144
208
|
|
|
145
209
|
for (let index = 0; index < argv.length; index += 1) {
|
|
146
210
|
const argument = argv[index];
|
|
147
|
-
if (
|
|
211
|
+
if (COMMANDS.includes(argument)) {
|
|
148
212
|
if (command) throw new Error(`Multiple commands are not supported: ${argument}`);
|
|
149
213
|
command = argument;
|
|
150
214
|
} else if (argument === "--help" || argument === "-h") {
|
|
@@ -155,6 +219,8 @@ export function parseArgs(argv) {
|
|
|
155
219
|
options.json = true;
|
|
156
220
|
} else if (argument === "--strict") {
|
|
157
221
|
options.strict = true;
|
|
222
|
+
} else if (argument === "--fix") {
|
|
223
|
+
options.fix = true;
|
|
158
224
|
} else if (argument === "--adopt") {
|
|
159
225
|
const relativePath = argv[index + 1];
|
|
160
226
|
if (!relativePath || relativePath.startsWith("-")) throw new Error("--adopt requires a path");
|
|
@@ -204,12 +270,13 @@ export function parseArgs(argv) {
|
|
|
204
270
|
if (!contractFile || contractFile.startsWith("-")) throw new Error("--contract-file requires a path");
|
|
205
271
|
options.contractFile = contractFile;
|
|
206
272
|
index += 1;
|
|
207
|
-
} else if (["--route-file", "--state-file", "--receipt-file"].includes(argument)) {
|
|
273
|
+
} else if (["--route-file", "--state-file", "--receipt-file", "--continuity-file"].includes(argument)) {
|
|
208
274
|
const file = argv[index + 1];
|
|
209
275
|
if (!file || file.startsWith("-")) throw new Error(`${argument} requires a path`);
|
|
210
276
|
if (argument === "--route-file") options.routeFile = file;
|
|
211
277
|
if (argument === "--state-file") options.stateFile = file;
|
|
212
278
|
if (argument === "--receipt-file") options.receiptFile = file;
|
|
279
|
+
if (argument === "--continuity-file") options.continuityFile = file;
|
|
213
280
|
index += 1;
|
|
214
281
|
} else if (argument === "--task-brief-file") {
|
|
215
282
|
const file = argv[index + 1];
|
|
@@ -304,6 +371,30 @@ export function parseArgs(argv) {
|
|
|
304
371
|
throw new Error("--details must be a JSON object");
|
|
305
372
|
}
|
|
306
373
|
index += 1;
|
|
374
|
+
} else if (argument === "--execution-ref") {
|
|
375
|
+
const executionRef = argv[index + 1];
|
|
376
|
+
if (!executionRef || executionRef.startsWith("-")) throw new Error("--execution-ref requires an execution ID");
|
|
377
|
+
options.checkExecutionRef = executionRef;
|
|
378
|
+
index += 1;
|
|
379
|
+
} else if (argument === "--provenance") {
|
|
380
|
+
const provenance = argv[index + 1];
|
|
381
|
+
if (!provenance || provenance.startsWith("-")) throw new Error("--provenance requires a provenance value");
|
|
382
|
+
options.checkProvenance = provenance;
|
|
383
|
+
index += 1;
|
|
384
|
+
} else if (argument === "--" && command === "run-check") {
|
|
385
|
+
options.commandArgv = argv.slice(index + 1);
|
|
386
|
+
break;
|
|
387
|
+
} else if ([
|
|
388
|
+
"--focus-id",
|
|
389
|
+
"--focus-summary",
|
|
390
|
+
"--remaining",
|
|
391
|
+
"--known-issue",
|
|
392
|
+
"--changed-area",
|
|
393
|
+
"--inspect-first",
|
|
394
|
+
"--resume-note",
|
|
395
|
+
].includes(argument)) {
|
|
396
|
+
const consumed = consumeContinuityOption({ argument, argv, index, options });
|
|
397
|
+
index = consumed.index;
|
|
307
398
|
} else if (argument === "--path") {
|
|
308
399
|
options.path = argv[index + 1];
|
|
309
400
|
if (!options.path || options.path.startsWith("-")) throw new Error("--path requires a directory");
|
|
@@ -324,7 +415,7 @@ export function parseArgs(argv) {
|
|
|
324
415
|
|
|
325
416
|
if (!command) return { command: null, options };
|
|
326
417
|
|
|
327
|
-
const jsonCommands = ["doctor", "route", "activate", "advance", "next", "prepare-completion", "record-check", "record-terminal-result", "preflight", "complete", "audit", "report", "policy", "bundle", "inspect", "status", "validate-state", "clear-state", "validate-receipt", "validate-protocol"];
|
|
418
|
+
const jsonCommands = ["doctor", "route", "activate", "advance", "next", "continuity", "record-continuity", "reconcile-continuity", "clear-continuity", "prepare-completion", "run-check", "record-check", "record-terminal-result", "preflight", "complete", "audit", "report", "policy", "bundle", "inspect", "status", "validate-state", "clear-state", "validate-receipt", "validate-protocol"];
|
|
328
419
|
if (!jsonCommands.includes(command) && options.json) {
|
|
329
420
|
throw new Error(`Option --json is not valid for ${command}`);
|
|
330
421
|
}
|
|
@@ -340,6 +431,9 @@ export function parseArgs(argv) {
|
|
|
340
431
|
if (command !== "doctor" && options.adopt.length > 0) {
|
|
341
432
|
throw new Error(`Option --adopt is not valid for ${command}`);
|
|
342
433
|
}
|
|
434
|
+
if (command !== "doctor" && options.fix) {
|
|
435
|
+
throw new Error(`Option --fix is not valid for ${command}`);
|
|
436
|
+
}
|
|
343
437
|
if (command !== "route" && (options.work || options.surfaces.length || options.risks.length || options.platforms.length || options.behaviorChange || options.executableChange)) {
|
|
344
438
|
throw new Error(`Route options are not valid for ${command}`);
|
|
345
439
|
}
|
|
@@ -364,7 +458,7 @@ export function parseArgs(argv) {
|
|
|
364
458
|
if (!["status", "inspect", "validate-protocol"].includes(command) && options.contractFile) {
|
|
365
459
|
throw new Error(`Option --contract-file is not valid for ${command}`);
|
|
366
460
|
}
|
|
367
|
-
if (command !== "validate-protocol" && (options.routeFile || options.stateFile || options.receiptFile || options.taskBriefFiles.length > 0 || options.delegatedResultFiles.length > 0)) {
|
|
461
|
+
if (command !== "validate-protocol" && (options.routeFile || options.stateFile || options.receiptFile || options.continuityFile || options.taskBriefFiles.length > 0 || options.delegatedResultFiles.length > 0)) {
|
|
368
462
|
throw new Error(`Protocol artifact options are not valid for ${command}`);
|
|
369
463
|
}
|
|
370
464
|
const checkOptions = [
|
|
@@ -377,10 +471,13 @@ export function parseArgs(argv) {
|
|
|
377
471
|
options.checkResult,
|
|
378
472
|
options.checkExitCode,
|
|
379
473
|
options.checkDetails,
|
|
474
|
+
options.checkExecutionRef,
|
|
475
|
+
options.checkProvenance,
|
|
380
476
|
];
|
|
381
|
-
if (
|
|
477
|
+
if (!["record-check", "run-check"].includes(command) && checkOptions.some((value) => value !== null)) {
|
|
382
478
|
throw new Error(`Check recording options are not valid for ${command}`);
|
|
383
479
|
}
|
|
480
|
+
validateContinuityOptions(command, options);
|
|
384
481
|
if (command === "record-check" && !options.help) {
|
|
385
482
|
if (!options.checkId) throw new Error("record-check requires --id");
|
|
386
483
|
if (!options.checkRequirement) throw new Error("record-check requires --requirement");
|
|
@@ -388,6 +485,17 @@ export function parseArgs(argv) {
|
|
|
388
485
|
if (!options.checkEvidenceKind) throw new Error("record-check requires --evidence-kind");
|
|
389
486
|
if (!options.checkCommand && !options.checkResult) throw new Error("record-check requires --command or --result");
|
|
390
487
|
}
|
|
488
|
+
if (command === "run-check" && !options.help) {
|
|
489
|
+
if (!options.checkId) throw new Error("run-check requires --id");
|
|
490
|
+
if (!options.checkRequirement) throw new Error("run-check requires --requirement");
|
|
491
|
+
if (options.checkKind || options.checkStatus || options.checkEvidenceKind || options.checkCommand
|
|
492
|
+
|| options.checkResult || options.checkExitCode !== null || options.checkExecutionRef || options.checkProvenance) {
|
|
493
|
+
throw new Error("run-check accepts only --id, --requirement, --details, and -- <argv>");
|
|
494
|
+
}
|
|
495
|
+
if (!Array.isArray(options.commandArgv) || options.commandArgv.length === 0) {
|
|
496
|
+
throw new Error("run-check requires -- followed by an exact command argv");
|
|
497
|
+
}
|
|
498
|
+
}
|
|
391
499
|
return { command, options };
|
|
392
500
|
}
|
|
393
501
|
|
|
@@ -405,6 +513,227 @@ function printActions(actions) {
|
|
|
405
513
|
}
|
|
406
514
|
}
|
|
407
515
|
|
|
516
|
+
export const COMMAND_HANDLERS = Object.freeze({
|
|
517
|
+
init: async ({ target, packageRoot, packageVersion, options }) => {
|
|
518
|
+
const result = await runInit({ target, dryRun: options.dryRun, packageRoot, packageVersion });
|
|
519
|
+
printActions(result.actions);
|
|
520
|
+
return 0;
|
|
521
|
+
},
|
|
522
|
+
doctor: async ({ target, packageRoot, options }) => {
|
|
523
|
+
const result = await runDoctor({
|
|
524
|
+
target,
|
|
525
|
+
packageRoot,
|
|
526
|
+
adoptPaths: options.adopt,
|
|
527
|
+
strict: options.strict,
|
|
528
|
+
fix: options.fix,
|
|
529
|
+
});
|
|
530
|
+
if (options.json) {
|
|
531
|
+
console.log(JSON.stringify(result, null, 2));
|
|
532
|
+
} else {
|
|
533
|
+
for (const item of result.findings) {
|
|
534
|
+
console.log(`${item.severity}: ${item.code}: ${item.path} - ${item.message}`);
|
|
535
|
+
}
|
|
536
|
+
console.log(result.ok ? "healthy: ForgeLoop target is ready" : "unhealthy: ForgeLoop target needs attention");
|
|
537
|
+
}
|
|
538
|
+
return result.ok ? 0 : 1;
|
|
539
|
+
},
|
|
540
|
+
route: async ({ target, packageRoot, options }) => {
|
|
541
|
+
const result = await runRoute({
|
|
542
|
+
target,
|
|
543
|
+
packageRoot,
|
|
544
|
+
workType: options.work,
|
|
545
|
+
surfaces: options.surfaces,
|
|
546
|
+
risks: options.risks,
|
|
547
|
+
platforms: options.platforms,
|
|
548
|
+
behaviorChange: options.behaviorChange,
|
|
549
|
+
executableChange: options.executableChange,
|
|
550
|
+
});
|
|
551
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatRouteResult(result));
|
|
552
|
+
return 0;
|
|
553
|
+
},
|
|
554
|
+
activate: async ({ target, packageRoot, options }) => {
|
|
555
|
+
const result = await runActivate({ target, packageRoot });
|
|
556
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatActivateResult(result));
|
|
557
|
+
return 0;
|
|
558
|
+
},
|
|
559
|
+
preflight: async ({ target, packageRoot, options }) => {
|
|
560
|
+
const result = await runPreflight({ target, packageRoot, strict: options.strict });
|
|
561
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatPreflightResult(result));
|
|
562
|
+
return result.status === "READY" ? 0 : 1;
|
|
563
|
+
},
|
|
564
|
+
advance: async ({ target, packageRoot, options }) => {
|
|
565
|
+
const result = await runAdvance({ target, packageRoot, to: options.to });
|
|
566
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatAdvanceResult(result));
|
|
567
|
+
return 0;
|
|
568
|
+
},
|
|
569
|
+
next: async ({ target, packageRoot, options }) => {
|
|
570
|
+
const result = await runNext({ target, packageRoot });
|
|
571
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatNextActionResult(result));
|
|
572
|
+
return 0;
|
|
573
|
+
},
|
|
574
|
+
continuity: async ({ target, packageRoot, options }) => {
|
|
575
|
+
const result = await runContinuity({ target, packageRoot });
|
|
576
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatContinuityResult(result));
|
|
577
|
+
return 0;
|
|
578
|
+
},
|
|
579
|
+
"record-continuity": async ({ target, packageRoot, options }) => {
|
|
580
|
+
const result = await runRecordContinuity({
|
|
581
|
+
target, packageRoot,
|
|
582
|
+
focusId: options.continuityFocusId,
|
|
583
|
+
focusSummary: options.continuityFocusSummary,
|
|
584
|
+
remaining: options.continuityRemaining,
|
|
585
|
+
knownIssues: options.continuityKnownIssues,
|
|
586
|
+
changedAreas: options.continuityChangedAreas,
|
|
587
|
+
inspectFirst: options.continuityInspectFirst,
|
|
588
|
+
resumeNote: options.continuityResumeNote,
|
|
589
|
+
});
|
|
590
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatRecordContinuityResult(result));
|
|
591
|
+
return 0;
|
|
592
|
+
},
|
|
593
|
+
"reconcile-continuity": async ({ target, packageRoot, options }) => {
|
|
594
|
+
const result = await runReconcileContinuity({ target, packageRoot });
|
|
595
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatReconcileContinuityResult(result));
|
|
596
|
+
return 0;
|
|
597
|
+
},
|
|
598
|
+
"clear-continuity": async ({ target, options }) => {
|
|
599
|
+
const result = await runClearContinuity({ target });
|
|
600
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatClearContinuityResult(result));
|
|
601
|
+
return 0;
|
|
602
|
+
},
|
|
603
|
+
"prepare-completion": async ({ target, packageRoot, options }) => {
|
|
604
|
+
const result = await runPrepareCompletion({ target, packageRoot });
|
|
605
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatPrepareCompletionResult(result));
|
|
606
|
+
return 0;
|
|
607
|
+
},
|
|
608
|
+
"run-check": async ({ target, packageRoot, options }) => {
|
|
609
|
+
const result = await runCheck({
|
|
610
|
+
target,
|
|
611
|
+
packageRoot,
|
|
612
|
+
id: options.checkId,
|
|
613
|
+
requirement: options.checkRequirement,
|
|
614
|
+
argv: options.commandArgv,
|
|
615
|
+
details: options.checkDetails ?? undefined,
|
|
616
|
+
});
|
|
617
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatRunCheckResult(result));
|
|
618
|
+
return result.check.status === "passed" ? 0 : 1;
|
|
619
|
+
},
|
|
620
|
+
"record-check": async ({ target, packageRoot, options }) => {
|
|
621
|
+
const result = await runRecordCheck({
|
|
622
|
+
target,
|
|
623
|
+
packageRoot,
|
|
624
|
+
id: options.checkId,
|
|
625
|
+
kind: options.checkKind ?? "command",
|
|
626
|
+
requirement: options.checkRequirement,
|
|
627
|
+
status: options.checkStatus,
|
|
628
|
+
evidenceKind: options.checkEvidenceKind,
|
|
629
|
+
command: options.checkCommand ?? undefined,
|
|
630
|
+
result: options.checkResult ?? undefined,
|
|
631
|
+
...(options.checkExitCode === null ? {} : { exitCode: options.checkExitCode }),
|
|
632
|
+
details: options.checkDetails ?? undefined,
|
|
633
|
+
executionRef: options.checkExecutionRef ?? undefined,
|
|
634
|
+
provenance: options.checkProvenance ?? undefined,
|
|
635
|
+
});
|
|
636
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatRecordCheckResult(result));
|
|
637
|
+
return 0;
|
|
638
|
+
},
|
|
639
|
+
"record-terminal-result": async ({ target, packageRoot, options }) => {
|
|
640
|
+
const result = await runRecordTerminalResult({
|
|
641
|
+
target,
|
|
642
|
+
packageRoot,
|
|
643
|
+
requirement: options.checkRequirement,
|
|
644
|
+
type: options.checkType,
|
|
645
|
+
status: options.checkStatus,
|
|
646
|
+
source: options.checkSource ?? options.checkCommand,
|
|
647
|
+
result: options.checkResult,
|
|
648
|
+
details: options.checkDetails ?? undefined,
|
|
649
|
+
});
|
|
650
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatRecordTerminalResult(result));
|
|
651
|
+
return 0;
|
|
652
|
+
},
|
|
653
|
+
complete: async ({ target, packageRoot, options }) => {
|
|
654
|
+
const result = await runComplete({ target, packageRoot, strict: options.strict });
|
|
655
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatCompleteResult(result));
|
|
656
|
+
return result.status === "VALID" ? 0 : 1;
|
|
657
|
+
},
|
|
658
|
+
audit: async ({ target, packageRoot, options }) => {
|
|
659
|
+
const result = await runAudit({ target, packageRoot, strict: options.strict });
|
|
660
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatAuditResult(result));
|
|
661
|
+
return result.status === "VALID" ? 0 : 1;
|
|
662
|
+
},
|
|
663
|
+
report: async ({ target, packageRoot, options }) => {
|
|
664
|
+
const result = await runReport({ target, packageRoot, strict: options.strict });
|
|
665
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatReportResult(result));
|
|
666
|
+
return result.verdict === "VALID" ? 0 : 1;
|
|
667
|
+
},
|
|
668
|
+
policy: async ({ target, packageRoot, options }) => {
|
|
669
|
+
const result = await runPolicy({ target, packageRoot, name: options.policy });
|
|
670
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatPolicyResult(result));
|
|
671
|
+
return 0;
|
|
672
|
+
},
|
|
673
|
+
bundle: async ({ target, packageRoot, options }) => {
|
|
674
|
+
const result = await runBundle({ target, packageRoot, taskId: options.task });
|
|
675
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatBundleResult(result));
|
|
676
|
+
return 0;
|
|
677
|
+
},
|
|
678
|
+
inspect: async ({ target, packageRoot, options }) => {
|
|
679
|
+
const result = await inspectTarget({ target, packageRoot, contractFile: options.contractFile });
|
|
680
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatInspectResult(result));
|
|
681
|
+
return result.ok ? 0 : 1;
|
|
682
|
+
},
|
|
683
|
+
"validate-receipt": async ({ target, packageRoot, options }) => {
|
|
684
|
+
const result = await runValidateReceipt({ target, packageRoot, file: options.file });
|
|
685
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : "valid: execution receipt");
|
|
686
|
+
return 0;
|
|
687
|
+
},
|
|
688
|
+
"validate-protocol": async ({ target, packageRoot, options }) => {
|
|
689
|
+
const result = await runValidateProtocol({
|
|
690
|
+
target,
|
|
691
|
+
packageRoot,
|
|
692
|
+
stateFile: options.stateFile ?? ARTIFACT_PATHS.state,
|
|
693
|
+
receiptFile: options.receiptFile ?? ARTIFACT_PATHS.receipt,
|
|
694
|
+
routeFile: options.routeFile ?? ARTIFACT_PATHS.route,
|
|
695
|
+
contractFile: options.contractFile,
|
|
696
|
+
continuityFile: options.continuityFile,
|
|
697
|
+
taskBriefFiles: options.taskBriefFiles,
|
|
698
|
+
delegatedResultFiles: options.delegatedResultFiles,
|
|
699
|
+
});
|
|
700
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatValidateProtocolResult(result));
|
|
701
|
+
return result.status === "VALID" ? 0 : 1;
|
|
702
|
+
},
|
|
703
|
+
status: async ({ target, packageRoot, options }) => {
|
|
704
|
+
const result = await runStatus({ target, packageRoot, contractFile: options.contractFile });
|
|
705
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatStatusResult(result));
|
|
706
|
+
return 0;
|
|
707
|
+
},
|
|
708
|
+
"validate-state": async ({ target, packageRoot, options }) => {
|
|
709
|
+
const result = await runValidateState({ target, packageRoot });
|
|
710
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatValidateStateResult(result));
|
|
711
|
+
return result.ok ? 0 : 1;
|
|
712
|
+
},
|
|
713
|
+
"clear-state": async ({ target, options }) => {
|
|
714
|
+
const result = await runClearState({ target });
|
|
715
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatClearStateResult(result));
|
|
716
|
+
return 0;
|
|
717
|
+
},
|
|
718
|
+
update: async ({ target, packageRoot, packageVersion, options }) => {
|
|
719
|
+
const result = await runUpdate({ target, dryRun: options.dryRun, packageRoot, packageVersion });
|
|
720
|
+
printActions(result.actions);
|
|
721
|
+
for (const conflict of result.conflicts) {
|
|
722
|
+
const code = conflict.code ? `${conflict.code}: ` : "";
|
|
723
|
+
console.log(`conflict: ${code}${conflict.path} - ${conflict.message}`);
|
|
724
|
+
}
|
|
725
|
+
return result.conflicts.length === 0 ? 0 : 1;
|
|
726
|
+
},
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
export const COMMAND_TABLE = Object.freeze(
|
|
730
|
+
COMMANDS.map((name) => Object.freeze({
|
|
731
|
+
name,
|
|
732
|
+
handler: COMMAND_HANDLERS[name],
|
|
733
|
+
usage: usage(name),
|
|
734
|
+
})),
|
|
735
|
+
);
|
|
736
|
+
|
|
408
737
|
export async function main(argv = process.argv.slice(2)) {
|
|
409
738
|
try {
|
|
410
739
|
const { command, options } = parseArgs(argv);
|
|
@@ -421,192 +750,18 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
421
750
|
const packageRoot = getPackageRoot();
|
|
422
751
|
const version = await packageVersion(packageRoot);
|
|
423
752
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
return 0;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
if (command === "doctor") {
|
|
431
|
-
const result = await runDoctor({
|
|
432
|
-
target,
|
|
433
|
-
packageRoot,
|
|
434
|
-
adoptPaths: options.adopt,
|
|
435
|
-
strict: options.strict,
|
|
436
|
-
});
|
|
437
|
-
if (options.json) {
|
|
438
|
-
console.log(JSON.stringify(result, null, 2));
|
|
439
|
-
} else {
|
|
440
|
-
for (const item of result.findings) {
|
|
441
|
-
console.log(`${item.severity}: ${item.code}: ${item.path} - ${item.message}`);
|
|
442
|
-
}
|
|
443
|
-
console.log(result.ok ? "healthy: ForgeLoop target is ready" : "unhealthy: ForgeLoop target needs attention");
|
|
444
|
-
}
|
|
445
|
-
return result.ok ? 0 : 1;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
if (command === "route") {
|
|
449
|
-
const result = await runRoute({
|
|
450
|
-
target,
|
|
451
|
-
packageRoot,
|
|
452
|
-
workType: options.work,
|
|
453
|
-
surfaces: options.surfaces,
|
|
454
|
-
risks: options.risks,
|
|
455
|
-
platforms: options.platforms,
|
|
456
|
-
behaviorChange: options.behaviorChange,
|
|
457
|
-
executableChange: options.executableChange,
|
|
458
|
-
});
|
|
459
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : formatRouteResult(result));
|
|
460
|
-
return 0;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
if (command === "activate") {
|
|
464
|
-
const result = await runActivate({ target, packageRoot });
|
|
465
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : formatActivateResult(result));
|
|
466
|
-
return 0;
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
if (command === "preflight") {
|
|
470
|
-
const result = await runPreflight({ target, packageRoot, strict: options.strict });
|
|
471
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : formatPreflightResult(result));
|
|
472
|
-
return result.status === "READY" ? 0 : 1;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
if (command === "advance") {
|
|
476
|
-
const result = await runAdvance({ target, packageRoot, to: options.to });
|
|
477
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : formatAdvanceResult(result));
|
|
478
|
-
return 0;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
if (command === "next") {
|
|
482
|
-
const result = await runNext({ target, packageRoot });
|
|
483
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : formatNextActionResult(result));
|
|
484
|
-
return 0;
|
|
753
|
+
const handler = COMMAND_HANDLERS[command];
|
|
754
|
+
if (typeof handler !== "function") {
|
|
755
|
+
throw new Error(`Unsupported command: ${command}`);
|
|
485
756
|
}
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
if (command === "record-check") {
|
|
494
|
-
const result = await runRecordCheck({
|
|
495
|
-
target,
|
|
496
|
-
packageRoot,
|
|
497
|
-
id: options.checkId,
|
|
498
|
-
kind: options.checkKind ?? "command",
|
|
499
|
-
requirement: options.checkRequirement,
|
|
500
|
-
status: options.checkStatus,
|
|
501
|
-
evidenceKind: options.checkEvidenceKind,
|
|
502
|
-
command: options.checkCommand ?? undefined,
|
|
503
|
-
result: options.checkResult ?? undefined,
|
|
504
|
-
exitCode: options.checkExitCode,
|
|
505
|
-
details: options.checkDetails ?? undefined,
|
|
506
|
-
});
|
|
507
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : formatRecordCheckResult(result));
|
|
508
|
-
return 0;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
if (command === "record-terminal-result") {
|
|
512
|
-
const result = await runRecordTerminalResult({
|
|
513
|
-
target,
|
|
514
|
-
packageRoot,
|
|
515
|
-
requirement: options.checkRequirement,
|
|
516
|
-
type: options.checkType,
|
|
517
|
-
status: options.checkStatus,
|
|
518
|
-
source: options.checkSource ?? options.checkCommand,
|
|
519
|
-
result: options.checkResult,
|
|
520
|
-
details: options.checkDetails ?? undefined,
|
|
521
|
-
});
|
|
522
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : formatRecordTerminalResult(result));
|
|
523
|
-
return 0;
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
if (command === "complete") {
|
|
527
|
-
const result = await runComplete({ target, packageRoot, strict: options.strict });
|
|
528
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : formatCompleteResult(result));
|
|
529
|
-
return result.status === "VALID" ? 0 : 1;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
if (command === "audit") {
|
|
533
|
-
const result = await runAudit({ target, packageRoot, strict: options.strict });
|
|
534
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : formatAuditResult(result));
|
|
535
|
-
return result.status === "VALID" ? 0 : 1;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
if (command === "report") {
|
|
539
|
-
const result = await runReport({ target, packageRoot, strict: options.strict });
|
|
540
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : formatReportResult(result));
|
|
541
|
-
return result.verdict === "VALID" ? 0 : 1;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
if (command === "policy") {
|
|
545
|
-
const result = await runPolicy({ target, packageRoot, name: options.policy });
|
|
546
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : formatPolicyResult(result));
|
|
547
|
-
return 0;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
if (command === "bundle") {
|
|
551
|
-
const result = await runBundle({ target, packageRoot, taskId: options.task });
|
|
552
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : formatBundleResult(result));
|
|
553
|
-
return 0;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
if (command === "inspect") {
|
|
557
|
-
const result = await inspectTarget({ target, packageRoot, contractFile: options.contractFile });
|
|
558
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : formatInspectResult(result));
|
|
559
|
-
return result.ok ? 0 : 1;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
if (command === "validate-receipt") {
|
|
563
|
-
const result = await runValidateReceipt({ target, packageRoot, file: options.file });
|
|
564
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : "valid: execution receipt");
|
|
565
|
-
return 0;
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
if (command === "validate-protocol") {
|
|
569
|
-
const result = await runValidateProtocol({
|
|
570
|
-
target,
|
|
571
|
-
packageRoot,
|
|
572
|
-
stateFile: options.stateFile ?? ARTIFACT_PATHS.state,
|
|
573
|
-
receiptFile: options.receiptFile ?? ARTIFACT_PATHS.receipt,
|
|
574
|
-
routeFile: options.routeFile ?? ARTIFACT_PATHS.route,
|
|
575
|
-
contractFile: options.contractFile,
|
|
576
|
-
taskBriefFiles: options.taskBriefFiles,
|
|
577
|
-
delegatedResultFiles: options.delegatedResultFiles,
|
|
578
|
-
});
|
|
579
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : formatValidateProtocolResult(result));
|
|
580
|
-
return result.status === "VALID" ? 0 : 1;
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
if (command === "status") {
|
|
584
|
-
const result = await runStatus({ target, packageRoot, contractFile: options.contractFile });
|
|
585
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : formatStatusResult(result));
|
|
586
|
-
return 0;
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
if (command === "validate-state") {
|
|
590
|
-
const result = await runValidateState({ target, packageRoot });
|
|
591
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : formatValidateStateResult(result));
|
|
592
|
-
return result.ok ? 0 : 1;
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
if (command === "clear-state") {
|
|
596
|
-
const result = await runClearState({ target });
|
|
597
|
-
console.log(options.json ? JSON.stringify(result, null, 2) : formatClearStateResult(result));
|
|
598
|
-
return 0;
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
const result = await runUpdate({ target, dryRun: options.dryRun, packageRoot, packageVersion: version });
|
|
602
|
-
printActions(result.actions);
|
|
603
|
-
for (const conflict of result.conflicts) {
|
|
604
|
-
const code = conflict.code ? `${conflict.code}: ` : "";
|
|
605
|
-
console.log(`conflict: ${code}${conflict.path} - ${conflict.message}`);
|
|
606
|
-
}
|
|
607
|
-
return result.conflicts.length === 0 ? 0 : 1;
|
|
757
|
+
return await handler({
|
|
758
|
+
target,
|
|
759
|
+
packageRoot,
|
|
760
|
+
packageVersion: version,
|
|
761
|
+
options,
|
|
762
|
+
});
|
|
608
763
|
} catch (error) {
|
|
609
|
-
console.error(`error: ${error.message}`);
|
|
764
|
+
console.error(`error: ${error.code ? `${error.code}: ` : ""}${error.message}`);
|
|
610
765
|
return 1;
|
|
611
766
|
}
|
|
612
767
|
}
|