@deksden-com/dd-flow-cli 0.7.0 → 0.8.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/CHANGELOG.md +666 -0
- package/README.md +7 -2
- package/dist/build-info.json +5 -5
- package/dist/cli/help.js +88 -10
- package/dist/cli/run-cli.js +523 -28
- package/dist/domain/stage-catalog.js +22 -0
- package/dist/domain/validation.js +1 -1
- package/dist/schemas/code-review-decision.schema.json +26 -0
- package/dist/schemas/code-review-result.schema.json +14 -0
- package/dist/schemas/code-verification.schema.json +14 -0
- package/dist/schemas/code-work-batch.schema.json +24 -0
- package/dist/schemas/code-work-result.schema.json +16 -0
- package/dist/schemas/compatibility.schema.json +32 -0
- package/dist/schemas/flow-contract.schema.json +9 -5
- package/dist/schemas/flow-run.schema.json +16 -123
- package/dist/schemas/plan-aspect-map.schema.json +22 -0
- package/dist/schemas/plan-review-decision.schema.json +14 -0
- package/dist/schemas/plan-review-result.schema.json +42 -0
- package/dist/schemas/protocol-plan.schema.json +15 -182
- package/dist/schemas/stage-finish-input.schema.json +16 -2
- package/dist/schemas/stage-report.schema.json +8 -7
- package/dist/schemas/stage-start-response.schema.json +4 -2
- package/dist/schemas/status-report.schema.json +76 -0
- package/dist/schemas/vnext-protocol-plan.schema.json +37 -0
- package/dist/schemas/vnext-protocolize-result.schema.json +29 -0
- package/dist/schemas/vnext-specify.schema.json +45 -0
- package/dist/services/branch-context.js +1 -1
- package/dist/services/cleanup.js +8 -8
- package/dist/services/cli-operation-classifier.js +10 -2
- package/dist/services/code-checks.js +244 -0
- package/dist/services/config.js +7 -1
- package/dist/services/dashboard.js +12 -12
- package/dist/services/engines.js +1 -1
- package/dist/services/eval-snapshots.js +404 -0
- package/dist/services/hooks.js +774 -18
- package/dist/services/ids.js +16 -6
- package/dist/services/lanes.js +1 -1
- package/dist/services/merge-queue.js +5 -5
- package/dist/services/merge-worker.js +2 -2
- package/dist/services/migrations.js +2 -2
- package/dist/services/plan-runtime.js +1 -1
- package/dist/services/projects.js +4 -4
- package/dist/services/prompts.js +17 -11
- package/dist/services/protocols.js +8 -8
- package/dist/services/run-projection.js +49 -13
- package/dist/services/runs.js +504 -51
- package/dist/services/schema-validation.js +21 -3
- package/dist/services/sessions.js +51 -12
- package/dist/services/stage-blocker.js +57 -0
- package/dist/services/stage-context.js +90 -0
- package/dist/services/stage-lifecycle.js +198 -75
- package/dist/services/stage-pause.js +175 -0
- package/dist/services/stage-report-renderer.js +65 -0
- package/dist/services/usage.js +526 -18
- package/dist/services/vnext-code-review.js +305 -0
- package/dist/services/vnext-code.js +686 -0
- package/dist/services/vnext-contracts.js +1 -0
- package/dist/services/vnext-execution-profile.js +27 -0
- package/dist/services/vnext-fanout.js +79 -0
- package/dist/services/vnext-plan-review.js +499 -0
- package/dist/services/vnext-plan.js +552 -0
- package/dist/services/vnext-protocolize.js +542 -0
- package/dist/services/vnext-specify.js +595 -0
- package/dist/services/vnext-workspace-policy.js +87 -0
- package/dist/services/work-registry.js +522 -0
- package/dist/services/worktrees.js +58 -37
- package/dist/storage/database.js +263 -34
- package/dist/storage/paths.js +47 -1
- package/package.json +12 -12
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { AppError } from "../shared/errors.js";
|
|
4
|
+
import { gitFacts } from "./runs.js";
|
|
5
|
+
const configRelativePath = path.join(".memory-bank", "dd-flow", "project-workspace.json");
|
|
6
|
+
/** The runtime reads explicit configuration; it never attempts to infer route from policy prose. */
|
|
7
|
+
export function loadVnextWorkspacePolicy(projectRoot) {
|
|
8
|
+
const file = path.join(projectRoot, configRelativePath);
|
|
9
|
+
if (!fs.existsSync(file)) {
|
|
10
|
+
throw new AppError("workspace_policy_missing", "vNext flow requires .memory-bank/dd-flow/project-workspace.json", 1, { file });
|
|
11
|
+
}
|
|
12
|
+
let value;
|
|
13
|
+
try {
|
|
14
|
+
value = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
throw new AppError("workspace_policy_invalid", "Project workspace policy is not valid JSON", 1, { file, cause: String(error) });
|
|
18
|
+
}
|
|
19
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
20
|
+
throw new AppError("workspace_policy_invalid", "Project workspace policy must be an object", 1, { file });
|
|
21
|
+
}
|
|
22
|
+
const raw = value;
|
|
23
|
+
const workspace = raw.workspace;
|
|
24
|
+
const route = workspace?.route;
|
|
25
|
+
const integrationBranch = workspace?.integration_branch;
|
|
26
|
+
const template = workspace?.feature_branch_template;
|
|
27
|
+
const provisionStage = workspace?.provision_stage;
|
|
28
|
+
if (raw.schema_id !== "dd-flow/project-workspace@1" || !workspace || (route !== "feature_worktree" && route !== "integration_branch_direct") || typeof integrationBranch !== "string" || !integrationBranch || provisionStage !== "protocolize_start") {
|
|
29
|
+
throw new AppError("workspace_policy_invalid", "Project workspace policy does not match dd-flow/project-workspace@1", 1, { file });
|
|
30
|
+
}
|
|
31
|
+
if (route === "feature_worktree" && (typeof template !== "string" || !template.includes("<RUN>"))) {
|
|
32
|
+
throw new AppError("workspace_policy_invalid", "feature_worktree policy needs a branch template containing <RUN>", 1, { file });
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
schema_id: "dd-flow/project-workspace@1",
|
|
36
|
+
workspace: {
|
|
37
|
+
route,
|
|
38
|
+
integration_branch: integrationBranch,
|
|
39
|
+
feature_branch_template: typeof template === "string" ? template : null,
|
|
40
|
+
provision_stage: "protocolize_start"
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function vnextRunBranch(policy, run) {
|
|
45
|
+
if (policy.workspace.route !== "feature_worktree")
|
|
46
|
+
return null;
|
|
47
|
+
return policy.workspace.feature_branch_template
|
|
48
|
+
.replaceAll("<RUN>", run.short_id.toLowerCase())
|
|
49
|
+
.replaceAll("<slug>", safeSlug(run.slug));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The route receipt is the single source of truth after PROTOCOLIZE provisions
|
|
53
|
+
* the workspace. Every later mutating vNext stage calls this before it opens.
|
|
54
|
+
*/
|
|
55
|
+
export function requireVnextWorkspaceRoute(input) {
|
|
56
|
+
const file = path.join(input.runHome, "02-protocolize", "workspace-route.json");
|
|
57
|
+
let receipt;
|
|
58
|
+
try {
|
|
59
|
+
receipt = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
throw new AppError("workspace_route_missing", `${input.stage} requires the PROTOCOLIZE workspace route receipt`, 1, { file, run_id: input.runId, cause: String(error) });
|
|
63
|
+
}
|
|
64
|
+
const policy = receipt.policy;
|
|
65
|
+
if (receipt.schema_id !== "dd-flow/vnext-workspace-route@1" || !policy?.provisioned || (policy.route !== "feature_worktree" && policy.route !== "integration_branch_direct")) {
|
|
66
|
+
throw new AppError("workspace_route_missing", `${input.stage} requires a valid provisioned workspace route`, 1, { file, run_id: input.runId });
|
|
67
|
+
}
|
|
68
|
+
const workspaceRoot = realPath(input.workspaceRoot);
|
|
69
|
+
if (policy.worktree_path && realPath(policy.worktree_path) !== workspaceRoot) {
|
|
70
|
+
throw new AppError("workspace_route_invalid", `${input.stage} RUN workspace differs from its frozen route`, 1, { run_id: input.runId, expected_workspace_root: policy.worktree_path, actual_workspace_root: workspaceRoot });
|
|
71
|
+
}
|
|
72
|
+
if (policy.route === "feature_worktree") {
|
|
73
|
+
if (!receipt.created || !receipt.bootstrap || !policy.worktree_path || !policy.feature_branch || !policy.base_ref || workspaceRoot === realPath(input.projectRoot)) {
|
|
74
|
+
throw new AppError("workspace_route_missing", `${input.stage} requires a provisioned feature worktree`, 1, { run_id: input.runId, workspace_root: workspaceRoot, policy });
|
|
75
|
+
}
|
|
76
|
+
const facts = gitFacts(workspaceRoot);
|
|
77
|
+
if (facts.status === "unavailable" || facts.branch !== policy.feature_branch || facts.head !== policy.base_ref) {
|
|
78
|
+
throw new AppError("workspace_route_invalid", `${input.stage} workspace no longer matches its frozen feature branch and base`, 1, { run_id: input.runId, workspace_root: workspaceRoot, expected: policy, actual: facts });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return policy;
|
|
82
|
+
}
|
|
83
|
+
function realPath(value) { return fs.existsSync(value) ? fs.realpathSync(value) : path.resolve(value); }
|
|
84
|
+
function safeSlug(value) {
|
|
85
|
+
const slug = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
86
|
+
return slug || "work";
|
|
87
|
+
}
|