@deksden-com/dd-flow-cli 0.9.0-beta.109 → 0.9.0-beta.110
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
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @deksden-com/dd-flow-cli
|
|
2
2
|
|
|
3
|
+
## 0.9.0-beta.110
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Pass retained runtime ownership to the ZCode ACP provider so managed Turns do not accept an inferred idle result as native completion. Reject an empty review set while PLAN-REVIEW is explicitly standard/deep, before publishing PLAN, and explain that mode in the shared PLAN prompt.
|
|
8
|
+
|
|
3
9
|
## 0.9.0-beta.109
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/dist/build-info.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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-09-
|
|
3
|
+
"cli_version": "0.9.0-beta.110",
|
|
4
|
+
"cli_commit": "dbb41705604e422795167f32b74fb92ee34fa1ae",
|
|
5
|
+
"built_at": "2026-09-27T09:03:36.141Z",
|
|
6
6
|
"built_with_canon": {
|
|
7
7
|
"version": "4.1.1",
|
|
8
8
|
"commit": "678daa038287c948ada5b2d785a6dcc925c7b891",
|
|
@@ -593,11 +593,16 @@ export class DaemonRuntime {
|
|
|
593
593
|
}
|
|
594
594
|
}
|
|
595
595
|
|
|
596
|
+
export function zcodeBridgeEnv(config, daemonId) {
|
|
597
|
+
return { ...config.env, DD_FLOW_DAEMON_ID: daemonId,
|
|
598
|
+
DD_FLOW_RUNTIME_OWNER: config.runtime_owner ? JSON.stringify(config.runtime_owner) : undefined };
|
|
599
|
+
}
|
|
600
|
+
|
|
596
601
|
export async function serveDaemon(stateDir) {
|
|
597
602
|
const paths = locations(stateDir);
|
|
598
603
|
const state = await readState(paths.dir);
|
|
599
604
|
if (!state || state.schema_id !== STATE_SCHEMA) throw new DaemonError("daemon_state_missing", "daemon state is missing or incompatible");
|
|
600
|
-
const bridge = new AcpBridge({ ...state.config, env:
|
|
605
|
+
const bridge = new AcpBridge({ ...state.config, env: zcodeBridgeEnv(state.config, state.daemon_id) });
|
|
601
606
|
const initialized = await startManagedBridge({ config: state.config, state, bridge, kind: "zcode-provider", publish: snapshot => writeState(paths.state, snapshot) });
|
|
602
607
|
const runtime = new DaemonRuntime(paths, state, bridge, initialized);
|
|
603
608
|
scheduleDaemonProcessHeartbeat(state.config, state.resource_process);
|
|
@@ -803,6 +803,7 @@ export function zcodeLifecycleQualification(sha256, bridgeCommit, harnessContrac
|
|
|
803
803
|
["8c0a893f3c26a0b96cb138acf762db84c800298b", ZCODE_HARNESS_CONTRACT],
|
|
804
804
|
["f4d47b517073f9bdb8d4eba3d0d59ce66c6a2833", "dd-zcode-harness@2"],
|
|
805
805
|
["5a8c89ab716a4b2ccc50df81cb4d204ff5c06368", "dd-zcode-harness@2"],
|
|
806
|
+
["91a1470650f5fd6105f9863fd31d1cad7b90a109", "dd-zcode-harness@2"],
|
|
806
807
|
]);
|
|
807
808
|
const qualified = qualifiedBridgeCommits.get(bridgeCommit) === harnessContract;
|
|
808
809
|
return { status: qualified ? "qualified" : "unqualified", mechanism: "cli-invocation@1", sha256,
|
|
@@ -91,6 +91,7 @@ export function startVnextPlan(context, input, prepared = prepareVnextPlanStart(
|
|
|
91
91
|
`${flowCommand(context)} schema validate --schema plan-aspect-map --file ${JSON.stringify(mapPaths[index])} --project-root ${JSON.stringify(run.workspace_root)} --run ${run.id} --json`
|
|
92
92
|
]);
|
|
93
93
|
const measuredCapacity = runVariables.variables[subagentCapacityKey];
|
|
94
|
+
const planReviewMode = requestedPlanReviewMode(context, project.id, run.id);
|
|
94
95
|
const capacityContext = typeof measuredCapacity === "number" && Number.isInteger(measuredCapacity) && measuredCapacity >= 0
|
|
95
96
|
? `- The qualified reviewer capacity is ${measuredCapacity}. This is a runtime fact for later PLAN-REVIEW dispatch; do not repeat qualification or invent a different value.`
|
|
96
97
|
: "- Reviewer capacity is not qualified yet. PLAN must not qualify or launch reviewers; an external harness controller supplies it before fan-out.";
|
|
@@ -107,7 +108,10 @@ export function startVnextPlan(context, input, prepared = prepareVnextPlanStart(
|
|
|
107
108
|
// This explicit final rule supersedes historical pack wording: a flow gate
|
|
108
109
|
// has only executable autonomous evidence. Human or external confirmation
|
|
109
110
|
// is neither a check nor a permitted completion condition.
|
|
110
|
-
|
|
111
|
+
const reviewModeRule = planReviewMode === "standard" || planReviewMode === "deep"
|
|
112
|
+
? `PLAN-REVIEW mode is ${planReviewMode}: assign at least one genuinely applicable aspect to a review group. Small feature size alone does not make every aspect not applicable; PLAN finish rejects an empty review set.`
|
|
113
|
+
: `PLAN-REVIEW mode is ${planReviewMode}: include review groups only for genuinely applicable aspects; an empty set is allowed.`;
|
|
114
|
+
fs.writeFileSync(promptPath, `${prompt}\n<review_mode_rule>${reviewModeRule}</review_mode_rule>\n<verification_rule>Every flow check must be an autonomous executable command. Do not declare external/manual proof or a human review as a check, evidence substitute, DEF, or gate. The only user interaction supported by this flow is an explicit stage pause for a material unanswered question.</verification_rule>\n${stageLifecycleInstruction}\n`);
|
|
111
115
|
const externalContext = applyExternalStageContext({ stageRoot: root, promptPath, ...(input.externalContext ? { loaded: input.externalContext } : {}) });
|
|
112
116
|
fs.writeFileSync(path.join(root, "work-context.json"), JSON.stringify({ schema_id: "dd-flow/work-context@1", system: { run_id: run.id, work_id: planWorkId, stage: "plan" }, workspace: { project_root: projectRoot, workspace_root: run.workspace_root, stage_root: root }, artifacts: artifactMaterialization, input: { protocols, owned_obligations: Object.fromEntries(owned) } }, null, 2));
|
|
113
117
|
const binding = bindStageCoordinatorWork(context, { workId: planWorkId, hookEventId: input.hookEventId, stage: "plan", promptPath, resultPath: path.join(root, "stage-report.json"), ...(input.contextSha256 ? { contextSha256: input.contextSha256 } : {}) });
|
|
@@ -193,6 +197,7 @@ export function prepareVnextPlanArtifacts(context, input) {
|
|
|
193
197
|
const workspaceRoot = input.workspaceRoot ?? input.projectRoot;
|
|
194
198
|
const planFiles = input.protocols.map((id) => path.join(workspaceRoot, ".memory-bank", "protocol", id, "plan.json"));
|
|
195
199
|
const mapFiles = input.protocols.map((id) => path.join(input.home, "03-plan", id, "aspect-map.json"));
|
|
200
|
+
let reviewGroupCount = 0;
|
|
196
201
|
const batch = path.join(input.home, "03-plan", "code-work-batch.json");
|
|
197
202
|
const ownership = protocolOwnership(input.home, input.protocols);
|
|
198
203
|
const obligations = acceptedObligations(input.home);
|
|
@@ -232,12 +237,19 @@ export function prepareVnextPlanArtifacts(context, input) {
|
|
|
232
237
|
throw new AppError("validation", "Accepted aspect-map requires normalization; regenerate it in PLAN", 2, { file });
|
|
233
238
|
const value = JSON.parse(bytes);
|
|
234
239
|
validateAspectMap(file, input.protocols, workspaceRoot, value);
|
|
240
|
+
reviewGroupCount += Array.isArray(value.review_groups) ? value.review_groups.length : 0;
|
|
235
241
|
publications.set(file, bytes);
|
|
236
242
|
}
|
|
237
243
|
catch (error) {
|
|
238
244
|
failures.push(validationFailure(file, error));
|
|
239
245
|
}
|
|
240
246
|
}
|
|
247
|
+
if (!failures.length && reviewGroupCount === 0) {
|
|
248
|
+
const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot));
|
|
249
|
+
const mode = requestedPlanReviewMode(context, project.id, input.runId);
|
|
250
|
+
if (mode === "standard" || mode === "deep")
|
|
251
|
+
failures.push(validationFailure(mapFiles[0] ?? batch, new AppError("validation", "Configured PLAN-REVIEW requires at least one applicable aspect and review group in the PLAN map", 2, { mode })));
|
|
252
|
+
}
|
|
241
253
|
if (!failures.length) {
|
|
242
254
|
try {
|
|
243
255
|
validatePsetCheckIdentity(plans);
|
|
@@ -670,6 +682,10 @@ function validatePsetCheckIdentity(plans) {
|
|
|
670
682
|
owners.set(check.id, plan.protocolId);
|
|
671
683
|
}
|
|
672
684
|
}
|
|
685
|
+
function requestedPlanReviewMode(context, projectId, runId) {
|
|
686
|
+
const row = context.db.get("SELECT index_json FROM runs WHERE project_id = ? AND id = ?", [projectId, runId]);
|
|
687
|
+
return JSON.parse(row?.index_json ?? "{}").settings?.plan_review?.mode ?? "auto";
|
|
688
|
+
}
|
|
673
689
|
function runEndsAtMerge(context, projectRoot, runId) {
|
|
674
690
|
const project = requireProjectByRoot(context, resolveProjectRoot(projectRoot));
|
|
675
691
|
const row = context.db.get("SELECT index_json FROM runs WHERE project_id = ? AND id = ?", [project.id, runId]);
|