opencastle 0.32.0 → 0.32.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.
- package/README.md +5 -3
- package/dist/cli/adapters/antigravity.d.ts +17 -0
- package/dist/cli/adapters/antigravity.d.ts.map +1 -0
- package/dist/cli/adapters/antigravity.js +27 -0
- package/dist/cli/adapters/antigravity.js.map +1 -0
- package/dist/cli/adapters/codex.d.ts +17 -0
- package/dist/cli/adapters/codex.d.ts.map +1 -0
- package/dist/cli/adapters/codex.js +27 -0
- package/dist/cli/adapters/codex.js.map +1 -0
- package/dist/cli/adapters/index.d.ts.map +1 -1
- package/dist/cli/adapters/index.js +3 -0
- package/dist/cli/adapters/index.js.map +1 -1
- package/dist/cli/adapters/windsurf.d.ts +21 -0
- package/dist/cli/adapters/windsurf.d.ts.map +1 -0
- package/dist/cli/adapters/windsurf.js +271 -0
- package/dist/cli/adapters/windsurf.js.map +1 -0
- package/dist/cli/detect.d.ts.map +1 -1
- package/dist/cli/detect.js +3 -0
- package/dist/cli/detect.js.map +1 -1
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +25 -1
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/init.test.js +157 -2
- package/dist/cli/init.test.js.map +1 -1
- package/dist/cli/mcp.d.ts.map +1 -1
- package/dist/cli/mcp.js +10 -1
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/types.d.ts +1 -1
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/cli/types.js +3 -0
- package/dist/cli/types.js.map +1 -1
- package/dist/dashboard/scripts/etl.d.ts.map +1 -1
- package/dist/dashboard/scripts/etl.js +44 -11
- package/dist/dashboard/scripts/etl.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/adapters/antigravity.ts +30 -0
- package/src/cli/adapters/codex.ts +30 -0
- package/src/cli/adapters/index.ts +6 -0
- package/src/cli/adapters/windsurf.ts +422 -0
- package/src/cli/detect.ts +3 -0
- package/src/cli/init.test.ts +182 -2
- package/src/cli/init.ts +27 -1
- package/src/cli/mcp.ts +10 -1
- package/src/cli/types.ts +4 -1
- package/src/dashboard/dist/_astro/index.D6quLrA6.css +1 -0
- package/src/dashboard/dist/data/convoy-list.json +21 -7
- package/src/dashboard/dist/data/convoys/demo-api-v2.json +3 -3
- package/src/dashboard/dist/data/convoys/demo-auth-revamp.json +5 -5
- package/src/dashboard/dist/data/convoys/demo-convoy-1.json +2 -2
- package/src/dashboard/dist/data/convoys/demo-convoy-2.json +1 -1
- package/src/dashboard/dist/data/convoys/demo-dashboard-ui.json +7 -7
- package/src/dashboard/dist/data/convoys/demo-data-pipeline.json +3 -3
- package/src/dashboard/dist/data/convoys/demo-deploy-ci.json +2 -2
- package/src/dashboard/dist/data/convoys/demo-docs-update.json +2 -2
- package/src/dashboard/dist/data/convoys/demo-perf-opt.json +4 -4
- package/src/dashboard/dist/index.html +306 -33
- package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
- package/src/dashboard/public/data/convoy-list.json +21 -7
- package/src/dashboard/public/data/convoys/demo-api-v2.json +3 -3
- package/src/dashboard/public/data/convoys/demo-auth-revamp.json +5 -5
- package/src/dashboard/public/data/convoys/demo-convoy-1.json +2 -2
- package/src/dashboard/public/data/convoys/demo-convoy-2.json +1 -1
- package/src/dashboard/public/data/convoys/demo-dashboard-ui.json +7 -7
- package/src/dashboard/public/data/convoys/demo-data-pipeline.json +3 -3
- package/src/dashboard/public/data/convoys/demo-deploy-ci.json +2 -2
- package/src/dashboard/public/data/convoys/demo-docs-update.json +2 -2
- package/src/dashboard/public/data/convoys/demo-perf-opt.json +4 -4
- package/src/dashboard/scripts/etl.test.ts +14 -0
- package/src/dashboard/scripts/etl.ts +48 -16
- package/src/dashboard/scripts/generate-demo-db.ts +18 -10
- package/src/dashboard/src/pages/index.astro +348 -45
- package/src/dashboard/src/styles/dashboard.css +56 -0
- package/src/dashboard/dist/_astro/index.BRDFmNzR.css +0 -1
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
{
|
|
2
|
-
"hash": "
|
|
2
|
+
"hash": "c6dcc53c",
|
|
3
3
|
"configHash": "30f8ea04",
|
|
4
|
-
"lockfileHash": "
|
|
5
|
-
"browserHash": "
|
|
4
|
+
"lockfileHash": "7356d5b9",
|
|
5
|
+
"browserHash": "aba458ee",
|
|
6
6
|
"optimized": {
|
|
7
7
|
"astro > cssesc": {
|
|
8
8
|
"src": "../../../../../node_modules/cssesc/cssesc.js",
|
|
9
9
|
"file": "astro___cssesc.js",
|
|
10
|
-
"fileHash": "
|
|
10
|
+
"fileHash": "91039890",
|
|
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": "
|
|
16
|
+
"fileHash": "faea4472",
|
|
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": "
|
|
22
|
+
"fileHash": "7f1d1663",
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
63
|
+
"data": {"mechanism": "sub-agent"},
|
|
64
64
|
"created_at": "2026-01-15T10:00:01.000Z"
|
|
65
65
|
}
|
|
66
66
|
],
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
{
|
|
101
101
|
"type": "task_started",
|
|
102
102
|
"task_id": "ui-t7",
|
|
103
|
-
"data":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|