opencastle 0.31.7 → 0.32.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.
Files changed (220) hide show
  1. package/README.md +4 -1
  2. package/bin/cli.mjs +15 -0
  3. package/dist/cli/agents.d.ts.map +1 -1
  4. package/dist/cli/agents.js +19 -5
  5. package/dist/cli/agents.js.map +1 -1
  6. package/dist/cli/artifacts-cli.d.ts +3 -0
  7. package/dist/cli/artifacts-cli.d.ts.map +1 -0
  8. package/dist/cli/artifacts-cli.js +36 -0
  9. package/dist/cli/artifacts-cli.js.map +1 -0
  10. package/dist/cli/baselines.d.ts.map +1 -1
  11. package/dist/cli/baselines.js +11 -0
  12. package/dist/cli/baselines.js.map +1 -1
  13. package/dist/cli/convoy/artifacts.d.ts +25 -0
  14. package/dist/cli/convoy/artifacts.d.ts.map +1 -0
  15. package/dist/cli/convoy/artifacts.js +129 -0
  16. package/dist/cli/convoy/artifacts.js.map +1 -0
  17. package/dist/cli/convoy/artifacts.test.d.ts +2 -0
  18. package/dist/cli/convoy/artifacts.test.d.ts.map +1 -0
  19. package/dist/cli/convoy/artifacts.test.js +169 -0
  20. package/dist/cli/convoy/artifacts.test.js.map +1 -0
  21. package/dist/cli/convoy/compaction.d.ts +23 -0
  22. package/dist/cli/convoy/compaction.d.ts.map +1 -0
  23. package/dist/cli/convoy/compaction.js +117 -0
  24. package/dist/cli/convoy/compaction.js.map +1 -0
  25. package/dist/cli/convoy/compaction.test.d.ts +2 -0
  26. package/dist/cli/convoy/compaction.test.d.ts.map +1 -0
  27. package/dist/cli/convoy/compaction.test.js +205 -0
  28. package/dist/cli/convoy/compaction.test.js.map +1 -0
  29. package/dist/cli/convoy/contracts.d.ts +22 -0
  30. package/dist/cli/convoy/contracts.d.ts.map +1 -0
  31. package/dist/cli/convoy/contracts.js +254 -0
  32. package/dist/cli/convoy/contracts.js.map +1 -0
  33. package/dist/cli/convoy/contracts.test.d.ts +2 -0
  34. package/dist/cli/convoy/contracts.test.d.ts.map +1 -0
  35. package/dist/cli/convoy/contracts.test.js +239 -0
  36. package/dist/cli/convoy/contracts.test.js.map +1 -0
  37. package/dist/cli/convoy/dag-analysis.d.ts +40 -0
  38. package/dist/cli/convoy/dag-analysis.d.ts.map +1 -0
  39. package/dist/cli/convoy/dag-analysis.js +282 -0
  40. package/dist/cli/convoy/dag-analysis.js.map +1 -0
  41. package/dist/cli/convoy/dag-analysis.test.d.ts +2 -0
  42. package/dist/cli/convoy/dag-analysis.test.d.ts.map +1 -0
  43. package/dist/cli/convoy/dag-analysis.test.js +289 -0
  44. package/dist/cli/convoy/dag-analysis.test.js.map +1 -0
  45. package/dist/cli/convoy/effort-scaling.d.ts +20 -0
  46. package/dist/cli/convoy/effort-scaling.d.ts.map +1 -0
  47. package/dist/cli/convoy/effort-scaling.js +82 -0
  48. package/dist/cli/convoy/effort-scaling.js.map +1 -0
  49. package/dist/cli/convoy/effort-scaling.test.d.ts +2 -0
  50. package/dist/cli/convoy/effort-scaling.test.d.ts.map +1 -0
  51. package/dist/cli/convoy/effort-scaling.test.js +120 -0
  52. package/dist/cli/convoy/effort-scaling.test.js.map +1 -0
  53. package/dist/cli/convoy/engine.d.ts.map +1 -1
  54. package/dist/cli/convoy/engine.js +280 -6
  55. package/dist/cli/convoy/engine.js.map +1 -1
  56. package/dist/cli/convoy/engine.test.js +155 -18
  57. package/dist/cli/convoy/engine.test.js.map +1 -1
  58. package/dist/cli/convoy/event-schemas.d.ts.map +1 -1
  59. package/dist/cli/convoy/event-schemas.js +55 -0
  60. package/dist/cli/convoy/event-schemas.js.map +1 -1
  61. package/dist/cli/convoy/isolation.d.ts +27 -0
  62. package/dist/cli/convoy/isolation.d.ts.map +1 -0
  63. package/dist/cli/convoy/isolation.js +120 -0
  64. package/dist/cli/convoy/isolation.js.map +1 -0
  65. package/dist/cli/convoy/isolation.test.d.ts +2 -0
  66. package/dist/cli/convoy/isolation.test.d.ts.map +1 -0
  67. package/dist/cli/convoy/isolation.test.js +105 -0
  68. package/dist/cli/convoy/isolation.test.js.map +1 -0
  69. package/dist/cli/convoy/review-stages.d.ts +9 -0
  70. package/dist/cli/convoy/review-stages.d.ts.map +1 -0
  71. package/dist/cli/convoy/review-stages.js +134 -0
  72. package/dist/cli/convoy/review-stages.js.map +1 -0
  73. package/dist/cli/convoy/review-stages.test.d.ts +2 -0
  74. package/dist/cli/convoy/review-stages.test.d.ts.map +1 -0
  75. package/dist/cli/convoy/review-stages.test.js +197 -0
  76. package/dist/cli/convoy/review-stages.test.js.map +1 -0
  77. package/dist/cli/convoy/skill-refinement.d.ts +39 -0
  78. package/dist/cli/convoy/skill-refinement.d.ts.map +1 -0
  79. package/dist/cli/convoy/skill-refinement.js +239 -0
  80. package/dist/cli/convoy/skill-refinement.js.map +1 -0
  81. package/dist/cli/convoy/skill-refinement.test.d.ts +2 -0
  82. package/dist/cli/convoy/skill-refinement.test.d.ts.map +1 -0
  83. package/dist/cli/convoy/skill-refinement.test.js +230 -0
  84. package/dist/cli/convoy/skill-refinement.test.js.map +1 -0
  85. package/dist/cli/convoy/spec-builder.d.ts +1 -0
  86. package/dist/cli/convoy/spec-builder.d.ts.map +1 -1
  87. package/dist/cli/convoy/spec-builder.js +11 -0
  88. package/dist/cli/convoy/spec-builder.js.map +1 -1
  89. package/dist/cli/convoy/spec-builder.test.js +54 -0
  90. package/dist/cli/convoy/spec-builder.test.js.map +1 -1
  91. package/dist/cli/convoy/store.d.ts +3 -2
  92. package/dist/cli/convoy/store.d.ts.map +1 -1
  93. package/dist/cli/convoy/store.js +20 -2
  94. package/dist/cli/convoy/store.js.map +1 -1
  95. package/dist/cli/convoy/store.test.js +15 -15
  96. package/dist/cli/convoy/store.test.js.map +1 -1
  97. package/dist/cli/convoy/tdd-gate.d.ts +15 -0
  98. package/dist/cli/convoy/tdd-gate.d.ts.map +1 -0
  99. package/dist/cli/convoy/tdd-gate.js +119 -0
  100. package/dist/cli/convoy/tdd-gate.js.map +1 -0
  101. package/dist/cli/convoy/tdd-gate.test.d.ts +2 -0
  102. package/dist/cli/convoy/tdd-gate.test.d.ts.map +1 -0
  103. package/dist/cli/convoy/tdd-gate.test.js +227 -0
  104. package/dist/cli/convoy/tdd-gate.test.js.map +1 -0
  105. package/dist/cli/convoy/types.d.ts +91 -0
  106. package/dist/cli/convoy/types.d.ts.map +1 -1
  107. package/dist/cli/convoy/types.js +8 -0
  108. package/dist/cli/convoy/types.js.map +1 -1
  109. package/dist/cli/insights.d.ts +3 -0
  110. package/dist/cli/insights.d.ts.map +1 -0
  111. package/dist/cli/insights.js +94 -0
  112. package/dist/cli/insights.js.map +1 -0
  113. package/dist/cli/lesson.d.ts.map +1 -1
  114. package/dist/cli/lesson.js +7 -0
  115. package/dist/cli/lesson.js.map +1 -1
  116. package/dist/cli/log.d.ts.map +1 -1
  117. package/dist/cli/log.js +7 -0
  118. package/dist/cli/log.js.map +1 -1
  119. package/dist/cli/package-config.d.ts +12 -0
  120. package/dist/cli/package-config.d.ts.map +1 -0
  121. package/dist/cli/package-config.js +37 -0
  122. package/dist/cli/package-config.js.map +1 -0
  123. package/dist/cli/package.d.ts +23 -0
  124. package/dist/cli/package.d.ts.map +1 -0
  125. package/dist/cli/package.js +285 -0
  126. package/dist/cli/package.js.map +1 -0
  127. package/dist/cli/package.test.d.ts +2 -0
  128. package/dist/cli/package.test.d.ts.map +1 -0
  129. package/dist/cli/package.test.js +236 -0
  130. package/dist/cli/package.test.js.map +1 -0
  131. package/dist/cli/pipeline.d.ts +6 -0
  132. package/dist/cli/pipeline.d.ts.map +1 -1
  133. package/dist/cli/pipeline.js +15 -2
  134. package/dist/cli/pipeline.js.map +1 -1
  135. package/dist/cli/run/schema.d.ts.map +1 -1
  136. package/dist/cli/run/schema.js +32 -0
  137. package/dist/cli/run/schema.js.map +1 -1
  138. package/dist/cli/run/schema.test.js +51 -0
  139. package/dist/cli/run/schema.test.js.map +1 -1
  140. package/dist/cli/skills.d.ts +3 -0
  141. package/dist/cli/skills.d.ts.map +1 -0
  142. package/dist/cli/skills.js +107 -0
  143. package/dist/cli/skills.js.map +1 -0
  144. package/dist/cli/types.d.ts +4 -1
  145. package/dist/cli/types.d.ts.map +1 -1
  146. package/dist/dashboard/scripts/etl.d.ts.map +1 -1
  147. package/dist/dashboard/scripts/etl.js +44 -11
  148. package/dist/dashboard/scripts/etl.js.map +1 -1
  149. package/package.json +2 -1
  150. package/src/cli/agents.ts +20 -5
  151. package/src/cli/artifacts-cli.ts +41 -0
  152. package/src/cli/baselines.ts +12 -0
  153. package/src/cli/convoy/artifacts.test.ts +201 -0
  154. package/src/cli/convoy/artifacts.ts +186 -0
  155. package/src/cli/convoy/compaction.test.ts +245 -0
  156. package/src/cli/convoy/compaction.ts +164 -0
  157. package/src/cli/convoy/contracts.test.ts +279 -0
  158. package/src/cli/convoy/contracts.ts +280 -0
  159. package/src/cli/convoy/dag-analysis.test.ts +349 -0
  160. package/src/cli/convoy/dag-analysis.ts +371 -0
  161. package/src/cli/convoy/effort-scaling.test.ts +140 -0
  162. package/src/cli/convoy/effort-scaling.ts +90 -0
  163. package/src/cli/convoy/engine.test.ts +175 -18
  164. package/src/cli/convoy/engine.ts +301 -7
  165. package/src/cli/convoy/event-schemas.ts +55 -0
  166. package/src/cli/convoy/isolation.test.ts +137 -0
  167. package/src/cli/convoy/isolation.ts +165 -0
  168. package/src/cli/convoy/review-stages.test.ts +235 -0
  169. package/src/cli/convoy/review-stages.ts +166 -0
  170. package/src/cli/convoy/skill-refinement.test.ts +277 -0
  171. package/src/cli/convoy/skill-refinement.ts +306 -0
  172. package/src/cli/convoy/spec-builder.test.ts +61 -0
  173. package/src/cli/convoy/spec-builder.ts +9 -0
  174. package/src/cli/convoy/store.test.ts +15 -15
  175. package/src/cli/convoy/store.ts +26 -4
  176. package/src/cli/convoy/tdd-gate.test.ts +281 -0
  177. package/src/cli/convoy/tdd-gate.ts +154 -0
  178. package/src/cli/convoy/types.ts +51 -0
  179. package/src/cli/insights.ts +99 -0
  180. package/src/cli/lesson.ts +8 -0
  181. package/src/cli/log.ts +8 -0
  182. package/src/cli/package-config.ts +48 -0
  183. package/src/cli/package.test.ts +276 -0
  184. package/src/cli/package.ts +329 -0
  185. package/src/cli/pipeline.ts +21 -2
  186. package/src/cli/run/schema.test.ts +58 -0
  187. package/src/cli/run/schema.ts +33 -0
  188. package/src/cli/skills.ts +121 -0
  189. package/src/cli/types.ts +4 -1
  190. package/src/dashboard/dist/_astro/index.D6quLrA6.css +1 -0
  191. package/src/dashboard/dist/data/convoy-list.json +21 -7
  192. package/src/dashboard/dist/data/convoys/demo-api-v2.json +3 -3
  193. package/src/dashboard/dist/data/convoys/demo-auth-revamp.json +5 -5
  194. package/src/dashboard/dist/data/convoys/demo-convoy-1.json +2 -2
  195. package/src/dashboard/dist/data/convoys/demo-convoy-2.json +1 -1
  196. package/src/dashboard/dist/data/convoys/demo-dashboard-ui.json +7 -7
  197. package/src/dashboard/dist/data/convoys/demo-data-pipeline.json +3 -3
  198. package/src/dashboard/dist/data/convoys/demo-deploy-ci.json +2 -2
  199. package/src/dashboard/dist/data/convoys/demo-docs-update.json +2 -2
  200. package/src/dashboard/dist/data/convoys/demo-perf-opt.json +4 -4
  201. package/src/dashboard/dist/index.html +306 -33
  202. package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
  203. package/src/dashboard/public/data/convoy-list.json +21 -7
  204. package/src/dashboard/public/data/convoys/demo-api-v2.json +3 -3
  205. package/src/dashboard/public/data/convoys/demo-auth-revamp.json +5 -5
  206. package/src/dashboard/public/data/convoys/demo-convoy-1.json +2 -2
  207. package/src/dashboard/public/data/convoys/demo-convoy-2.json +1 -1
  208. package/src/dashboard/public/data/convoys/demo-dashboard-ui.json +7 -7
  209. package/src/dashboard/public/data/convoys/demo-data-pipeline.json +3 -3
  210. package/src/dashboard/public/data/convoys/demo-deploy-ci.json +2 -2
  211. package/src/dashboard/public/data/convoys/demo-docs-update.json +2 -2
  212. package/src/dashboard/public/data/convoys/demo-perf-opt.json +4 -4
  213. package/src/dashboard/scripts/etl.test.ts +14 -0
  214. package/src/dashboard/scripts/etl.ts +48 -16
  215. package/src/dashboard/scripts/generate-demo-db.ts +18 -10
  216. package/src/dashboard/src/pages/index.astro +348 -45
  217. package/src/dashboard/src/styles/dashboard.css +56 -0
  218. package/src/orchestrator/prompts/assess-complexity.prompt.md +13 -0
  219. package/src/orchestrator/prompts/generate-convoy.prompt.md +19 -0
  220. package/src/dashboard/dist/_astro/index.BRDFmNzR.css +0 -1
