@cassiomc1/forgeloop 1.3.0 → 1.6.0
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/.github/copilot-instructions.md +1 -0
- package/AGENTS.md +1 -0
- package/CLAUDE.md +1 -0
- package/DOCS_INDEX.md +20 -8
- package/EXECUTION_STATE.md +60 -0
- package/LOOP_ENGINEERING.md +135 -5
- package/LOOP_SYSTEM_DESIGN.md +54 -1
- package/PROTOCOL_INTEGRATION.md +87 -0
- package/QUALITY_SCORECARD.md +2 -0
- package/README.md +69 -9
- package/TERMINOLOGY.md +15 -0
- package/THIRD_PARTY_NOTICES.md +30 -0
- package/THREAT_MODEL.md +59 -1
- package/docs/ARTIFACT_REFERENCE.md +183 -0
- package/docs/CLI_REFERENCE.md +391 -6
- package/docs/CROSS_HARNESS_CONTINUITY.md +23 -0
- package/docs/DIAGNOSTIC_MODEL.md +181 -0
- package/docs/DOCUMENTATION_GUIDE.md +36 -13
- package/docs/EXECUTION_TRACE.md +76 -0
- package/docs/GETTING_STARTED.md +1 -0
- package/docs/MCP.md +159 -0
- package/docs/RECIPES.md +149 -0
- package/docs/RELEASE_CHECKLIST_1_4.md +38 -0
- package/docs/RELEASE_CHECKLIST_1_5_MCP.md +78 -0
- package/docs/TROUBLESHOOTING.md +217 -3
- package/docs/UNIVERSAL_INTEGRATION.md +48 -0
- package/docs/assets/diagrams/forgeloop-engineering-flow.html +13797 -0
- package/docs/assets/diagrams/forgeloop-engineering-flow.receipt.json +37 -0
- package/docs/assets/diagrams/forgeloop-engineering-flow.svg +5002 -0
- package/docs/diagrams/README.md +55 -0
- package/docs/diagrams/forgeloop-engineering-flow.workflow.json +122 -0
- package/docs/diagrams/manifest.json +42 -0
- package/docs/diagrams/reviews/forgeloop-engineering-flow.review.json +20 -0
- package/package.json +21 -8
- package/schemas/action.schema.json +100 -0
- package/schemas/approval.schema.json +51 -0
- package/schemas/capability-policy.schema.json +41 -0
- package/schemas/diagnostic-case.schema.json +85 -0
- package/schemas/execution-receipt.schema.json +16 -0
- package/schemas/hypothesis-disposition.schema.json +16 -0
- package/schemas/intervention.schema.json +27 -0
- package/schemas/policy-lock.schema.json +1 -0
- package/schemas/policy-snapshot.schema.json +2 -0
- package/schemas/task-recovery.schema.json +61 -0
- package/schemas/trajectory-evaluation.schema.json +64 -0
- package/schemas/trajectory-scenario.schema.json +42 -0
- package/src/cli.js +267 -347
- package/src/commands/action-authorize.js +41 -0
- package/src/commands/action-propose.js +10 -0
- package/src/commands/action-reconcile.js +10 -0
- package/src/commands/action-record.js +47 -0
- package/src/commands/action-show.js +10 -0
- package/src/commands/action-verify.js +10 -0
- package/src/commands/advance.js +7 -2
- package/src/commands/approval-request.js +64 -0
- package/src/commands/approval-resolve.js +10 -0
- package/src/commands/audit.js +5 -0
- package/src/commands/baseline.js +3 -3
- package/src/commands/eval.js +6 -0
- package/src/commands/history.js +18 -0
- package/src/commands/init.js +2 -2
- package/src/commands/inspect.js +55 -0
- package/src/commands/metrics.js +7 -0
- package/src/commands/next.js +8 -2
- package/src/commands/policy-discover.js +2 -2
- package/src/commands/progress.js +6 -2
- package/src/commands/record-diagnosis.js +37 -1
- package/src/commands/record-hypothesis-disposition.js +45 -0
- package/src/commands/record-intervention.js +35 -0
- package/src/commands/reflect.js +38 -0
- package/src/commands/report.js +9 -1
- package/src/commands/run-action.js +18 -0
- package/src/commands/status.js +17 -0
- package/src/commands/task-create.js +39 -1
- package/src/commands/task-list.js +14 -1
- package/src/commands/task-lock-status.js +2 -2
- package/src/commands/task-recover.js +202 -0
- package/src/commands/task-repair-legacy-recovery.js +417 -0
- package/src/commands/task-resume.js +172 -0
- package/src/commands/task-scope.js +23 -4
- package/src/commands/task-show.js +18 -4
- package/src/commands/trace.js +34 -0
- package/src/commands/validate-protocol.js +40 -15
- package/src/core/action-authorization.js +106 -0
- package/src/core/action-constants.js +86 -0
- package/src/core/action-execution.js +105 -0
- package/src/core/action-ledger-projection.js +302 -0
- package/src/core/action-model.js +581 -0
- package/src/core/action-readiness.js +141 -0
- package/src/core/action-reconciliation-policy.js +49 -0
- package/src/core/action-reconciliation.js +66 -0
- package/src/core/action-verification.js +111 -0
- package/src/core/actions.js +462 -0
- package/src/core/approvals.js +405 -0
- package/src/core/artifact-registry.js +60 -0
- package/src/core/audit.js +45 -4
- package/src/core/bundles.js +30 -0
- package/src/core/capability-policy.js +226 -0
- package/src/core/cli-command-definitions.js +260 -5
- package/src/core/command-executors.js +543 -0
- package/src/core/command-input.js +107 -0
- package/src/core/command-runtime.js +117 -0
- package/src/core/completion-artifacts.js +39 -15
- package/src/core/completion-ownership.js +88 -0
- package/src/core/completion-recovery-rebind.js +194 -0
- package/src/core/completion.js +70 -0
- package/src/core/continuity-reconciliation.js +24 -5
- package/src/core/diagnostic-model.js +396 -0
- package/src/core/diagnostic-projection.js +51 -0
- package/src/core/diagnostic-record.js +360 -0
- package/src/core/error-codes.js +461 -1
- package/src/core/events.js +171 -2
- package/src/core/execution-prerequisites.js +4 -1
- package/src/core/execution.js +26 -188
- package/src/core/failure-signature.js +70 -0
- package/src/core/failure-surface.js +57 -0
- package/src/core/filesystem.js +55 -6
- package/src/core/history.js +110 -0
- package/src/core/hypothesis-projection.js +85 -0
- package/src/core/information-gain-projection.js +283 -0
- package/src/core/information-gain.js +138 -0
- package/src/core/inspect.js +132 -7
- package/src/core/integration-invocation-policy.js +217 -0
- package/src/core/integration-limits.js +20 -0
- package/src/core/integration-resources.js +178 -0
- package/src/core/next-action-model.js +94 -0
- package/src/core/next-action.js +490 -3
- package/src/core/phase.js +42 -22
- package/src/core/policy-engine.js +113 -6
- package/src/core/preflight-consistency.js +31 -5
- package/src/core/preflight.js +19 -2
- package/src/core/prepared-execution.js +227 -0
- package/src/core/progress.js +41 -4
- package/src/core/project-root.js +21 -0
- package/src/core/protocol-info.js +61 -0
- package/src/core/protocol.js +14 -0
- package/src/core/receipt.js +1 -0
- package/src/core/reconcile-closure.js +35 -10
- package/src/core/recovery-history.js +116 -0
- package/src/core/reflection.js +305 -0
- package/src/core/resumability.js +57 -3
- package/src/core/schema-validation.js +9 -0
- package/src/core/strategy-analysis.js +97 -0
- package/src/core/task-claim-state.js +272 -0
- package/src/core/task-command.js +5 -1
- package/src/core/task-conflict-inspection.js +321 -0
- package/src/core/task-context.js +32 -29
- package/src/core/task-discovery.js +14 -1
- package/src/core/task-lock.js +216 -22
- package/src/core/task-paths.js +31 -2
- package/src/core/task-recovery-migration.js +192 -0
- package/src/core/task-recovery.js +205 -0
- package/src/core/task-scope.js +33 -1
- package/src/core/task-snapshot.js +53 -0
- package/src/core/templates.js +9 -0
- package/src/core/trace.js +548 -0
- package/src/core/trajectory-evaluation.js +71 -0
- package/src/core/trajectory-metrics.js +80 -0
- package/src/core/transaction.js +36 -2
- package/src/core/work-state.js +10 -5
- package/src/integration.js +47 -0
- package/docs/assets/forgeloop-flow.svg +0 -1
- package/docs/forgeloop-flow.mmd +0 -51
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { canonicalFingerprint } from "./artifacts.js";
|
|
2
|
+
import { sha256 } from "./manifest.js";
|
|
3
|
+
import { ACTION_CAPABILITIES } from "./action-constants.js";
|
|
4
|
+
import { validateCapabilityPolicy } from "./action-model.js";
|
|
5
|
+
import { PROJECT_ARTIFACT_PATHS } from "./task-paths.js";
|
|
6
|
+
import { assertSafePath, ensureWithin, fileExists } from "./filesystem.js";
|
|
7
|
+
import {
|
|
8
|
+
E_ACTION_INVALID,
|
|
9
|
+
E_POLICY_INVALID,
|
|
10
|
+
} from "./error-codes.js";
|
|
11
|
+
|
|
12
|
+
const ALLOWED_POLICY_PROPERTIES = new Set(["schemaVersion", "defaultDecision", "rules"]);
|
|
13
|
+
|
|
14
|
+
function policyError(code, message) {
|
|
15
|
+
const error = new Error(message);
|
|
16
|
+
error.code = code;
|
|
17
|
+
return error;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function loadCapabilityPolicy(target, packageRoot) {
|
|
21
|
+
const relativePath = PROJECT_ARTIFACT_PATHS.capabilityPolicy;
|
|
22
|
+
await assertSafePath(target, relativePath);
|
|
23
|
+
const absolutePath = ensureWithin(target, relativePath);
|
|
24
|
+
if (!(await fileExists(absolutePath))) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
let parsed;
|
|
28
|
+
try {
|
|
29
|
+
const { readFile } = await import("node:fs/promises");
|
|
30
|
+
parsed = JSON.parse(await readFile(absolutePath, "utf8"));
|
|
31
|
+
} catch (error) {
|
|
32
|
+
throw policyError(E_POLICY_INVALID, `capability policy is not valid JSON: ${error.message}`);
|
|
33
|
+
}
|
|
34
|
+
for (const key of Object.keys(parsed ?? {})) {
|
|
35
|
+
if (!ALLOWED_POLICY_PROPERTIES.has(key)) {
|
|
36
|
+
throw policyError(
|
|
37
|
+
E_POLICY_INVALID,
|
|
38
|
+
`capability policy.${key} is not an allowed property; project-local policy can never declare authority or trust metadata`,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
validateCapabilityPolicy(parsed);
|
|
43
|
+
return {
|
|
44
|
+
policy: parsed,
|
|
45
|
+
fingerprint: canonicalFingerprint(parsed),
|
|
46
|
+
path: relativePath,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Canonical current capability-policy identity. The fingerprint matches the
|
|
52
|
+
* authorization-time binding; the digest is the same sha256 representation
|
|
53
|
+
* used by the policy lock so a single identity participates in locks, task
|
|
54
|
+
* snapshots, and action authorization evidence.
|
|
55
|
+
*/
|
|
56
|
+
export async function readCapabilityPolicyIdentity(target, packageRoot) {
|
|
57
|
+
const loaded = await loadCapabilityPolicy(target, packageRoot);
|
|
58
|
+
if (!loaded) {
|
|
59
|
+
return {
|
|
60
|
+
policy: null,
|
|
61
|
+
fingerprint: null,
|
|
62
|
+
digest: null,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
policy: loaded.policy,
|
|
67
|
+
fingerprint: loaded.fingerprint,
|
|
68
|
+
digest: `sha256:${sha256(canonicalFingerprint(loaded.policy))}`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function resolveCapabilityDecision(policy, capability) {
|
|
73
|
+
if (typeof capability !== "string" || !capability) {
|
|
74
|
+
throw policyError(E_ACTION_INVALID, "capability must be a non-empty string");
|
|
75
|
+
}
|
|
76
|
+
// Capabilities outside the canonical protocol vocabulary always fail closed.
|
|
77
|
+
if (!ACTION_CAPABILITIES.includes(capability)) {
|
|
78
|
+
return { decision: "DENY", reasonCode: "E_ACTION_CAPABILITY_UNKNOWN" };
|
|
79
|
+
}
|
|
80
|
+
const rule = policy.rules.find((candidate) => candidate.capability === capability);
|
|
81
|
+
const decision = rule?.decision ?? policy.defaultDecision;
|
|
82
|
+
switch (decision) {
|
|
83
|
+
case "ALLOW":
|
|
84
|
+
return { decision: "ALLOW", reasonCode: null };
|
|
85
|
+
case "DENY":
|
|
86
|
+
return { decision: "DENY", reasonCode: "E_ACTION_CAPABILITY_DENIED" };
|
|
87
|
+
case "REQUIRE_AUTHORITY":
|
|
88
|
+
return { decision: "REQUIRE_AUTHORITY", reasonCode: "E_ACTION_AUTHORITY_REQUIRED" };
|
|
89
|
+
case "REQUIRE_APPROVAL":
|
|
90
|
+
return { decision: "REQUIRE_APPROVAL", reasonCode: "E_ACTION_APPROVAL_REQUIRED" };
|
|
91
|
+
default:
|
|
92
|
+
return { decision: "DENY", reasonCode: "E_ACTION_CAPABILITY_DENIED" };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function isTrustedHostAuthorityContext(authorityContext) {
|
|
97
|
+
// Only a genuine host-controlled trust boundary may satisfy
|
|
98
|
+
// REQUIRE_AUTHORITY. A project-local file, environment-selected source,
|
|
99
|
+
// CLI flag, or transport session can never promote itself to HOST_ATTESTED.
|
|
100
|
+
if (!authorityContext || typeof authorityContext !== "object") return false;
|
|
101
|
+
if (authorityContext.trustMode !== "HOST_ATTESTED") return false;
|
|
102
|
+
const source = typeof authorityContext.source === "string" ? authorityContext.source : "";
|
|
103
|
+
const forbiddenSources = ["project-local-file", "environment", "cli-flag", "transport-session"];
|
|
104
|
+
if (forbiddenSources.includes(source)) return false;
|
|
105
|
+
return authorityContext.hostSupplied === true && source === "host-boundary";
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export async function evaluateActionCapability({
|
|
109
|
+
target,
|
|
110
|
+
packageRoot,
|
|
111
|
+
action,
|
|
112
|
+
authorityContext = { trustMode: "NONE" },
|
|
113
|
+
approval,
|
|
114
|
+
}) {
|
|
115
|
+
if (!action || typeof action !== "object") {
|
|
116
|
+
throw policyError(E_ACTION_INVALID, "action is required for capability evaluation");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let loaded = null;
|
|
120
|
+
try {
|
|
121
|
+
loaded = await loadCapabilityPolicy(target, packageRoot);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
if (error.code === E_POLICY_INVALID) throw error;
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// A poisoned local policy artifact must never grant authority.
|
|
128
|
+
if (
|
|
129
|
+
loaded &&
|
|
130
|
+
(loaded.policy.authority !== undefined ||
|
|
131
|
+
loaded.policy.trustMode !== undefined ||
|
|
132
|
+
loaded.policy.hostAttested !== undefined)
|
|
133
|
+
) {
|
|
134
|
+
loaded = null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (!loaded) {
|
|
138
|
+
// No capability policy present. v1 keeps legacy flows unchanged and fails
|
|
139
|
+
// closed for new durable-action execution.
|
|
140
|
+
return {
|
|
141
|
+
capability: action.capability,
|
|
142
|
+
decision: "REQUIRE_APPROVAL",
|
|
143
|
+
allowed: false,
|
|
144
|
+
reasonCode: "E_ACTION_APPROVAL_REQUIRED",
|
|
145
|
+
policyFingerprint: null,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const resolved = resolveCapabilityDecision(loaded.policy, action.capability);
|
|
150
|
+
const base = {
|
|
151
|
+
capability: action.capability,
|
|
152
|
+
decision: resolved.decision,
|
|
153
|
+
policyFingerprint: loaded.fingerprint,
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
if (resolved.decision === "ALLOW") {
|
|
157
|
+
return { ...base, allowed: true, reasonCode: null };
|
|
158
|
+
}
|
|
159
|
+
if (resolved.decision === "DENY") {
|
|
160
|
+
return { ...base, allowed: false, reasonCode: resolved.reasonCode ?? "E_ACTION_CAPABILITY_DENIED" };
|
|
161
|
+
}
|
|
162
|
+
if (resolved.decision === "REQUIRE_AUTHORITY") {
|
|
163
|
+
if (
|
|
164
|
+
isTrustedHostAuthorityContext(authorityContext)
|
|
165
|
+
&& typeof authorityContext.grantRef === "string"
|
|
166
|
+
&& authorityContext.grantRef.length > 0
|
|
167
|
+
&& authorityContext.grantRef.length <= 256
|
|
168
|
+
) {
|
|
169
|
+
return {
|
|
170
|
+
...base,
|
|
171
|
+
allowed: true,
|
|
172
|
+
reasonCode: null,
|
|
173
|
+
authority: {
|
|
174
|
+
authorityKind: "HOST_ATTESTED",
|
|
175
|
+
authorityRef: authorityContext.grantRef,
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return { ...base, allowed: false, reasonCode: "E_ACTION_AUTHORITY_REQUIRED" };
|
|
180
|
+
}
|
|
181
|
+
if (approval?.approvalId) {
|
|
182
|
+
const { validateApprovalForAction, approvalFingerprint } = await import("./approvals.js");
|
|
183
|
+
try {
|
|
184
|
+
const resolvedApproval = await validateApprovalForAction(target, {
|
|
185
|
+
packageRoot,
|
|
186
|
+
taskId: action.taskId,
|
|
187
|
+
action,
|
|
188
|
+
approvalId: approval.approvalId,
|
|
189
|
+
});
|
|
190
|
+
if (resolvedApproval.authorityKind !== "HOST_ATTESTED" || !resolvedApproval.hostGrantRef) {
|
|
191
|
+
return { ...base, allowed: false, reasonCode: "E_ACTION_AUTHORITY_REQUIRED" };
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
...base,
|
|
195
|
+
allowed: true,
|
|
196
|
+
reasonCode: null,
|
|
197
|
+
approval: {
|
|
198
|
+
approvalId: resolvedApproval.approvalId,
|
|
199
|
+
approvalFingerprint: approvalFingerprint(resolvedApproval),
|
|
200
|
+
authorityKind: "HOST_ATTESTED",
|
|
201
|
+
authorityRef: resolvedApproval.hostGrantRef,
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
} catch (error) {
|
|
205
|
+
return { ...base, allowed: false, reasonCode: error.code ?? "E_APPROVAL_INVALID" };
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return { ...base, allowed: false, reasonCode: "E_ACTION_APPROVAL_REQUIRED" };
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Least-privilege diagnostics for project capability policies (policy is
|
|
213
|
+
* policy, never authority). A broad defaultDecision=ALLOW grants every known
|
|
214
|
+
* capability without an explicit DENY rule; standard mode surfaces a warning
|
|
215
|
+
* so operators see the least-privilege tradeoff.
|
|
216
|
+
*/
|
|
217
|
+
export function capabilityPolicyWarnings(policy) {
|
|
218
|
+
if (!policy || typeof policy !== "object" || policy.defaultDecision !== "ALLOW") {
|
|
219
|
+
return [];
|
|
220
|
+
}
|
|
221
|
+
return [{
|
|
222
|
+
code: "W_CAPABILITY_POLICY_BROAD_DEFAULT",
|
|
223
|
+
message:
|
|
224
|
+
"Capability policy defaultDecision=ALLOW grants every known capability without an explicit DENY rule.",
|
|
225
|
+
}];
|
|
226
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Canonical, declarative definition of all
|
|
2
|
+
* Canonical, declarative definition of all ForgeLoop CLI commands.
|
|
3
3
|
* This is the machine source of truth for CLI option parsing, help text,
|
|
4
4
|
* metadata, documentation generation, and conformance validation.
|
|
5
5
|
*
|
|
@@ -43,7 +43,7 @@ export const CLI_COMMON_OPTIONS = Object.freeze({
|
|
|
43
43
|
*/
|
|
44
44
|
export const CLI_TASK_OPTION = Object.freeze({
|
|
45
45
|
"--task": Object.freeze({
|
|
46
|
-
targetKey: "
|
|
46
|
+
targetKey: "taskId",
|
|
47
47
|
parseType: "string",
|
|
48
48
|
takesValue: true,
|
|
49
49
|
valueName: "id",
|
|
@@ -133,7 +133,7 @@ export const CLI_COMMAND_DEFINITIONS = Object.freeze({
|
|
|
133
133
|
options: Object.freeze({
|
|
134
134
|
...CLI_COMMON_OPTIONS,
|
|
135
135
|
...CLI_TASK_OPTION,
|
|
136
|
-
"--work": Object.freeze({ targetKey: "
|
|
136
|
+
"--work": Object.freeze({ targetKey: "workType", parseType: "string", takesValue: true, valueName: "type", missingValueMessage: "--work requires a type", description: "declared work type" }),
|
|
137
137
|
"--surface": Object.freeze({ targetKey: "surfaces", parseType: "string", takesValue: true, valueName: "value", repeatable: true, missingValueMessage: "--surface requires a value", description: "affected surface" }),
|
|
138
138
|
"--risk": Object.freeze({ targetKey: "risks", parseType: "string", takesValue: true, valueName: "value", repeatable: true, missingValueMessage: "--risk requires a value", description: "task risk" }),
|
|
139
139
|
"--platform": Object.freeze({ targetKey: "platforms", parseType: "string", takesValue: true, valueName: "value", repeatable: true, missingValueMessage: "--platform requires a value", description: "affected platform" }),
|
|
@@ -286,6 +286,130 @@ export const CLI_COMMAND_DEFINITIONS = Object.freeze({
|
|
|
286
286
|
mayExecuteExternalProcess: true,
|
|
287
287
|
description: "Runs an exact command, records the execution provenance artifact, and binds observed check evidence.",
|
|
288
288
|
}),
|
|
289
|
+
"run-action": Object.freeze({
|
|
290
|
+
name: "run-action",
|
|
291
|
+
category: "actions",
|
|
292
|
+
mutation: "EXTERNAL_EXECUTION",
|
|
293
|
+
options: Object.freeze({
|
|
294
|
+
...CLI_COMMON_OPTIONS,
|
|
295
|
+
...CLI_TASK_OPTION,
|
|
296
|
+
"--action": Object.freeze({ targetKey: "actionId", parseType: "string", takesValue: true, valueName: "id", missingValueMessage: "--action requires an action ID", description: "stable durable action ID" }),
|
|
297
|
+
"--capability": Object.freeze({ targetKey: "actionCapability", parseType: "string", takesValue: true, valueName: "capability", missingValueMessage: "--capability requires a capability", description: "canonical action capability" }),
|
|
298
|
+
"--effect-class": Object.freeze({ targetKey: "actionEffectClass", parseType: "string", takesValue: true, valueName: "class", missingValueMessage: "--effect-class requires a class", description: "durable action effect class" }),
|
|
299
|
+
"--target": Object.freeze({ targetKey: "actionTarget", parseType: "string", takesValue: true, valueName: "target", missingValueMessage: "--target requires a bounded target", description: "bounded external action target" }),
|
|
300
|
+
"--idempotency-key": Object.freeze({ targetKey: "actionIdempotencyKey", parseType: "string", takesValue: true, valueName: "key", missingValueMessage: "--idempotency-key requires a key", description: "immutable logical action idempotency key" }),
|
|
301
|
+
"--requirement": Object.freeze({ targetKey: "actionRequirement", parseType: "string", takesValue: true, valueName: "id", missingValueMessage: "--requirement requires an ID", description: "bound completion requirement" }),
|
|
302
|
+
"--required-for-completion": Object.freeze({ targetKey: "actionRequiredForCompletion", parseType: "boolean", takesValue: false, description: "mark the action as required for completion" }),
|
|
303
|
+
"--approval": Object.freeze({ targetKey: "approvalId", parseType: "string", takesValue: true, valueName: "id", missingValueMessage: "--approval requires an approval ID", description: "current fingerprint-bound approval" }),
|
|
304
|
+
"--timeout-ms": Object.freeze({ targetKey: "timeoutMs", parseType: "non-negative-integer", takesValue: true, valueName: "number", missingValueMessage: "--timeout-ms requires a non-negative integer", description: "maximum command duration before termination" }),
|
|
305
|
+
"--": Object.freeze({ targetKey: "commandArgv", parseType: "argv", takesValue: true, valueName: "argv...", description: "exact command argv; shell mode is never used" }),
|
|
306
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
307
|
+
}),
|
|
308
|
+
writes: [".forgeloop/task-state/<taskKey>/actions/action-<id>.json", ".forgeloop/task-state/<taskKey>/executions/exec-<id>.json", ".forgeloop/task-state/<taskKey>/events.ndjson"],
|
|
309
|
+
removes: [],
|
|
310
|
+
mayExecuteExternalProcess: true,
|
|
311
|
+
description: "Executes one policy-authorized durable action using exact argv and shell:false semantics.",
|
|
312
|
+
}),
|
|
313
|
+
"action-propose": Object.freeze({
|
|
314
|
+
name: "action-propose", category: "actions", mutation: "MUTATING",
|
|
315
|
+
options: Object.freeze({ ...CLI_COMMON_OPTIONS, ...CLI_TASK_OPTION,
|
|
316
|
+
"--id": Object.freeze({ targetKey: "actionId", parseType: "string", takesValue: true, valueName: "id", missingValueMessage: "--id requires an action ID", description: "stable action ID" }),
|
|
317
|
+
"--capability": Object.freeze({ targetKey: "actionCapability", parseType: "string", takesValue: true, valueName: "capability", missingValueMessage: "--capability requires a capability", description: "canonical capability" }),
|
|
318
|
+
"--effect-class": Object.freeze({ targetKey: "actionEffectClass", parseType: "string", takesValue: true, valueName: "class", missingValueMessage: "--effect-class requires a class", description: "effect class" }),
|
|
319
|
+
"--target": Object.freeze({ targetKey: "actionTarget", parseType: "string", takesValue: true, valueName: "target", missingValueMessage: "--target requires a target", description: "bounded action target" }),
|
|
320
|
+
"--operation": Object.freeze({ targetKey: "actionOperation", parseType: "string", takesValue: true, valueName: "text", missingValueMessage: "--operation requires text", description: "bounded operation description" }),
|
|
321
|
+
"--idempotency-key": Object.freeze({ targetKey: "actionIdempotencyKey", parseType: "string", takesValue: true, valueName: "key", missingValueMessage: "--idempotency-key requires a key", description: "logical action idempotency key" }),
|
|
322
|
+
"--requirement": Object.freeze({ targetKey: "actionRequirement", parseType: "string", takesValue: true, valueName: "id", missingValueMessage: "--requirement requires an ID", description: "bound requirement" }),
|
|
323
|
+
"--required-for-completion": Object.freeze({ targetKey: "actionRequiredForCompletion", parseType: "boolean", takesValue: false, description: "mark required for completion" }),
|
|
324
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
325
|
+
}), writes: [".forgeloop/task-state/<taskKey>/actions/action-<id>.json", ".forgeloop/task-state/<taskKey>/events.ndjson"], removes: [], mayExecuteExternalProcess: false,
|
|
326
|
+
description: "Proposes a caller-reported durable action without executing it.",
|
|
327
|
+
}),
|
|
328
|
+
"action-record": Object.freeze({
|
|
329
|
+
name: "action-record", category: "actions", mutation: "MUTATING",
|
|
330
|
+
options: Object.freeze({ ...CLI_COMMON_OPTIONS, ...CLI_TASK_OPTION,
|
|
331
|
+
"--action": Object.freeze({ targetKey: "actionId", parseType: "string", takesValue: true, valueName: "id", missingValueMessage: "--action requires an action ID", description: "durable action ID" }),
|
|
332
|
+
"--state": Object.freeze({ targetKey: "actionState", parseType: "string", takesValue: true, valueName: "state", missingValueMessage: "--state requires a state", description: "next canonical action state" }),
|
|
333
|
+
"--provenance": Object.freeze({ targetKey: "actionProvenance", parseType: "string", takesValue: true, valueName: "value", missingValueMessage: "--provenance requires a value", description: "CALLER_REPORTED or EXTERNAL_OBSERVED" }),
|
|
334
|
+
"--evidence-ref": Object.freeze({ targetKey: "actionEvidenceRef", parseType: "string", takesValue: true, valueName: "ref", missingValueMessage: "--evidence-ref requires a reference", description: "bounded external evidence reference" }),
|
|
335
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
336
|
+
}), writes: [".forgeloop/task-state/<taskKey>/actions/action-<id>.json", ".forgeloop/task-state/<taskKey>/events.ndjson"], removes: [], mayExecuteExternalProcess: false,
|
|
337
|
+
description: "Records a caller-reported or externally observed non-authority action transition.",
|
|
338
|
+
}),
|
|
339
|
+
"action-show": Object.freeze({
|
|
340
|
+
name: "action-show", category: "actions", mutation: "READ_ONLY",
|
|
341
|
+
options: Object.freeze({ ...CLI_COMMON_OPTIONS, ...CLI_TASK_OPTION,
|
|
342
|
+
"--action": Object.freeze({ targetKey: "actionId", parseType: "string", takesValue: true, valueName: "id", missingValueMessage: "--action requires an action ID", description: "durable action ID" }),
|
|
343
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
344
|
+
}), writes: [], removes: [], mayExecuteExternalProcess: false,
|
|
345
|
+
description: "Reads one canonical durable action artifact.",
|
|
346
|
+
}),
|
|
347
|
+
"action-reconcile": Object.freeze({
|
|
348
|
+
name: "action-reconcile", category: "actions", mutation: "MUTATING",
|
|
349
|
+
options: Object.freeze({ ...CLI_COMMON_OPTIONS, ...CLI_TASK_OPTION,
|
|
350
|
+
"--action": Object.freeze({ targetKey: "actionId", parseType: "string", takesValue: true, valueName: "id", missingValueMessage: "--action requires an action ID", description: "ambiguous durable action ID" }),
|
|
351
|
+
"--outcome": Object.freeze({ targetKey: "reconciliationOutcome", parseType: "string", takesValue: true, valueName: "outcome", missingValueMessage: "--outcome requires COMMITTED, NOT_COMMITTED, or UNKNOWN", description: "externally observed reconciliation outcome" }),
|
|
352
|
+
"--evidence-ref": Object.freeze({ targetKey: "evidenceRefs", parseType: "string", takesValue: true, repeatable: true, valueName: "ref", missingValueMessage: "--evidence-ref requires a reference", description: "bounded external evidence reference" }),
|
|
353
|
+
"--observed-at": Object.freeze({ targetKey: "observedAt", parseType: "string", takesValue: true, valueName: "timestamp", missingValueMessage: "--observed-at requires a timestamp", description: "external observation timestamp" }),
|
|
354
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
355
|
+
}), writes: [".forgeloop/task-state/<taskKey>/actions/action-<id>.json", ".forgeloop/task-state/<taskKey>/events.ndjson"], removes: [], mayExecuteExternalProcess: false,
|
|
356
|
+
description: "Reconciles a COMMIT_UNKNOWN action from externally observed evidence without retrying it.",
|
|
357
|
+
}),
|
|
358
|
+
"action-verify": Object.freeze({
|
|
359
|
+
name: "action-verify", category: "actions", mutation: "MUTATING",
|
|
360
|
+
options: Object.freeze({ ...CLI_COMMON_OPTIONS, ...CLI_TASK_OPTION,
|
|
361
|
+
"--action": Object.freeze({ targetKey: "actionId", parseType: "string", takesValue: true, valueName: "id", missingValueMessage: "--action requires an action ID", description: "durable action ID" }),
|
|
362
|
+
"--evidence": Object.freeze({ targetKey: "actionEvidenceRef", parseType: "string", takesValue: true, valueName: "ref", missingValueMessage: "--evidence requires a canonical execution reference", description: "canonical execution or check reference proving the postcondition" }),
|
|
363
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
364
|
+
}), writes: [".forgeloop/task-state/<taskKey>/actions/action-<id>.json", ".forgeloop/task-state/<taskKey>/events.ndjson"], removes: [], mayExecuteExternalProcess: false,
|
|
365
|
+
description: "Verifies a COMMITTED action against independent canonical evidence; caller claims can never verify.",
|
|
366
|
+
}),
|
|
367
|
+
"action-authorize": Object.freeze({
|
|
368
|
+
name: "action-authorize", category: "actions", mutation: "MUTATING",
|
|
369
|
+
options: Object.freeze({ ...CLI_COMMON_OPTIONS, ...CLI_TASK_OPTION,
|
|
370
|
+
"--action": Object.freeze({ targetKey: "actionId", parseType: "string", takesValue: true, valueName: "id", missingValueMessage: "--action requires an action ID", description: "durable action ID" }),
|
|
371
|
+
"--approval": Object.freeze({ targetKey: "approvalId", parseType: "string", takesValue: true, valueName: "id", missingValueMessage: "--approval requires an approval ID", description: "current fingerprint-bound approval" }),
|
|
372
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
373
|
+
}), writes: [".forgeloop/task-state/<taskKey>/actions/action-<id>.json", ".forgeloop/task-state/<taskKey>/events.ndjson"], removes: [], mayExecuteExternalProcess: false,
|
|
374
|
+
description: "Authorizes one PROPOSED durable action through the canonical capability-policy and approval service.",
|
|
375
|
+
}),
|
|
376
|
+
metrics: Object.freeze({
|
|
377
|
+
name: "metrics", category: "diagnostics", mutation: "READ_ONLY",
|
|
378
|
+
options: Object.freeze({ ...CLI_COMMON_OPTIONS, ...CLI_TASK_OPTION,
|
|
379
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit trajectory metrics as JSON" }),
|
|
380
|
+
}), writes: [], removes: [], mayExecuteExternalProcess: false,
|
|
381
|
+
description: "Projects trajectory, action, execution, timing, and known usage metrics without mutating state.",
|
|
382
|
+
}),
|
|
383
|
+
eval: Object.freeze({
|
|
384
|
+
name: "eval", category: "diagnostics", mutation: "MUTATING",
|
|
385
|
+
options: Object.freeze({ ...CLI_COMMON_OPTIONS, ...CLI_TASK_OPTION,
|
|
386
|
+
"--scenario": Object.freeze({ targetKey: "scenarioPath", parseType: "string", takesValue: true, valueName: "path", missingValueMessage: "--scenario requires a path", description: "project-local trajectory scenario JSON" }),
|
|
387
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit evaluation as JSON" }),
|
|
388
|
+
}), writes: [".forgeloop/task-state/<taskKey>/evaluations/eval-<id>.json", ".forgeloop/task-state/<taskKey>/events.ndjson"], removes: [], mayExecuteExternalProcess: false,
|
|
389
|
+
description: "Evaluates the current trajectory against a validated project-local reference scenario.",
|
|
390
|
+
}),
|
|
391
|
+
"approval-request": Object.freeze({
|
|
392
|
+
name: "approval-request", category: "actions", mutation: "MUTATING",
|
|
393
|
+
options: Object.freeze({ ...CLI_COMMON_OPTIONS, ...CLI_TASK_OPTION,
|
|
394
|
+
"--approval": Object.freeze({ targetKey: "approvalId", parseType: "string", takesValue: true, valueName: "id", missingValueMessage: "--approval requires an ID", description: "approval artifact ID" }),
|
|
395
|
+
"--action": Object.freeze({ targetKey: "actionId", parseType: "string", takesValue: true, valueName: "id", missingValueMessage: "--action requires an ID", description: "bound action ID" }),
|
|
396
|
+
"--reason": Object.freeze({ targetKey: "reason", parseType: "string", takesValue: true, valueName: "text", missingValueMessage: "--reason requires text", description: "bounded approval reason" }),
|
|
397
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
398
|
+
}), writes: [".forgeloop/task-state/<taskKey>/approvals/approval-<id>.json", ".forgeloop/task-state/<taskKey>/events.ndjson"], removes: [], mayExecuteExternalProcess: false,
|
|
399
|
+
description: "Creates a durable fingerprint-bound approval request.",
|
|
400
|
+
}),
|
|
401
|
+
"approval-resolve": Object.freeze({
|
|
402
|
+
name: "approval-resolve", category: "actions", mutation: "MUTATING",
|
|
403
|
+
options: Object.freeze({ ...CLI_COMMON_OPTIONS, ...CLI_TASK_OPTION,
|
|
404
|
+
"--approval": Object.freeze({ targetKey: "approvalId", parseType: "string", takesValue: true, valueName: "id", missingValueMessage: "--approval requires an ID", description: "approval artifact ID" }),
|
|
405
|
+
"--decision": Object.freeze({ targetKey: "approvalDecision", parseType: "string", takesValue: true, valueName: "decision", missingValueMessage: "--decision requires APPROVED or REJECTED", description: "approval decision" }),
|
|
406
|
+
"--authority": Object.freeze({ targetKey: "approvalAuthorityKind", parseType: "string", takesValue: true, valueName: "kind", missingValueMessage: "--authority requires a kind", description: "CALLER_ACKNOWLEDGED or HOST_ATTESTED" }),
|
|
407
|
+
"--host-grant-ref": Object.freeze({ targetKey: "hostGrantRef", parseType: "string", takesValue: true, valueName: "ref", missingValueMessage: "--host-grant-ref requires a reference", description: "host boundary grant reference" }),
|
|
408
|
+
"--reason": Object.freeze({ targetKey: "reason", parseType: "string", takesValue: true, valueName: "text", missingValueMessage: "--reason requires text", description: "bounded resolution reason" }),
|
|
409
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
410
|
+
}), writes: [".forgeloop/task-state/<taskKey>/approvals/approval-<id>.json", ".forgeloop/task-state/<taskKey>/events.ndjson"], removes: [], mayExecuteExternalProcess: false,
|
|
411
|
+
description: "Resolves one durable approval exactly once.",
|
|
412
|
+
}),
|
|
289
413
|
"record-check": Object.freeze({
|
|
290
414
|
name: "record-check",
|
|
291
415
|
category: "verification",
|
|
@@ -338,6 +462,7 @@ export const CLI_COMMAND_DEFINITIONS = Object.freeze({
|
|
|
338
462
|
options: Object.freeze({
|
|
339
463
|
...CLI_COMMON_OPTIONS,
|
|
340
464
|
...CLI_TASK_OPTION,
|
|
465
|
+
"--file": Object.freeze({ targetKey: "file", parseType: "string", takesValue: true, valueName: "path", missingValueMessage: "--file requires a path", description: "structured diagnostic case JSON file (mutually exclusive with legacy diagnosis fields)" }),
|
|
341
466
|
"--hypothesis": Object.freeze({ targetKey: "hypothesis", parseType: "string", takesValue: true, valueName: "text", missingValueMessage: "--hypothesis requires text", description: "specific root-cause hypothesis explaining the verification failure" }),
|
|
342
467
|
"--failure-class": Object.freeze({ targetKey: "failureClass", parseType: "string", takesValue: true, valueName: "class", missingValueMessage: "--failure-class requires a class", description: "canonical failure class taxonomy" }),
|
|
343
468
|
"--evidence-ref": Object.freeze({ targetKey: "evidenceRefs", parseType: "string", takesValue: true, valueName: "check-id", repeatable: true, missingValueMessage: "--evidence-ref requires a check ID", description: "reference to failed/blocked check from current cycle" }),
|
|
@@ -348,7 +473,91 @@ export const CLI_COMMAND_DEFINITIONS = Object.freeze({
|
|
|
348
473
|
writes: [".forgeloop/task-state/<taskKey>/events.ndjson", ".forgeloop/task-state/<taskKey>/work-state.json"],
|
|
349
474
|
removes: [],
|
|
350
475
|
mayExecuteExternalProcess: false,
|
|
351
|
-
description: "Records an append-only diagnosis event in the lifecycle event ledger
|
|
476
|
+
description: "Records an append-only diagnosis event or structured diagnostic case in the lifecycle event ledger.",
|
|
477
|
+
}),
|
|
478
|
+
"record-intervention": Object.freeze({
|
|
479
|
+
name: "record-intervention",
|
|
480
|
+
category: "lifecycle",
|
|
481
|
+
mutation: "MUTATING",
|
|
482
|
+
options: Object.freeze({
|
|
483
|
+
...CLI_COMMON_OPTIONS,
|
|
484
|
+
...CLI_TASK_OPTION,
|
|
485
|
+
"--file": Object.freeze({ targetKey: "file", parseType: "string", takesValue: true, valueName: "path", missingValueMessage: "--file requires a path", description: "intervention JSON file describing the recorded change (never executed)" }),
|
|
486
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
487
|
+
}),
|
|
488
|
+
writes: [".forgeloop/task-state/<taskKey>/events.ndjson"],
|
|
489
|
+
removes: [],
|
|
490
|
+
mayExecuteExternalProcess: false,
|
|
491
|
+
description: "Records an append-only intervention bound to hypotheses; the described change is never executed by ForgeLoop.",
|
|
492
|
+
}),
|
|
493
|
+
"record-hypothesis-disposition": Object.freeze({
|
|
494
|
+
name: "record-hypothesis-disposition",
|
|
495
|
+
category: "lifecycle",
|
|
496
|
+
mutation: "MUTATING",
|
|
497
|
+
options: Object.freeze({
|
|
498
|
+
...CLI_COMMON_OPTIONS,
|
|
499
|
+
...CLI_TASK_OPTION,
|
|
500
|
+
"--hypothesis": Object.freeze({ targetKey: "hypothesis", parseType: "string", takesValue: true, valueName: "id", missingValueMessage: "--hypothesis requires a hypothesis ID", description: "existing hypothesis ID to disposition" }),
|
|
501
|
+
"--status": Object.freeze({ targetKey: "dispositionStatus", parseType: "string", takesValue: true, valueName: "status", missingValueMessage: "--status requires a status", description: "SUPPORTED, WEAKENED, FALSIFIED, SUPERSEDED, or UNRESOLVED" }),
|
|
502
|
+
"--evidence-ref": Object.freeze({ targetKey: "evidenceRefs", parseType: "string", takesValue: true, valueName: "check-id", repeatable: true, missingValueMessage: "--evidence-ref requires a check ID", description: "check ID supporting this disposition" }),
|
|
503
|
+
"--reason": Object.freeze({ targetKey: "reason", parseType: "string", takesValue: true, valueName: "text", missingValueMessage: "--reason requires text", description: "evidence-bound reason for the disposition" }),
|
|
504
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
505
|
+
}),
|
|
506
|
+
writes: [".forgeloop/task-state/<taskKey>/events.ndjson"],
|
|
507
|
+
removes: [],
|
|
508
|
+
mayExecuteExternalProcess: false,
|
|
509
|
+
description: "Records an evidence-bound hypothesis disposition update in the lifecycle event ledger.",
|
|
510
|
+
}),
|
|
511
|
+
history: Object.freeze({
|
|
512
|
+
name: "history",
|
|
513
|
+
category: "diagnostics",
|
|
514
|
+
mutation: "READ_ONLY",
|
|
515
|
+
options: Object.freeze({
|
|
516
|
+
...CLI_COMMON_OPTIONS,
|
|
517
|
+
...CLI_TASK_OPTION,
|
|
518
|
+
"--type": Object.freeze({ targetKey: "historyType", parseType: "string", takesValue: true, valueName: "list", missingValueMessage: "--type requires a value", description: "comma-separated event types or categories to include" }),
|
|
519
|
+
"--phase": Object.freeze({ targetKey: "historyPhase", parseType: "string", takesValue: true, valueName: "list", missingValueMessage: "--phase requires a value", description: "comma-separated lifecycle phases to include" }),
|
|
520
|
+
"--failures": Object.freeze({ targetKey: "historyFailures", parseType: "boolean", takesValue: false, description: "show only failed/blocked verification events" }),
|
|
521
|
+
"--checks": Object.freeze({ targetKey: "historyChecks", parseType: "boolean", takesValue: false, description: "show only verification events" }),
|
|
522
|
+
"--since": Object.freeze({ targetKey: "historySince", parseType: "string", takesValue: true, valueName: "timestamp", missingValueMessage: "--since requires a timestamp", description: "include events at or after this timestamp" }),
|
|
523
|
+
"--until": Object.freeze({ targetKey: "historyUntil", parseType: "string", takesValue: true, valueName: "timestamp", missingValueMessage: "--until requires a timestamp", description: "include events at or before this timestamp" }),
|
|
524
|
+
"--limit": Object.freeze({ targetKey: "historyLimit", parseType: "non-negative-integer", takesValue: true, valueName: "number", missingValueMessage: "--limit requires a non-negative integer", description: "show only the last N events after filtering" }),
|
|
525
|
+
"--compact": Object.freeze({ targetKey: "compact", parseType: "boolean", takesValue: false, description: "one line per event" }),
|
|
526
|
+
"--verbose": Object.freeze({ targetKey: "verbose", parseType: "boolean", takesValue: false, description: "show full event data" }),
|
|
527
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured history output as JSON" }),
|
|
528
|
+
}),
|
|
529
|
+
writes: [],
|
|
530
|
+
removes: [],
|
|
531
|
+
mayExecuteExternalProcess: false,
|
|
532
|
+
description: "Shows chronological protocol history reconstructed from canonical ForgeLoop state.",
|
|
533
|
+
}),
|
|
534
|
+
trace: Object.freeze({
|
|
535
|
+
name: "trace",
|
|
536
|
+
category: "diagnostics",
|
|
537
|
+
mutation: "READ_ONLY",
|
|
538
|
+
options: Object.freeze({
|
|
539
|
+
...CLI_COMMON_OPTIONS,
|
|
540
|
+
...CLI_TASK_OPTION,
|
|
541
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured trace output as JSON (default rendering is a summary)" }),
|
|
542
|
+
}),
|
|
543
|
+
writes: [],
|
|
544
|
+
removes: [],
|
|
545
|
+
mayExecuteExternalProcess: false,
|
|
546
|
+
description: "Emits detailed structured task trace with provenance and artifact relationships.",
|
|
547
|
+
}),
|
|
548
|
+
reflect: Object.freeze({
|
|
549
|
+
name: "reflect",
|
|
550
|
+
category: "diagnostics",
|
|
551
|
+
mutation: "READ_ONLY",
|
|
552
|
+
options: Object.freeze({
|
|
553
|
+
...CLI_COMMON_OPTIONS,
|
|
554
|
+
...CLI_TASK_OPTION,
|
|
555
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured reflection output as JSON" }),
|
|
556
|
+
}),
|
|
557
|
+
writes: [],
|
|
558
|
+
removes: [],
|
|
559
|
+
mayExecuteExternalProcess: false,
|
|
560
|
+
description: "Analyzes diagnostic and correction history deterministically for information gain, repeated failures, ineffective interventions, and oscillation.",
|
|
352
561
|
}),
|
|
353
562
|
progress: Object.freeze({
|
|
354
563
|
name: "progress",
|
|
@@ -767,10 +976,56 @@ export const CLI_COMMAND_DEFINITIONS = Object.freeze({
|
|
|
767
976
|
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
768
977
|
}),
|
|
769
978
|
writes: [],
|
|
770
|
-
removes: [".forgeloop/
|
|
979
|
+
removes: [".forgeloop/locks/<taskKey>.lock"],
|
|
771
980
|
mayExecuteExternalProcess: false,
|
|
772
981
|
description: "Removes an orphaned task lock file to recover an interrupted task.",
|
|
773
982
|
}),
|
|
983
|
+
"task-recover": Object.freeze({
|
|
984
|
+
name: "task-recover",
|
|
985
|
+
category: "project-maintenance",
|
|
986
|
+
mutation: "MUTATING",
|
|
987
|
+
options: Object.freeze({
|
|
988
|
+
...CLI_COMMON_OPTIONS,
|
|
989
|
+
...CLI_TASK_OPTION,
|
|
990
|
+
"--acknowledge-recovery": Object.freeze({ targetKey: "acknowledgeRecovery", parseType: "boolean", takesValue: false, description: "acknowledge release of claims for a STALE or ABANDONED task (required; not host attestation)" }),
|
|
991
|
+
"--operator-authorized": Object.freeze({ targetKey: "operatorAuthorized", parseType: "boolean", takesValue: false, description: "deprecated alias for --acknowledge-recovery; does not attest operator authority" }),
|
|
992
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
993
|
+
}),
|
|
994
|
+
writes: [".forgeloop/task-state/<taskKey>/recovery.json", ".forgeloop/task-state/<taskKey>/events.ndjson"],
|
|
995
|
+
removes: [],
|
|
996
|
+
mayExecuteExternalProcess: false,
|
|
997
|
+
description: "Caller-acknowledged recovery of a STALE or ABANDONED task; records durable state and releases effective write claims.",
|
|
998
|
+
}),
|
|
999
|
+
"task-repair-legacy-recovery": Object.freeze({
|
|
1000
|
+
name: "task-repair-legacy-recovery",
|
|
1001
|
+
category: "project-maintenance",
|
|
1002
|
+
mutation: "MUTATING",
|
|
1003
|
+
options: Object.freeze({
|
|
1004
|
+
...CLI_COMMON_OPTIONS,
|
|
1005
|
+
...CLI_TASK_OPTION,
|
|
1006
|
+
"--acknowledge-recovery": Object.freeze({ targetKey: "acknowledgeRecovery", parseType: "boolean", takesValue: false, description: "fresh explicit acknowledgement of the legacy boundary migration (required)" }),
|
|
1007
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
1008
|
+
}),
|
|
1009
|
+
writes: [".forgeloop/task-state/<taskKey>/recovery.json", ".forgeloop/task-state/<taskKey>/events.ndjson"],
|
|
1010
|
+
removes: [],
|
|
1011
|
+
mayExecuteExternalProcess: false,
|
|
1012
|
+
description: "Migrates one recognized legacy OPERATOR_RECOVERY_RECORDED boundary event into the modern durable recovery representation (append-only; original event unchanged).",
|
|
1013
|
+
}),
|
|
1014
|
+
"task-resume": Object.freeze({
|
|
1015
|
+
name: "task-resume",
|
|
1016
|
+
category: "project-maintenance",
|
|
1017
|
+
mutation: "MUTATING",
|
|
1018
|
+
options: Object.freeze({
|
|
1019
|
+
...CLI_COMMON_OPTIONS,
|
|
1020
|
+
...CLI_TASK_OPTION,
|
|
1021
|
+
"--claim": Object.freeze({ targetKey: "claims", parseType: "string", takesValue: true, repeatable: true, valueName: "path", missingValueMessage: "--claim requires a path", description: "write claim to reacquire (defaults to all released claims)" }),
|
|
1022
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
1023
|
+
}),
|
|
1024
|
+
writes: [".forgeloop/task-state/<taskKey>/task.json", ".forgeloop/task-state/<taskKey>/events.ndjson"],
|
|
1025
|
+
removes: [".forgeloop/task-state/<taskKey>/recovery.json"],
|
|
1026
|
+
mayExecuteExternalProcess: false,
|
|
1027
|
+
description: "Reacquires a recovered task's write claims under project serialization and restores ordinary mutation authority.",
|
|
1028
|
+
}),
|
|
774
1029
|
});
|
|
775
1030
|
|
|
776
1031
|
/**
|