@deksden-com/dd-flow-cli 0.4.0 → 0.4.2

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 (43) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +25 -9
  3. package/dist/build-info.json +5 -5
  4. package/dist/cli/help.js +45 -29
  5. package/dist/cli/run-cli.js +229 -49
  6. package/dist/domain/entity-ids.js +4 -4
  7. package/dist/domain/flow-contract.js +502 -36
  8. package/dist/domain/validation.js +34 -0
  9. package/dist/protocol/local-files.js +8 -6
  10. package/dist/schemas/code-stage-report.schema.json +197 -2
  11. package/dist/schemas/flow-contract.schema.json +126 -0
  12. package/dist/schemas/flow-run-index-v3.schema.json +203 -0
  13. package/dist/schemas/flow-run-index.schema.json +22 -2
  14. package/dist/schemas/flow-run.schema.json +36 -0
  15. package/dist/schemas/merge-stage-report.schema.json +213 -2
  16. package/dist/schemas/plan-stage-report.schema.json +156 -2
  17. package/dist/schemas/release-impact.schema.json +16 -0
  18. package/dist/services/audit.js +3 -3
  19. package/dist/services/branch-context.js +17 -5
  20. package/dist/services/canon.js +0 -1
  21. package/dist/services/cleanup.js +6 -6
  22. package/dist/services/cli-operation-classifier.js +1 -1
  23. package/dist/services/compatibility-preflight.js +3 -75
  24. package/dist/services/dashboard.js +48 -11
  25. package/dist/services/engines.js +124 -13
  26. package/dist/services/hooks.js +6 -6
  27. package/dist/services/ids.js +40 -49
  28. package/dist/services/merge-queue.js +33 -26
  29. package/dist/services/merge-worker.js +2 -1
  30. package/dist/services/migrations.js +64 -0
  31. package/dist/services/plans.js +23 -16
  32. package/dist/services/projects.js +2 -2
  33. package/dist/services/prompts.js +322 -0
  34. package/dist/services/protocols.js +77 -46
  35. package/dist/services/run-projection.js +80 -0
  36. package/dist/services/runs.js +360 -22
  37. package/dist/services/schema-validation.js +35 -12
  38. package/dist/services/sessions.js +81 -3
  39. package/dist/services/status.js +32 -1
  40. package/dist/services/usage.js +233 -0
  41. package/dist/services/worktrees.js +24 -19
  42. package/dist/storage/database.js +223 -9
  43. package/package.json +1 -1