@@ -1,25 +1,25 @@
1
1
  {
2
- "hash": "c528922f",
2
+ "hash": "42ad0be8",
3
3
  "configHash": "30f8ea04",
4
- "lockfileHash": "63c2924c",
5
- "browserHash": "aa68e6f4",
4
+ "lockfileHash": "7ba8cfcb",
5
+ "browserHash": "aa161107",
6
6
  "optimized": {
7
7
  "astro > cssesc": {
8
8
  "src": "../../../../../node_modules/cssesc/cssesc.js",
9
9
  "file": "astro___cssesc.js",
10
- "fileHash": "b21790d2",
10
+ "fileHash": "143daaef",
11
11
  "needsInterop": true
12
12
  },
13
13
  "astro > aria-query": {
14
14
  "src": "../../../../../node_modules/aria-query/lib/index.js",
15
15
  "file": "astro___aria-query.js",
16
- "fileHash": "641b31ce",
16
+ "fileHash": "2d31d52d",
17
17
  "needsInterop": true
18
18
  },
19
19
  "astro > axobject-query": {
20
20
  "src": "../../../../../node_modules/axobject-query/lib/index.js",
21
21
  "file": "astro___axobject-query.js",
22
- "fileHash": "6c823ca6",
22
+ "fileHash": "6161fe29",
23
23
  "needsInterop": true
24
24
  }
25
25
  },
@@ -6,7 +6,9 @@
6
6
  "created_at": "2026-03-11T08:00:00.000Z",
7
7
  "finished_at": null,
8
8
  "total_tokens": null,
9
- "total_cost_usd": null
9
+ "total_cost_usd": null,
10
+ "task_count": 3,
11
+ "pipeline_id": null
10
12
  },
