@deksden-com/dd-flow-cli 0.2.0 → 0.3.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/README.md +2 -0
- package/dist/build-info.json +10 -6
- package/dist/cli/help.js +70 -13
- package/dist/cli/run-cli.js +140 -10
- package/dist/schemas/compatibility.schema.json +26 -0
- package/dist/schemas/flow-guidance.schema.json +73 -0
- package/dist/schemas/flow-run-index.schema.json +30 -4
- package/dist/schemas/global-dashboard-data.schema.json +68 -0
- package/dist/schemas/mb-sdlc-review-report.schema.json +242 -0
- package/dist/schemas/plan-stage-report.schema.json +83 -0
- package/dist/schemas/project-dashboard-data.schema.json +98 -0
- package/dist/schemas/project-flow-pack-manifest.schema.json +5 -1
- package/dist/schemas/protocol-dashboard-data.schema.json +89 -0
- package/dist/schemas/status-report.schema.json +34 -0
- package/dist/schemas/version-report.schema.json +22 -0
- package/dist/services/build-info.js +26 -3
- package/dist/services/canon.js +93 -22
- package/dist/services/cleanup.js +14 -1
- package/dist/services/config.js +25 -0
- package/dist/services/dashboard.js +655 -10
- package/dist/services/flow-guidance.js +214 -0
- package/dist/services/ids.js +106 -0
- package/dist/services/merge-queue.js +9 -1
- package/dist/services/merge-worker.js +31 -2
- package/dist/services/projects.js +7 -1
- package/dist/services/protocols.js +637 -6
- package/dist/services/runs.js +98 -21
- package/dist/services/schema-validation.js +84 -4
- package/dist/services/status.js +189 -1
- package/dist/services/version-status.js +28 -2
- package/dist/storage/database.js +6 -0
- package/dist/storage/paths.js +21 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -229,6 +229,8 @@ Defaults:
|
|
|
229
229
|
```text
|
|
230
230
|
project dashboard: .tasks/dd-flow-dashboard.md
|
|
231
231
|
global dashboard: ~/.dd-flow/dashboard.md
|
|
232
|
+
project HTML: ~/.dd-flow/projects/<PRJ-ID>/dashboard/project-dashboard.html
|
|
233
|
+
protocol HTML: ~/.dd-flow/projects/<PRJ-ID>/dashboard/protocols/<PRT-ID>.html
|
|
232
234
|
```
|
|
233
235
|
|
|
234
236
|
Useful commands:
|
package/dist/build-info.json
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"cli_package": "@deksden-com/dd-flow-cli",
|
|
3
|
-
"cli_version": "0.
|
|
4
|
-
"cli_commit": "
|
|
5
|
-
"built_at": "2026-06-
|
|
3
|
+
"cli_version": "0.3.0",
|
|
4
|
+
"cli_commit": "059594c2096e080548d470e789f594e20a1a8ebd",
|
|
5
|
+
"built_at": "2026-06-30T20:32:13.018Z",
|
|
6
6
|
"built_with_canon": {
|
|
7
|
-
"version": "2.
|
|
8
|
-
"commit": "
|
|
9
|
-
"flow_contract": "dd-flow-canonical-2026-
|
|
7
|
+
"version": "2.8.0",
|
|
8
|
+
"commit": "f549c33bd73d8d18b5cb07d9737b02fe638e61b8",
|
|
9
|
+
"flow_contract": "dd-flow-canonical-2026-06",
|
|
10
|
+
"repo_root": "/Users/deksden/Documents/_Projects/dd-memorybank",
|
|
11
|
+
"memorybank_root": "/Users/deksden/Documents/_Projects/dd-memorybank/.memory-bank",
|
|
12
|
+
"flow_root": "/Users/deksden/Documents/_Projects/dd-memorybank/.memory-bank/dd-flow",
|
|
13
|
+
"layout": "dot_memory_bank"
|
|
10
14
|
}
|
|
11
15
|
}
|
package/dist/cli/help.js
CHANGED
|
@@ -9,21 +9,23 @@ Usage:
|
|
|
9
9
|
dd-flow <command> --help
|
|
10
10
|
|
|
11
11
|
Core commands:
|
|
12
|
+
version Print the installed dd-flow CLI package version.
|
|
12
13
|
status Inspect dd-flow runtime, project and canon roots.
|
|
13
14
|
canon register/status/resolve Register and resolve the canonical Memory Bank.
|
|
14
15
|
project register/status Register a project and inspect runtime state.
|
|
15
16
|
project resolve/archive Resolve typed ids and archive stale project roots.
|
|
16
17
|
project migrate-ids Migrate old project ids.
|
|
17
|
-
protocol register/status
|
|
18
|
+
protocol register/status/transition Register, inspect, transition and repair protocol state.
|
|
18
19
|
cleanup scan/apply Detect and repair stale local runtime state.
|
|
19
20
|
run start/status/list Track concrete flow executions and stage artifacts.
|
|
21
|
+
id next Preview next typed ids for protocol or run allocation.
|
|
20
22
|
plan set/status/item Attach and update protocol plans.
|
|
21
23
|
lane workspace/lock/status Manage shared workspace lanes and leases.
|
|
22
24
|
merge status/one-shot Inspect or claim one merge job from the current session.
|
|
23
25
|
merge-worker status/start/stop Manage long-lived project merge workers.
|
|
24
26
|
merge-queue status/next Claim, wait for, complete, or fail merge jobs.
|
|
25
27
|
session register/status/stop Register flow sessions and stop workers.
|
|
26
|
-
dashboard render/open/refresh Render markdown project/global dashboards.
|
|
28
|
+
dashboard data/render/open/refresh Render markdown or HTML project/global dashboards.
|
|
27
29
|
schema validate Validate canonical dd-flow JSON data contracts.
|
|
28
30
|
memory permissions preflight Check Memory Bank write/read permissions.
|
|
29
31
|
integration cmux status Inspect optional cmux integration.
|
|
@@ -32,6 +34,7 @@ Core commands:
|
|
|
32
34
|
|
|
33
35
|
Examples:
|
|
34
36
|
dd-flow project register --root "$PWD"
|
|
37
|
+
dd-flow version
|
|
35
38
|
dd-flow status --project-root "$PWD" --json
|
|
36
39
|
dd-flow canon register --root "$DD_MEMORYBANK" --json
|
|
37
40
|
dd-flow canon resolve --json
|
|
@@ -39,7 +42,9 @@ Examples:
|
|
|
39
42
|
dd-flow project resolve PRJ-001 --json
|
|
40
43
|
dd-flow project archive PRJ-001 --reason "old missing worktree root" --json
|
|
41
44
|
dd-flow project migrate-ids --root "$PWD" --apply --json
|
|
42
|
-
dd-flow run start --project-root "$PWD" --flow-kind
|
|
45
|
+
dd-flow run start --project-root "$PWD" --flow-kind mb_sdlc --subject-type protocol --subject-id PRT-001-demo --slug demo --json
|
|
46
|
+
dd-flow id next --type protocol --project-root "$PWD" --slug demo --json
|
|
47
|
+
dd-flow protocol transition PRT-001-demo --to implementation --payload-file transition.json --json
|
|
43
48
|
dd-flow lane workspace set --project-root "$PWD" --lane merge --path "$PWD" --branch main --json
|
|
44
49
|
dd-flow lane lock acquire --project-root "$PWD" --lane merge --worker-id worker-1 --path "$PWD" --ttl 300 --reason "merge worker" --json
|
|
45
50
|
dd-flow merge status --project-root "$PWD" --json
|
|
@@ -48,6 +53,21 @@ Examples:
|
|
|
48
53
|
Default output is human-readable. Use --json for hooks, prompts, scripts and other agent automation; JSON mode never mixes human progress text into stdout.
|
|
49
54
|
|
|
50
55
|
project_root is the stable repository identity. workspace_path is the concrete checkout where an agent is about to work.`
|
|
56
|
+
],
|
|
57
|
+
[
|
|
58
|
+
"version",
|
|
59
|
+
`dd-flow version - print CLI package version
|
|
60
|
+
|
|
61
|
+
Usage:
|
|
62
|
+
dd-flow version
|
|
63
|
+
dd-flow version --json
|
|
64
|
+
dd-flow --version
|
|
65
|
+
|
|
66
|
+
version reports the installed dd-flow CLI package version from package metadata. Use status for richer canon/project compatibility diagnostics.
|
|
67
|
+
|
|
68
|
+
Examples:
|
|
69
|
+
dd-flow version
|
|
70
|
+
dd-flow version --json`
|
|
51
71
|
],
|
|
52
72
|
[
|
|
53
73
|
"status",
|
|
@@ -56,9 +76,12 @@ project_root is the stable repository identity. workspace_path is the concrete c
|
|
|
56
76
|
Usage:
|
|
57
77
|
dd-flow status [--project-root <root>] --json
|
|
58
78
|
dd-flow status [--root <root>] --json
|
|
79
|
+
dd-flow status [--project-root <root>] [--check-registry] --json
|
|
59
80
|
|
|
60
81
|
status reports DD_FLOW_HOME, the requested or current project root, registered project identity when available, and canonical Memory Bank discovery. It does not require the project to be registered and does not mutate state. In JSON mode canon discovery is embedded as a structured assessment so agents can detect missing or ambiguous canon roots without parsing stderr.
|
|
61
82
|
|
|
83
|
+
By default status does not call the network. Use --check-registry for an explicit cached npm latest check.
|
|
84
|
+
|
|
62
85
|
Examples:
|
|
63
86
|
dd-flow status --project-root "$PWD" --json
|
|
64
87
|
dd-flow status --json`
|
|
@@ -87,18 +110,33 @@ Examples:
|
|
|
87
110
|
|
|
88
111
|
Usage:
|
|
89
112
|
dd-flow run start --project-root <root> [--workspace-root <checkout>] --flow-kind <kind> --subject-type <type> --subject-id <id> --slug <slug> [--next-action <text>] --json
|
|
113
|
+
dd-flow id next --type protocol|run --project-root <root> --slug <slug> --json
|
|
90
114
|
dd-flow run status <RUN-ID|RUN-NNN> --project-root <root> --json
|
|
91
115
|
dd-flow run list --project-root <root> --json
|
|
92
116
|
dd-flow run attach-stage <RUN-ID|RUN-NNN> --project-root <root> --stage <name> --dir <NN-stage-slug> --status <status> [--data-schema-id <id>] --json
|
|
93
117
|
dd-flow run complete-stage <RUN-ID|RUN-NNN> --project-root <root> --stage <name> --status <status> [--stage-report <path>] [--data <path>] [--data-schema-id <id>] [--report <path>] [--alias <path>] --json
|
|
94
118
|
dd-flow run complete <RUN-ID|RUN-NNN> --project-root <root> --status done|blocked|cancelled|failed [--verdict <text>] [--next-action <text>] --json
|
|
95
119
|
|
|
96
|
-
RUN-* is the execution envelope for one concrete flow launch. Semantic truth remains in protocol, experiment, DEF, scenario, evidence, and Memory Bank documents.
|
|
120
|
+
RUN-* is the execution envelope for one concrete flow launch. Semantic truth remains in protocol, experiment, DEF, scenario, evidence, and Memory Bank documents. New run artifacts are stored under DD_FLOW_HOME/projects/<PRJ-ID-slug>/runs/<RUN-ID-slug>/ with run.json and run-index.json together. Legacy <workspace>/.tasks/dd-flow-runs/<RUN-ID-slug>/ indexes remain readable.
|
|
97
121
|
|
|
98
122
|
Examples:
|
|
99
|
-
dd-flow run start --project-root "$PWD" --flow-kind
|
|
123
|
+
dd-flow run start --project-root "$PWD" --flow-kind mb_sdlc --subject-type protocol --subject-id PRT-001-demo --slug demo --json
|
|
124
|
+
dd-flow id next --type run --project-root "$PWD" --slug demo --json
|
|
100
125
|
dd-flow run attach-stage RUN-001 --project-root "$PWD" --stage plan --dir 01-plan --status running --json
|
|
101
126
|
dd-flow run complete-stage RUN-001 --project-root "$PWD" --stage plan --status done --data 01-plan/stage-report.json --stage-report 01-plan/stage-report.html --report 01-plan/report.md --json`
|
|
127
|
+
],
|
|
128
|
+
[
|
|
129
|
+
"id",
|
|
130
|
+
`dd-flow id - preview next typed ids
|
|
131
|
+
|
|
132
|
+
Usage:
|
|
133
|
+
dd-flow id next --type protocol|run --project-root <root> --slug <slug> --json
|
|
134
|
+
|
|
135
|
+
id next is read-only: it scans runtime records and known project files, then returns the next available TYPE-NNN-slug without reserving it. Use run start or protocol register to create durable state.
|
|
136
|
+
|
|
137
|
+
Examples:
|
|
138
|
+
dd-flow id next --type protocol --project-root "$PWD" --slug demo --json
|
|
139
|
+
dd-flow id next --type run --project-root "$PWD" --slug demo --json`
|
|
102
140
|
],
|
|
103
141
|
[
|
|
104
142
|
"protocol",
|
|
@@ -107,10 +145,27 @@ Examples:
|
|
|
107
145
|
Usage:
|
|
108
146
|
dd-flow protocol register <handshake-id> --project-root <root> [--workspace-path <checkout>] --json
|
|
109
147
|
dd-flow protocol status <protocol-id> --json
|
|
148
|
+
dd-flow protocol ready --project-root <root> --json
|
|
149
|
+
dd-flow protocol blockers <protocol-id> --project-root <root> --json
|
|
150
|
+
dd-flow protocol implement <protocol-id> --project-root <root> [--force --reason <text>] --json
|
|
151
|
+
dd-flow protocol transition <protocol-id> --to <stage> --payload-file <file> [--force --reason <text>] --json
|
|
152
|
+
dd-flow protocol sync-from-run <protocol-id> --run <RUN-ID|RUN-NNN> [--target auto|<stage>] --json
|
|
110
153
|
dd-flow protocol ready-for-merge <protocol-id> --json
|
|
111
154
|
dd-flow protocol cancel <protocol-id> --reason <text> [--close-sessions true|false] [--cancel-queue true|false] [--release-locks true|false] [--worktree keep|remove] [--force] --json
|
|
112
155
|
|
|
156
|
+
ready, blockers and implement read protocol markdown frontmatter plus runtime state. implement is a preflight/guidance command: it never performs implementation, refuses unresolved blocked_by_protocols unless --force --reason is supplied, refuses terminal protocols and reports the expected next prompt/stage. transition validates the snapshotted flow contract stored in protocol runtime state, writes an audit event and updates lifecycle fields from the payload. --json-file is accepted as a compatibility alias for --payload-file. sync-from-run repairs legacy protocol/run mismatch from concrete RUN evidence instead of requiring manual runtime JSON edits.
|
|
157
|
+
|
|
113
158
|
The project_root is the stable project identity used for queues, sessions, lanes, and dashboards. Runtime state is stored under DD_FLOW_HOME/projects/<PRJ-ID-slug>/runtime so feature worktree removal does not break status, cancel, or merge finalization. The optional workspace_path records the concrete checkout where the agent works. With --worktree remove, cancel removes the disposable git worktree recorded in runtime state or worktree records; with --force it also force-deletes the local feature branch when present.`
|
|
159
|
+
],
|
|
160
|
+
[
|
|
161
|
+
"transition",
|
|
162
|
+
`dd-flow transition - compatibility alias for protocol transition
|
|
163
|
+
|
|
164
|
+
Usage:
|
|
165
|
+
dd-flow transition <protocol-id> --to <stage> --payload-file <file> [--force --reason <text>] --json
|
|
166
|
+
dd-flow transition <protocol-id> --to <stage> --json-file <file> [--force --reason <text>] --json
|
|
167
|
+
|
|
168
|
+
Prefer dd-flow protocol transition in new prompts and scripts. This top-level alias remains for older canonical prompts and experiments.`
|
|
114
169
|
],
|
|
115
170
|
[
|
|
116
171
|
"project",
|
|
@@ -277,16 +332,18 @@ Usage:
|
|
|
277
332
|
],
|
|
278
333
|
[
|
|
279
334
|
"dashboard",
|
|
280
|
-
`dd-flow dashboard - render or open markdown dashboards
|
|
335
|
+
`dd-flow dashboard - render or open markdown and HTML dashboards
|
|
281
336
|
|
|
282
337
|
Usage:
|
|
283
|
-
dd-flow dashboard
|
|
284
|
-
dd-flow dashboard
|
|
285
|
-
dd-flow dashboard
|
|
286
|
-
dd-flow dashboard
|
|
287
|
-
dd-flow dashboard
|
|
288
|
-
|
|
289
|
-
|
|
338
|
+
dd-flow dashboard data --project-root <root> [--protocol <PRT-ID>] --json
|
|
339
|
+
dd-flow dashboard data --global --json
|
|
340
|
+
dd-flow dashboard render --project-root <root> [--format markdown|html] [--protocol <PRT-ID>] [--output <path>] --json
|
|
341
|
+
dd-flow dashboard render-global [--format markdown|html] [--output <path>] --json
|
|
342
|
+
dd-flow dashboard open --project-root <root> [--format markdown|html] [--viewer cmux] --json
|
|
343
|
+
dd-flow dashboard refresh --project-root <root> [--format markdown|html] [--protocol <PRT-ID>] [--open auto|true|false] --json
|
|
344
|
+
dd-flow dashboard refresh-global [--format markdown|html] [--output <path>] --json
|
|
345
|
+
|
|
346
|
+
Dashboards are rendered views of dd-flow state. Markdown remains the compatibility fallback. HTML dashboards write JSON next to self-contained local HTML: global under DD_FLOW_HOME/dashboard/ and project/protocol pages under DD_FLOW_HOME/projects/<PRJ-ID-slug>/dashboard/. State-changing commands still auto-refresh markdown during the transition. cmux is used only by explicit open/refresh commands and only according to project config.`
|
|
290
347
|
],
|
|
291
348
|
[
|
|
292
349
|
"schema",
|
package/dist/cli/run-cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { helpForArgs } from "./help.js";
|
|
|
3
3
|
import { AppError, isAppError } from "../shared/errors.js";
|
|
4
4
|
import { writeJson } from "../shared/json.js";
|
|
5
5
|
import { archiveProject, getProjectStatus, migrateProjectIds, registerProject, resolveProject } from "../services/projects.js";
|
|
6
|
-
import { cancelProtocol, getProtocolStatus, readyForMerge, registerProtocol, requireProtocol, transitionProtocol } from "../services/protocols.js";
|
|
6
|
+
import { cancelProtocol, getProtocolBlockers, getProtocolStatus, getReadyProtocols, implementProtocol, readyForMerge, registerProtocol, requireProtocol, syncProtocolFromRun, transitionProtocol } from "../services/protocols.js";
|
|
7
7
|
import { blockPlanItem, completePlanItem, getPlanStatus, setProtocolPlan, skipPlanItem, startPlanItem } from "../services/plans.js";
|
|
8
8
|
import { cancelMergeQueueJob, claimNextMergeJob, completeMergeJob, failMergeJob, getMergeQueueStatus, noteMergeJob, waitNextMergeJob } from "../services/merge-queue.js";
|
|
9
9
|
import { getMergeWorkerStatus, oneShotMergeClaim, startMergeWorker, stopProjectMergeWorker } from "../services/merge-worker.js";
|
|
@@ -14,9 +14,11 @@ import { acquireLaneLock, checkLaneWorkspace, getLaneStatus, heartbeatLaneLock,
|
|
|
14
14
|
import { getProjectConfigStatus, setProjectConfigValue } from "../services/config.js";
|
|
15
15
|
import { getCanonStatus, registerCanonRoot, resolveCanonRoot } from "../services/canon.js";
|
|
16
16
|
import { getRuntimeStatus } from "../services/status.js";
|
|
17
|
-
import {
|
|
17
|
+
import { getCliVersionReport } from "../services/build-info.js";
|
|
18
|
+
import { autoRefreshDashboards, dashboardData, getCmuxStatus, openDashboard, refreshDashboard, refreshGlobalDashboard, renderDashboard, renderGlobalDashboard } from "../services/dashboard.js";
|
|
18
19
|
import { getFlowSessionStatus, registerFlowSession, stopFlowSession, stopMergeWorker } from "../services/sessions.js";
|
|
19
20
|
import { attachFlowRunStage, completeFlowRun, completeFlowRunStage, getFlowRunStatus, listFlowRuns, startFlowRun } from "../services/runs.js";
|
|
21
|
+
import { previewNextEntityId } from "../services/ids.js";
|
|
20
22
|
import { validateSchema } from "../services/schema-validation.js";
|
|
21
23
|
import { preflightMemoryPermissions } from "../services/memory-permissions.js";
|
|
22
24
|
import { requireProjectByRoot } from "../services/projects.js";
|
|
@@ -34,6 +36,14 @@ export async function runCli(args, io = defaultIo, env = process.env) {
|
|
|
34
36
|
if (args.includes("--progress-jsonl")) {
|
|
35
37
|
throw new AppError("usage", "--progress-jsonl is not implemented yet; use --json for final structured progress", 2);
|
|
36
38
|
}
|
|
39
|
+
if (output.args.length === 1 && output.args[0] === "--version") {
|
|
40
|
+
const payload = getCliVersionReport();
|
|
41
|
+
if (output.json)
|
|
42
|
+
writeJson(io.stdout, payload);
|
|
43
|
+
else
|
|
44
|
+
io.stdout.write(`dd-flow ${payload.cli.version}\n`);
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
37
47
|
const help = helpForArgs(output.args);
|
|
38
48
|
if (help) {
|
|
39
49
|
io.stdout.write(`${help}\n`);
|
|
@@ -152,6 +162,10 @@ function renderHumanResult(args, result) {
|
|
|
152
162
|
if (family === "status") {
|
|
153
163
|
return renderStatusHuman(record);
|
|
154
164
|
}
|
|
165
|
+
if (family === "version") {
|
|
166
|
+
const cli = recordObject(record.cli);
|
|
167
|
+
return `dd-flow ${stringValue(cli?.version) ?? "unknown"}\n`;
|
|
168
|
+
}
|
|
155
169
|
const lines = [`dd-flow ${family ?? ""}${command ? ` ${command}` : ""}: ${ok}`.trim()];
|
|
156
170
|
const project = record.project && typeof record.project === "object" ? record.project : null;
|
|
157
171
|
const protocol = record.protocol && typeof record.protocol === "object" ? record.protocol : null;
|
|
@@ -176,6 +190,7 @@ function renderHumanResult(args, result) {
|
|
|
176
190
|
if (run.run_index_path)
|
|
177
191
|
lines.push(`run_index: ${String(run.run_index_path)}`);
|
|
178
192
|
}
|
|
193
|
+
appendFlowGuidanceHuman(lines, record);
|
|
179
194
|
return `${lines.join("\n")}\n`;
|
|
180
195
|
}
|
|
181
196
|
function renderStatusHuman(record) {
|
|
@@ -183,6 +198,8 @@ function renderStatusHuman(record) {
|
|
|
183
198
|
const cli = recordObject(record.cli);
|
|
184
199
|
const cliBuild = recordObject(cli?.build);
|
|
185
200
|
const builtWithCanon = recordObject(cliBuild?.built_with_canon);
|
|
201
|
+
const cliCompatibility = recordObject(cli?.compatibility);
|
|
202
|
+
const registry = recordObject(cli?.registry);
|
|
186
203
|
const canon = recordObject(record.canon);
|
|
187
204
|
const resolvedCanon = recordObject(canon?.resolved);
|
|
188
205
|
const project = recordObject(record.project);
|
|
@@ -190,16 +207,48 @@ function renderStatusHuman(record) {
|
|
|
190
207
|
const flowPack = recordObject(project?.flow_pack);
|
|
191
208
|
const drift = recordObject(project?.drift);
|
|
192
209
|
lines.push(`CLI package: ${stringValue(cli?.package_name) ?? "unknown"} ${stringValue(cli?.version) ?? "unknown"}`);
|
|
210
|
+
if (cliCompatibility) {
|
|
211
|
+
lines.push(`CLI compatibility: ${stringValue(cliCompatibility.verdict) ?? "unknown"} (${stringValue(cliCompatibility.reason) ?? "no_reason"})`);
|
|
212
|
+
if (cliCompatibility.update_command)
|
|
213
|
+
lines.push(`CLI update: ${String(cliCompatibility.update_command)}`);
|
|
214
|
+
}
|
|
215
|
+
if (registry) {
|
|
216
|
+
lines.push(`CLI registry: ${stringValue(registry.latest) ?? "unknown"} (${stringValue(registry.status) ?? "unknown"})`);
|
|
217
|
+
}
|
|
193
218
|
lines.push(`CLI tested with canon: ${stringValue(builtWithCanon?.version) ?? "unknown"} @ ${shortSha(stringValue(builtWithCanon?.commit))}`);
|
|
194
|
-
lines.push(`Active local canon: ${stringValue(resolvedCanon?.root) ?? "unresolved"} ${stringValue(resolvedCanon?.version) ?? "unknown"} @ ${shortSha(stringValue(resolvedCanon?.commit))}`);
|
|
219
|
+
lines.push(`Active local canon: ${stringValue(resolvedCanon?.root) ?? "unresolved"} ${stringValue(resolvedCanon?.version) ?? "unknown"} @ ${shortSha(stringValue(resolvedCanon?.commit))} (${stringValue(resolvedCanon?.layout) ?? "unknown"})`);
|
|
220
|
+
if (resolvedCanon?.memorybank_root)
|
|
221
|
+
lines.push(`Canon Memory Bank: ${String(resolvedCanon.memorybank_root)}`);
|
|
222
|
+
if (resolvedCanon?.flow_root)
|
|
223
|
+
lines.push(`Canon flow root: ${String(resolvedCanon.flow_root)}`);
|
|
195
224
|
lines.push(`Project: ${stringValue(project?.root) ?? "unknown"}${project?.registered === true ? " (registered)" : " (unregistered)"}`);
|
|
196
225
|
lines.push(`Project Memory Bank: ${stringValue(memoryBank?.version) ?? stringValue(memoryBank?.status) ?? "unknown"}`);
|
|
197
226
|
lines.push(`Project flow pack: ${stringValue(flowPack?.pack_version) ?? stringValue(flowPack?.status) ?? "unknown"} @ ${shortSha(stringValue(flowPack?.source_commit))}`);
|
|
198
227
|
lines.push(`Drift: ${stringValue(drift?.overall) ?? "unknown"}`);
|
|
199
228
|
if (drift?.next_action)
|
|
200
229
|
lines.push(`Next action: ${String(drift.next_action)}`);
|
|
230
|
+
appendFlowGuidanceHuman(lines, record);
|
|
201
231
|
return `${lines.join("\n")}\n`;
|
|
202
232
|
}
|
|
233
|
+
function appendFlowGuidanceHuman(lines, record) {
|
|
234
|
+
const guidance = recordObject(record.flow_guidance);
|
|
235
|
+
if (!guidance)
|
|
236
|
+
return;
|
|
237
|
+
const currentStage = stringValue(guidance.current_stage);
|
|
238
|
+
const nextAction = stringValue(guidance.recommended_next_action);
|
|
239
|
+
const prompt = stringValue(guidance.recommended_prompt);
|
|
240
|
+
if (currentStage)
|
|
241
|
+
lines.push(`stage: ${currentStage}`);
|
|
242
|
+
if (nextAction)
|
|
243
|
+
lines.push(`next: ${nextAction}${prompt && prompt !== "none" ? ` (${prompt})` : ""}`);
|
|
244
|
+
const guards = Array.isArray(guidance.guards) ? guidance.guards : [];
|
|
245
|
+
const firstGuard = guards.find((item) => item && typeof item === "object" && !Array.isArray(item));
|
|
246
|
+
if (firstGuard?.id)
|
|
247
|
+
lines.push(`guard: ${String(firstGuard.id)} ${String(firstGuard.status ?? "unknown")}`);
|
|
248
|
+
const missing = Array.isArray(guidance.blocked_if_missing) ? guidance.blocked_if_missing : [];
|
|
249
|
+
if (missing.length > 0)
|
|
250
|
+
lines.push(`missing: ${missing.map(String).join(", ")}`);
|
|
251
|
+
}
|
|
203
252
|
function recordObject(value) {
|
|
204
253
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
205
254
|
}
|
|
@@ -214,7 +263,13 @@ async function dispatch(args, context, io) {
|
|
|
214
263
|
const parsed = parseArgs(rest);
|
|
215
264
|
if (family === "status") {
|
|
216
265
|
const rootParsed = parseArgs([command ?? "", ...rest]);
|
|
217
|
-
return getRuntimeStatus(context, {
|
|
266
|
+
return getRuntimeStatus(context, {
|
|
267
|
+
projectRoot: optionalOption(rootParsed, "project-root") ?? optionalOption(rootParsed, "root"),
|
|
268
|
+
checkRegistry: hasOption(rootParsed, "check-registry")
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
if (family === "version") {
|
|
272
|
+
return getCliVersionReport();
|
|
218
273
|
}
|
|
219
274
|
if (family === "canon") {
|
|
220
275
|
return dispatchCanon(context, command, parsed);
|
|
@@ -255,9 +310,44 @@ async function dispatch(args, context, io) {
|
|
|
255
310
|
if (family === "protocol" && command === "status") {
|
|
256
311
|
return getProtocolStatus(context, { protocolId: requiredPosition(parsed, 0, "protocol-id") });
|
|
257
312
|
}
|
|
313
|
+
if (family === "protocol" && command === "ready") {
|
|
314
|
+
return getReadyProtocols(context, { projectRoot: requiredOption(parsed, "project-root") });
|
|
315
|
+
}
|
|
316
|
+
if (family === "protocol" && command === "blockers") {
|
|
317
|
+
return getProtocolBlockers(context, {
|
|
318
|
+
protocolId: requiredPosition(parsed, 0, "protocol-id"),
|
|
319
|
+
projectRoot: requiredOption(parsed, "project-root")
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
if (family === "protocol" && command === "implement") {
|
|
323
|
+
const reason = optionalOption(parsed, "reason");
|
|
324
|
+
return implementProtocol(context, {
|
|
325
|
+
protocolId: requiredPosition(parsed, 0, "protocol-id"),
|
|
326
|
+
projectRoot: requiredOption(parsed, "project-root"),
|
|
327
|
+
force: hasOption(parsed, "force"),
|
|
328
|
+
...(reason ? { reason } : {})
|
|
329
|
+
});
|
|
330
|
+
}
|
|
258
331
|
if (family === "protocol" && command === "ready-for-merge") {
|
|
259
332
|
return readyForMerge(context, { protocolId: requiredPosition(parsed, 0, "protocol-id") });
|
|
260
333
|
}
|
|
334
|
+
if (family === "protocol" && command === "transition") {
|
|
335
|
+
const reason = optionalOption(parsed, "reason");
|
|
336
|
+
return transitionProtocol(context, {
|
|
337
|
+
protocolId: requiredPosition(parsed, 0, "protocol-id"),
|
|
338
|
+
to: requiredOption(parsed, "to"),
|
|
339
|
+
jsonFile: requiredOptionAlias(parsed, ["payload-file", "json-file"]),
|
|
340
|
+
force: hasOption(parsed, "force"),
|
|
341
|
+
...(reason ? { reason } : {})
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
if (family === "protocol" && command === "sync-from-run") {
|
|
345
|
+
return syncProtocolFromRun(context, {
|
|
346
|
+
protocolId: requiredPosition(parsed, 0, "protocol-id"),
|
|
347
|
+
runId: requiredOption(parsed, "run"),
|
|
348
|
+
target: optionalOption(parsed, "target") ?? "auto"
|
|
349
|
+
});
|
|
350
|
+
}
|
|
261
351
|
if (family === "protocol" && command === "cancel") {
|
|
262
352
|
return cancelProtocol(context, {
|
|
263
353
|
protocolId: requiredPosition(parsed, 0, "protocol-id"),
|
|
@@ -275,7 +365,7 @@ async function dispatch(args, context, io) {
|
|
|
275
365
|
return transitionProtocol(context, {
|
|
276
366
|
protocolId: requiredPosition(transitionParsed, 0, "protocol-id"),
|
|
277
367
|
to: requiredOption(transitionParsed, "to"),
|
|
278
|
-
jsonFile:
|
|
368
|
+
jsonFile: requiredOptionAlias(transitionParsed, ["payload-file", "json-file"]),
|
|
279
369
|
force: hasOption(transitionParsed, "force"),
|
|
280
370
|
...(reason ? { reason } : {})
|
|
281
371
|
});
|
|
@@ -313,6 +403,9 @@ async function dispatch(args, context, io) {
|
|
|
313
403
|
if (family === "run") {
|
|
314
404
|
return dispatchRun(context, command, parsed);
|
|
315
405
|
}
|
|
406
|
+
if (family === "id") {
|
|
407
|
+
return dispatchId(context, command, parsed);
|
|
408
|
+
}
|
|
316
409
|
if (family === "integration" && command === "cmux") {
|
|
317
410
|
return dispatchCmux(context, parsed);
|
|
318
411
|
}
|
|
@@ -579,6 +672,16 @@ function dispatchRun(context, command, parsed) {
|
|
|
579
672
|
}
|
|
580
673
|
throw new AppError("usage", `Unknown run command: ${command ?? "<empty>"}`, 2);
|
|
581
674
|
}
|
|
675
|
+
function dispatchId(context, command, parsed) {
|
|
676
|
+
if (command === "next") {
|
|
677
|
+
return previewNextEntityId(context, {
|
|
678
|
+
projectRoot: requiredOption(parsed, "project-root"),
|
|
679
|
+
type: requiredOption(parsed, "type"),
|
|
680
|
+
slug: requiredOption(parsed, "slug")
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
throw new AppError("usage", `Unknown id command: ${command ?? "<empty>"}`, 2);
|
|
684
|
+
}
|
|
582
685
|
function dispatchCmux(context, parsed) {
|
|
583
686
|
const action = requiredPosition(parsed, 0, "integration cmux action");
|
|
584
687
|
if (action === "status") {
|
|
@@ -587,14 +690,31 @@ function dispatchCmux(context, parsed) {
|
|
|
587
690
|
throw new AppError("usage", `Unknown integration cmux action: ${action}`, 2);
|
|
588
691
|
}
|
|
589
692
|
function dispatchDashboard(context, command, parsed) {
|
|
693
|
+
if (command === "data") {
|
|
694
|
+
const global = hasOption(parsed, "global");
|
|
695
|
+
return dashboardData(context, {
|
|
696
|
+
global,
|
|
697
|
+
projectRoot: global ? undefined : requiredOption(parsed, "project-root"),
|
|
698
|
+
protocol: optionalOption(parsed, "protocol")
|
|
699
|
+
});
|
|
700
|
+
}
|
|
590
701
|
if (command === "render") {
|
|
591
|
-
return renderDashboard(context, {
|
|
702
|
+
return renderDashboard(context, {
|
|
703
|
+
projectRoot: requiredOption(parsed, "project-root"),
|
|
704
|
+
output: optionalOption(parsed, "output"),
|
|
705
|
+
format: optionalOption(parsed, "format"),
|
|
706
|
+
protocol: optionalOption(parsed, "protocol")
|
|
707
|
+
});
|
|
592
708
|
}
|
|
593
709
|
if (command === "render-global") {
|
|
594
|
-
return renderGlobalDashboard(context, { output: optionalOption(parsed, "output") });
|
|
710
|
+
return renderGlobalDashboard(context, { output: optionalOption(parsed, "output"), format: optionalOption(parsed, "format") });
|
|
595
711
|
}
|
|
596
712
|
if (command === "open") {
|
|
597
|
-
return openDashboard(context, {
|
|
713
|
+
return openDashboard(context, {
|
|
714
|
+
projectRoot: requiredOption(parsed, "project-root"),
|
|
715
|
+
viewer: optionalOption(parsed, "viewer"),
|
|
716
|
+
format: optionalOption(parsed, "format")
|
|
717
|
+
});
|
|
598
718
|
}
|
|
599
719
|
if (command === "refresh") {
|
|
600
720
|
const open = optionalOption(parsed, "open");
|
|
@@ -603,11 +723,13 @@ function dispatchDashboard(context, command, parsed) {
|
|
|
603
723
|
}
|
|
604
724
|
return refreshDashboard(context, {
|
|
605
725
|
projectRoot: requiredOption(parsed, "project-root"),
|
|
606
|
-
open: open
|
|
726
|
+
open: open,
|
|
727
|
+
format: optionalOption(parsed, "format"),
|
|
728
|
+
protocol: optionalOption(parsed, "protocol")
|
|
607
729
|
});
|
|
608
730
|
}
|
|
609
731
|
if (command === "refresh-global") {
|
|
610
|
-
return refreshGlobalDashboard(context, { output: optionalOption(parsed, "output") });
|
|
732
|
+
return refreshGlobalDashboard(context, { output: optionalOption(parsed, "output"), format: optionalOption(parsed, "format") });
|
|
611
733
|
}
|
|
612
734
|
throw new AppError("usage", `Unknown dashboard command: ${command ?? "<empty>"}`, 2);
|
|
613
735
|
}
|
|
@@ -882,6 +1004,14 @@ function requiredOption(parsed, key) {
|
|
|
882
1004
|
}
|
|
883
1005
|
return value;
|
|
884
1006
|
}
|
|
1007
|
+
function requiredOptionAlias(parsed, keys) {
|
|
1008
|
+
for (const key of keys) {
|
|
1009
|
+
const value = optionalOption(parsed, key);
|
|
1010
|
+
if (value)
|
|
1011
|
+
return value;
|
|
1012
|
+
}
|
|
1013
|
+
throw new AppError("usage", `Missing required option: ${keys.map((key) => `--${key}`).join(" or ")}`, 2);
|
|
1014
|
+
}
|
|
885
1015
|
function hasOption(parsed, key) {
|
|
886
1016
|
return parsed.options.has(key);
|
|
887
1017
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "dd-flow/compatibility@1",
|
|
4
|
+
"title": "dd-flow compatibility manifest",
|
|
5
|
+
"description": "Canonical compatibility map between a Memory Bank release and the dd-flow CLI package required by that release.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["schema_id", "memory_bank_version", "dd_flow_cli"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"schema_id": { "const": "dd-flow/compatibility@1" },
|
|
11
|
+
"memory_bank_version": { "type": "string", "minLength": 1 },
|
|
12
|
+
"dd_flow_cli": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"additionalProperties": false,
|
|
15
|
+
"required": ["package_name", "min_version", "recommended_version", "status_contract", "version_contract", "flow_contract"],
|
|
16
|
+
"properties": {
|
|
17
|
+
"package_name": { "type": "string", "minLength": 1 },
|
|
18
|
+
"min_version": { "type": "string", "minLength": 1 },
|
|
19
|
+
"recommended_version": { "type": "string", "minLength": 1 },
|
|
20
|
+
"status_contract": { "type": "string", "minLength": 1 },
|
|
21
|
+
"version_contract": { "type": "string", "minLength": 1 },
|
|
22
|
+
"flow_contract": { "type": "string", "minLength": 1 }
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "dd-flow/flow-guidance@1",
|
|
4
|
+
"title": "dd-flow CLI flow guidance block",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": [
|
|
8
|
+
"current_stage",
|
|
9
|
+
"allowed_next_stages",
|
|
10
|
+
"recommended_next_action",
|
|
11
|
+
"recommended_prompt",
|
|
12
|
+
"required_predecessor_evidence",
|
|
13
|
+
"guards",
|
|
14
|
+
"blocked_if_missing"
|
|
15
|
+
],
|
|
16
|
+
"properties": {
|
|
17
|
+
"current_stage": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"minLength": 1
|
|
20
|
+
},
|
|
21
|
+
"allowed_next_stages": {
|
|
22
|
+
"type": "array",
|
|
23
|
+
"items": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"minLength": 1
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"recommended_next_action": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"minLength": 1
|
|
31
|
+
},
|
|
32
|
+
"recommended_prompt": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"minLength": 1
|
|
35
|
+
},
|
|
36
|
+
"required_predecessor_evidence": {
|
|
37
|
+
"type": "array",
|
|
38
|
+
"items": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"minLength": 1
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"guards": {
|
|
44
|
+
"type": "array",
|
|
45
|
+
"items": {
|
|
46
|
+
"type": "object",
|
|
47
|
+
"additionalProperties": false,
|
|
48
|
+
"required": ["id", "status", "summary"],
|
|
49
|
+
"properties": {
|
|
50
|
+
"id": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"minLength": 1
|
|
53
|
+
},
|
|
54
|
+
"status": {
|
|
55
|
+
"type": "string",
|
|
56
|
+
"enum": ["pass", "fail", "unknown", "not_applicable", "degraded"]
|
|
57
|
+
},
|
|
58
|
+
"summary": {
|
|
59
|
+
"type": "string",
|
|
60
|
+
"minLength": 1
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"blocked_if_missing": {
|
|
66
|
+
"type": "array",
|
|
67
|
+
"items": {
|
|
68
|
+
"type": "string",
|
|
69
|
+
"minLength": 1
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
-
"$id": "dd-flow/flow-run-index@
|
|
3
|
+
"$id": "dd-flow/flow-run-index@2",
|
|
4
4
|
"title": "dd-flow run index",
|
|
5
5
|
"description": "Navigation and artifact discovery contract for one concrete dd-flow execution.",
|
|
6
6
|
"type": "object",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
],
|
|
25
25
|
"properties": {
|
|
26
26
|
"schema_id": {
|
|
27
|
-
"
|
|
27
|
+
"enum": ["dd-flow/flow-run-index@1", "dd-flow/flow-run-index@2"]
|
|
28
28
|
},
|
|
29
29
|
"run_id": {
|
|
30
30
|
"type": "string",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"flow_kind": {
|
|
38
38
|
"type": "string",
|
|
39
|
-
"enum": ["coding", "experiment", "mb-init", "mb-upgrade", "mb-audit", "mb-distill", "mb-upgrade-review", "custom"]
|
|
39
|
+
"enum": ["mb_sdlc", "coding", "experiment", "mb-init", "mb-upgrade", "mb-audit", "mb-distill", "mb-upgrade-review", "mb-sdlc-review", "review", "custom"]
|
|
40
40
|
},
|
|
41
41
|
"subject": {
|
|
42
42
|
"type": "object",
|
|
@@ -62,7 +62,33 @@
|
|
|
62
62
|
"required": ["root", "run_dir"],
|
|
63
63
|
"properties": {
|
|
64
64
|
"root": { "type": "string", "minLength": 1 },
|
|
65
|
-
"run_dir": { "type": "string", "
|
|
65
|
+
"run_dir": { "type": "string", "minLength": 1 }
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"run_home": {
|
|
69
|
+
"type": "object",
|
|
70
|
+
"additionalProperties": false,
|
|
71
|
+
"required": ["storage", "path"],
|
|
72
|
+
"properties": {
|
|
73
|
+
"storage": { "type": "string", "enum": ["dd_flow_home", "workspace_tasks_legacy", "project_projection"] },
|
|
74
|
+
"path": { "type": "string", "minLength": 1 },
|
|
75
|
+
"relative_path": { "type": "string", "minLength": 1 }
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"execution": {
|
|
79
|
+
"type": "object",
|
|
80
|
+
"additionalProperties": false,
|
|
81
|
+
"required": ["project_root", "workspace_root"],
|
|
82
|
+
"properties": {
|
|
83
|
+
"project_root": { "type": "string", "minLength": 1 },
|
|
84
|
+
"workspace_root": { "type": "string", "minLength": 1 }
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"legacy": {
|
|
88
|
+
"type": "object",
|
|
89
|
+
"additionalProperties": false,
|
|
90
|
+
"properties": {
|
|
91
|
+
"project_tasks_run_dir": { "type": ["string", "null"] }
|
|
66
92
|
}
|
|
67
93
|
},
|
|
68
94
|
"stage_runs": {
|