@deksden-com/dd-flow-cli 0.4.2 → 0.6.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 +33 -4
- package/README.md +2 -2
- package/dist/build-info.json +6 -6
- package/dist/cli/help.js +16 -4
- package/dist/cli/run-cli.js +42 -17
- package/dist/domain/flow-contract.js +82 -3
- package/dist/domain/session-coverage.js +88 -0
- package/dist/domain/validation.js +56 -28
- package/dist/protocol/local-files.js +1 -16
- package/dist/schemas/code-stage-report.schema.json +2 -2
- package/dist/schemas/flow-contract.schema.json +152 -94
- package/dist/schemas/flow-run.schema.json +129 -23
- package/dist/schemas/mb-upgrade-review-data.schema.json +2 -2
- package/dist/schemas/memorybank-permissions-preflight.schema.json +13 -73
- package/dist/schemas/merge-stage-report.schema.json +2 -2
- package/dist/schemas/plan-stage-report.schema.json +38 -335
- package/dist/schemas/project-flow-pack-manifest.schema.json +4 -4
- package/dist/schemas/protocol-plan.schema.json +197 -0
- package/dist/schemas/release-impact.schema.json +9 -5
- package/dist/schemas/session-usage.schema.json +16 -0
- package/dist/schemas/stage-finish-input.schema.json +20 -0
- package/dist/schemas/stage-prompt.schema.json +35 -0
- package/dist/schemas/stage-report.schema.json +20 -0
- package/dist/schemas/stage-start-response.schema.json +30 -0
- package/dist/schemas/timeline-event.schema.json +29 -0
- package/dist/schemas/worktrunk-workspace.schema.json +19 -0
- package/dist/services/branch-context.js +9 -4
- package/dist/services/cleanup.js +77 -0
- package/dist/services/dashboard.js +51 -26
- package/dist/services/engines.js +84 -18
- package/dist/services/hooks.js +101 -250
- package/dist/services/memory-permissions.js +77 -69
- package/dist/services/migrations.js +1 -1
- package/dist/services/plan-runtime.js +124 -0
- package/dist/services/plans.js +22 -84
- package/dist/services/projects.js +2 -1
- package/dist/services/prompts.js +26 -21
- package/dist/services/protocols.js +29 -25
- package/dist/services/run-projection.js +93 -13
- package/dist/services/runs.js +128 -61
- package/dist/services/schema-validation.js +168 -7
- package/dist/services/sessions.js +97 -73
- package/dist/services/stage-lifecycle.js +737 -0
- package/dist/services/tooling.js +285 -0
- package/dist/services/usage.js +183 -30
- package/dist/services/version-status.js +1 -1
- package/dist/services/worktrees.js +88 -39
- package/dist/storage/database.js +72 -30
- package/dist/storage/paths.js +0 -9
- package/package.json +14 -13
- package/tools/worktrunk-manifest.json +34 -0
- package/dist/schemas/flow-run-index-v3.schema.json +0 -203
- package/dist/schemas/flow-run-index.schema.json +0 -175
|
@@ -8,7 +8,7 @@ import { projectCheckoutRoot, resolveProjectRoot } from "../storage/paths.js";
|
|
|
8
8
|
import { appendAudit } from "./audit.js";
|
|
9
9
|
import { persistProtocolState, readProtocolRuntimeState, requireProtocol } from "./protocols.js";
|
|
10
10
|
import { requireProjectByRoot } from "./projects.js";
|
|
11
|
-
|
|
11
|
+
import { ensureManagedWorktrunk, inspectManagedWorktrunk } from "./tooling.js";
|
|
12
12
|
export function planWorktree(context, input) {
|
|
13
13
|
const protocol = scopedProtocol(context, input.projectRoot, input.protocolId);
|
|
14
14
|
const state = readProtocolRuntimeState(context, protocol).state;
|
|
@@ -25,7 +25,7 @@ export function planWorktree(context, input) {
|
|
|
25
25
|
owner: "dd-flow",
|
|
26
26
|
purpose: "feature"
|
|
27
27
|
},
|
|
28
|
-
worktrunk:
|
|
28
|
+
worktrunk: inspectManagedWorktrunk(context)
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
export function createWorktreeRecord(context, input) {
|
|
@@ -37,15 +37,16 @@ export function createWorktreeRecord(context, input) {
|
|
|
37
37
|
worktree_path: existing.worktree_path
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
|
-
const worktrunk =
|
|
41
|
-
const
|
|
42
|
-
if (isTrackedProjectPath(protocol.project_root, worktreePath)) {
|
|
43
|
-
throw new AppError("worktree_active", "Worktree path is inside tracked project files", 1, { path: worktreePath });
|
|
44
|
-
}
|
|
45
|
-
const command = [worktrunk.bin, "worktree", "create", "--branch", input.branch, "--base", input.base, "--path", worktreePath];
|
|
40
|
+
const worktrunk = ensureManagedWorktrunk(context);
|
|
41
|
+
const command = [worktrunk.bin, "-C", protocol.project_root, "switch", "--create", input.branch, "--base", input.base, "--no-cd", "--format=json", "-y"];
|
|
46
42
|
const result = runExternal(command);
|
|
47
43
|
if (result.exit_code !== 0) {
|
|
48
|
-
throw new AppError("
|
|
44
|
+
throw new AppError("worktrunk_command_unavailable", "Worktrunk switch failed", 1, { command: sanitizeCommand(command), result });
|
|
45
|
+
}
|
|
46
|
+
const response = parseWorktrunkResponse(result.stdout, command);
|
|
47
|
+
const worktreePath = response.workspace_path;
|
|
48
|
+
if (isTrackedProjectPath(protocol.project_root, worktreePath)) {
|
|
49
|
+
throw new AppError("worktree_active", "Worktrunk returned a workspace inside tracked project files", 1, { path: worktreePath });
|
|
49
50
|
}
|
|
50
51
|
const now = context.now();
|
|
51
52
|
const state = readProtocolRuntimeState(context, protocol).state;
|
|
@@ -59,7 +60,7 @@ export function createWorktreeRecord(context, input) {
|
|
|
59
60
|
input.branch,
|
|
60
61
|
input.base,
|
|
61
62
|
worktreePath,
|
|
62
|
-
JSON.stringify({ bin: worktrunk.bin }),
|
|
63
|
+
JSON.stringify({ bin: worktrunk.bin, version: worktrunk.version, command, response }),
|
|
63
64
|
JSON.stringify(result),
|
|
64
65
|
now,
|
|
65
66
|
now
|
|
@@ -71,8 +72,8 @@ export function createWorktreeRecord(context, input) {
|
|
|
71
72
|
feature_branch: input.branch,
|
|
72
73
|
worktree_path: worktreePath,
|
|
73
74
|
base_commit: input.base,
|
|
74
|
-
worktrunk: { bin: worktrunk.bin },
|
|
75
|
-
bootstrap: { status: "pending" }
|
|
75
|
+
worktrunk: { bin: worktrunk.bin, version: worktrunk.version, response },
|
|
76
|
+
bootstrap: { status: typeof response.bootstrap_status === "string" ? response.bootstrap_status : "pending" }
|
|
76
77
|
},
|
|
77
78
|
updated_at: now
|
|
78
79
|
});
|
|
@@ -86,7 +87,7 @@ export function createWorktreeRecord(context, input) {
|
|
|
86
87
|
}
|
|
87
88
|
export function getWorktreeStatus(context, input) {
|
|
88
89
|
const protocol = scopedProtocol(context, input.projectRoot, input.protocolId);
|
|
89
|
-
return { ok: true, protocol_id: protocol.id, worktree: worktreeRecord(context, protocol.project_id, protocol.id), worktrunk:
|
|
90
|
+
return { ok: true, protocol_id: protocol.id, worktree: worktreeRecord(context, protocol.project_id, protocol.id), worktrunk: inspectManagedWorktrunk(context) };
|
|
90
91
|
}
|
|
91
92
|
export function bootstrapWorktree(context, input) {
|
|
92
93
|
const protocol = scopedProtocol(context, input.projectRoot, input.protocolId);
|
|
@@ -94,12 +95,32 @@ export function bootstrapWorktree(context, input) {
|
|
|
94
95
|
if (!record) {
|
|
95
96
|
throw new AppError("not_found", `Worktree record is not active for protocol: ${protocol.id}`, 1);
|
|
96
97
|
}
|
|
98
|
+
const includeFile = path.join(protocol.project_root, ".worktreeinclude");
|
|
99
|
+
const configFile = path.join(protocol.project_root, ".config", "wt.toml");
|
|
100
|
+
if (!fs.existsSync(includeFile) || !fs.existsSync(configFile)) {
|
|
101
|
+
throw new AppError("bootstrap_unavailable", "Project-owned Worktrunk bootstrap files are required", 1, {
|
|
102
|
+
include_file: includeFile,
|
|
103
|
+
config_file: configFile,
|
|
104
|
+
next_action: "Add .worktreeinclude and .config/wt.toml before bootstrapping the workspace."
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
const worktrunk = ensureManagedWorktrunk(context);
|
|
108
|
+
const commands = [
|
|
109
|
+
[worktrunk.bin, "-C", record.worktree_path, "step", "copy-ignored", "--require-include"],
|
|
110
|
+
[worktrunk.bin, "-C", record.worktree_path, "hook", "pre-start", "--yes"]
|
|
111
|
+
];
|
|
112
|
+
const results = [];
|
|
113
|
+
for (const command of commands) {
|
|
114
|
+
const result = runExternal(command);
|
|
115
|
+
results.push({ command: sanitizeCommand(command), ...result });
|
|
116
|
+
if (result.exit_code !== 0) {
|
|
117
|
+
const failed = { command: sanitizeCommand(command), result, results };
|
|
118
|
+
markBootstrapFailed(context, protocol, record, failed);
|
|
119
|
+
throw new AppError("bootstrap_failed", "Project-owned Worktrunk bootstrap failed", 1, failed);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
97
122
|
const now = context.now();
|
|
98
|
-
const result = {
|
|
99
|
-
exit_code: 0,
|
|
100
|
-
stdout: "No project bootstrap command configured.",
|
|
101
|
-
stderr: ""
|
|
102
|
-
};
|
|
123
|
+
const result = { commands: results, status: "succeeded" };
|
|
103
124
|
context.db.run(`UPDATE worktree_records
|
|
104
125
|
SET bootstrap_status = 'succeeded', last_command_result_json = ?, updated_at = ?
|
|
105
126
|
WHERE project_id = ? AND protocol_id = ?`, [JSON.stringify(result), now, protocol.project_id, protocol.id]);
|
|
@@ -108,7 +129,7 @@ export function bootstrapWorktree(context, input) {
|
|
|
108
129
|
...state,
|
|
109
130
|
workspace: {
|
|
110
131
|
...state.workspace,
|
|
111
|
-
bootstrap: { status: "succeeded", commands:
|
|
132
|
+
bootstrap: { status: "succeeded", commands: results, blockers: [] }
|
|
112
133
|
},
|
|
113
134
|
updated_at: now
|
|
114
135
|
});
|
|
@@ -116,7 +137,7 @@ export function bootstrapWorktree(context, input) {
|
|
|
116
137
|
protocolId: protocol.id,
|
|
117
138
|
projectId: protocol.project_id,
|
|
118
139
|
eventType: "worktree.bootstrap_succeeded",
|
|
119
|
-
payload: { protocol_id: protocol.id, worktree_path: record.worktree_path }
|
|
140
|
+
payload: { protocol_id: protocol.id, worktree_path: record.worktree_path, commands: results }
|
|
120
141
|
});
|
|
121
142
|
return { ok: true, worktree: worktreeRecord(context, protocol.project_id, protocol.id) };
|
|
122
143
|
}
|
|
@@ -167,24 +188,6 @@ export function worktreeRecord(context, projectId, protocolId) {
|
|
|
167
188
|
function activeWorktreeRecord(context, projectId, protocolId) {
|
|
168
189
|
return context.db.get("SELECT * FROM worktree_records WHERE project_id = ? AND protocol_id = ? AND status = 'active'", [projectId, protocolId]);
|
|
169
190
|
}
|
|
170
|
-
function detectWorktrunk(context) {
|
|
171
|
-
const configured = context.env[worktrunkBinEnv];
|
|
172
|
-
if (configured && fs.existsSync(configured)) {
|
|
173
|
-
return { available: true, bin: configured };
|
|
174
|
-
}
|
|
175
|
-
const probe = spawnSync("worktrunk", ["--version"], { encoding: "utf8" });
|
|
176
|
-
return probe.error ? { available: false, bin: null } : { available: true, bin: "worktrunk" };
|
|
177
|
-
}
|
|
178
|
-
function requireWorktrunk(context) {
|
|
179
|
-
const detected = detectWorktrunk(context);
|
|
180
|
-
if (!detected.available || !detected.bin) {
|
|
181
|
-
throw new AppError("tool_unavailable", "Worktrunk executable is unavailable", 1, {
|
|
182
|
-
tool: "worktrunk",
|
|
183
|
-
next_action: `Set ${worktrunkBinEnv} to a Worktrunk-compatible executable for local proof.`
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
return { bin: detected.bin };
|
|
187
|
-
}
|
|
188
191
|
function runExternal(command) {
|
|
189
192
|
const [bin, ...args] = command;
|
|
190
193
|
if (!bin) {
|
|
@@ -203,7 +206,53 @@ function sanitizeCommand(command) {
|
|
|
203
206
|
function sanitizeOutput(value) {
|
|
204
207
|
return value.replace(/(token|secret|password)=\S+/gi, "$1=<redacted>");
|
|
205
208
|
}
|
|
209
|
+
function parseWorktrunkResponse(stdout, command) {
|
|
210
|
+
let parsed;
|
|
211
|
+
try {
|
|
212
|
+
parsed = JSON.parse(stdout.trim());
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
throw new AppError("worktrunk_invalid_response", "Worktrunk did not return valid JSON", 1, {
|
|
216
|
+
command: sanitizeCommand(command),
|
|
217
|
+
stdout: sanitizeOutput(stdout),
|
|
218
|
+
cause: String(error)
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
222
|
+
throw new AppError("worktrunk_invalid_response", "Worktrunk JSON response must be an object", 1, { command: sanitizeCommand(command) });
|
|
223
|
+
}
|
|
224
|
+
const response = parsed;
|
|
225
|
+
if (typeof response.workspace_path !== "string" || !path.isAbsolute(response.workspace_path)) {
|
|
226
|
+
throw new AppError("worktrunk_invalid_response", "Worktrunk response must contain an absolute workspace_path", 1, {
|
|
227
|
+
command: sanitizeCommand(command),
|
|
228
|
+
response
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
return { ...response, workspace_path: path.resolve(response.workspace_path) };
|
|
232
|
+
}
|
|
233
|
+
function markBootstrapFailed(context, protocol, record, failure) {
|
|
234
|
+
const now = context.now();
|
|
235
|
+
context.db.run(`UPDATE worktree_records
|
|
236
|
+
SET bootstrap_status = 'failed', last_command_result_json = ?, updated_at = ?
|
|
237
|
+
WHERE project_id = ? AND protocol_id = ?`, [JSON.stringify(failure), now, protocol.project_id, protocol.id]);
|
|
238
|
+
const state = readProtocolRuntimeState(context, protocol).state;
|
|
239
|
+
persistProtocolState(context, protocol, {
|
|
240
|
+
...state,
|
|
241
|
+
workspace: {
|
|
242
|
+
...state.workspace,
|
|
243
|
+
worktree_path: record.worktree_path,
|
|
244
|
+
bootstrap: { status: "failed", commands: failure.results ?? [], blockers: [failure] }
|
|
245
|
+
},
|
|
246
|
+
updated_at: now
|
|
247
|
+
});
|
|
248
|
+
appendAudit(context, {
|
|
249
|
+
protocolId: protocol.id,
|
|
250
|
+
projectId: protocol.project_id,
|
|
251
|
+
eventType: "worktree.bootstrap_failed",
|
|
252
|
+
payload: { protocol_id: protocol.id, worktree_path: record.worktree_path, failure }
|
|
253
|
+
});
|
|
254
|
+
}
|
|
206
255
|
function isTrackedProjectPath(projectRoot, candidate) {
|
|
207
256
|
const relative = path.relative(projectRoot, candidate);
|
|
208
|
-
return
|
|
257
|
+
return !relative || (!relative.startsWith("..") && !path.isAbsolute(relative));
|
|
209
258
|
}
|
package/dist/storage/database.js
CHANGED
|
@@ -60,15 +60,34 @@ function migrate(db) {
|
|
|
60
60
|
FOREIGN KEY(project_id) REFERENCES projects(id)
|
|
61
61
|
);
|
|
62
62
|
|
|
63
|
-
CREATE TABLE IF NOT EXISTS
|
|
63
|
+
CREATE TABLE IF NOT EXISTS plan_bindings (
|
|
64
64
|
project_id TEXT NOT NULL,
|
|
65
65
|
protocol_id TEXT NOT NULL,
|
|
66
|
-
|
|
66
|
+
plan_revision INTEGER NOT NULL,
|
|
67
|
+
plan_sha256 TEXT NOT NULL,
|
|
68
|
+
plan_path TEXT NOT NULL,
|
|
69
|
+
bound_at TEXT NOT NULL,
|
|
67
70
|
updated_at TEXT NOT NULL,
|
|
68
71
|
PRIMARY KEY(project_id, protocol_id),
|
|
69
72
|
FOREIGN KEY(project_id, protocol_id) REFERENCES protocols(project_id, id)
|
|
70
73
|
);
|
|
71
74
|
|
|
75
|
+
CREATE TABLE IF NOT EXISTS plan_progress (
|
|
76
|
+
project_id TEXT NOT NULL,
|
|
77
|
+
protocol_id TEXT NOT NULL,
|
|
78
|
+
item_id TEXT NOT NULL,
|
|
79
|
+
plan_revision INTEGER NOT NULL,
|
|
80
|
+
plan_sha256 TEXT NOT NULL,
|
|
81
|
+
status TEXT NOT NULL,
|
|
82
|
+
summary TEXT NOT NULL DEFAULT '',
|
|
83
|
+
evidence_json TEXT NOT NULL DEFAULT '[]',
|
|
84
|
+
block_reason TEXT,
|
|
85
|
+
user_required INTEGER NOT NULL DEFAULT 0,
|
|
86
|
+
updated_at TEXT NOT NULL,
|
|
87
|
+
PRIMARY KEY(project_id, protocol_id, item_id),
|
|
88
|
+
FOREIGN KEY(project_id, protocol_id) REFERENCES protocols(project_id, id)
|
|
89
|
+
);
|
|
90
|
+
|
|
72
91
|
CREATE TABLE IF NOT EXISTS audit_events (
|
|
73
92
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
74
93
|
protocol_id TEXT,
|
|
@@ -313,6 +332,9 @@ function migrate(db) {
|
|
|
313
332
|
total_tokens INTEGER,
|
|
314
333
|
input_tokens INTEGER,
|
|
315
334
|
cached_input_tokens INTEGER,
|
|
335
|
+
cache_read_input_tokens INTEGER,
|
|
336
|
+
cache_write_input_tokens INTEGER,
|
|
337
|
+
uncached_input_tokens INTEGER,
|
|
316
338
|
output_tokens INTEGER,
|
|
317
339
|
reasoning_output_tokens INTEGER,
|
|
318
340
|
source_kind TEXT NOT NULL,
|
|
@@ -329,34 +351,62 @@ function migrate(db) {
|
|
|
329
351
|
CREATE INDEX IF NOT EXISTS idx_flow_run_usage_snapshots_run
|
|
330
352
|
ON flow_run_usage_snapshots(project_id, run_id, session_id, observed_at, id);
|
|
331
353
|
|
|
332
|
-
CREATE TABLE IF NOT EXISTS
|
|
333
|
-
|
|
354
|
+
CREATE TABLE IF NOT EXISTS codex_hook_events (
|
|
355
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
334
356
|
project_id TEXT NOT NULL,
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
transcript_path TEXT,
|
|
357
|
+
protocol_id TEXT,
|
|
358
|
+
session_id TEXT,
|
|
338
359
|
turn_id TEXT,
|
|
360
|
+
event_key TEXT,
|
|
361
|
+
event_name TEXT NOT NULL,
|
|
362
|
+
tool_name TEXT,
|
|
339
363
|
status TEXT NOT NULL,
|
|
364
|
+
sanitized_summary TEXT NOT NULL,
|
|
340
365
|
created_at TEXT NOT NULL,
|
|
341
|
-
updated_at TEXT NOT NULL,
|
|
342
|
-
PRIMARY KEY(session_id, project_id),
|
|
343
366
|
FOREIGN KEY(project_id) REFERENCES projects(id)
|
|
344
367
|
);
|
|
345
368
|
|
|
346
|
-
CREATE TABLE IF NOT EXISTS
|
|
369
|
+
CREATE TABLE IF NOT EXISTS flow_session_segments (
|
|
347
370
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
348
371
|
project_id TEXT NOT NULL,
|
|
372
|
+
session_id TEXT NOT NULL,
|
|
373
|
+
run_id TEXT,
|
|
349
374
|
protocol_id TEXT,
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
375
|
+
started_at TEXT NOT NULL,
|
|
376
|
+
ended_at TEXT,
|
|
377
|
+
cwd TEXT,
|
|
353
378
|
tool_name TEXT,
|
|
379
|
+
event_key TEXT NOT NULL,
|
|
380
|
+
FOREIGN KEY(project_id) REFERENCES projects(id)
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
CREATE INDEX IF NOT EXISTS idx_flow_session_segments_session
|
|
384
|
+
ON flow_session_segments(project_id, session_id, started_at, id);
|
|
385
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_flow_session_segments_event
|
|
386
|
+
ON flow_session_segments(project_id, event_key);
|
|
387
|
+
|
|
388
|
+
CREATE TABLE IF NOT EXISTS flow_jobs (
|
|
389
|
+
job_id TEXT PRIMARY KEY,
|
|
390
|
+
project_id TEXT NOT NULL,
|
|
391
|
+
run_id TEXT NOT NULL,
|
|
392
|
+
protocol_id TEXT,
|
|
393
|
+
plan_item_id TEXT NOT NULL,
|
|
394
|
+
group_id TEXT,
|
|
354
395
|
status TEXT NOT NULL,
|
|
355
|
-
|
|
356
|
-
|
|
396
|
+
worker_session_id TEXT,
|
|
397
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
398
|
+
last_error TEXT,
|
|
399
|
+
registered_at TEXT NOT NULL,
|
|
400
|
+
updated_at TEXT NOT NULL,
|
|
401
|
+
started_at TEXT,
|
|
402
|
+
finished_at TEXT,
|
|
403
|
+
UNIQUE(project_id, run_id, plan_item_id),
|
|
357
404
|
FOREIGN KEY(project_id) REFERENCES projects(id)
|
|
358
405
|
);
|
|
359
406
|
|
|
407
|
+
CREATE INDEX IF NOT EXISTS idx_flow_jobs_resume
|
|
408
|
+
ON flow_jobs(project_id, run_id, status, plan_item_id);
|
|
409
|
+
|
|
360
410
|
CREATE TABLE IF NOT EXISTS worktree_records (
|
|
361
411
|
protocol_id TEXT NOT NULL,
|
|
362
412
|
project_id TEXT NOT NULL,
|
|
@@ -399,9 +449,16 @@ function migrate(db) {
|
|
|
399
449
|
ensureColumn(db, "flow_sessions", "plan_item_id", "ALTER TABLE flow_sessions ADD COLUMN plan_item_id TEXT");
|
|
400
450
|
ensureColumn(db, "flow_sessions", "session_kind", "ALTER TABLE flow_sessions ADD COLUMN session_kind TEXT");
|
|
401
451
|
ensureColumn(db, "flow_sessions", "coverage_units_json", "ALTER TABLE flow_sessions ADD COLUMN coverage_units_json TEXT NOT NULL DEFAULT '[]'");
|
|
452
|
+
ensureColumn(db, "flow_run_usage_snapshots", "cache_read_input_tokens", "ALTER TABLE flow_run_usage_snapshots ADD COLUMN cache_read_input_tokens INTEGER");
|
|
453
|
+
ensureColumn(db, "flow_run_usage_snapshots", "cache_write_input_tokens", "ALTER TABLE flow_run_usage_snapshots ADD COLUMN cache_write_input_tokens INTEGER");
|
|
454
|
+
ensureColumn(db, "flow_run_usage_snapshots", "uncached_input_tokens", "ALTER TABLE flow_run_usage_snapshots ADD COLUMN uncached_input_tokens INTEGER");
|
|
455
|
+
db.prepare("UPDATE flow_run_usage_snapshots SET cache_read_input_tokens = cached_input_tokens WHERE cache_read_input_tokens IS NULL AND cached_input_tokens IS NOT NULL").run();
|
|
402
456
|
ensureColumn(db, "flow_runs", "run_home_path", "ALTER TABLE flow_runs ADD COLUMN run_home_path TEXT");
|
|
403
457
|
ensureColumn(db, "flow_runs", "layout_version", "ALTER TABLE flow_runs ADD COLUMN layout_version TEXT");
|
|
404
458
|
ensureColumn(db, "flow_runs", "artifact_root_kind", "ALTER TABLE flow_runs ADD COLUMN artifact_root_kind TEXT");
|
|
459
|
+
ensureColumn(db, "codex_hook_events", "event_key", "ALTER TABLE codex_hook_events ADD COLUMN event_key TEXT");
|
|
460
|
+
ensureColumn(db, "flow_jobs", "updated_at", "ALTER TABLE flow_jobs ADD COLUMN updated_at TEXT NOT NULL DEFAULT ''");
|
|
461
|
+
db.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_codex_hook_events_event_key ON codex_hook_events(project_id, event_key) WHERE event_key IS NOT NULL");
|
|
405
462
|
ensureColumn(db, "lane_waiters", "expires_at", "ALTER TABLE lane_waiters ADD COLUMN expires_at TEXT");
|
|
406
463
|
db.exec(`
|
|
407
464
|
CREATE INDEX IF NOT EXISTS idx_flow_runs_project_updated
|
|
@@ -420,7 +477,6 @@ function migrateProjectScopedIdentity(db) {
|
|
|
420
477
|
PRAGMA foreign_keys = OFF;
|
|
421
478
|
BEGIN IMMEDIATE;
|
|
422
479
|
|
|
423
|
-
ALTER TABLE plans RENAME TO plans_legacy_global_identity;
|
|
424
480
|
ALTER TABLE merge_queue RENAME TO merge_queue_legacy_global_identity;
|
|
425
481
|
ALTER TABLE worktree_records RENAME TO worktree_records_legacy_global_identity;
|
|
426
482
|
ALTER TABLE flow_runs RENAME TO flow_runs_legacy_global_identity;
|
|
@@ -455,19 +511,6 @@ function migrateProjectScopedIdentity(db) {
|
|
|
455
511
|
state_path, plan_path, created_at, updated_at
|
|
456
512
|
FROM protocols_legacy_global_identity;
|
|
457
513
|
|
|
458
|
-
CREATE TABLE plans (
|
|
459
|
-
project_id TEXT NOT NULL,
|
|
460
|
-
protocol_id TEXT NOT NULL,
|
|
461
|
-
plan_json TEXT NOT NULL,
|
|
462
|
-
updated_at TEXT NOT NULL,
|
|
463
|
-
PRIMARY KEY(project_id, protocol_id),
|
|
464
|
-
FOREIGN KEY(project_id, protocol_id) REFERENCES protocols(project_id, id)
|
|
465
|
-
);
|
|
466
|
-
INSERT INTO plans (project_id, protocol_id, plan_json, updated_at)
|
|
467
|
-
SELECT p.project_id, legacy.protocol_id, legacy.plan_json, legacy.updated_at
|
|
468
|
-
FROM plans_legacy_global_identity legacy
|
|
469
|
-
JOIN protocols p ON p.id = legacy.protocol_id;
|
|
470
|
-
|
|
471
514
|
CREATE TABLE merge_queue (
|
|
472
515
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
473
516
|
protocol_id TEXT NOT NULL,
|
|
@@ -554,7 +597,6 @@ function migrateProjectScopedIdentity(db) {
|
|
|
554
597
|
artifact_root_kind, index_json, created_at, updated_at, completed_at
|
|
555
598
|
FROM flow_runs_legacy_global_identity;
|
|
556
599
|
|
|
557
|
-
DROP TABLE plans_legacy_global_identity;
|
|
558
600
|
DROP TABLE merge_queue_legacy_global_identity;
|
|
559
601
|
DROP TABLE worktree_records_legacy_global_identity;
|
|
560
602
|
DROP TABLE flow_runs_legacy_global_identity;
|
package/dist/storage/paths.js
CHANGED
|
@@ -24,9 +24,6 @@ export function runtimeProtocolDir(ddFlowHome, projectId, protocolId) {
|
|
|
24
24
|
export function runtimeStateJsonPath(ddFlowHome, projectId, protocolId) {
|
|
25
25
|
return path.join(runtimeProtocolDir(ddFlowHome, projectId, protocolId), "state.json");
|
|
26
26
|
}
|
|
27
|
-
export function runtimePlanJsonPath(ddFlowHome, projectId, protocolId) {
|
|
28
|
-
return path.join(runtimeProtocolDir(ddFlowHome, projectId, protocolId), "plan.json");
|
|
29
|
-
}
|
|
30
27
|
export function runtimeRunDir(ddFlowHome, projectId, runId) {
|
|
31
28
|
return path.join(projectRuntimeRoot(ddFlowHome, projectId), "runs", runId);
|
|
32
29
|
}
|
|
@@ -39,9 +36,6 @@ export function projectRunHome(ddFlowHome, projectId, runId) {
|
|
|
39
36
|
export function projectRunJsonPath(ddFlowHome, projectId, runId) {
|
|
40
37
|
return path.join(projectRunHome(ddFlowHome, projectId, runId), "run.json");
|
|
41
38
|
}
|
|
42
|
-
export function projectRunIndexPath(ddFlowHome, projectId, runId) {
|
|
43
|
-
return path.join(projectRunHome(ddFlowHome, projectId, runId), "run-index.json");
|
|
44
|
-
}
|
|
45
39
|
export function projectRunStageDir(ddFlowHome, projectId, runId, stageDir) {
|
|
46
40
|
return path.join(projectRunHome(ddFlowHome, projectId, runId), stageDir);
|
|
47
41
|
}
|
|
@@ -51,9 +45,6 @@ export function userFacingRunDir(workspaceRoot, runId) {
|
|
|
51
45
|
export function legacyWorkspaceRunDir(workspaceRoot, runId) {
|
|
52
46
|
return userFacingRunDir(workspaceRoot, runId);
|
|
53
47
|
}
|
|
54
|
-
export function userFacingRunIndexPath(workspaceRoot, runId) {
|
|
55
|
-
return path.join(userFacingRunDir(workspaceRoot, runId), "run-index.json");
|
|
56
|
-
}
|
|
57
48
|
export function userFacingRunStageDir(workspaceRoot, runId, stageDir) {
|
|
58
49
|
return path.join(userFacingRunDir(workspaceRoot, runId), stageDir);
|
|
59
50
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deksden-com/dd-flow-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Mechanical runtime CLI for dd-flow workflows.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -9,12 +9,22 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
11
|
"README.md",
|
|
12
|
-
"CHANGELOG.md"
|
|
12
|
+
"CHANGELOG.md",
|
|
13
|
+
"tools"
|
|
13
14
|
],
|
|
14
15
|
"engines": {
|
|
15
16
|
"node": ">=26.0.0",
|
|
16
17
|
"pnpm": ">=10.0.0"
|
|
17
18
|
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc -p tsconfig.build.json && node scripts/generate-build-info.mjs && node scripts/copy-assets.mjs",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"lint": "eslint . --max-warnings=0",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"changeset": "changeset",
|
|
25
|
+
"version-packages": "changeset version",
|
|
26
|
+
"release": "pnpm run build && changeset publish"
|
|
27
|
+
},
|
|
18
28
|
"devDependencies": {
|
|
19
29
|
"@changesets/cli": "^2.31.0",
|
|
20
30
|
"@eslint/js": "^9.39.1",
|
|
@@ -32,14 +42,5 @@
|
|
|
32
42
|
"publishConfig": {
|
|
33
43
|
"access": "public"
|
|
34
44
|
},
|
|
35
|
-
"license": "MIT"
|
|
36
|
-
|
|
37
|
-
"build": "tsc -p tsconfig.build.json && node scripts/generate-build-info.mjs && node scripts/copy-assets.mjs",
|
|
38
|
-
"typecheck": "tsc --noEmit",
|
|
39
|
-
"lint": "eslint . --max-warnings=0",
|
|
40
|
-
"test": "vitest run",
|
|
41
|
-
"changeset": "changeset",
|
|
42
|
-
"version-packages": "changeset version",
|
|
43
|
-
"release": "pnpm run build && changeset publish"
|
|
44
|
-
}
|
|
45
|
-
}
|
|
45
|
+
"license": "MIT"
|
|
46
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_id": "dd-flow/managed-tool-manifest@1",
|
|
3
|
+
"tool": "wt",
|
|
4
|
+
"version": "0.72.0",
|
|
5
|
+
"repository": "https://github.com/max-sixty/worktrunk",
|
|
6
|
+
"release_tag": "v0.72.0",
|
|
7
|
+
"artifacts": {
|
|
8
|
+
"darwin-arm64": {
|
|
9
|
+
"url": "https://github.com/max-sixty/worktrunk/releases/download/v0.72.0/worktrunk-aarch64-apple-darwin.tar.xz",
|
|
10
|
+
"sha256": "7e6cf79a3ef67559240431aae93c137d9a2b28a8ccdb55b64edead904b21ff73",
|
|
11
|
+
"archive": "tar.xz"
|
|
12
|
+
},
|
|
13
|
+
"darwin-x64": {
|
|
14
|
+
"url": "https://github.com/max-sixty/worktrunk/releases/download/v0.72.0/worktrunk-x86_64-apple-darwin.tar.xz",
|
|
15
|
+
"sha256": "2356bee43a6688a03d24b27dd18ce0db1f4666f111ee06f3c829d1f248472401",
|
|
16
|
+
"archive": "tar.xz"
|
|
17
|
+
},
|
|
18
|
+
"linux-arm64": {
|
|
19
|
+
"url": "https://github.com/max-sixty/worktrunk/releases/download/v0.72.0/worktrunk-aarch64-unknown-linux-musl.tar.xz",
|
|
20
|
+
"sha256": "2f6b45fd0592e4b0f66ca3c34cbaf90c7643a7eaabf8a9c4b0e12d48251a086c",
|
|
21
|
+
"archive": "tar.xz"
|
|
22
|
+
},
|
|
23
|
+
"linux-x64": {
|
|
24
|
+
"url": "https://github.com/max-sixty/worktrunk/releases/download/v0.72.0/worktrunk-x86_64-unknown-linux-musl.tar.xz",
|
|
25
|
+
"sha256": "e91bc7ceb0623942a797317f56541a825d6a36e24d055985a8299d30345be346",
|
|
26
|
+
"archive": "tar.xz"
|
|
27
|
+
},
|
|
28
|
+
"windows-x64": {
|
|
29
|
+
"url": "https://github.com/max-sixty/worktrunk/releases/download/v0.72.0/worktrunk-x86_64-pc-windows-msvc.zip",
|
|
30
|
+
"sha256": "cd1933e9c40836df460b6feb732999d20387bfda41da6e0972b392fadd087c03",
|
|
31
|
+
"archive": "zip"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|