11
13
  {
12
14
  "id": "demo-docs-update",
@@ -15,7 +17,9 @@
15
17
  "created_at": "2026-02-28T15:00:00.000Z",
16
18
  "finished_at": "2026-02-28T15:22:00.000Z",
17
19
  "total_tokens": 14800,
18
- "total_cost_usd": 1.48
20
+ "total_cost_usd": 1.48,
21
+ "task_count": 3,
22
+ "pipeline_id": null
19
23
  },
20
24
  {
21
25
  "id": "demo-data-pipeline",
@@ -24,7 +28,9 @@
24
28
  "created_at": "2026-02-22T13:00:00.000Z",
25
29
  "finished_at": "2026-02-22T13:38:00.000Z",
26
30
  "total_tokens": 28900,
27
- "total_cost_usd": 2.89
31
+ "total_cost_usd": 2.89,
32
+ "task_count": 4,
33
+ "pipeline_id": null
28
34
  },
29
35
  {
30
36
  "id": "demo-perf-opt",
@@ -33,7 +39,9 @@
33
39
  "created_at": "2026-02-17T10:00:00.000Z",
34
40
  "finished_at": "2026-02-17T11:02:00.000Z",
35
41
  "total_tokens": 37200,
36
- "total_cost_usd": 3.72
42
+ "total_cost_usd": 3.72,
43
+ "task_count": 5,
44
+ "pipeline_id": null
37
45
  },
