@deksden-com/dd-flow-cli 0.2.0 → 0.3.1
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 +43 -0
- package/README.md +76 -5
- package/dist/build-info.json +10 -6
- package/dist/cli/help.js +165 -20
- package/dist/cli/run-cli.js +427 -17
- package/dist/schemas/compatibility.schema.json +105 -0
- package/dist/schemas/engine-manifest.schema.json +61 -0
- package/dist/schemas/flow-guidance.schema.json +90 -0
- package/dist/schemas/flow-run-index.schema.json +30 -4
- package/dist/schemas/global-dashboard-data.schema.json +126 -0
- package/dist/schemas/mb-sdlc-review-report.schema.json +242 -0
- package/dist/schemas/mb-upgrade-migration-report.schema.json +93 -0
- package/dist/schemas/plan-stage-report.schema.json +83 -0
- package/dist/schemas/project-dashboard-data.schema.json +122 -0
- package/dist/schemas/project-flow-pack-manifest.schema.json +5 -1
- package/dist/schemas/project-summary.schema.json +73 -0
- package/dist/schemas/protocol-dashboard-data.schema.json +112 -0
- package/dist/schemas/status-report.schema.json +38 -2
- 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 +45 -1
- package/dist/services/cli-operation-classifier.js +104 -0
- package/dist/services/compatibility-preflight.js +124 -0
- package/dist/services/config.js +31 -0
- package/dist/services/dashboard-targets.js +95 -0
- package/dist/services/dashboard.js +972 -10
- package/dist/services/engines.js +532 -0
- package/dist/services/flow-guidance.js +221 -0
- package/dist/services/hooks.js +1 -1
- package/dist/services/ids.js +106 -0
- package/dist/services/lanes.js +333 -1
- package/dist/services/merge-queue.js +106 -16
- package/dist/services/merge-worker.js +67 -4
- package/dist/services/migrations.js +231 -0
- package/dist/services/project-summary.js +122 -0
- package/dist/services/projects.js +44 -3
- package/dist/services/protocol-lifecycle.js +144 -0
- package/dist/services/protocols.js +660 -7
- package/dist/services/runs.js +98 -21
- package/dist/services/schema-validation.js +84 -4
- package/dist/services/sessions.js +21 -4
- package/dist/services/status.js +199 -1
- package/dist/services/version-status.js +59 -9
- package/dist/storage/database.js +31 -0
- package/dist/storage/paths.js +33 -0
- package/package.json +3 -2
|
@@ -22,7 +22,8 @@ export function getProjectVersionStatus(input) {
|
|
|
22
22
|
const flowPack = readFlowPackMetadata(input.projectRoot, memoryBank.root);
|
|
23
23
|
const memoryBankDrift = compareMemoryBankVersion(memoryBank.version, input.canon?.metadata.version ?? null, memoryBank.status);
|
|
24
24
|
const flowPackDrift = compareFlowPackCommit(flowPack.source_commit, input.canon?.metadata.commit ?? null, input.canon?.root ?? null, flowPack.status);
|
|
25
|
-
const
|
|
25
|
+
const flowContractDrift = compareFlowContract(flowPack.flow_contract, input.canon?.metadata.flow_contract ?? null, flowPack.status);
|
|
26
|
+
const overall = overallDrift(memoryBankDrift, flowPackDrift, flowContractDrift, memoryBank.status, flowPack.status);
|
|
26
27
|
return {
|
|
27
28
|
root: input.projectRoot,
|
|
28
29
|
root_source: input.rootSource,
|
|
@@ -31,8 +32,9 @@ export function getProjectVersionStatus(input) {
|
|
|
31
32
|
drift: {
|
|
32
33
|
memory_bank_version: memoryBankDrift,
|
|
33
34
|
flow_pack_commit: flowPackDrift,
|
|
35
|
+
flow_contract: flowContractDrift,
|
|
34
36
|
overall,
|
|
35
|
-
next_action: nextAction(overall, memoryBank.status, flowPack.status)
|
|
37
|
+
next_action: nextAction(overall, memoryBank.status, flowPack.status, flowContractDrift.status)
|
|
36
38
|
}
|
|
37
39
|
};
|
|
38
40
|
}
|
|
@@ -62,8 +64,12 @@ function readFlowPackMetadata(projectRoot, memoryBankRoot) {
|
|
|
62
64
|
manifest_path: null,
|
|
63
65
|
schema_id: null,
|
|
64
66
|
pack_version: null,
|
|
67
|
+
canon_root: null,
|
|
68
|
+
canon_memory_bank_root: null,
|
|
69
|
+
canon_flow_root: null,
|
|
65
70
|
source_commit: null,
|
|
66
71
|
canon_version_at_source_commit: null,
|
|
72
|
+
flow_contract: null,
|
|
67
73
|
status: "missing",
|
|
68
74
|
reason: "no_memory_bank",
|
|
69
75
|
canonical_only_files: []
|
|
@@ -77,8 +83,12 @@ function readFlowPackMetadata(projectRoot, memoryBankRoot) {
|
|
|
77
83
|
manifest_path: path.relative(projectRoot, manifestPath),
|
|
78
84
|
schema_id: null,
|
|
79
85
|
pack_version: null,
|
|
86
|
+
canon_root: null,
|
|
87
|
+
canon_memory_bank_root: null,
|
|
88
|
+
canon_flow_root: null,
|
|
80
89
|
source_commit: null,
|
|
81
90
|
canon_version_at_source_commit: null,
|
|
91
|
+
flow_contract: null,
|
|
82
92
|
status: "missing",
|
|
83
93
|
reason: "flow_pack_manifest_missing",
|
|
84
94
|
canonical_only_files: canonicalOnlyFiles
|
|
@@ -96,8 +106,12 @@ function readFlowPackMetadata(projectRoot, memoryBankRoot) {
|
|
|
96
106
|
manifest_path: path.relative(projectRoot, manifestPath),
|
|
97
107
|
schema_id: null,
|
|
98
108
|
pack_version: null,
|
|
109
|
+
canon_root: null,
|
|
110
|
+
canon_memory_bank_root: null,
|
|
111
|
+
canon_flow_root: null,
|
|
99
112
|
source_commit: null,
|
|
100
113
|
canon_version_at_source_commit: null,
|
|
114
|
+
flow_contract: null,
|
|
101
115
|
status: "invalid",
|
|
102
116
|
reason: "flow_pack_manifest_invalid_json",
|
|
103
117
|
canonical_only_files: canonicalOnlyFiles
|
|
@@ -106,14 +120,35 @@ function readFlowPackMetadata(projectRoot, memoryBankRoot) {
|
|
|
106
120
|
const schemaId = stringOrNull(manifest.schema_id);
|
|
107
121
|
const canonVersion = stringOrNull(manifest.canon_version_at_source_commit) ?? stringOrNull(manifest.canon_version);
|
|
108
122
|
const sourceCommit = stringOrNull(manifest.source_commit);
|
|
109
|
-
const
|
|
110
|
-
const
|
|
123
|
+
const canonRoot = stringOrNull(manifest.canon_root);
|
|
124
|
+
const canonMemoryBankRoot = stringOrNull(manifest.canon_memory_bank_root);
|
|
125
|
+
const canonFlowRoot = stringOrNull(manifest.canon_flow_root);
|
|
126
|
+
const flowContract = stringOrNull(manifest.flow_contract);
|
|
127
|
+
const status = schemaId === "dd-flow/project-flow-pack-manifest@2" && canonVersion && canonMemoryBankRoot && canonFlowRoot && flowContract
|
|
128
|
+
? "present"
|
|
129
|
+
: schemaId === "dd-flow/project-flow-pack-manifest@1" ||
|
|
130
|
+
(schemaId === "dd-flow/project-flow-pack-manifest@2" && canonVersion && (!canonMemoryBankRoot || !canonFlowRoot || !flowContract))
|
|
131
|
+
? "degraded"
|
|
132
|
+
: "invalid";
|
|
133
|
+
const reason = status === "degraded" && schemaId === "dd-flow/project-flow-pack-manifest@2" && (!canonMemoryBankRoot || !canonFlowRoot)
|
|
134
|
+
? "flow_pack_manifest_missing_explicit_canon_roots"
|
|
135
|
+
: status === "degraded" && schemaId === "dd-flow/project-flow-pack-manifest@2" && !flowContract
|
|
136
|
+
? "flow_pack_manifest_missing_flow_contract"
|
|
137
|
+
: status === "degraded"
|
|
138
|
+
? "legacy_flow_pack_manifest"
|
|
139
|
+
: status === "invalid"
|
|
140
|
+
? "flow_pack_manifest_schema_unknown"
|
|
141
|
+
: undefined;
|
|
111
142
|
return {
|
|
112
143
|
manifest_path: path.relative(projectRoot, manifestPath),
|
|
113
144
|
schema_id: schemaId,
|
|
114
145
|
pack_version: stringOrNull(manifest.pack_version),
|
|
146
|
+
canon_root: canonRoot,
|
|
147
|
+
canon_memory_bank_root: canonMemoryBankRoot,
|
|
148
|
+
canon_flow_root: canonFlowRoot,
|
|
115
149
|
source_commit: sourceCommit,
|
|
116
150
|
canon_version_at_source_commit: canonVersion,
|
|
151
|
+
flow_contract: flowContract,
|
|
117
152
|
status,
|
|
118
153
|
...(reason ? { reason } : {}),
|
|
119
154
|
canonical_only_files: canonicalOnlyFiles
|
|
@@ -190,28 +225,43 @@ function compareFlowPackCommit(current, target, canonRoot, artifactStatus) {
|
|
|
190
225
|
target
|
|
191
226
|
};
|
|
192
227
|
}
|
|
193
|
-
function
|
|
228
|
+
function compareFlowContract(current, target, artifactStatus) {
|
|
229
|
+
if (artifactStatus === "missing")
|
|
230
|
+
return { status: "missing", confidence: "none", reason: "flow_pack_manifest_missing", current, target };
|
|
231
|
+
if (artifactStatus === "invalid")
|
|
232
|
+
return { status: "invalid", confidence: "none", reason: "flow_pack_manifest_invalid", current, target };
|
|
233
|
+
if (!current)
|
|
234
|
+
return { status: "unknown", confidence: "none", reason: "flow_pack_flow_contract_missing", current, target };
|
|
235
|
+
if (!target)
|
|
236
|
+
return { status: "unknown", confidence: "none", reason: "canon_flow_contract_unknown", current, target };
|
|
237
|
+
if (current === target)
|
|
238
|
+
return { status: "same", confidence: "exact", reason: "flow_contract_equal", current, target };
|
|
239
|
+
return { status: "diverged", confidence: "declared", reason: "flow_contract_mismatch", current, target };
|
|
240
|
+
}
|
|
241
|
+
function overallDrift(memoryBank, flowPack, flowContract, memoryStatus, flowStatus) {
|
|
194
242
|
if (memoryStatus === "missing")
|
|
195
243
|
return "not_applicable";
|
|
196
|
-
if (memoryBank.status === "invalid" || flowPack.status === "invalid")
|
|
244
|
+
if (memoryBank.status === "invalid" || flowPack.status === "invalid" || flowContract.status === "invalid")
|
|
197
245
|
return "invalid";
|
|
198
|
-
if (memoryBank.status === "missing" || flowPack.status === "missing")
|
|
246
|
+
if (memoryBank.status === "missing" || flowPack.status === "missing" || flowContract.status === "missing")
|
|
199
247
|
return "missing";
|
|
200
248
|
if (memoryBank.status === "ahead" || flowPack.status === "ahead")
|
|
201
249
|
return "ahead";
|
|
202
250
|
if (memoryBank.status === "behind" || flowPack.status === "behind")
|
|
203
251
|
return "behind";
|
|
204
|
-
if (memoryBank.status === "diverged" || flowPack.status === "diverged")
|
|
252
|
+
if (memoryBank.status === "diverged" || flowPack.status === "diverged" || flowContract.status === "diverged")
|
|
205
253
|
return "diverged";
|
|
206
254
|
if (memoryBank.status === "same" && (flowPack.status === "same" || flowStatus === "degraded"))
|
|
207
255
|
return flowStatus === "degraded" ? "unknown" : "same";
|
|
208
256
|
return "unknown";
|
|
209
257
|
}
|
|
210
|
-
function nextAction(overall, memoryStatus, flowStatus) {
|
|
258
|
+
function nextAction(overall, memoryStatus, flowStatus, flowContractStatus) {
|
|
211
259
|
if (overall === "same")
|
|
212
260
|
return "no_action";
|
|
213
261
|
if (overall === "not_applicable" && memoryStatus === "missing")
|
|
214
262
|
return "run_mb_init_if_project_needs_memory_bank";
|
|
263
|
+
if (flowContractStatus === "diverged" || flowContractStatus === "unknown")
|
|
264
|
+
return "run_canonical_mb_upgrade_before_lifecycle_mutations";
|
|
215
265
|
if (overall === "behind" || flowStatus === "degraded")
|
|
216
266
|
return "run_canonical_mb_upgrade";
|
|
217
267
|
if (overall === "missing")
|
package/dist/storage/database.js
CHANGED
|
@@ -134,10 +134,34 @@ function migrate(db) {
|
|
|
134
134
|
FOREIGN KEY(project_id) REFERENCES projects(id)
|
|
135
135
|
);
|
|
136
136
|
|
|
137
|
+
CREATE TABLE IF NOT EXISTS lane_waiters (
|
|
138
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
139
|
+
project_id TEXT NOT NULL,
|
|
140
|
+
lane TEXT NOT NULL,
|
|
141
|
+
worker_id TEXT NOT NULL,
|
|
142
|
+
status TEXT NOT NULL,
|
|
143
|
+
queued_at TEXT NOT NULL,
|
|
144
|
+
acquired_at TEXT,
|
|
145
|
+
cancelled_at TEXT,
|
|
146
|
+
expires_at TEXT,
|
|
147
|
+
reason TEXT,
|
|
148
|
+
metadata_json TEXT NOT NULL,
|
|
149
|
+
created_at TEXT NOT NULL,
|
|
150
|
+
updated_at TEXT NOT NULL,
|
|
151
|
+
FOREIGN KEY(project_id) REFERENCES projects(id)
|
|
152
|
+
);
|
|
153
|
+
|
|
137
154
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_lane_locks_one_active
|
|
138
155
|
ON lane_locks(project_id, lane)
|
|
139
156
|
WHERE status = 'active';
|
|
140
157
|
|
|
158
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_lane_waiters_one_queued_worker
|
|
159
|
+
ON lane_waiters(project_id, lane, worker_id)
|
|
160
|
+
WHERE status = 'queued';
|
|
161
|
+
|
|
162
|
+
CREATE INDEX IF NOT EXISTS idx_lane_waiters_fifo
|
|
163
|
+
ON lane_waiters(project_id, lane, status, queued_at, id);
|
|
164
|
+
|
|
141
165
|
CREATE TABLE IF NOT EXISTS hook_installations (
|
|
142
166
|
project_id TEXT NOT NULL,
|
|
143
167
|
scope TEXT NOT NULL,
|
|
@@ -243,6 +267,9 @@ function migrate(db) {
|
|
|
243
267
|
runtime_path TEXT NOT NULL,
|
|
244
268
|
run_dir TEXT NOT NULL,
|
|
245
269
|
run_index_path TEXT NOT NULL,
|
|
270
|
+
run_home_path TEXT,
|
|
271
|
+
layout_version TEXT,
|
|
272
|
+
artifact_root_kind TEXT,
|
|
246
273
|
index_json TEXT NOT NULL,
|
|
247
274
|
created_at TEXT NOT NULL,
|
|
248
275
|
updated_at TEXT NOT NULL,
|
|
@@ -318,6 +345,10 @@ function migrate(db) {
|
|
|
318
345
|
ensureColumn(db, "flow_sessions", "next_action", "ALTER TABLE flow_sessions ADD COLUMN next_action TEXT");
|
|
319
346
|
ensureColumn(db, "flow_sessions", "metadata_json", "ALTER TABLE flow_sessions ADD COLUMN metadata_json TEXT NOT NULL DEFAULT '{}'");
|
|
320
347
|
ensureColumn(db, "flow_sessions", "run_id", "ALTER TABLE flow_sessions ADD COLUMN run_id TEXT");
|
|
348
|
+
ensureColumn(db, "flow_runs", "run_home_path", "ALTER TABLE flow_runs ADD COLUMN run_home_path TEXT");
|
|
349
|
+
ensureColumn(db, "flow_runs", "layout_version", "ALTER TABLE flow_runs ADD COLUMN layout_version TEXT");
|
|
350
|
+
ensureColumn(db, "flow_runs", "artifact_root_kind", "ALTER TABLE flow_runs ADD COLUMN artifact_root_kind TEXT");
|
|
351
|
+
ensureColumn(db, "lane_waiters", "expires_at", "ALTER TABLE lane_waiters ADD COLUMN expires_at TEXT");
|
|
321
352
|
}
|
|
322
353
|
function ensureColumn(db, table, column, sql) {
|
|
323
354
|
const columns = db.prepare(`PRAGMA table_info(${table})`).all();
|
package/dist/storage/paths.js
CHANGED
|
@@ -33,12 +33,30 @@ export function runtimeRunDir(ddFlowHome, projectId, runId) {
|
|
|
33
33
|
export function runtimeRunJsonPath(ddFlowHome, projectId, runId) {
|
|
34
34
|
return path.join(runtimeRunDir(ddFlowHome, projectId, runId), "run.json");
|
|
35
35
|
}
|
|
36
|
+
export function projectRunHome(ddFlowHome, projectId, runId) {
|
|
37
|
+
return path.join(projectHome(ddFlowHome, projectId), "runs", runId);
|
|
38
|
+
}
|
|
39
|
+
export function projectRunJsonPath(ddFlowHome, projectId, runId) {
|
|
40
|
+
return path.join(projectRunHome(ddFlowHome, projectId, runId), "run.json");
|
|
41
|
+
}
|
|
42
|
+
export function projectRunIndexPath(ddFlowHome, projectId, runId) {
|
|
43
|
+
return path.join(projectRunHome(ddFlowHome, projectId, runId), "run-index.json");
|
|
44
|
+
}
|
|
45
|
+
export function projectRunStageDir(ddFlowHome, projectId, runId, stageDir) {
|
|
46
|
+
return path.join(projectRunHome(ddFlowHome, projectId, runId), stageDir);
|
|
47
|
+
}
|
|
36
48
|
export function userFacingRunDir(workspaceRoot, runId) {
|
|
37
49
|
return path.join(workspaceRoot, ".tasks", "dd-flow-runs", runId);
|
|
38
50
|
}
|
|
51
|
+
export function legacyWorkspaceRunDir(workspaceRoot, runId) {
|
|
52
|
+
return userFacingRunDir(workspaceRoot, runId);
|
|
53
|
+
}
|
|
39
54
|
export function userFacingRunIndexPath(workspaceRoot, runId) {
|
|
40
55
|
return path.join(userFacingRunDir(workspaceRoot, runId), "run-index.json");
|
|
41
56
|
}
|
|
57
|
+
export function userFacingRunStageDir(workspaceRoot, runId, stageDir) {
|
|
58
|
+
return path.join(userFacingRunDir(workspaceRoot, runId), stageDir);
|
|
59
|
+
}
|
|
42
60
|
export function stateJsonPath(projectRoot, protocolId) {
|
|
43
61
|
return path.join(protocolDir(projectRoot, protocolId), "state.json");
|
|
44
62
|
}
|
|
@@ -54,3 +72,18 @@ export function projectRuntimeRoot(ddFlowHome, projectId) {
|
|
|
54
72
|
export function projectCheckoutRoot(ddFlowHome, projectId) {
|
|
55
73
|
return path.join(projectHome(ddFlowHome, projectId), "checkouts");
|
|
56
74
|
}
|
|
75
|
+
export function projectFeatureWorktreePath(ddFlowHome, projectId, runOrProtocolId, repoName) {
|
|
76
|
+
return path.join(projectCheckoutRoot(ddFlowHome, projectId), "worktrees", runOrProtocolId, repoName);
|
|
77
|
+
}
|
|
78
|
+
export function engineStoreRoot(ddFlowHome) {
|
|
79
|
+
return path.join(ddFlowHome, "engines");
|
|
80
|
+
}
|
|
81
|
+
export function packageEngineRoot(ddFlowHome, packageName) {
|
|
82
|
+
return path.join(engineStoreRoot(ddFlowHome), safePathSegment(packageName));
|
|
83
|
+
}
|
|
84
|
+
export function engineVersionRoot(ddFlowHome, packageName, version) {
|
|
85
|
+
return path.join(packageEngineRoot(ddFlowHome, packageName), safePathSegment(version));
|
|
86
|
+
}
|
|
87
|
+
function safePathSegment(value) {
|
|
88
|
+
return value.replace(/[^a-zA-Z0-9_.@-]+/g, "_");
|
|
89
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deksden-com/dd-flow-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Mechanical runtime CLI for dd-flow workflows.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
|
-
"README.md"
|
|
11
|
+
"README.md",
|
|
12
|
+
"CHANGELOG.md"
|
|
12
13
|
],
|
|
13
14
|
"engines": {
|
|
14
15
|
"node": ">=26.0.0",
|