@@ -10,8 +10,8 @@ export function getDatabase(ddFlowHome) {
10
10
  const dbPath = path.join(ddFlowHome, "db.sqlite");
11
11
  const db = new DatabaseSync(dbPath);
12
12
  configureDatabase(db);
13
- db.exec("PRAGMA foreign_keys = ON");
14
13
  migrate(db);
14
+ db.exec("PRAGMA foreign_keys = ON");
15
15
  return {
16
16
  path: dbPath,
17
17
  exec: (sql) => db.exec(sql),
@@ -41,7 +41,7 @@ function migrate(db) {
41
41
  );
42
42
 
43
43
  CREATE TABLE IF NOT EXISTS protocols (
44
- id TEXT PRIMARY KEY,
44
+ id TEXT NOT NULL,
45
45
  handshake_id TEXT NOT NULL,
46
46
  project_id TEXT NOT NULL,
47
47
  project_root TEXT NOT NULL,
@@ -56,14 +56,17 @@ function migrate(db) {
56
56
  plan_path TEXT NOT NULL,
57
57
  created_at TEXT NOT NULL,
58
58
  updated_at TEXT NOT NULL,
59
+ PRIMARY KEY(project_id, id),
59
60
  FOREIGN KEY(project_id) REFERENCES projects(id)
60
61
  );
61
62
 
62
63
  CREATE TABLE IF NOT EXISTS plans (
63
- protocol_id TEXT PRIMARY KEY,
64
+ project_id TEXT NOT NULL,
65
+ protocol_id TEXT NOT NULL,
64
66
  plan_json TEXT NOT NULL,
65
67
  updated_at TEXT NOT NULL,
66
- FOREIGN KEY(protocol_id) REFERENCES protocols(id)
68
+ PRIMARY KEY(project_id, protocol_id),
69
+ FOREIGN KEY(project_id, protocol_id) REFERENCES protocols(project_id, id)
67
70
  );
68
71
 
69
72
  CREATE TABLE IF NOT EXISTS audit_events (
@@ -79,7 +82,7 @@ function migrate(db) {
79
82
 
80
83
  CREATE TABLE IF NOT EXISTS merge_queue (
81
84
  id INTEGER PRIMARY KEY AUTOINCREMENT,
82
- protocol_id TEXT NOT NULL UNIQUE,
85
+ protocol_id TEXT NOT NULL,
83
86
  project_id TEXT NOT NULL,
84
87
  status TEXT NOT NULL,
85
88
  claimed_by_session_id TEXT,
@@ -88,7 +91,8 @@ function migrate(db) {
88
91
  last_reason TEXT,
89
92
  completed_at TEXT,
90
93
  created_at TEXT NOT NULL,
91
- updated_at TEXT NOT NULL
94
+ updated_at TEXT NOT NULL,
95
+ UNIQUE(project_id, protocol_id)
92
96
  );
93
97
 
94
98
  CREATE TABLE IF NOT EXISTS merge_sessions (
@@ -244,6 +248,7 @@ function migrate(db) {
244
248
  transcript_path TEXT,
245
249
  cwd TEXT,
246
250
  metadata_json TEXT NOT NULL,
251
+ coverage_units_json TEXT NOT NULL DEFAULT '[]',
247
252
  created_at TEXT NOT NULL,
248
253
  updated_at TEXT NOT NULL,
249
254
  stopped_at TEXT,
@@ -252,7 +257,7 @@ function migrate(db) {
252
257
  );
253
258
 
254
259
  CREATE TABLE IF NOT EXISTS flow_runs (
255
- id TEXT PRIMARY KEY,
260
+ id TEXT NOT NULL,
256
261
  short_id TEXT NOT NULL,
257
262
  slug TEXT NOT NULL,
258
263
  project_id TEXT NOT NULL,
@@ -274,6 +279,7 @@ function migrate(db) {
274
279
  created_at TEXT NOT NULL,
275
280
  updated_at TEXT NOT NULL,
276
281
  completed_at TEXT,
282
+ PRIMARY KEY(project_id, id),
277
283
  FOREIGN KEY(project_id) REFERENCES projects(id)
278
284
  );
279
285
 
@@ -283,6 +289,46 @@ function migrate(db) {
283
289
  CREATE INDEX IF NOT EXISTS idx_flow_runs_short_id
284
290
  ON flow_runs(short_id);
285
291
 
292
+ CREATE TABLE IF NOT EXISTS flow_run_flag_mutations (
293
+ project_id TEXT NOT NULL,
294
+ run_id TEXT NOT NULL,
295
+ idempotency_key TEXT NOT NULL,
296
+ expected_revision INTEGER NOT NULL,
297
+ resulting_revision INTEGER NOT NULL,
298
+ result_json TEXT NOT NULL,
299
+ created_at TEXT NOT NULL,
300
+ PRIMARY KEY(project_id, run_id, idempotency_key),
301
+ FOREIGN KEY(project_id) REFERENCES projects(id)
302
+ );
303
+
304
+ CREATE TABLE IF NOT EXISTS flow_run_usage_snapshots (
305
+ id TEXT PRIMARY KEY,
306
+ project_id TEXT NOT NULL,
307
+ run_id TEXT NOT NULL,
308
+ session_id TEXT NOT NULL,
309
+ checkpoint TEXT NOT NULL,
310
+ stage TEXT,
311
+ stage_attempt TEXT,
312
+ observed_at TEXT NOT NULL,
313
+ total_tokens INTEGER,
314
+ input_tokens INTEGER,
315
+ cached_input_tokens INTEGER,
316
+ output_tokens INTEGER,
317
+ reasoning_output_tokens INTEGER,
318
+ source_kind TEXT NOT NULL,
319
+ token_event_at TEXT,
320
+ turn_id TEXT,
321
+ turn_attribution TEXT NOT NULL,
322
+ parser_version INTEGER NOT NULL,
323
+ extraction_status TEXT NOT NULL,
324
+ diagnostic_code TEXT,
325
+ created_at TEXT NOT NULL,
326
+ FOREIGN KEY(project_id) REFERENCES projects(id)
327
+ );
328
+
329
+ CREATE INDEX IF NOT EXISTS idx_flow_run_usage_snapshots_run
330
+ ON flow_run_usage_snapshots(project_id, run_id, session_id, observed_at, id);
331
+
286
332
  CREATE TABLE IF NOT EXISTS pending_flow_session_bindings (
287
333
  session_id TEXT NOT NULL,
288
334
  project_id TEXT NOT NULL,
@@ -312,7 +358,7 @@ function migrate(db) {
312
358
  );
313
359
 
314
360
  CREATE TABLE IF NOT EXISTS worktree_records (
315
- protocol_id TEXT PRIMARY KEY,
361
+ protocol_id TEXT NOT NULL,
316
362
  project_id TEXT NOT NULL,
317
363
  integration_branch TEXT,
318
364
  feature_branch TEXT NOT NULL,
@@ -325,10 +371,12 @@ function migrate(db) {
325
371
  created_at TEXT NOT NULL,
326
372
  updated_at TEXT NOT NULL,
327
373
  closed_at TEXT,
328
- FOREIGN KEY(protocol_id) REFERENCES protocols(id),
374
+ PRIMARY KEY(project_id, protocol_id),
375
+ FOREIGN KEY(project_id, protocol_id) REFERENCES protocols(project_id, id),
329
376
  FOREIGN KEY(project_id) REFERENCES projects(id)
330
377
  );
331
378
  `);
379
+ migrateProjectScopedIdentity(db);
332
380
  ensureColumn(db, "projects", "short_id", "ALTER TABLE projects ADD COLUMN short_id TEXT");
333
381
  ensureColumn(db, "projects", "slug", "ALTER TABLE projects ADD COLUMN slug TEXT");
334
382
  ensureColumn(db, "projects", "status", "ALTER TABLE projects ADD COLUMN status TEXT NOT NULL DEFAULT 'active'");
@@ -345,10 +393,176 @@ function migrate(db) {
345
393
  ensureColumn(db, "flow_sessions", "next_action", "ALTER TABLE flow_sessions ADD COLUMN next_action TEXT");
346
394
  ensureColumn(db, "flow_sessions", "metadata_json", "ALTER TABLE flow_sessions ADD COLUMN metadata_json TEXT NOT NULL DEFAULT '{}'");
347
395
  ensureColumn(db, "flow_sessions", "run_id", "ALTER TABLE flow_sessions ADD COLUMN run_id TEXT");
396
+ ensureColumn(db, "flow_sessions", "parent_session_id", "ALTER TABLE flow_sessions ADD COLUMN parent_session_id TEXT");
397
+ ensureColumn(db, "flow_sessions", "role", "ALTER TABLE flow_sessions ADD COLUMN role TEXT");
398
+ ensureColumn(db, "flow_sessions", "aspect_id", "ALTER TABLE flow_sessions ADD COLUMN aspect_id TEXT");
399
+ ensureColumn(db, "flow_sessions", "plan_item_id", "ALTER TABLE flow_sessions ADD COLUMN plan_item_id TEXT");
400
+ ensureColumn(db, "flow_sessions", "session_kind", "ALTER TABLE flow_sessions ADD COLUMN session_kind TEXT");
401
+ ensureColumn(db, "flow_sessions", "coverage_units_json", "ALTER TABLE flow_sessions ADD COLUMN coverage_units_json TEXT NOT NULL DEFAULT '[]'");
348
402
  ensureColumn(db, "flow_runs", "run_home_path", "ALTER TABLE flow_runs ADD COLUMN run_home_path TEXT");
349
403
  ensureColumn(db, "flow_runs", "layout_version", "ALTER TABLE flow_runs ADD COLUMN layout_version TEXT");
350
404
  ensureColumn(db, "flow_runs", "artifact_root_kind", "ALTER TABLE flow_runs ADD COLUMN artifact_root_kind TEXT");
351
405
  ensureColumn(db, "lane_waiters", "expires_at", "ALTER TABLE lane_waiters ADD COLUMN expires_at TEXT");
406
+ db.exec(`
407
+ CREATE INDEX IF NOT EXISTS idx_flow_runs_project_updated
408
+ ON flow_runs(project_id, updated_at DESC);
409
+ CREATE INDEX IF NOT EXISTS idx_flow_runs_short_id
410
+ ON flow_runs(short_id);
411
+ `);
412
+ }
413
+ function migrateProjectScopedIdentity(db) {
414
+ const protocolColumns = db.prepare("PRAGMA table_info(protocols)").all();
415
+ const legacyGlobalPrimaryKey = protocolColumns.some((column) => column.name === "id" && column.pk === 1)
416
+ && protocolColumns.some((column) => column.name === "project_id" && column.pk === 0);
417
+ if (!legacyGlobalPrimaryKey)
418
+ return;
419
+ db.exec(`
420
+ PRAGMA foreign_keys = OFF;
421
+ BEGIN IMMEDIATE;
422
+
423
+ ALTER TABLE plans RENAME TO plans_legacy_global_identity;
424
+ ALTER TABLE merge_queue RENAME TO merge_queue_legacy_global_identity;
425
+ ALTER TABLE worktree_records RENAME TO worktree_records_legacy_global_identity;
426
+ ALTER TABLE flow_runs RENAME TO flow_runs_legacy_global_identity;
427
+ ALTER TABLE protocols RENAME TO protocols_legacy_global_identity;
428
+
429
+ CREATE TABLE protocols (
430
+ id TEXT NOT NULL,
431
+ handshake_id TEXT NOT NULL,
432
+ project_id TEXT NOT NULL,
433
+ project_root TEXT NOT NULL,
434
+ status TEXT NOT NULL,
435
+ stage TEXT NOT NULL,
436
+ next_action TEXT,
437
+ route_json TEXT NOT NULL,
438
+ workspace_json TEXT NOT NULL,
439
+ blockers_json TEXT NOT NULL,
440
+ active_def_json TEXT NOT NULL,
441
+ state_path TEXT NOT NULL,
442
+ plan_path TEXT NOT NULL,
443
+ created_at TEXT NOT NULL,
444
+ updated_at TEXT NOT NULL,
445
+ PRIMARY KEY(project_id, id),
446
+ FOREIGN KEY(project_id) REFERENCES projects(id)
447
+ );
448
+
449
+ INSERT INTO protocols
450
+ (id, handshake_id, project_id, project_root, status, stage, next_action,
451
+ route_json, workspace_json, blockers_json, active_def_json, state_path,
452
+ plan_path, created_at, updated_at)
453
+ SELECT id, handshake_id, project_id, project_root, status, stage,
454
+ next_action, route_json, workspace_json, blockers_json, active_def_json,
455
+ state_path, plan_path, created_at, updated_at
456
+ FROM protocols_legacy_global_identity;
457
+
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
+ CREATE TABLE merge_queue (
472
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
473
+ protocol_id TEXT NOT NULL,
474
+ project_id TEXT NOT NULL,
475
+ status TEXT NOT NULL,
476
+ claimed_by_session_id TEXT,
477
+ claimed_at TEXT,
478
+ attempts_count INTEGER NOT NULL DEFAULT 0,
479
+ last_reason TEXT,
480
+ completed_at TEXT,
481
+ created_at TEXT NOT NULL,
482
+ updated_at TEXT NOT NULL,
483
+ UNIQUE(project_id, protocol_id)
484
+ );
485
+ INSERT INTO merge_queue
486
+ (id, protocol_id, project_id, status, claimed_by_session_id, claimed_at,
487
+ attempts_count, last_reason, completed_at, created_at, updated_at)
488
+ SELECT id, protocol_id, project_id, status, claimed_by_session_id,
489
+ claimed_at, COALESCE(attempts_count, 0), last_reason, completed_at,
490
+ created_at, updated_at
491
+ FROM merge_queue_legacy_global_identity;
492
+
493
+ CREATE TABLE worktree_records (
494
+ protocol_id TEXT NOT NULL,
495
+ project_id TEXT NOT NULL,
496
+ integration_branch TEXT,
497
+ feature_branch TEXT NOT NULL,
498
+ base_ref TEXT NOT NULL,
499
+ worktree_path TEXT NOT NULL,
500
+ worktrunk_metadata_json TEXT NOT NULL,
501
+ bootstrap_status TEXT NOT NULL,
502
+ status TEXT NOT NULL,
503
+ last_command_result_json TEXT NOT NULL,
504
+ created_at TEXT NOT NULL,
505
+ updated_at TEXT NOT NULL,
506
+ closed_at TEXT,
507
+ PRIMARY KEY(project_id, protocol_id),
508
+ FOREIGN KEY(project_id, protocol_id) REFERENCES protocols(project_id, id),
509
+ FOREIGN KEY(project_id) REFERENCES projects(id)
510
+ );
511
+ INSERT INTO worktree_records
512
+ (protocol_id, project_id, integration_branch, feature_branch, base_ref,
513
+ worktree_path, worktrunk_metadata_json, bootstrap_status, status,
514
+ last_command_result_json, created_at, updated_at, closed_at)
515
+ SELECT protocol_id, project_id, integration_branch, feature_branch,
516
+ base_ref, worktree_path, worktrunk_metadata_json, bootstrap_status,
517
+ status, last_command_result_json, created_at, updated_at, closed_at
518
+ FROM worktree_records_legacy_global_identity;
519
+
520
+ CREATE TABLE flow_runs (
521
+ id TEXT NOT NULL,
522
+ short_id TEXT NOT NULL,
523
+ slug TEXT NOT NULL,
524
+ project_id TEXT NOT NULL,
525
+ project_root TEXT NOT NULL,
526
+ workspace_root TEXT NOT NULL,
527
+ flow_kind TEXT NOT NULL,
528
+ subject_type TEXT NOT NULL,
529
+ subject_id TEXT NOT NULL,
530
+ status TEXT NOT NULL,
531
+ verdict TEXT NOT NULL,
532
+ next_action TEXT,
533
+ runtime_path TEXT NOT NULL,
534
+ run_dir TEXT NOT NULL,
535
+ run_index_path TEXT NOT NULL,
536
+ run_home_path TEXT,
537
+ layout_version TEXT,
538
+ artifact_root_kind TEXT,
539
+ index_json TEXT NOT NULL,
540
+ created_at TEXT NOT NULL,
541
+ updated_at TEXT NOT NULL,
542
+ completed_at TEXT,
543
+ PRIMARY KEY(project_id, id),
544
+ FOREIGN KEY(project_id) REFERENCES projects(id)
545
+ );
546
+ INSERT INTO flow_runs
547
+ (id, short_id, slug, project_id, project_root, workspace_root, flow_kind,
548
+ subject_type, subject_id, status, verdict, next_action, runtime_path,
549
+ run_dir, run_index_path, run_home_path, layout_version,
550
+ artifact_root_kind, index_json, created_at, updated_at, completed_at)
551
+ SELECT id, short_id, slug, project_id, project_root, workspace_root,
552
+ flow_kind, subject_type, subject_id, status, verdict, next_action,
553
+ runtime_path, run_dir, run_index_path, run_home_path, layout_version,
554
+ artifact_root_kind, index_json, created_at, updated_at, completed_at
555
+ FROM flow_runs_legacy_global_identity;
556
+
557
+ DROP TABLE plans_legacy_global_identity;
558
+ DROP TABLE merge_queue_legacy_global_identity;
559
+ DROP TABLE worktree_records_legacy_global_identity;
560
+ DROP TABLE flow_runs_legacy_global_identity;
561
+ DROP TABLE protocols_legacy_global_identity;
562
+
563
+ COMMIT;
564
+ PRAGMA foreign_keys = ON;
565
+ `);
352
566
  }
353
567
  function ensureColumn(db, table, column, sql) {
354
568
  const columns = db.prepare(`PRAGMA table_info(${table})`).all();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deksden-com/dd-flow-cli",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Mechanical runtime CLI for dd-flow workflows.",
5
5
  "type": "module",
6
6
  "bin": {