38
46
  {
39
47
  "id": "demo-api-v2",
@@ -42,7 +50,9 @@
42
50
  "created_at": "2026-02-12T16:00:00.000Z",
43
51
  "finished_at": "2026-02-12T16:28:00.000Z",
44
52
  "total_tokens": 24600,
45
- "total_cost_usd": 2.46
53
+ "total_cost_usd": 2.46,
54
+ "task_count": 3,
55
+ "pipeline_id": null
46
56
  },
47
57
  {
48
58
  "id": "demo-dashboard-ui",
@@ -51,7 +61,9 @@
51
61
  "created_at": "2026-02-07T14:00:00.000Z",
52
62
  "finished_at": "2026-02-07T15:38:00.000Z",
53
63
  "total_tokens": 78400,
54
- "total_cost_usd": 7.84
64
+ "total_cost_usd": 7.84,
65
+ "task_count": 7,
66
+ "pipeline_id": "demo-pipeline-1"
55
67
  },
56
68
  {
57
69
  "id": "demo-auth-revamp",
@@ -60,6 +72,8 @@
60
72
  "created_at": "2026-02-03T09:00:00.000Z",
61
73
  "finished_at": "2026-02-03T09:47:00.000Z",
62
74
  "total_tokens": 42850,
63
- "total_cost_usd": 4.28
75
+ "total_cost_usd": 4.28,
76
+ "task_count": 5,
77
+ "pipeline_id": "demo-pipeline-1"
64
78
  }
65
79
  ]
@@ -81,7 +81,7 @@
81
81
  {
82
82
  "type": "task_started",
83
83
  "task_id": "api-t3",
84
- "data": null,
84
+ "data": {"mechanism": "sub-agent"},
85
85
  "created_at": "2026-02-12T16:24:00.000Z"
86
86
  },
