@deksden-com/dd-flow-cli 0.9.0-beta.145 → 0.9.0-beta.149
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/CHANGELOG.md +71 -0
- package/dist/build-info.json +7 -7
- package/dist/cli/command-inputs.js +6 -2
- package/dist/cli/command-metadata.js +18 -2
- package/dist/cli/diagnostic-invocation.js +46 -0
- package/dist/cli/diagnostic.js +120 -0
- package/dist/cli/help.js +35 -0
- package/dist/cli/memory-flow-admission.js +4 -2
- package/dist/cli/memory-init.js +5 -2
- package/dist/cli/run-cli.js +16 -15
- package/dist/cli.js +6 -0
- package/dist/domain/diagnostic-aspects.js +103 -0
- package/dist/domain/diagnostic-flows.js +8 -0
- package/dist/harness-runtime/lib/agy-native-inspection.mjs +216 -0
- package/dist/harness-runtime/lib/agy-native_pb.js +117 -0
- package/dist/harness-runtime/lib/daemon-operations.d.mts +1 -0
- package/dist/harness-runtime/lib/daemon-operations.mjs +84 -10
- package/dist/harness-runtime/lib/dd-agy-daemon.mjs +306 -34
- package/dist/harness-runtime/lib/dd-codex-daemon.mjs +27 -13
- package/dist/harness-runtime/lib/dd-codex.mjs +4 -0
- package/dist/harness-runtime/lib/dd-droid-daemon.mjs +4 -3
- package/dist/harness-runtime/lib/dd-droid.mjs +70 -28
- package/dist/harness-runtime/lib/dd-grok-daemon.mjs +3 -3
- package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +66 -20
- package/dist/harness-runtime/lib/dd-opencode.mjs +30 -3
- package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +7 -6
- package/dist/harness-runtime/lib/driver-recovery.mjs +9 -8
- package/dist/harness-runtime/lib/managed-daemon.d.mts +1 -1
- package/dist/harness-runtime/lib/managed-daemon.mjs +11 -3
- package/dist/harness-runtime/lib/native-children.d.mts +8 -1
- package/dist/harness-runtime/lib/native-children.mjs +114 -8
- package/dist/harness-runtime/lib/native-request-proof.mjs +1 -1
- package/dist/harness-runtime/lib/observation-clock.d.mts +2 -2
- package/dist/harness-runtime/lib/observation-clock.mjs +7 -4
- package/dist/harness-runtime/lib/provider-overload-policy.d.mts +1 -1
- package/dist/harness-runtime/lib/provider-overload-policy.mjs +1 -1
- package/dist/harness-runtime/lib/tool-observations.mjs +1 -1
- package/dist/schemas/diagnostic-stage-result.schema.json +354 -0
- package/dist/schemas/diagnostic-work-result.schema.json +296 -0
- package/dist/schemas/execution-bundle.schema.json +7 -1
- package/dist/schemas/project-flow-pack-manifest.schema.json +1 -1
- package/dist/services/check-environment.js +21 -0
- package/dist/services/check-runner-evidence.js +267 -15
- package/dist/services/code-checks.js +23 -15
- package/dist/services/controller-execution.js +10 -4
- package/dist/services/controller-fanout.js +13 -6
- package/dist/services/controller-memory-worker.js +3 -2
- package/dist/services/dashboard.js +2 -2
- package/dist/services/descriptor-run-settlement.js +5 -3
- package/dist/services/descriptor-run-start.js +22 -3
- package/dist/services/descriptor-stage-coordinator.js +37 -4
- package/dist/services/descriptor-stage-settlement.js +2 -1
- package/dist/services/diagnostic-evidence.js +73 -0
- package/dist/services/diagnostic-report-publication.js +72 -0
- package/dist/services/diagnostic-report.js +67 -0
- package/dist/services/diagnostic-run-bundle.js +74 -0
- package/dist/services/diagnostic-snapshot.js +159 -0
- package/dist/services/diagnostic-stage-handlers.js +108 -0
- package/dist/services/diagnostic-stage-results.js +132 -0
- package/dist/services/diagnostic-start.js +84 -0
- package/dist/services/diagnostic-work-batch.js +34 -0
- package/dist/services/diagnostic-work-collection.js +97 -0
- package/dist/services/diagnostic-work-registration.js +101 -0
- package/dist/services/diagnostic-work-results.js +93 -0
- package/dist/services/eval-snapshots.js +85 -29
- package/dist/services/execution-bundles.js +19 -7
- package/dist/services/flow-catalog.js +6 -1
- package/dist/services/frozen-engine.js +37 -2
- package/dist/services/hybrid-contracts.js +2 -0
- package/dist/services/installed-flow-source.js +25 -3
- package/dist/services/lifecycle-invocations.js +147 -34
- package/dist/services/memory-init-contexts.js +16 -0
- package/dist/services/memory-init-controller-start.js +12 -4
- package/dist/services/memory-init-lint-capability.js +5 -5
- package/dist/services/memory-init-native-capacity.js +4 -4
- package/dist/services/memory-init-preflight.js +10 -16
- package/dist/services/memory-init-worktrunk-capability.js +3 -7
- package/dist/services/memory-layer.js +4 -3
- package/dist/services/memory-tool-probe.js +25 -0
- package/dist/services/memory-verification-checks.js +15 -4
- package/dist/services/native-daemon-history.js +2 -1
- package/dist/services/provider-capacity.js +43 -38
- package/dist/services/release-cache.js +8 -0
- package/dist/services/run-control.js +2 -1
- package/dist/services/run-controller-adapter.js +2 -1
- package/dist/services/run-controller-process.js +2 -1
- package/dist/services/run-controller-recovery.js +2 -1
- package/dist/services/run-controller.js +85 -15
- package/dist/services/run-fork.js +1 -1
- package/dist/services/runs.js +6 -1
- package/dist/services/runtime-scope-resume.js +12 -6
- package/dist/services/runtime-scope-stop.js +3 -2
- package/dist/services/runtime-service.js +2 -1
- package/dist/services/stage-handlers.js +16 -3
- package/dist/services/stage-pause.js +4 -1
- package/dist/services/version-status.js +1 -1
- package/dist/services/vnext-code.js +2 -2
- package/dist/services/vnext-fanout.js +31 -1
- package/dist/services/work-registry.js +37 -6
- package/dist/services/workspace-bootstrap.js +2 -1
- package/package.json +6 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,76 @@
|
|
|
1
1
|
# @deksden-com/dd-flow-cli
|
|
2
2
|
|
|
3
|
+
## 0.9.0-beta.149
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 54899ed: Publish explicit proven Codex and OpenCode shutdown activity, reject unknown activity as clean settlement, and decode OpenCode finite log synchronization markers consistently for revision and completion.
|
|
8
|
+
|
|
9
|
+
## 0.9.0-beta.148
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Validate lifecycle issuance before accessing storage, and align native readiness,
|
|
14
|
+
shutdown and overload regression fixtures with the current execution contract.
|
|
15
|
+
|
|
16
|
+
## 0.9.0-beta.147
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- Use the shared setup startup budget for silent prerequisite probes and preserve
|
|
21
|
+
typed subprocess failure diagnostics for init and upgrade without leaking output.
|
|
22
|
+
|
|
23
|
+
## 0.9.0-beta.146
|
|
24
|
+
|
|
25
|
+
### Patch Changes
|
|
26
|
+
|
|
27
|
+
- d031e09: Add owned, trajectory-bound read-only AGY node-state inspection for native qualification. Capture parent executor idle independently from required-tree readiness, native task inventories and pending completion messages. Preserve qualified production prompt/stop ordering and owned fixture cleanup in native acceptance tooling.
|
|
28
|
+
- acee374: Dispatch independent architectural criticism for Memory Bank audits when their accepted architecture aspect is applicable, matching the frozen review instructions.
|
|
29
|
+
- 709f281: Reject diagnostic citation hash mismatches as correctable no-effect proposal errors, returning only the assigned relative path and computed digest. Retain bounded lifecycle correction, strict evidence acceptance and fatal snapshot/custody protection.
|
|
30
|
+
- 18b0593: Treat unchanged-scope coverage annotations as correctable proposal errors and assign global diagnostic finding IDs from exact completed Work results during analysis settlement. Preserve strict scope, content, source and independent-review custody checks.
|
|
31
|
+
- 7457963: Reject rewritten diagnostic focus as a bounded, no-effect proposal correction
|
|
32
|
+
requiring an exact copy of the accepted predecessor. Foreign focus modes,
|
|
33
|
+
changed aspect applicability and ownership violations remain fatal; no changed
|
|
34
|
+
focus is accepted and no frozen source selection is rewritten.
|
|
35
|
+
- 1b315bf: Issue the exact immediate predecessor in diagnostic coordinator bindings and
|
|
36
|
+
align the frozen schema's list bound with the runtime contract. Transitive
|
|
37
|
+
history is a correctable proposal shape error; foreign direct bindings still
|
|
38
|
+
fail without acceptance.
|
|
39
|
+
- da5bbf0: Allow diagnostics to record newly discovered unavailable sources without treating
|
|
40
|
+
them as a scope change. Retain accepted source-gap observations independently of
|
|
41
|
+
coordinator paraphrasing, while keeping focus, coverage and source-custody guards.
|
|
42
|
+
- 6825b76: Allow diagnostic reports to disclose additional limitations while retaining all reviewed evidence, decisions and existing uncertainty unchanged.
|
|
43
|
+
- e779d4d: Express diagnostic analyst/critic field restrictions in the frozen Work schema.
|
|
44
|
+
An analyst supplying review decisions remains rejected, but uses the existing
|
|
45
|
+
correctable schema-output path rather than a fatal foreign-aspect error.
|
|
46
|
+
- 9939c87: Carry accepted predecessor and independently settled Work limitations into diagnostic analytical and review results in the CLI. Preserve coordinator annotations and raw proposals; retain schema bounds, scope, evidence and independent-review checks.
|
|
47
|
+
- b765022: Clarify that generated review observations are not original project evidence.
|
|
48
|
+
Reject missing snapshot citations as correctable no-effect result errors while
|
|
49
|
+
preserving fatal containment, non-file and filesystem-access failures.
|
|
50
|
+
- 249e5e3: Express preflight and analytical coordinator output boundaries in the frozen
|
|
51
|
+
stage schema, so unsupported findings or review decisions use existing format
|
|
52
|
+
correction while independent review remains mandatory.
|
|
53
|
+
- 6f4011f: Separate required native execution readiness from owned resource retirement across harnesses. Require versioned, incarnation-bound shutdown phase proofs and retain process birth identities before provider shutdown. Qualify AGY daemon readiness independently from physical cleanup; ambiguous ancestry and native service identities remain unproven.
|
|
54
|
+
|
|
55
|
+
Fence retained recovery by the current control generation and preserve late activity during shutdown publication. Add metadata-bound AGY native tree control for typed services, gated by complete native qualification; control acknowledgements never substitute for physical retirement.
|
|
56
|
+
|
|
57
|
+
- a5461c9: Preserve validated repair authority through lifecycle settlement, atomically issue
|
|
58
|
+
nonterminal successors, and retain accepted HITL context across same-session
|
|
59
|
+
overload continuation. Support versioned bounded runner and browser evidence,
|
|
60
|
+
and separate AGY physical shutdown from current native idle proof.
|
|
61
|
+
- e00cda9: Use the verified relocated engine when launching a forked hybrid RUN. Preserve
|
|
62
|
+
the original bundle and manifest bytes as provenance; reject changed executable
|
|
63
|
+
content, semantic manifest metadata, or an unbound relocation path.
|
|
64
|
+
- 759138b: Start restored generic-flow coordinator sessions in the current admitted RUN
|
|
65
|
+
workspace instead of the historical frozen execution path, without changing
|
|
66
|
+
retained execution bytes or profiles.
|
|
67
|
+
- 5bea245: Use the verified current RUN project and workspace paths when settling restored
|
|
68
|
+
descriptor stages and terminal RUNs. Preserve frozen provenance, ownership,
|
|
69
|
+
Git-drift checks and exact replay rather than querying historical project roots.
|
|
70
|
+
- 42cb47b: Read retained descriptor stage-input custody through trusted RUN publication
|
|
71
|
+
relocations after restore, preserving original packet bytes and rejecting
|
|
72
|
+
ambiguous or changed custody.
|
|
73
|
+
|
|
3
74
|
## 0.9.0-beta.145
|
|
4
75
|
|
|
5
76
|
### Patch Changes
|
package/dist/build-info.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"cli_package": "@deksden-com/dd-flow-cli",
|
|
3
|
-
"cli_version": "0.9.0-beta.
|
|
4
|
-
"cli_commit": "
|
|
5
|
-
"built_at": "2026-10-
|
|
3
|
+
"cli_version": "0.9.0-beta.149",
|
|
4
|
+
"cli_commit": "7d17167f768483ffdb5d37f64cc385035c7d4658",
|
|
5
|
+
"built_at": "2026-10-24T10:44:58.080Z",
|
|
6
6
|
"built_with_canon": {
|
|
7
7
|
"version": "4.1.2",
|
|
8
|
-
"commit": "
|
|
8
|
+
"commit": "925ef10ecc0b683f7feba6f74913e15560842500",
|
|
9
9
|
"flow_contract": "dd-flow-canonical-2026-08",
|
|
10
|
-
"repo_root": "/Users/deksden/Documents/_Projects/_worktrees/dd-canon-
|
|
11
|
-
"memorybank_root": "/Users/deksden/Documents/_Projects/_worktrees/dd-canon-
|
|
12
|
-
"flow_root": "/Users/deksden/Documents/_Projects/_worktrees/dd-canon-
|
|
10
|
+
"repo_root": "/Users/deksden/Documents/_Projects/_worktrees/dd-canon-release146",
|
|
11
|
+
"memorybank_root": "/Users/deksden/Documents/_Projects/_worktrees/dd-canon-release146/.memory-bank",
|
|
12
|
+
"flow_root": "/Users/deksden/Documents/_Projects/_worktrees/dd-canon-release146/.memory-bank/dd-flow",
|
|
13
13
|
"layout": "dot_memory_bank"
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -15,7 +15,8 @@ const control = "project-root run";
|
|
|
15
15
|
const protocolTransitionInput = route(1, "to", `${scoped} payload-file json-file reason`, "force");
|
|
16
16
|
const setupInput = route(0, "request-id trust-file", "canon-source canon-version release-registry channel profile profile-file save-profile-intent", "non-interactive skip-agent-setup", "", { channel: ["stable", "preview", "development"] });
|
|
17
17
|
const memoryInitInput = route(0, "project-root workspace-root request-id", "intake-file intake-sha256 profile profile-file stage-profile work-profile max-parallel delegation native-config-home git-route integration-branch", "detach non-interactive prepare-only allow-live-probe", "stage-profile work-profile", { "git-route": ["integration_branch_direct", "feature_worktree"], delegation: ["external", "native"] });
|
|
18
|
-
|
|
18
|
+
const diagnosticInput = route(0, "project-root request-id", "intake-file profile profile-file stage-profile work-profile max-parallel", "detach non-interactive prepare-only", "stage-profile work-profile");
|
|
19
|
+
export const commandAliases = { transition: "protocol transition", init: "flow mb-init", upgrade: "flow mb-upgrade", review: "flow project-review" };
|
|
19
20
|
/** Path-shaped arguments default to physical paths unless the route explicitly
|
|
20
21
|
* opts into contextualPaths. This inventory does not expand arbitrary strings. */
|
|
21
22
|
export const physicalPathOptions = new Set(words("canon-source trust-file root project-root workspace-root workspace-path workspace-path path dir file schema-dir output result-file semantic-file data decision-file verification-file reason-file task-file intake-file context-file observations-file observation-file summary-file question-file answer-file payload-file json-file task-profile-file execution-routing-file protocol-override-file manifest-file routing-file config-file input-file report-file snapshot-file output-dir state-dir capture-root capture-path destination source archive snapshot plan-file backup-path database backup source-home target-home stdout stderr adapter-executable memory-bank flow stage-report dashboard report"));
|
|
@@ -35,10 +36,13 @@ export const commandInputs = {
|
|
|
35
36
|
"init": memoryInitInput,
|
|
36
37
|
"flow mb-upgrade": memoryInitInput,
|
|
37
38
|
"upgrade": memoryInitInput,
|
|
39
|
+
"flow mb-audit": diagnosticInput,
|
|
40
|
+
"flow project-review": diagnosticInput,
|
|
41
|
+
"review": diagnosticInput,
|
|
38
42
|
"runtime storage admit": route(0, "operation", "", "", "", { operation: ["memory-init", "memory-upgrade"] }),
|
|
39
43
|
"runtime storage qualify": route(0, "operation", "", "", "", { operation: ["memory-upgrade"] }),
|
|
40
44
|
"runtime storage transition": route(0, "action project-root workspace-root request-id selection-sha256", "expected-sha256 recovery-id", "offline", "", { action: ["plan", "apply", "status", "recovery-plan", "recover", "recovery-status"] }),
|
|
41
|
-
"runtime flow admit": route(0, "operation", "", "", "", { operation: ["memory-init", "memory-upgrade"] }),
|
|
45
|
+
"runtime flow admit": route(0, "operation", "", "", "", { operation: ["memory-init", "memory-upgrade", "mb-audit", "project-review"] }),
|
|
42
46
|
"completion bash": route(0),
|
|
43
47
|
"completion zsh": route(0),
|
|
44
48
|
"completion fish": route(0),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { commandInputs, physicalPathOptions } from "./command-inputs.js";
|
|
1
|
+
import { commandInputs, commandAliases, physicalPathOptions } from "./command-inputs.js";
|
|
2
2
|
import { runtimeOptionDescriptions } from "./command-option-descriptions.js";
|
|
3
3
|
const optionDescriptions = {
|
|
4
4
|
"intake-sha256": "SHA-256 of the exact original intake file bytes. Fresh execution verifies the bytes; replay compares the retained hash without reopening the original file.",
|
|
@@ -61,6 +61,20 @@ const memoryInitOptions = {
|
|
|
61
61
|
"non-interactive": "Never open the first-flow executor dialog, even on a terminal. Without an explicit profile/file or configured default, refuse before project effects; init cannot skip its executor."
|
|
62
62
|
};
|
|
63
63
|
const commandOptionDescriptions = {
|
|
64
|
+
"flow mb-audit": {
|
|
65
|
+
"project-root": "Canonical absolute project identity. The runtime creates an isolated read-only source snapshot; neither the project nor its Memory Bank is a write destination.",
|
|
66
|
+
"intake-file": "Bounded UTF-8 original diagnostic request, including audit mode/focus and constraints. Required for a fresh request; optional on exact replay, where supplied bytes must match.",
|
|
67
|
+
"stage-profile": "Repeatable preflight/audit/review/report=profile override. Each stage may occur once and all profiles are frozen before dispatch.",
|
|
68
|
+
"prepare-only": "Retain the request, source snapshot and RUN without starting its controller or provider Sessions. Runtime state is created; this is not a dry run.",
|
|
69
|
+
"max-parallel": "External Work concurrency from 1 to 64; default 1. Never claims native child qualification."
|
|
70
|
+
},
|
|
71
|
+
"flow project-review": {
|
|
72
|
+
"project-root": "Canonical absolute project identity, assessed through an isolated read-only snapshot. Findings never authorize implicit repair.",
|
|
73
|
+
"intake-file": "Bounded UTF-8 original project-conformance review request and focus. Required fresh; supplied replay bytes must match the retained objective.",
|
|
74
|
+
"stage-profile": "Repeatable preflight/analyze/review/report=profile override. This is project review, not the SDLC CODE-REVIEW stage.",
|
|
75
|
+
"prepare-only": "Retain the request, source snapshot and RUN without launching a controller or provider Sessions. Not a dry run.",
|
|
76
|
+
"max-parallel": "External Work concurrency from 1 to 64; default 1."
|
|
77
|
+
},
|
|
64
78
|
"flow mb-init": memoryInitOptions,
|
|
65
79
|
init: memoryInitOptions,
|
|
66
80
|
"flow mb-upgrade": { ...memoryInitOptions, "stage-profile": "Repeatable stage=profile assignment for preflight, diff-analysis, upgrade, verify, review or finish. The original selection is frozen before dispatch.", "prepare-only": "Prepare or replay the upgrade RUN and accepted storage/bootstrap selection without launching its controller or a productive Session. This is not a dry run; it does not publish the upgraded canonical layer or accept semantic preservation." },
|
|
@@ -162,7 +176,8 @@ export function optionsForCommand(input, command) {
|
|
|
162
176
|
}));
|
|
163
177
|
}
|
|
164
178
|
function optionDescription(name, command) {
|
|
165
|
-
const description = (command ? commandOptionDescriptions[command]?.[name]
|
|
179
|
+
const description = (command ? commandOptionDescriptions[command]?.[name]
|
|
180
|
+
?? commandOptionDescriptions[commandAliases[command] ?? command]?.[name] : undefined) ?? optionDescriptions[name] ?? runtimeOptionDescriptions[name];
|
|
166
181
|
if (!description)
|
|
167
182
|
throw new Error(`Missing CLI option documentation: ${command ?? "inventory"} --${name}`);
|
|
168
183
|
return description;
|
|
@@ -182,6 +197,7 @@ export function optionsForCommandTree(command) {
|
|
|
182
197
|
export function routerNativeRoute(key) {
|
|
183
198
|
return key === "version" || key.startsWith("engine ") || key === "schema validate"
|
|
184
199
|
|| key === "flow list" || key === "flow show" || key === "flow mb-init" || key === "init" || key === "flow mb-upgrade" || key === "upgrade"
|
|
200
|
+
|| key === "flow mb-audit" || key === "flow project-review" || key === "review"
|
|
185
201
|
|| key === "run reconcile" || key === "runtime storage admit" || key === "runtime storage qualify" || key === "runtime storage transition"
|
|
186
202
|
|| key === "runtime flow admit"
|
|
187
203
|
|| key.startsWith("profiles ") || key.startsWith("models ") || key.startsWith("harnesses ") || key.startsWith("completion ") || key === "setup" || key.startsWith("setup ")
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { AppError } from "../shared/errors.js";
|
|
3
|
+
import { diagnosticFlowStages } from "../domain/diagnostic-flows.js";
|
|
4
|
+
import { prepareCommandRoute } from "./command-inputs.js";
|
|
5
|
+
function refuse(message) { throw new AppError("usage", message, 2, { effect: "no_effect" }); }
|
|
6
|
+
/** Parser only: no files, operator settings, project mutation or runtime state. */
|
|
7
|
+
export function prepareDiagnosticInvocation(args) {
|
|
8
|
+
const route = prepareCommandRoute(args), options = route.parsed.options;
|
|
9
|
+
const flowId = route.key === "flow mb-audit" ? "mb-audit"
|
|
10
|
+
: ["review", "flow project-review"].includes(route.key) ? "project-review" : refuse("Use flow mb-audit or review / flow project-review");
|
|
11
|
+
const value = (key) => options.get(key)?.[0];
|
|
12
|
+
const projectRoot = value("project-root"), requestId = value("request-id");
|
|
13
|
+
if (!path.isAbsolute(projectRoot) || path.resolve(projectRoot) !== projectRoot
|
|
14
|
+
|| !/^[A-Za-z0-9][A-Za-z0-9_.-]{0,95}$/.test(requestId))
|
|
15
|
+
refuse("Use a canonical absolute project root and a bounded request ID");
|
|
16
|
+
if (value("profile") && value("profile-file"))
|
|
17
|
+
refuse("Use either --profile or --profile-file");
|
|
18
|
+
if (options.has("detach") && options.has("prepare-only"))
|
|
19
|
+
refuse("--detach and --prepare-only are exclusive");
|
|
20
|
+
const execution = {};
|
|
21
|
+
if (value("profile"))
|
|
22
|
+
execution.rootProfile = value("profile");
|
|
23
|
+
const stageProfiles = {};
|
|
24
|
+
for (const assignment of options.get("stage-profile") ?? []) {
|
|
25
|
+
const match = /^([^=]+)=([^=]+)$/.exec(assignment);
|
|
26
|
+
if (!match || !diagnosticFlowStages[flowId].includes(match[1]) || Object.hasOwn(stageProfiles, match[1]))
|
|
27
|
+
refuse("--stage-profile requires one known stage=profile assignment per stage");
|
|
28
|
+
stageProfiles[match[1]] = match[2];
|
|
29
|
+
}
|
|
30
|
+
if (Object.keys(stageProfiles).length)
|
|
31
|
+
execution.stageProfiles = stageProfiles;
|
|
32
|
+
const workProfiles = options.get("work-profile");
|
|
33
|
+
if (workProfiles) {
|
|
34
|
+
if (workProfiles.some(id => !id.trim()) || new Set(workProfiles).size !== workProfiles.length)
|
|
35
|
+
refuse("Work profiles must be nonempty and unique");
|
|
36
|
+
execution.workProfiles = [...workProfiles];
|
|
37
|
+
}
|
|
38
|
+
if (value("max-parallel") !== undefined) {
|
|
39
|
+
const raw = value("max-parallel"), n = Number(raw);
|
|
40
|
+
if (!/^[1-9][0-9]*$/.test(raw) || !Number.isSafeInteger(n) || n > 64)
|
|
41
|
+
refuse("--max-parallel must be an integer from 1 to 64");
|
|
42
|
+
execution.delegation = { mode: "external", max_parallel: n };
|
|
43
|
+
}
|
|
44
|
+
return { scope: { projectRoot, requestId, flowId }, execution, profileFile: value("profile-file"), intakeFile: value("intake-file"),
|
|
45
|
+
detach: options.has("detach"), prepareOnly: options.has("prepare-only"), nonInteractive: options.has("non-interactive") };
|
|
46
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { createContext } from "../runtime/context.js";
|
|
2
|
+
import { AppError, errorRecord } from "../shared/errors.js";
|
|
3
|
+
import { resolveDdFlowHome, resolveProjectRoot } from "../storage/paths.js";
|
|
4
|
+
import { readSetupStatus } from "../services/setup.js";
|
|
5
|
+
import { PreparedInstalledFlowSource } from "../services/installed-flow-source.js";
|
|
6
|
+
import { selectMemoryInitInstalledEngine } from "../services/memory-init-engine-release.js";
|
|
7
|
+
import { readOperatorProfiles, readOperatorProfileInput } from "../services/operator-profiles.js";
|
|
8
|
+
import { FrozenGenericExecution } from "../services/generic-execution.js";
|
|
9
|
+
import { openMemoryInitStores } from "../services/memory-init-stores.js";
|
|
10
|
+
import { registerProject, requireProjectByRoot } from "../services/projects.js";
|
|
11
|
+
import { diagnosticSnapshotRoot } from "../services/diagnostic-snapshot.js";
|
|
12
|
+
import { readDiagnosticRequest, retainDiagnosticRequest, startDiagnosticRun } from "../services/diagnostic-start.js";
|
|
13
|
+
import { readFlowRunExecutionBundle } from "../services/runs.js";
|
|
14
|
+
import { hybridDigest } from "../services/hybrid-contracts.js";
|
|
15
|
+
import { onboardExecutor } from "../services/executor-onboarding.js";
|
|
16
|
+
import { askExecutorChoice } from "./executor-onboarding.js";
|
|
17
|
+
import { prepareDiagnosticInvocation } from "./diagnostic-invocation.js";
|
|
18
|
+
import { parseOutputOptions } from "./output-options.js";
|
|
19
|
+
import { prepareResponseDestination } from "./response-file.js";
|
|
20
|
+
import { prepareFileBytes } from "./input-preparation.js";
|
|
21
|
+
import { writePreparationError } from "./error-output.js";
|
|
22
|
+
import { launchAndObserveMemoryFlow } from "./memory-init.js";
|
|
23
|
+
import { publishSetup } from "../harness-runtime/lib/setup-progress.mjs";
|
|
24
|
+
export async function runDiagnosticCli(args, env = process.env, io = process) {
|
|
25
|
+
let context, effects = false;
|
|
26
|
+
try {
|
|
27
|
+
const output = parseOutputOptions(args), invocation = prepareDiagnosticInvocation(output.args), home = resolveDdFlowHome(env);
|
|
28
|
+
if (output.responseFile)
|
|
29
|
+
prepareResponseDestination(output.responseFile);
|
|
30
|
+
const scope = invocation.scope;
|
|
31
|
+
if (resolveProjectRoot(scope.projectRoot) !== scope.projectRoot)
|
|
32
|
+
throw new AppError("usage", "Project root must be canonical", 2, { effect: "no_effect" });
|
|
33
|
+
const reader = createContext(env, "read_existing");
|
|
34
|
+
let retained = null;
|
|
35
|
+
try {
|
|
36
|
+
const project = reader.db.get("SELECT status FROM projects WHERE root=?", [scope.projectRoot]);
|
|
37
|
+
if (project?.status && project.status !== "active")
|
|
38
|
+
throw new AppError("diagnostic_project_inactive", "Activate the selected project explicitly before diagnosis", 2, { effect: "no_effect" });
|
|
39
|
+
if (project)
|
|
40
|
+
retained = readDiagnosticRequest(reader, scope);
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
reader.db.close?.();
|
|
44
|
+
}
|
|
45
|
+
if (invocation.profileFile)
|
|
46
|
+
invocation.execution.rootProfile = readOperatorProfileInput(invocation.profileFile);
|
|
47
|
+
const readIntake = () => {
|
|
48
|
+
if (!invocation.intakeFile)
|
|
49
|
+
throw new AppError("usage", "Fresh diagnosis requires --intake-file with the requested focus and constraints", 2, { effect: "no_effect" });
|
|
50
|
+
const bytes = prepareFileBytes(invocation.intakeFile, "diagnostic intake", 64 * 1024).bytes;
|
|
51
|
+
let text;
|
|
52
|
+
try {
|
|
53
|
+
text = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
throw new AppError("usage", "Diagnostic intake must be UTF-8", 2, { effect: "no_effect" });
|
|
57
|
+
}
|
|
58
|
+
if (!text.trim())
|
|
59
|
+
throw new AppError("usage", "Diagnostic intake cannot be empty", 2, { effect: "no_effect" });
|
|
60
|
+
return text;
|
|
61
|
+
};
|
|
62
|
+
if (retained) {
|
|
63
|
+
if (Object.entries(invocation.execution).some(([key, value]) => !Object.hasOwn(retained.selection, key) || hybridDigest(value) !== hybridDigest(retained.selection[key]))
|
|
64
|
+
|| invocation.intakeFile && readIntake() !== retained.objective)
|
|
65
|
+
throw new AppError("diagnostic_request_conflict", "Supplied selectors differ from the original diagnostic request", 2, { effect: "no_effect" });
|
|
66
|
+
}
|
|
67
|
+
const objective = retained?.objective ?? readIntake();
|
|
68
|
+
let source, engine;
|
|
69
|
+
let rootProfile = invocation.execution.rootProfile;
|
|
70
|
+
if (!retained) {
|
|
71
|
+
const setup = readSetupStatus(home), installation = setup.installation;
|
|
72
|
+
if (!installation || setup.installation_readiness !== "installed")
|
|
73
|
+
throw new AppError("diagnostic_setup_required", "Install the desired canon and CLI with setup before diagnosis", 2, { effect: "no_effect" });
|
|
74
|
+
publishSetup("dependency_check_completed", "diagnostic:installation");
|
|
75
|
+
source = PreparedInstalledFlowSource.fromInstalledRelease(home, installation.manifest_sha256, scope.flowId);
|
|
76
|
+
publishSetup("dependency_check_completed", "diagnostic:canon");
|
|
77
|
+
engine = selectMemoryInitInstalledEngine(home, installation.manifest_sha256);
|
|
78
|
+
publishSetup("dependency_check_completed", "diagnostic:engine");
|
|
79
|
+
engine.admitDiagnosticFlow(source, scope.flowId);
|
|
80
|
+
publishSetup("dependency_check_completed", "diagnostic:handlers");
|
|
81
|
+
const stdin = io.stdin ?? process.stdin;
|
|
82
|
+
const selected = await onboardExecutor({ ...(typeof rootProfile === "string" ? { profileId: rootProfile } : {}),
|
|
83
|
+
...(invocation.profileFile ? { profileFile: invocation.profileFile } : {}) }, () => readOperatorProfiles(home), { allowSkip: false, nonInteractive: invocation.nonInteractive || output.json || output.progressJsonl
|
|
84
|
+
|| !stdin.isTTY || !io.stderr.isTTY }, settings => askExecutorChoice(settings, { stdin, stderr: io.stderr }, { allowSave: false, allowSkip: false }));
|
|
85
|
+
if (!selected.profile)
|
|
86
|
+
throw new AppError("diagnostic_executor_required", "Select an executor profile before diagnosis", 2, { effect: "no_effect" });
|
|
87
|
+
rootProfile ??= selected.profile;
|
|
88
|
+
}
|
|
89
|
+
effects = true;
|
|
90
|
+
context = openMemoryInitStores(env, { scope: { projectRoot: scope.projectRoot, workspaceRoot: scope.projectRoot, requestId: scope.requestId },
|
|
91
|
+
selectionSha256: hybridDigest({ scope, objective, selection: retained?.selection ?? invocation.execution }) }).context;
|
|
92
|
+
publishSetup("dependency_check_completed", "diagnostic:stores");
|
|
93
|
+
registerProject(context, { root: scope.projectRoot });
|
|
94
|
+
if (!retained) {
|
|
95
|
+
const project = requireProjectByRoot(context, scope.projectRoot);
|
|
96
|
+
const workspace = diagnosticSnapshotRoot(context, { projectId: project.id, projectRoot: scope.projectRoot, sourceRoot: scope.projectRoot,
|
|
97
|
+
requestId: scope.requestId, flowId: scope.flowId });
|
|
98
|
+
const execution = FrozenGenericExecution.prepare(source.resolveRegisteredFlow(), readOperatorProfiles(home), {
|
|
99
|
+
...invocation.execution, ...(rootProfile !== undefined ? { rootProfile } : {}), execution: "managed", stageSessionMode: "new_session",
|
|
100
|
+
delegation: invocation.execution.delegation ?? { mode: "external", max_parallel: 1 }
|
|
101
|
+
}, { requestId: scope.requestId, projectRoot: scope.projectRoot, workspace });
|
|
102
|
+
retainDiagnosticRequest(context, { scope, source: source, execution, engine: engine, objective, selection: invocation.execution });
|
|
103
|
+
}
|
|
104
|
+
const started = startDiagnosticRun(context, scope), bundle = readFlowRunExecutionBundle(context, { projectRoot: scope.projectRoot, runId: started.runId });
|
|
105
|
+
if (!bundle)
|
|
106
|
+
throw new AppError("diagnostic_bundle_missing", "Restore the retained diagnostic bundle", 1, { effect: "committed" });
|
|
107
|
+
return await launchAndObserveMemoryFlow(context, { ...invocation,
|
|
108
|
+
scope: { projectRoot: scope.projectRoot, workspaceRoot: bundle.execution.snapshot().scope.workspace, requestId: scope.requestId } }, started, scope.flowId, output, env, io);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
const record = errorRecord(error);
|
|
112
|
+
if (effects)
|
|
113
|
+
record.details = { ...record.details, effect: ["unknown", "committed", "partial"].includes(String(record.details.effect)) ? record.details.effect : "partial", next_action: "reconcile_exact_request" };
|
|
114
|
+
writePreparationError(io, args, record);
|
|
115
|
+
return record.exitCode;
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
context?.db.close?.();
|
|
119
|
+
}
|
|
120
|
+
}
|
package/dist/cli/help.js
CHANGED
|
@@ -2,6 +2,41 @@ import { AppError } from "../shared/errors.js";
|
|
|
2
2
|
import { commandInputs, commandAliases } from "./command-inputs.js";
|
|
3
3
|
import { commandKeyForPositions, globalOptionDocumentation, optionsForCommandTree, routerNativeRoute } from "./command-metadata.js";
|
|
4
4
|
const helpPages = new Map([
|
|
5
|
+
["flow mb-audit", `dd-flow flow mb-audit - read-only Memory Bank audit
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
dd-flow flow mb-audit --project-root /absolute/project --request-id ID --intake-file /absolute/request.txt [--profile ID] --json
|
|
9
|
+
|
|
10
|
+
Describe quick/full or focused audit scope in the original intake. Stages are
|
|
11
|
+
preflight → audit → review → report. Applicable aspects use assigned read-only
|
|
12
|
+
Work and independent critics. Missing evidence and active DEFs remain visible.
|
|
13
|
+
Reports and runtime state live in DD_FLOW_HOME; project files are not repaired.
|
|
14
|
+
The snapshot includes selected dirty/untracked source, excluding private inputs.
|
|
15
|
+
|
|
16
|
+
Profiles, engine, canon and objective are frozen before dispatch. Exact replay
|
|
17
|
+
may omit intake/profile selectors; supplied selectors must match the original.
|
|
18
|
+
--prepare-only creates the snapshot and RUN without Sessions; --detach returns
|
|
19
|
+
the controller receipt. Neither is a dry run. Default execution is managed,
|
|
20
|
+
with fresh stage Sessions and external Work (concurrency 1).
|
|
21
|
+
Use existing run drive status and run control commands for observation/recovery.`],
|
|
22
|
+
["flow project-review", `dd-flow review / flow project-review - read-only project-conformance review
|
|
23
|
+
|
|
24
|
+
Usage:
|
|
25
|
+
dd-flow review --project-root /absolute/project --request-id ID --intake-file /absolute/request.txt [--profile ID] --json
|
|
26
|
+
|
|
27
|
+
Both spellings share validation and effects. Describe the review focus and
|
|
28
|
+
constraints in the original intake. Stages are preflight → analyze → review →
|
|
29
|
+
report. Compare specs, features, ADRs, scenarios and policy with actual code and
|
|
30
|
+
evidence. This is not SDLC CODE-REVIEW and never implicitly repairs the project.
|
|
31
|
+
All baseline aspects retain applicability and coverage; independent criticism,
|
|
32
|
+
rejected findings and uncertainty remain in runtime evidence.
|
|
33
|
+
|
|
34
|
+
Execution uses an isolated read-only snapshot and frozen global canon. No local
|
|
35
|
+
Memory Bank installation is required. Profiles and the original request remain
|
|
36
|
+
pinned on replay. --prepare-only creates runtime state without Sessions;
|
|
37
|
+
--detach returns the accepted controller receipt. Default execution is managed,
|
|
38
|
+
with fresh stage Sessions and external Work. Use run drive status / run control
|
|
39
|
+
to observe, answer, stop or reconcile the exact retained RUN.`],
|
|
5
40
|
["runtime storage qualify", `dd-flow runtime storage qualify - pre-probe selected-engine capability
|
|
6
41
|
|
|
7
42
|
--operation memory-upgrade checks existing storage with the executing engine.
|
|
@@ -6,6 +6,7 @@ import { hybridDigest } from "../services/hybrid-contracts.js";
|
|
|
6
6
|
import { AppError, errorRecord } from "../shared/errors.js";
|
|
7
7
|
import { writePreparationError } from "./error-output.js";
|
|
8
8
|
import { memoryInitStartupInputSchemas } from "../services/memory-init-startup-custody.js";
|
|
9
|
+
import { isDiagnosticFlow } from "../domain/diagnostic-flows.js";
|
|
9
10
|
/** Executing engine's real handler admission only. The caller owns independent
|
|
10
11
|
* release/source selection; this command never opens storage or creates a RUN. */
|
|
11
12
|
export async function runMemoryFlowAdmissionCli(args, io = process) {
|
|
@@ -20,7 +21,8 @@ export async function runMemoryFlowAdmissionCli(args, io = process) {
|
|
|
20
21
|
throw new AppError("usage", "Flow admission requires an exact source snapshot and independent digest", 2, { effect: "no_effect" });
|
|
21
22
|
}
|
|
22
23
|
const selected = input;
|
|
23
|
-
const
|
|
24
|
+
const operation = route.parsed.options.get("operation")?.[0] ?? "";
|
|
25
|
+
const flowId = isDiagnosticFlow(operation) ? operation : operation === "memory-upgrade" ? "mb-upgrade" : "mb-init";
|
|
24
26
|
const startupSchema = memoryInitStartupInputSchemas.find(schema => schema === selected.startup_input_schema);
|
|
25
27
|
if (Object.hasOwn(selected, "startup_input_schema") && (startupSchema === undefined || flowId !== "mb-init")) {
|
|
26
28
|
throw new AppError("usage", "Executing engine does not support the requested startup input schema", 2, { effect: "no_effect" });
|
|
@@ -32,7 +34,7 @@ export async function runMemoryFlowAdmissionCli(args, io = process) {
|
|
|
32
34
|
const flow = source.resolveRegisteredFlow();
|
|
33
35
|
if (flow.descriptor.id !== flowId)
|
|
34
36
|
throw new AppError("usage", "Flow source does not match the requested engine admission operation", 2, { effect: "no_effect" });
|
|
35
|
-
const facts = { schema_id: flowId === "mb-upgrade" ? "dd-flow/memory-upgrade-engine-flow@1"
|
|
37
|
+
const facts = { schema_id: isDiagnosticFlow(flowId) ? "dd-flow/diagnostic-engine-flow@1" : flowId === "mb-upgrade" ? "dd-flow/memory-upgrade-engine-flow@1"
|
|
36
38
|
: startupSchema === undefined ? "dd-flow/memory-init-engine-flow@1" : "dd-flow/memory-init-engine-flow@2",
|
|
37
39
|
...(startupSchema === undefined ? {} : { startup_input_schema: startupSchema }),
|
|
38
40
|
flow_id: flowId, source_sha256: source.sha256,
|
package/dist/cli/memory-init.js
CHANGED
|
@@ -28,6 +28,8 @@ import { onboardExecutor } from "../services/executor-onboarding.js";
|
|
|
28
28
|
import { readOperatorProfiles, readOperatorProfileInput } from "../services/operator-profiles.js";
|
|
29
29
|
import { resolveDdFlowHome } from "../storage/paths.js";
|
|
30
30
|
import { askExecutorChoice } from "./executor-onboarding.js";
|
|
31
|
+
import { isDiagnosticFlow } from "../domain/diagnostic-flows.js";
|
|
32
|
+
import { prepareDiagnosticControllerStart } from "../services/memory-init-controller-start.js";
|
|
31
33
|
/** Backpressure bounds the observing client's output; closing it never controls the RUN. */
|
|
32
34
|
export async function writeMemoryInitObservation(stdout, text) {
|
|
33
35
|
const disconnected = () => Boolean(stdout.destroyed);
|
|
@@ -175,7 +177,7 @@ export async function runMemoryInitCli(args, env = process.env, io = process) {
|
|
|
175
177
|
/** Shared foreground observer only; the existing RUN-bound controller owns
|
|
176
178
|
* physical Sessions. Neither alias gains another orchestration lifecycle. */
|
|
177
179
|
export async function launchAndObserveMemoryFlow(context, invocation, started, flowId, output, env, io) {
|
|
178
|
-
const action = flowId
|
|
180
|
+
const action = `flow_${flowId.replaceAll("-", "_")}`;
|
|
179
181
|
if (invocation.prepareOnly) {
|
|
180
182
|
const run = requireRun(context, requireProjectByRoot(context, invocation.scope.projectRoot).id, started.runId);
|
|
181
183
|
const response = { ok: true, action: `${action}_prepared`, flow_id: flowId, ...started,
|
|
@@ -184,7 +186,8 @@ export async function launchAndObserveMemoryFlow(context, invocation, started, f
|
|
|
184
186
|
await writeMemoryInitObservation(io.stdout, `${JSON.stringify(writeResponseFile(response, output), null, output.json || output.progressJsonl ? undefined : 2)}\n`);
|
|
185
187
|
return 0;
|
|
186
188
|
}
|
|
187
|
-
const launch = (flowId
|
|
189
|
+
const launch = isDiagnosticFlow(flowId) ? prepareDiagnosticControllerStart(context, invocation.scope, flowId)
|
|
190
|
+
: (flowId === "mb-init" ? prepareMemoryInitControllerStart : prepareMemoryUpgradeControllerStart)(context, invocation.scope);
|
|
188
191
|
// Use the existing RUN-bound router: a global CLI must not launch its own
|
|
189
192
|
// controller code in place of the independently frozen RUN executable.
|
|
190
193
|
const receiptChunks = [];
|
package/dist/cli/run-cli.js
CHANGED
|
@@ -65,6 +65,8 @@ import { isVnextCodeReviewRun, prepareCodeReviewDecision, prepareVnextCodeReview
|
|
|
65
65
|
import { applyVnextMerge, getVnextMergeRequest, isVnextMergeRun, prepareVnextMergeFinish, prepareVnextMergeStart, repairVnextMerge, routeVnextMergeRequest } from "../services/vnext-merge.js";
|
|
66
66
|
import { sdlcStageHandlers } from "../services/stage-handlers.js";
|
|
67
67
|
import { startMemoryStage, finishMemoryStage, startMemoryUpgradeStage, finishMemoryUpgradeStage } from "../services/memory-stage-dispatch.js";
|
|
68
|
+
import { startDiagnosticStage, finishDiagnosticStage } from "../services/diagnostic-stage-handlers.js";
|
|
69
|
+
import { isDiagnosticFlow } from "../domain/diagnostic-flows.js";
|
|
68
70
|
import { bindStageCoordinatorWork } from "../services/work-registry.js";
|
|
69
71
|
import { registerMemoryCompositionFromStage, publishMemoryUpgradeFromStage } from "../services/memory-compose-handler.js";
|
|
70
72
|
import { runMemoryVerificationChecks } from "../services/memory-verify-handler.js";
|
|
@@ -75,7 +77,7 @@ import { registerMemoryCorrectionsFromStage, registerMemorySecondCorrectionsFrom
|
|
|
75
77
|
import { integrateMemoryFinishFromStage, registerMemoryFinishEvidenceFromStage } from "../services/memory-finish-handler.js";
|
|
76
78
|
import { registerMemoryRepairBaselineFromStage, registerMemorySecondRepairBaselineFromStage, reserveMemoryRepairWriterCopyFromStage, reserveMemorySecondRepairCopyFromStage, materializeMemoryRepairWriterCopyFromStage, materializeMemorySecondRepairCopyFromStage, prepareMemoryRepairDispatchFromStage, prepareMemorySecondRepairDispatchFromStage, registerMemoryRepairCurrentViewFromStage, registerMemorySecondRepairCurrentViewFromStage, registerMemoryRepairPublicationSourceFromStage, reserveMemoryRepairPublicationAgainstSourceFromStage, reserveMemorySecondRepairPublicationFromStage, applyMemoryRepairPublicationFromStage, applyMemorySecondRepairPublicationFromStage, finishMemoryRepairPublicationFromStage, finishMemorySecondRepairPublicationFromStage } from "../services/memory-review-handler.js";
|
|
77
79
|
import { mergeServerStatus, serveMergeRequests, stopMergeServer } from "../services/merge-server.js";
|
|
78
|
-
import { getVnextFanoutStatus, memoryStageFanoutDescriptor, observeVnextNativeChildren, prepareNativeObservations, reconcileVnextFanout } from "../services/vnext-fanout.js";
|
|
80
|
+
import { getVnextFanoutStatus, memoryStageFanoutDescriptor, diagnosticStageFanoutDescriptor, observeVnextNativeChildren, prepareNativeObservations, reconcileVnextFanout } from "../services/vnext-fanout.js";
|
|
79
81
|
import { pauseStageForUser, resumeStageAfterUser, prepareStagePause, prepareStageResume, stagePauseCommand } from "../services/stage-pause.js";
|
|
80
82
|
import { runtimeCommand } from "../services/runtime-command.js";
|
|
81
83
|
import { managedLifecycleCommand } from "../services/lifecycle-invocations.js";
|
|
@@ -483,11 +485,9 @@ async function runCliRequest(args, io, env) {
|
|
|
483
485
|
if (isAppError(error)) {
|
|
484
486
|
delete error.details.retry_command;
|
|
485
487
|
delete error.details.retry_instruction;
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
// the original rejection which has no successor authority.
|
|
490
|
-
Object.assign(error.details, settled.details);
|
|
488
|
+
// The common settlement classifies original validated proof before
|
|
489
|
+
// errorRecord clones diagnostic objects and loses capability identity.
|
|
490
|
+
settleLifecycleRejection(invocationSettlement.context, invocationSettlement.id, error);
|
|
491
491
|
}
|
|
492
492
|
else
|
|
493
493
|
settleLifecycleInvocation(invocationSettlement.context, invocationSettlement.id, { error: { code: "unexpected", message: String(error), exitCode: 1, details: {} } });
|
|
@@ -1232,7 +1232,7 @@ async function prepareCliInputValue(args, context, io, scopeProjectRoot, respons
|
|
|
1232
1232
|
const bundle = readFlowRunExecutionBundle(context, { projectRoot: requiredOption(parsed, "project-root"), runId: requiredPosition(parsed, 0, "run-id") });
|
|
1233
1233
|
if (bundle)
|
|
1234
1234
|
prepared.stageBindingBundle = { stage, bundle, ...(contextSha256 ? { contextSha256 } : {}) };
|
|
1235
|
-
if (bundle && ["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id)) {
|
|
1235
|
+
if (bundle && (["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id) || isDiagnosticFlow(bundle.descriptor.descriptor.id))) {
|
|
1236
1236
|
bundle.descriptor.stage(stage);
|
|
1237
1237
|
if (hasOption(parsed, "dir"))
|
|
1238
1238
|
throw new AppError("usage", "Memory stage layout belongs to its frozen descriptor", 2);
|
|
@@ -1240,7 +1240,7 @@ async function prepareCliInputValue(args, context, io, scopeProjectRoot, respons
|
|
|
1240
1240
|
if (loaded)
|
|
1241
1241
|
prepared.stageStart = { externalContext: loaded };
|
|
1242
1242
|
prepared.memoryStage = { operation: "start", bytes: loaded ? Buffer.from(loaded.bytes) : Buffer.alloc(0),
|
|
1243
|
-
flowId: bundle.descriptor.descriptor.id === "mb-upgrade" ? "mb-upgrade" : "mb-init" };
|
|
1243
|
+
flowId: isDiagnosticFlow(bundle.descriptor.descriptor.id) ? bundle.descriptor.descriptor.id : bundle.descriptor.descriptor.id === "mb-upgrade" ? "mb-upgrade" : "mb-init" };
|
|
1244
1244
|
return prepared;
|
|
1245
1245
|
}
|
|
1246
1246
|
}
|
|
@@ -1374,10 +1374,11 @@ async function prepareCliInputValue(args, context, io, scopeProjectRoot, respons
|
|
|
1374
1374
|
const semanticFile = optionalOption(parsed, "semantic-file") ?? optionalOption(parsed, "data");
|
|
1375
1375
|
const resultFile = optionalOption(parsed, "result-file") ?? semanticFile;
|
|
1376
1376
|
const runtime = run(projectRoot, runId);
|
|
1377
|
-
|
|
1377
|
+
const retainedFlowId = JSON.parse(runtime.indexJson).execution_bundle?.flow_id;
|
|
1378
|
+
if (["mb-init", "mb-upgrade"].includes(retainedFlowId) || isDiagnosticFlow(retainedFlowId)) {
|
|
1378
1379
|
const bundle = readFlowRunExecutionBundle(context, { projectRoot, runId });
|
|
1379
|
-
if (!bundle || !["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id))
|
|
1380
|
-
throw new AppError("cli_input_unprepared", "
|
|
1380
|
+
if (!bundle || !["mb-init", "mb-upgrade"].includes(bundle.descriptor.descriptor.id) && !isDiagnosticFlow(bundle.descriptor.descriptor.id))
|
|
1381
|
+
throw new AppError("cli_input_unprepared", "Registered RUN bundle is unavailable", 1);
|
|
1381
1382
|
bundle.descriptor.stage(stage);
|
|
1382
1383
|
if (["dir", "outcome", "decision-file", "verification-file", "retry-check", "reason", "reason-file", "request", "work"].some(option => hasOption(parsed, option)))
|
|
1383
1384
|
throw new AppError("usage", "Memory stage finish requires its registered JSON result, not legacy result options", 2);
|
|
@@ -1386,7 +1387,7 @@ async function prepareCliInputValue(args, context, io, scopeProjectRoot, respons
|
|
|
1386
1387
|
const bytes = resultStdin ? Buffer.from(await readStdin(io.stdin, 1024 * 1024)) : prepareFileBytes(resultFile, "Memory stage result", 1024 * 1024).bytes;
|
|
1387
1388
|
if (!bytes.length || bytes.length > 1024 * 1024)
|
|
1388
1389
|
throw new AppError("usage", "Memory stage result exceeds its byte bound", 2);
|
|
1389
|
-
prepared.memoryStage = { operation: "finish", bytes, flowId: bundle.descriptor.descriptor.id === "mb-upgrade" ? "mb-upgrade" : "mb-init" };
|
|
1390
|
+
prepared.memoryStage = { operation: "finish", bytes, flowId: isDiagnosticFlow(bundle.descriptor.descriptor.id) ? bundle.descriptor.descriptor.id : bundle.descriptor.descriptor.id === "mb-upgrade" ? "mb-upgrade" : "mb-init" };
|
|
1390
1391
|
return prepared;
|
|
1391
1392
|
}
|
|
1392
1393
|
const terminalReplay = (name) => {
|
|
@@ -1780,7 +1781,7 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
|
|
|
1780
1781
|
matchKey: entityReferenceVariants(runId).map(reference => stageStartMatchKey(reference, stage, projectRoot, contextSha256)),
|
|
1781
1782
|
errorCode: "trusted_session_binding_required", operation: "Memory stage start"
|
|
1782
1783
|
}).eventKey;
|
|
1783
|
-
const work = (prepared.memoryStage.flowId === "mb-upgrade" ? startMemoryUpgradeStage : startMemoryStage)(context, { projectRoot, runId, stage, bytes: prepared.memoryStage.bytes });
|
|
1784
|
+
const work = (isDiagnosticFlow(prepared.memoryStage.flowId) ? startDiagnosticStage : prepared.memoryStage.flowId === "mb-upgrade" ? startMemoryUpgradeStage : startMemoryStage)(context, { projectRoot, runId, stage, bytes: prepared.memoryStage.bytes });
|
|
1784
1785
|
try {
|
|
1785
1786
|
const binding = bindStageCoordinatorWork(context, { workId: work.work_id, hookEventId: event, stage,
|
|
1786
1787
|
promptPath: work.prompt_path, resultPath: work.result_path, ...(contextSha256 ? { contextSha256 } : {}) });
|
|
@@ -1790,7 +1791,7 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
|
|
|
1790
1791
|
const finish = managedLifecycleCommand(context, runtimeCommand(context, ["stage", "finish", runId,
|
|
1791
1792
|
"--stage", stage, "--project-root", projectRoot, "--result-file", work.result_path, "--json"]));
|
|
1792
1793
|
const pause = stagePauseCommand(context, { projectRoot, runId, stage, workId: work.work_id });
|
|
1793
|
-
const orchestration = memoryStageFanoutDescriptor(context, { projectRoot, runId, stage });
|
|
1794
|
+
const orchestration = memoryStageFanoutDescriptor(context, { projectRoot, runId, stage }) ?? diagnosticStageFanoutDescriptor(context, { projectRoot, runId, stage });
|
|
1794
1795
|
const delivery = { ...work, binding, ...(orchestration ? { orchestration } : {}), next: { finish_command: finish, pause_command: pause },
|
|
1795
1796
|
worker_prompt_markdown: `${work.worker_prompt_markdown}\n## Current lifecycle commands\n\nWrite the semantic result to the assigned result path, then execute exactly:\n${finish}\n\nFor a required user choice, write the question file named by this command, then execute exactly:\n${pause}\n` };
|
|
1796
1797
|
bindLifecyclePublishedPacket(context, delivery.worker_prompt_markdown);
|
|
@@ -1899,7 +1900,7 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
|
|
|
1899
1900
|
// Descriptor settlement validates exact coordinator custody and claims
|
|
1900
1901
|
// the fresh hook atomically with result acceptance. Do not consume it
|
|
1901
1902
|
// through the SDLC lifecycle owner before that settlement.
|
|
1902
|
-
return controlledReply((prepared.memoryStage.flowId === "mb-upgrade" ? finishMemoryUpgradeStage : finishMemoryStage)(context, { projectRoot, runId, stage, bytes: prepared.memoryStage.bytes,
|
|
1903
|
+
return controlledReply((isDiagnosticFlow(prepared.memoryStage.flowId) ? finishDiagnosticStage : prepared.memoryStage.flowId === "mb-upgrade" ? finishMemoryUpgradeStage : finishMemoryStage)(context, { projectRoot, runId, stage, bytes: prepared.memoryStage.bytes,
|
|
1903
1904
|
hookEventId: hookEventId ?? findRecentMatchingHookEvent(context, {
|
|
1904
1905
|
projectId: requireProjectByRoot(context, resolveProjectRoot(projectRoot)).id,
|
|
1905
1906
|
matchKey: entityReferenceVariants(runId).map(reference => stageLifecycleMatchKey("stage_finish", reference, stage, projectRoot)),
|
package/dist/cli.js
CHANGED
|
@@ -53,6 +53,12 @@ if (args[0] === "upgrade" || args[0] === "flow" && args[1] === "mb-upgrade") {
|
|
|
53
53
|
const { runMemoryUpgradeCli } = await import("./cli/memory-upgrade.js");
|
|
54
54
|
process.exit(await runMemoryUpgradeCli(args, process.env));
|
|
55
55
|
}
|
|
56
|
+
if (args[0] === "review" || args[0] === "flow" && ["mb-audit", "project-review"].includes(args[1] ?? "")) {
|
|
57
|
+
publishSetup('ingress_entered');
|
|
58
|
+
const { runDiagnosticCli } = await import("./cli/diagnostic.js");
|
|
59
|
+
publishSetup('imports_ready');
|
|
60
|
+
process.exit(await runDiagnosticCli(args, process.env));
|
|
61
|
+
}
|
|
56
62
|
if (args.slice(0, 3).join(" ") === "runtime storage admit") {
|
|
57
63
|
const { runMemoryStorageAdmissionCli } = await import("./cli/memory-storage-admission.js");
|
|
58
64
|
process.exit(runMemoryStorageAdmissionCli(args));
|