@deksden-com/dd-flow-cli 0.4.1 → 0.5.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +33 -4
  2. package/dist/build-info.json +6 -6
  3. package/dist/cli/help.js +14 -3
  4. package/dist/cli/run-cli.js +32 -16
  5. package/dist/domain/flow-contract.js +81 -2
  6. package/dist/domain/validation.js +56 -28
  7. package/dist/protocol/local-files.js +1 -16
  8. package/dist/schemas/code-stage-report.schema.json +2 -2
  9. package/dist/schemas/flow-contract.schema.json +150 -94
  10. package/dist/schemas/flow-run.schema.json +129 -23
  11. package/dist/schemas/mb-upgrade-review-data.schema.json +2 -2
  12. package/dist/schemas/memorybank-permissions-preflight.schema.json +13 -73
  13. package/dist/schemas/merge-stage-report.schema.json +2 -2
  14. package/dist/schemas/plan-stage-report.schema.json +38 -335
  15. package/dist/schemas/project-flow-pack-manifest.schema.json +4 -4
  16. package/dist/schemas/protocol-plan.schema.json +197 -0
  17. package/dist/schemas/release-impact.schema.json +9 -5
  18. package/dist/schemas/session-usage.schema.json +16 -0
  19. package/dist/schemas/stage-finish-input.schema.json +20 -0
  20. package/dist/schemas/stage-prompt.schema.json +31 -0
  21. package/dist/schemas/stage-report.schema.json +20 -0
  22. package/dist/schemas/stage-start-response.schema.json +29 -0
  23. package/dist/schemas/timeline-event.schema.json +29 -0
  24. package/dist/schemas/worktrunk-workspace.schema.json +19 -0
  25. package/dist/services/branch-context.js +9 -4
  26. package/dist/services/dashboard.js +51 -26
  27. package/dist/services/engines.js +86 -19
  28. package/dist/services/hooks.js +80 -246
  29. package/dist/services/memory-permissions.js +77 -69
  30. package/dist/services/plan-runtime.js +124 -0
  31. package/dist/services/plans.js +22 -84
  32. package/dist/services/projects.js +2 -1
  33. package/dist/services/prompts.js +26 -21
  34. package/dist/services/protocols.js +29 -25
  35. package/dist/services/run-projection.js +77 -11
  36. package/dist/services/runs.js +95 -61
  37. package/dist/services/schema-validation.js +168 -7
  38. package/dist/services/sessions.js +132 -68
  39. package/dist/services/stage-lifecycle.js +572 -0
  40. package/dist/services/tooling.js +285 -0
  41. package/dist/services/usage.js +183 -30
  42. package/dist/services/version-status.js +1 -1
  43. package/dist/services/worktrees.js +88 -39
  44. package/dist/storage/database.js +72 -30
  45. package/dist/storage/paths.js +0 -9
  46. package/package.json +14 -13
  47. package/tools/worktrunk-manifest.json +34 -0
  48. package/dist/schemas/flow-run-index-v3.schema.json +0 -203
  49. 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
- const worktrunkBinEnv = "DD_FLOW_WORKTRUNK_BIN";
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: detectWorktrunk(context)
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 = requireWorktrunk(context);
41
- const worktreePath = path.resolve(input.path);
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("tool_unavailable", "Worktrunk command failed", 1, { command: sanitizeCommand(command), result });
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: detectWorktrunk(context) };
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: [], blockers: [] }
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 Boolean(relative && !relative.startsWith("..") && !path.isAbsolute(relative) && !relative.startsWith(".tasks"));
257
+ return !relative || (!relative.startsWith("..") && !path.isAbsolute(relative));
209
258
  }
@@ -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 plans (
63
+ CREATE TABLE IF NOT EXISTS plan_bindings (
64
64
  project_id TEXT NOT NULL,
65
65
  protocol_id TEXT NOT NULL,
66
- plan_json TEXT NOT NULL,
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 pending_flow_session_bindings (
333
- session_id TEXT NOT NULL,
354
+ CREATE TABLE IF NOT EXISTS codex_hook_events (
355
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
334
356
  project_id TEXT NOT NULL,
335
- payload_json TEXT NOT NULL,
336
- cwd TEXT,
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 codex_hook_events (
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
- session_id TEXT,
351
- turn_id TEXT,
352
- event_name TEXT NOT NULL,
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
- sanitized_summary TEXT NOT NULL,
356
- created_at TEXT NOT NULL,
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;
@@ -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.4.1",
3
+ "version": "0.5.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
- "scripts": {
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
+ }