87
87
  {
@@ -93,7 +93,7 @@
93
93
  {
94
94
  "type": "task_started",
95
95
  "task_id": "api-t2",
96
- "data": null,
96
+ "data": {"mechanism": "background"},
97
97
  "created_at": "2026-02-12T16:12:00.000Z"
98
98
  },
99
99
  {
@@ -105,7 +105,7 @@
105
105
  {
106
106
  "type": "task_started",
107
107
  "task_id": "api-t1",
108
- "data": null,
108
+ "data": {"mechanism": "sub-agent"},
109
109
  "created_at": "2026-02-12T16:00:05.000Z"
110
110
  }
111
111
  ],
@@ -77,7 +77,7 @@
77
77
  {
78
78
  "type": "task_started",
79
79
  "task_id": "auth-t5",
80
- "data": null,
80
+ "data": {"mechanism": "sub-agent"},
81
81
  "created_at": "2026-02-03T09:38:00.000Z"
82
82
  },
83
83
  {
@@ -89,7 +89,7 @@
89
89
  {
90
90
  "type": "task_started",
91
91
  "task_id": "auth-t4",
92
- "data": null,
92
+ "data": {"mechanism": "sub-agent"},
93
93
  "created_at": "2026-02-03T09:25:00.000Z"
94
94
  },
95
95
  {
@@ -101,7 +101,7 @@
101
101
  {
102
102
  "type": "task_started",
103
103
  "task_id": "auth-t3",
104
- "data": null,
104
+ "data": {"mechanism": "sub-agent"},
105
105
  "created_at": "2026-02-03T09:10:00.000Z"
106
106
  },
107
107
  {
@@ -113,7 +113,7 @@
113
113
  {
114
114
  "type": "task_started",
115
115
  "task_id": "auth-t2",
116
- "data": null,
116
+ "data": {"mechanism": "background"},
117
117
  "created_at": "2026-02-03T09:10:00.000Z"
118
118
  },
119
119
  {
@@ -125,7 +125,7 @@
125
125
  {
126
126
  "type": "task_started",
127
127
  "task_id": "auth-t1",
128
- "data": null,
128
+ "data": {"mechanism": "sub-agent"},
129
129
  "created_at": "2026-02-03T09:00:05.000Z"
130
130
  }
131
131
  ],
@@ -48,7 +48,7 @@
48
48
  {
49
49
  "type": "task_started",
50
50
  "task_id": "task-1-b",
51
- "data": null,
51
+ "data": {"mechanism": "background"},
52
52
  "created_at": "2026-01-15T10:00:16.000Z"
53
53
  },
54
54
  {
@@ -60,7 +60,7 @@
60
60
  {
61
61
  "type": "task_started",
62
62
  "task_id": "task-1-a",
63
- "data": null,
63
+ "data": {"mechanism": "sub-agent"},
64
64
  "created_at": "2026-01-15T10:00:01.000Z"
65
65
  }
66
66
  ],
@@ -42,7 +42,7 @@
42
42
  {
43
43
  "type": "task_started",
44
44
  "task_id": "task-2-a",
45
- "data": null,
45
+ "data": {"mechanism": "sub-agent"},
46
46
  "created_at": "2026-01-15T10:05:01.000Z"
47
47
  }
48
48
  ],
@@ -100,7 +100,7 @@
100
100
  {
101
101
  "type": "task_started",
102
102
  "task_id": "ui-t7",
103
- "data": null,
103
+ "data": {"mechanism": "sub-agent"},
104
104
  "created_at": "2026-02-07T15:03:00.000Z"
105
105
  },
106
106
  {
@@ -112,7 +112,7 @@
112
112
  {
113
113
  "type": "task_started",
114
114
  "task_id": "ui-t6",
115
- "data": null,
115
+ "data": {"mechanism": "background"},
116
116
  "created_at": "2026-02-07T14:45:00.000Z"
117
117
  },
118
118
  {
@@ -124,7 +124,7 @@
124
124
  {
125
125
  "type": "task_started",
126
126
  "task_id": "ui-t5",
127
- "data": null,
127
+ "data": {"mechanism": "sub-agent"},
128
128
  "created_at": "2026-02-07T14:45:00.000Z"
129
129
  },
130
130
  {
@@ -136,7 +136,7 @@
136
136
  {
137
137
  "type": "task_started",
138
138
  "task_id": "ui-t4",
139
- "data": null,
139
+ "data": {"mechanism": "background"},
140
140
  "created_at": "2026-02-07T14:20:00.000Z"
141
141
  },
142
142
  {
@@ -148,7 +148,7 @@
148
148
  {
149
149
  "type": "task_started",
150
150
  "task_id": "ui-t3",
151
- "data": null,
151
+ "data": {"mechanism": "background"},
152
152
  "created_at": "2026-02-07T14:20:00.000Z"
153
153
  },
154
154
  {
@@ -160,7 +160,7 @@
160
160
  {
161
161
  "type": "task_started",
162
162
  "task_id": "ui-t2",
163
- "data": null,
163
+ "data": {"mechanism": "background"},
164
164
  "created_at": "2026-02-07T14:00:05.000Z"
165
165
  },
166
166
  {
@@ -172,7 +172,7 @@
172
172
  {
173
173
  "type": "task_started",
174
174
  "task_id": "ui-t1",
175
- "data": null,
175
+ "data": {"mechanism": "sub-agent"},
176
176
  "created_at": "2026-02-07T14:00:05.000Z"
177
177
  }
178
178
  ],
@@ -70,7 +70,7 @@
70
70
  {
71
71
  "type": "task_started",
72
72
  "task_id": "etl-t3",
73
- "data": null,
73
+ "data": {"mechanism": "sub-agent"},
74
74
  "created_at": "2026-02-22T13:31:00.000Z"
75
75
  },
76
76
  {
@@ -82,7 +82,7 @@
82
82
  {
83
83
  "type": "task_started",
84
84
  "task_id": "etl-t2",
85
- "data": null,
85
+ "data": {"mechanism": "background"},
86
86
  "created_at": "2026-02-22T13:12:00.000Z"
87
87
  },
88
88
  {
@@ -94,7 +94,7 @@
94
94
  {
95
95
  "type": "task_started",
96
96
  "task_id": "etl-t1",
97
- "data": null,
97
+ "data": {"mechanism": "sub-agent"},
98
98
  "created_at": "2026-02-22T13:00:05.000Z"
99
99
  }
100
100
  ],
@@ -69,7 +69,7 @@
69
69
  {
70
70
  "type": "task_started",
71
71
  "task_id": "ci-t2",
72
- "data": null,
72
+ "data": {"mechanism": "background"},
73
73
  "created_at": "2026-03-11T08:15:00.000Z"
74
74
  },
75
75
  {
@@ -81,7 +81,7 @@
81
81
  {
82
82
  "type": "task_started",
83
83
  "task_id": "ci-t1",
84
- "data": null,
84
+ "data": {"mechanism": "sub-agent"},
85
85
  "created_at": "2026-03-11T08:00:05.000Z"
86
86
  }
87
87
  ],
@@ -70,7 +70,7 @@
70
70
  {
71
71
  "type": "task_started",
72
72
  "task_id": "docs-t2",
73
- "data": null,
73
+ "data": {"mechanism": "sub-agent"},
74
74
  "created_at": "2026-02-28T15:15:00.000Z"
75
75
  },
76
76
  {
@@ -82,7 +82,7 @@
82
82
  {
83
83
  "type": "task_started",
84
84
  "task_id": "docs-t1",
85
- "data": null,
85
+ "data": {"mechanism": "sub-agent"},
86
86
  "created_at": "2026-02-28T15:00:05.000Z"
87
87
  }
88
88
  ],
@@ -77,7 +77,7 @@
77
77
  {
78
78
  "type": "task_started",
79
79
  "task_id": "perf-t4",
80
- "data": null,
80
+ "data": {"mechanism": "sub-agent"},
81
81
  "created_at": "2026-02-17T10:31:00.000Z"
82
82
  },
83
83
  {
@@ -89,7 +89,7 @@
89
89
  {
90
90
  "type": "task_started",
91
91
  "task_id": "perf-t3",
92
- "data": null,
92
+ "data": {"mechanism": "background"},
93
93
  "created_at": "2026-02-17T10:14:00.000Z"
94
94
  },
95
95
  {
@@ -101,7 +101,7 @@
101
101
  {
102
102
  "type": "task_started",
103
103
  "task_id": "perf-t2",
104
- "data": null,
104
+ "data": {"mechanism": "background"},
105
105
  "created_at": "2026-02-17T10:14:00.000Z"
106
106
  },
107
107
  {
@@ -113,7 +113,7 @@
113
113
  {
114
114
  "type": "task_started",
115
115
  "task_id": "perf-t1",
116
- "data": null,
116
+ "data": {"mechanism": "sub-agent"},
117
117
  "created_at": "2026-02-17T10:00:05.000Z"
118
118
  }
119
119
  ],
@@ -33,6 +33,8 @@ describe('runEtl — no database', () => {
33
33
  topAgents: [],
34
34
  topModels: [],
35
35
  dlqSummary: { count: 0, top_failure_types: [] },
36
+ taskTotals: { totalTasks: 0, totalRetries: 0 },
37
+ activityTimeline: [],
36
38
  })
37
39
  })
38
40
 
@@ -135,6 +137,18 @@ describe('runEtl — with seeded database', () => {
135
137
  expect(stats.dlqSummary).toHaveProperty('count')
136
138
  })
137
139
 
140
+ it('overall-stats.json includes taskTotals and activityTimeline', async () => {
141
+ await runEtl({ dbPath, outputDir })
142
+ const stats = JSON.parse(readFileSync(join(outputDir, 'overall-stats.json'), 'utf8'))
143
+ expect(stats).toHaveProperty('taskTotals')
144
+ expect(stats.taskTotals).toHaveProperty('totalTasks')
145
+ expect(stats.taskTotals).toHaveProperty('totalRetries')
146
+ expect(typeof stats.taskTotals.totalTasks).toBe('number')
147
+ expect(typeof stats.taskTotals.totalRetries).toBe('number')
148
+ expect(stats).toHaveProperty('activityTimeline')
149
+ expect(Array.isArray(stats.activityTimeline)).toBe(true)
150
+ })
151
+
138
152
  it('convoy-list.json contains all convoys with required fields', async () => {
139
153
  await runEtl({ dbPath, outputDir })
140
154
  const list = JSON.parse(readFileSync(join(outputDir, 'convoy-list.json'), 'utf8'))
@@ -21,6 +21,8 @@ const EMPTY_OVERALL_STATS = {
21
21
  topAgents: [] as unknown[],
22
22
  topModels: [] as unknown[],
23
23
  dlqSummary: { count: 0, top_failure_types: [] as unknown[] },
24
+ taskTotals: { totalTasks: 0, totalRetries: 0 },
25
+ activityTimeline: [] as Array<{ date: string; count: number }>,
24
26
  }
25
27
 
26
28
  export async function runEtl(options: EtlOptions): Promise<EtlResult> {
@@ -50,24 +52,41 @@ export async function runEtl(options: EtlOptions): Promise<EtlResult> {
50
52
  topAgents: store.getTopAgents(5),
51
53
  topModels: store.getTopModels(5),
52
54
  dlqSummary: store.getDlqSummary(),
55
+ taskTotals: { totalTasks: 0, totalRetries: 0 },
56
+ activityTimeline: [] as Array<{ date: string; count: number }>,
53
57
  }
54
- writeFileSync(
55
- resolve(outputDir, 'overall-stats.json'),
56
- JSON.stringify(overallStats, null, 2),
57
- 'utf8',
58
- )
59
-
60
58
  const allConvoys = store.getConvoyList(1000, 0)
61
- const convoyList = allConvoys.map(c => ({
62
- id: c.id,
63
- name: c.name,
64
- status: c.status,
65
- created_at: c.created_at,
66
- started_at: c.started_at,
67
- finished_at: c.finished_at,
68
- total_tokens: c.total_tokens,
69
- total_cost_usd: c.total_cost_usd,
70
- }))
59
+ const dateCountMap = new Map<string, number>()
60
+ for (const c of allConvoys) {
61
+ const dateKey = c.created_at ? c.created_at.slice(0, 10) : null
62
+ if (dateKey) dateCountMap.set(dateKey, (dateCountMap.get(dateKey) || 0) + 1)
63
+ }
64
+ overallStats.activityTimeline = Array.from(dateCountMap.entries())
65
+ .map(([date, count]) => ({ date, count }))
66
+ .sort((a, b) => a.date.localeCompare(b.date))
67
+
68
+ const uniquePipelineIds = [...new Set(allConvoys.map(c => c.pipeline_id).filter(Boolean))] as string[]
69
+ const pipelineNames = new Map<string, string>()
70
+ for (const pid of uniquePipelineIds) {
71
+ const pipeline = store.getPipeline(pid)
72
+ if (pipeline?.name) pipelineNames.set(pid, pipeline.name)
73
+ }
74
+ const convoyList = allConvoys.map(c => {
75
+ const taskCount = store.getTasksByConvoy(c.id).length
76
+ return {
77
+ id: c.id,
78
+ name: c.name,
79
+ status: c.status,
80
+ created_at: c.created_at,
81
+ started_at: c.started_at,
82
+ finished_at: c.finished_at,
83
+ total_tokens: c.total_tokens,
84
+ total_cost_usd: c.total_cost_usd,
85
+ task_count: taskCount,
86
+ pipeline_id: c.pipeline_id || null,
87
+ pipeline_name: c.pipeline_id ? (pipelineNames.get(c.pipeline_id) || null) : null,
88
+ }
89
+ })
71
90
  writeFileSync(
72
91
  resolve(outputDir, 'convoy-list.json'),
73
92
  JSON.stringify(convoyList, null, 2),
@@ -76,9 +95,15 @@ export async function runEtl(options: EtlOptions): Promise<EtlResult> {
76
95
 
77
96
  mkdirSync(resolve(outputDir, 'convoys'), { recursive: true })
78
97
  let detailCount = 0
98
+ let totalTasks = 0
99
+ let totalRetries = 0
79
100
  for (const c of allConvoys) {
80
101
  const detail = store.getConvoyDetails(c.id)
81
102
  if (detail) {
103
+ for (const t of detail.tasks) {
104
+ totalTasks++
105
+ totalRetries += t.retries
106
+ }
82
107
  writeFileSync(
83
108
  resolve(outputDir, 'convoys', c.id + '.json'),
84
109
  JSON.stringify(detail, null, 2),
@@ -88,6 +113,13 @@ export async function runEtl(options: EtlOptions): Promise<EtlResult> {
88
113
  }
89
114
  }
90
115
 
116
+ overallStats.taskTotals = { totalTasks, totalRetries }
117
+ writeFileSync(
118
+ resolve(outputDir, 'overall-stats.json'),
119
+ JSON.stringify(overallStats, null, 2),
120
+ 'utf8',
121
+ )
122
+
91
123
  console.log(`ETL complete: ${allConvoys.length} convoys summarized, ${detailCount} detail files generated.`)
92
124
 
93
125
  return { convoyCount: allConvoys.length }
@@ -12,6 +12,12 @@ function iso(base: string, offsetMs = 0): string {
12
12
  }
13
13
  function min(m: number): number { return m * 60_000 }
14
14
  function sec(s: number): number { return s * 1_000 }
15
+ function getMechanism(phase: number, agent: string): string {
16
+ if (agent === 'Architect' || agent === 'Reviewer' || agent === 'Security Expert') return 'sub-agent'
17
+ if (phase === 1) return 'sub-agent'
18
+ if (phase >= 3) return 'sub-agent'
19
+ return 'background'
20
+ }
15
21
 
16
22
  // ---------------------------------------------------------------------------
17
23
  // Demo timestamps – spread over 40 days (2026-02-01 → 2026-03-12)
@@ -37,9 +43,11 @@ export async function createDemoDb(outPath: string, eventsOutPath?: string): Pro
37
43
  mkdirSync(dirname(dbPath), { recursive: true })
38
44
  const store = createConvoyStore(dbPath)
39
45
 
46
+ store.insertPipeline({ id: 'demo-pipeline-1', name: 'Auth & Dashboard Sprint', status: 'done', branch: 'sprint/auth-ui', spec_yaml: 'name: auth-dashboard-sprint', convoy_specs: JSON.stringify(['auth-revamp.yml', 'dashboard-ui.yml']), created_at: dayTs(2, 9) })
47
+
40
48
  // ── Convoy 1: Auth Revamp – DONE ─────────────────────────────────────
41
49
  const C1 = dayTs(2, 9)
42
- store.insertConvoy({ id: 'demo-auth-revamp', name: 'Auth System Revamp', spec_hash: 'h1', status: 'done', branch: 'feat/auth-v2', created_at: C1, spec_yaml: 'name: auth-revamp' })
50
+ store.insertConvoy({ id: 'demo-auth-revamp', name: 'Auth System Revamp', spec_hash: 'h1', status: 'done', branch: 'feat/auth-v2', created_at: C1, spec_yaml: 'name: auth-revamp', pipeline_id: 'demo-pipeline-1' })
43
51
  store.updateConvoyStatus('demo-auth-revamp', 'done', { started_at: C1, finished_at: iso(C1, min(47)), total_tokens: 42850, total_cost_usd: 4.28 })
44
52
  const authTasks = [
45
53
  { id: 'auth-t1', phase: 1, prompt: 'Design OAuth2 token refresh architecture', agent: 'Architect', status: 'done' as const, retries: 0, tokens: 8400, cost: 0.84, start: iso(C1, sec(5)), end: iso(C1, min(9)) },
@@ -51,13 +59,13 @@ export async function createDemoDb(outPath: string, eventsOutPath?: string): Pro
51
59
  for (const t of authTasks) {
52
60
  store.insertTask({ id: t.id, convoy_id: 'demo-auth-revamp', phase: t.phase, prompt: t.prompt, agent: t.agent, adapter: 'vscode', model: t.agent === 'Architect' ? 'claude-opus-4-6' : 'claude-sonnet-4-6', timeout_ms: 120000, status: t.status, retries: t.retries, max_retries: 3, files: null, depends_on: null, gates: null, outputs: JSON.stringify({ result: 'done' }), inputs: null })
53
61
  store.updateTaskStatus(t.id, 'demo-auth-revamp', t.status, { started_at: t.start, finished_at: t.end, total_tokens: t.tokens, cost_usd: t.cost })
54
- store.insertEvent({ convoy_id: 'demo-auth-revamp', task_id: t.id, worker_id: null, type: 'task_started', data: null, created_at: t.start })
62
+ store.insertEvent({ convoy_id: 'demo-auth-revamp', task_id: t.id, worker_id: null, type: 'task_started', data: JSON.stringify({ mechanism: getMechanism(t.phase, t.agent) }), created_at: t.start })
55
63
  store.insertEvent({ convoy_id: 'demo-auth-revamp', task_id: t.id, worker_id: null, type: 'task_done', data: null, created_at: t.end })
56
64
  }
57
65
 
58
66
  // ── Convoy 2: Dashboard UI – DONE ────────────────────────────────────
59
67
  const C2 = dayTs(6, 14)
60
- store.insertConvoy({ id: 'demo-dashboard-ui', name: 'Observability Dashboard UI', spec_hash: 'h2', status: 'done', branch: 'feat/dashboard-v2', created_at: C2, spec_yaml: 'name: dashboard-ui' })
68
+ store.insertConvoy({ id: 'demo-dashboard-ui', name: 'Observability Dashboard UI', spec_hash: 'h2', status: 'done', branch: 'feat/dashboard-v2', created_at: C2, spec_yaml: 'name: dashboard-ui', pipeline_id: 'demo-pipeline-1' })
61
69
  store.updateConvoyStatus('demo-dashboard-ui', 'done', { started_at: C2, finished_at: iso(C2, min(98)), total_tokens: 78400, total_cost_usd: 7.84 })
62
70
  const uiTasks = [
63
71
  { id: 'ui-t1', phase: 1, prompt: 'Design dark-theme component system', agent: 'UI/UX Expert', status: 'done' as const, retries: 0, tokens: 14200, cost: 1.42, start: iso(C2, sec(5)), end: iso(C2, min(19)) },
@@ -71,7 +79,7 @@ export async function createDemoDb(outPath: string, eventsOutPath?: string): Pro
71
79
  for (const t of uiTasks) {
72
80
  store.insertTask({ id: t.id, convoy_id: 'demo-dashboard-ui', phase: t.phase, prompt: t.prompt, agent: t.agent, adapter: 'vscode', model: t.agent === 'UI/UX Expert' ? 'claude-opus-4-6' : 'claude-sonnet-4-6', timeout_ms: 120000, status: t.status, retries: t.retries, max_retries: 3, files: null, depends_on: null, gates: null, outputs: JSON.stringify({ result: 'done' }), inputs: null })
73
81
  store.updateTaskStatus(t.id, 'demo-dashboard-ui', t.status, { started_at: t.start, finished_at: t.end, total_tokens: t.tokens, cost_usd: t.cost })
74
- store.insertEvent({ convoy_id: 'demo-dashboard-ui', task_id: t.id, worker_id: null, type: 'task_started', data: null, created_at: t.start })
82
+ store.insertEvent({ convoy_id: 'demo-dashboard-ui', task_id: t.id, worker_id: null, type: 'task_started', data: JSON.stringify({ mechanism: getMechanism(t.phase, t.agent) }), created_at: t.start })
75
83
  store.insertEvent({ convoy_id: 'demo-dashboard-ui', task_id: t.id, worker_id: null, type: 'task_done', data: null, created_at: t.end })
76
84
  }
77
85
 
@@ -87,7 +95,7 @@ export async function createDemoDb(outPath: string, eventsOutPath?: string): Pro
87
95
  for (const t of apiTasks) {
88
96
  store.insertTask({ id: t.id, convoy_id: 'demo-api-v2', phase: t.phase, prompt: t.prompt, agent: t.agent, adapter: 'vscode', model: 'claude-sonnet-4-6', timeout_ms: 120000, status: t.status, retries: t.retries, max_retries: 3, files: null, depends_on: null, gates: null, outputs: t.status === 'gate_failed' ? JSON.stringify({ gate_failure: 'SQL injection risk detected in query builder' }) : JSON.stringify({ result: 'done' }), inputs: null })
89
97
  store.updateTaskStatus(t.id, 'demo-api-v2', t.status, { started_at: t.start, finished_at: t.end, total_tokens: t.tokens, cost_usd: t.cost })
90
- store.insertEvent({ convoy_id: 'demo-api-v2', task_id: t.id, worker_id: null, type: 'task_started', data: null, created_at: t.start })
98
+ store.insertEvent({ convoy_id: 'demo-api-v2', task_id: t.id, worker_id: null, type: 'task_started', data: JSON.stringify({ mechanism: getMechanism(t.phase, t.agent) }), created_at: t.start })
91
99
  store.insertEvent({ convoy_id: 'demo-api-v2', task_id: t.id, worker_id: null, type: t.eventType, data: t.status === 'gate_failed' ? JSON.stringify({ reason: 'SQL injection risk' }) : null, created_at: t.end })
92
100
  }
93
101
 
@@ -104,7 +112,7 @@ export async function createDemoDb(outPath: string, eventsOutPath?: string): Pro
104
112
  for (const t of perfTasks) {
105
113
  store.insertTask({ id: t.id, convoy_id: 'demo-perf-opt', phase: t.phase, prompt: t.prompt, agent: t.agent, adapter: 'vscode', model: 'claude-sonnet-4-6', timeout_ms: 120000, status: t.status, retries: t.retries, max_retries: 3, files: null, depends_on: null, gates: null, outputs: JSON.stringify({ result: 'done' }), inputs: null })
106
114
  store.updateTaskStatus(t.id, 'demo-perf-opt', t.status, { started_at: t.start, finished_at: t.end, total_tokens: t.tokens, cost_usd: t.cost })
107
- store.insertEvent({ convoy_id: 'demo-perf-opt', task_id: t.id, worker_id: null, type: 'task_started', data: null, created_at: t.start })
115
+ store.insertEvent({ convoy_id: 'demo-perf-opt', task_id: t.id, worker_id: null, type: 'task_started', data: JSON.stringify({ mechanism: getMechanism(t.phase, t.agent) }), created_at: t.start })
108
116
  store.insertEvent({ convoy_id: 'demo-perf-opt', task_id: t.id, worker_id: null, type: 'task_done', data: null, created_at: t.end })
109
117
  }
110
118
 
@@ -120,7 +128,7 @@ export async function createDemoDb(outPath: string, eventsOutPath?: string): Pro
120
128
  for (const t of etlTasks) {
121
129
  store.insertTask({ id: t.id, convoy_id: 'demo-data-pipeline', phase: t.phase, prompt: t.prompt, agent: t.agent, adapter: 'vscode', model: 'claude-sonnet-4-6', timeout_ms: 120000, status: t.status, retries: t.retries, max_retries: 3, files: null, depends_on: null, gates: null, outputs: JSON.stringify({ result: 'done' }), inputs: null })
122
130
  store.updateTaskStatus(t.id, 'demo-data-pipeline', t.status, { started_at: t.start, finished_at: t.end, total_tokens: t.tokens, cost_usd: t.cost })
123
- store.insertEvent({ convoy_id: 'demo-data-pipeline', task_id: t.id, worker_id: null, type: 'task_started', data: null, created_at: t.start })
131
+ store.insertEvent({ convoy_id: 'demo-data-pipeline', task_id: t.id, worker_id: null, type: 'task_started', data: JSON.stringify({ mechanism: getMechanism(t.phase, t.agent) }), created_at: t.start })
124
132
  store.insertEvent({ convoy_id: 'demo-data-pipeline', task_id: t.id, worker_id: null, type: 'task_done', data: null, created_at: t.end })
125
133
  }
126
134
 
@@ -137,11 +145,11 @@ export async function createDemoDb(outPath: string, eventsOutPath?: string): Pro
137
145
  store.insertTask({ id: t.id, convoy_id: 'demo-deploy-ci', phase: t.phase, prompt: t.prompt, agent: t.agent, adapter: 'vscode', model: 'claude-sonnet-4-6', timeout_ms: 120000, status: t.status, retries: t.retries, max_retries: 3, files: null, depends_on: null, gates: null, outputs: t.status === 'done' ? JSON.stringify({ result: 'done' }) : null, inputs: null })
138
146
  if (t.status === 'done') {
139
147
  store.updateTaskStatus(t.id, 'demo-deploy-ci', t.status, { started_at: t.start, finished_at: t.end, total_tokens: t.tokens, cost_usd: t.cost })
140
- store.insertEvent({ convoy_id: 'demo-deploy-ci', task_id: t.id, worker_id: null, type: 'task_started', data: null, created_at: t.start })
148
+ store.insertEvent({ convoy_id: 'demo-deploy-ci', task_id: t.id, worker_id: null, type: 'task_started', data: JSON.stringify({ mechanism: getMechanism(t.phase, t.agent) }), created_at: t.start })
141
149
  store.insertEvent({ convoy_id: 'demo-deploy-ci', task_id: t.id, worker_id: null, type: 'task_done', data: null, created_at: t.end })
142
150
  } else if (t.running) {
143
151
  store.updateTaskStatus(t.id, 'demo-deploy-ci', t.status, { started_at: t.start })
144
- store.insertEvent({ convoy_id: 'demo-deploy-ci', task_id: t.id, worker_id: null, type: 'task_started', data: null, created_at: t.start })
152
+ store.insertEvent({ convoy_id: 'demo-deploy-ci', task_id: t.id, worker_id: null, type: 'task_started', data: JSON.stringify({ mechanism: getMechanism(t.phase, t.agent) }), created_at: t.start })
145
153
  }
146
154
  }
147
155
 
@@ -156,7 +164,7 @@ export async function createDemoDb(outPath: string, eventsOutPath?: string): Pro
156
164
  for (const t of docTasks) {
157
165
  store.insertTask({ id: t.id, convoy_id: 'demo-docs-update', phase: t.phase, prompt: t.prompt, agent: t.agent, adapter: 'vscode', model: 'claude-haiku-3-5', timeout_ms: 120000, status: t.status, retries: t.retries, max_retries: 3, files: null, depends_on: null, gates: null, outputs: JSON.stringify({ result: 'done' }), inputs: null })
158
166
  store.updateTaskStatus(t.id, 'demo-docs-update', t.status, { started_at: t.start, finished_at: t.end, total_tokens: t.tokens, cost_usd: t.cost })
159
- store.insertEvent({ convoy_id: 'demo-docs-update', task_id: t.id, worker_id: null, type: 'task_started', data: null, created_at: t.start })
167
+ store.insertEvent({ convoy_id: 'demo-docs-update', task_id: t.id, worker_id: null, type: 'task_started', data: JSON.stringify({ mechanism: getMechanism(t.phase, t.agent) }), created_at: t.start })
160
168
  store.insertEvent({ convoy_id: 'demo-docs-update', task_id: t.id, worker_id: null, type: 'task_done', data: null, created_at: t.end })
161
169
  }
162
170